|
@@ -1,20 +1,45 @@
|
|
|
package com.fdkankan.scene.service.impl;
|
|
|
|
|
|
+import cn.hutool.core.collection.CollUtil;
|
|
|
+import cn.hutool.core.io.FileUtil;
|
|
|
+import cn.hutool.core.util.StrUtil;
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.alibaba.fastjson.JSONArray;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
+import com.fdkankan.common.constant.CommonStatus;
|
|
|
import com.fdkankan.common.constant.ErrorCode;
|
|
|
import com.fdkankan.common.exception.BusinessException;
|
|
|
+import com.fdkankan.common.util.FileUtils;
|
|
|
+import com.fdkankan.fyun.face.FYunFileServiceInterface;
|
|
|
+import com.fdkankan.model.constants.ConstantFilePath;
|
|
|
+import com.fdkankan.model.constants.UploadFilePath;
|
|
|
+import com.fdkankan.redis.constant.RedisKey;
|
|
|
+import com.fdkankan.redis.constant.RedisLockKey;
|
|
|
+import com.fdkankan.redis.util.RedisLockUtil;
|
|
|
+import com.fdkankan.redis.util.RedisUtil;
|
|
|
+import com.fdkankan.scene.bean.TagBean;
|
|
|
import com.fdkankan.scene.entity.SceneEditInfo;
|
|
|
import com.fdkankan.scene.entity.SceneEditInfoExt;
|
|
|
import com.fdkankan.scene.entity.ScenePlus;
|
|
|
+import com.fdkankan.scene.entity.ScenePlusExt;
|
|
|
import com.fdkankan.scene.mapper.ISceneEditInfoExtMapper;
|
|
|
import com.fdkankan.scene.service.ISceneEditInfoExtService;
|
|
|
import com.fdkankan.scene.service.ISceneEditInfoService;
|
|
|
+import com.fdkankan.scene.service.IScenePlusExtService;
|
|
|
import com.fdkankan.scene.service.IScenePlusService;
|
|
|
-import java.util.Objects;
|
|
|
+import com.fdkankan.scene.vo.BaseJsonArrayParamVO;
|
|
|
+import com.fdkankan.scene.vo.BaseSceneParamVO;
|
|
|
+import com.fdkankan.scene.vo.DeleteSidListParamVO;
|
|
|
+import com.fdkankan.web.response.ResultData;
|
|
|
+import org.aspectj.apache.bcel.generic.RET;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
/**
|
|
|
* <p>
|
|
|
* 服务实现类
|
|
@@ -29,7 +54,15 @@ public class SceneEditInfoExtServiceImpl extends ServiceImpl<ISceneEditInfoExtMa
|
|
|
@Autowired
|
|
|
private IScenePlusService scenePlusService;
|
|
|
@Autowired
|
|
|
+ private IScenePlusExtService scenePlusExtService;
|
|
|
+ @Autowired
|
|
|
private ISceneEditInfoService sceneEditInfoService;
|
|
|
+ @Autowired
|
|
|
+ private RedisUtil redisUtil;
|
|
|
+ @Autowired
|
|
|
+ private RedisLockUtil redisLockUtil;
|
|
|
+ @Autowired
|
|
|
+ private FYunFileServiceInterface fYunFileService;
|
|
|
|
|
|
@Override
|
|
|
public SceneEditInfoExt getByScenePlusId(long scenePlusId) {
|
|
@@ -53,4 +86,219 @@ public class SceneEditInfoExtServiceImpl extends ServiceImpl<ISceneEditInfoExtMa
|
|
|
sceneEditInfoExt.setTours(tours);
|
|
|
this.updateById(sceneEditInfoExt);
|
|
|
}
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ResultData saveBillboards(BaseJsonArrayParamVO param) throws Exception {
|
|
|
+ ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
|
|
|
+
|
|
|
+ this.addOrUpdateBillboards(param.getNum(), param.getData());
|
|
|
+
|
|
|
+ //写入本地文件,作为备份
|
|
|
+ this.writeBillboardJson(param.getNum());
|
|
|
+
|
|
|
+ //保存数据库
|
|
|
+ SceneEditInfoExt sceneEditInfoExt = this.getByScenePlusId(scenePlus.getId());
|
|
|
+ this.updateBillboards(param.getNum(), sceneEditInfoExt);
|
|
|
+// this.updateById(sceneEditInfoExt);
|
|
|
+
|
|
|
+ sceneEditInfoService.upgradeVersionById(sceneEditInfoExt.getEditInfoId());
|
|
|
+
|
|
|
+ return ResultData.ok();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ResultData deleteBillboards(DeleteSidListParamVO param) throws Exception {
|
|
|
+ ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
|
|
|
+ ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
|
|
|
+ String bucket = scenePlusExt.getYunFileBucket();
|
|
|
+
|
|
|
+ List<String> deleteSidList = param.getSidList();
|
|
|
+
|
|
|
+ this.syncBillboardsFromFileToRedis(param.getNum());
|
|
|
+
|
|
|
+ //处理删除状态数据
|
|
|
+ this.deleteBillboards(param.getNum(), deleteSidList, bucket);
|
|
|
+
|
|
|
+ //写入本地文件,作为备份
|
|
|
+ this.writeBillboardJson(param.getNum());
|
|
|
+
|
|
|
+ //保存数据库
|
|
|
+ SceneEditInfoExt sceneEditInfoExt = this.getByScenePlusId(scenePlus.getId());
|
|
|
+ this.updateBillboards(param.getNum(), sceneEditInfoExt);
|
|
|
+ sceneEditInfoService.upgradeVersionById(sceneEditInfoExt.getEditInfoId());
|
|
|
+
|
|
|
+ return ResultData.ok();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<JSONObject> listBillboards(BaseSceneParamVO param) throws Exception {
|
|
|
+
|
|
|
+ ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
|
|
|
+ SceneEditInfoExt sceneEditInfoExt = this.getByScenePlusId(scenePlus.getId());
|
|
|
+ if(sceneEditInfoExt.getBillboards() == CommonStatus.NO.code().intValue()){
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.syncBillboardsFromFileToRedis(param.getNum());
|
|
|
+ String key = String.format(RedisKey.SCENE_BILLBOARDS, param.getNum());
|
|
|
+ List<String> list = redisUtil.hgetValues(key);
|
|
|
+ List<TagBean> sortList = list.stream().map(str -> {
|
|
|
+ JSONObject jsonObject = JSON.parseObject(str);
|
|
|
+ TagBean tagBean = new TagBean();
|
|
|
+ tagBean.setCreateTime(jsonObject.getLong("createTime"));
|
|
|
+ jsonObject.remove("createTime");
|
|
|
+ tagBean.setTag(jsonObject);
|
|
|
+ return tagBean;
|
|
|
+ }).collect(Collectors.toList());
|
|
|
+ sortList.sort(Comparator.comparingLong(TagBean::getCreateTime).reversed());
|
|
|
+ return sortList.stream().map(item -> item.getTag()).collect(Collectors.toList());
|
|
|
+ }
|
|
|
+
|
|
|
+ private void deleteBillboards(String num, List<String> deleteSidList, String bucket) throws Exception {
|
|
|
+ if(CollUtil.isEmpty(deleteSidList)){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ //从redis中加载热点数据
|
|
|
+ String key = String.format(RedisKey.SCENE_BILLBOARDS, num);
|
|
|
+ List<String> deletDataList = redisUtil.hMultiGet(key, deleteSidList);
|
|
|
+ if(CollUtil.isEmpty(deletDataList))
|
|
|
+ return;
|
|
|
+ //从redis中移除热点数据
|
|
|
+ redisUtil.hdel(key, deleteSidList.toArray());
|
|
|
+
|
|
|
+ String userDataPath = String.format(UploadFilePath.USER_EDIT_PATH, num);
|
|
|
+ //删除图片音频视频等资源文件
|
|
|
+ for (String data : deletDataList) {
|
|
|
+ if(StrUtil.isBlank(data)){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ JSONObject jsonObject = JSON.parseObject(data);
|
|
|
+ String icon = jsonObject.getString("icon");
|
|
|
+ if(StrUtil.isEmpty(icon)){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ fYunFileService.deleteFile(bucket, userDataPath.concat(icon));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void addOrUpdateBillboards(String num, JSONArray data) throws Exception{
|
|
|
+ Map<String, String> addOrUpdateMap = new HashMap<>();
|
|
|
+ int i = 0;
|
|
|
+ for (Object item : data) {
|
|
|
+ JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(item));
|
|
|
+ jsonObject.put("createTime", Calendar.getInstance().getTimeInMillis() + i++);
|
|
|
+ addOrUpdateMap.put(jsonObject.getString("sid"), JSON.toJSONString(jsonObject));
|
|
|
+ }
|
|
|
+
|
|
|
+ this.syncBillboardsFromFileToRedis(num);
|
|
|
+
|
|
|
+ //处理新增和修改数据
|
|
|
+ this.addOrUpdateBillboardsHandler(num, addOrUpdateMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ 保证指示牌数据安全性,当redis宕机导致热点数据丢失时,可以从文件中读取,恢复到redis
|
|
|
+ * </p>
|
|
|
+ * @author dengsixing
|
|
|
+ * @date 2022/3/3
|
|
|
+ **/
|
|
|
+ private void syncBillboardsFromFileToRedis(String num) throws Exception{
|
|
|
+
|
|
|
+ String key = String.format(RedisKey.SCENE_BILLBOARDS, num);
|
|
|
+ boolean exist = redisUtil.hasKey(key);
|
|
|
+ if(exist){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ String lockKey = String.format(RedisLockKey.LOCK_BILLBOARDS_SYNC, num);
|
|
|
+ String lockVal = cn.hutool.core.lang.UUID.randomUUID().toString();
|
|
|
+ boolean lock = redisLockUtil.lock(lockKey, lockVal, RedisKey.EXPIRE_TIME_1_MINUTE);
|
|
|
+ if(!lock){
|
|
|
+ throw new BusinessException(ErrorCode.SYSTEM_BUSY);
|
|
|
+ }
|
|
|
+ try{
|
|
|
+ exist = redisUtil.hasKey(key);
|
|
|
+ if(exist){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ String billboardsFilePath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + "billboards.json";
|
|
|
+ String billboardsData = FileUtils.readUtf8String(billboardsFilePath);
|
|
|
+ if(StrUtil.isEmpty(billboardsData)){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ JSONArray billboardArr = JSON.parseArray(billboardsData);
|
|
|
+ if(CollUtil.isEmpty(billboardArr)){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Map<String, String> map = new HashMap<>();
|
|
|
+ for (Object o : billboardArr) {
|
|
|
+ JSONObject jo = (JSONObject)o;
|
|
|
+ map.put(jo.getString("sid"), jo.toJSONString());
|
|
|
+ }
|
|
|
+ redisUtil.hmset(key, map);
|
|
|
+ }finally {
|
|
|
+ redisLockUtil.unlockLua(lockKey, lockVal);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void addOrUpdateBillboardsHandler(String num, Map<String, String> addOrUpdateMap){
|
|
|
+ if(CollUtil.isEmpty(addOrUpdateMap))
|
|
|
+ return;
|
|
|
+
|
|
|
+ //批量写入缓存
|
|
|
+ String key = String.format(RedisKey.SCENE_BILLBOARDS, num);
|
|
|
+ redisUtil.hmset(key, addOrUpdateMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ 热点数据保存
|
|
|
+
|
|
|
+ * </p>
|
|
|
+ * @author dengsixing
|
|
|
+ * @date 2022/3/3
|
|
|
+ **/
|
|
|
+ private void writeBillboardJson(String num) throws Exception{
|
|
|
+ String lockKey = String.format(RedisLockKey.LOCK_BILLBOARDS_SYNC, num);
|
|
|
+ String lockVal = cn.hutool.core.lang.UUID.randomUUID().toString();
|
|
|
+ boolean lock = redisLockUtil.lock(lockKey, lockVal, RedisKey.EXPIRE_TIME_1_MINUTE);
|
|
|
+ if(!lock){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try{
|
|
|
+ String dataKey = String.format(RedisKey.SCENE_BILLBOARDS, num);
|
|
|
+ String hotJsonPath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + "billboards.json";
|
|
|
+ if(!redisUtil.hasKey(dataKey)){
|
|
|
+ FileUtil.del(hotJsonPath);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Map<String, String> billboardMap = redisUtil.hmget(dataKey);
|
|
|
+ List<JSONObject> billboardList = billboardMap.entrySet().stream().map(entry->JSON.parseObject(entry.getValue())).collect(Collectors.toList());
|
|
|
+ FileUtil.writeUtf8String(JSON.toJSONString(billboardList), hotJsonPath);
|
|
|
+ }finally {
|
|
|
+ redisLockUtil.unlockLua(lockKey, lockVal);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void updateBillboards(String num, SceneEditInfoExt sceneEditInfoExt){
|
|
|
+ //查询缓存是否包含热点数据
|
|
|
+ String key = String.format(RedisKey.SCENE_BILLBOARDS, num);
|
|
|
+ Map<String, String> billboardsMap = redisUtil.hmget(key);
|
|
|
+ boolean hashBillboards= false;
|
|
|
+ for (Map.Entry<String, String> tagMap : billboardsMap.entrySet()) {
|
|
|
+ if(StrUtil.isEmpty(tagMap.getValue())){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ hashBillboards = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ //更改热点状态
|
|
|
+ sceneEditInfoExt.setBillboards(hashBillboards ? CommonStatus.YES.code().intValue() : CommonStatus.NO.code().intValue());
|
|
|
+ this.updateById(sceneEditInfoExt);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
}
|