|
@@ -2,7 +2,6 @@ package com.fdkankan.scene.service.impl;
|
|
|
|
|
|
import cn.hutool.core.bean.BeanUtil;
|
|
|
import cn.hutool.core.collection.CollUtil;
|
|
|
-import cn.hutool.core.net.multipart.UploadFile;
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
import cn.hutool.core.util.ZipUtil;
|
|
|
import com.alibaba.fastjson.JSON;
|
|
@@ -13,9 +12,6 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
|
|
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
-import com.dtflys.forest.exceptions.ForestRuntimeException;
|
|
|
-import com.dtflys.forest.http.ForestRequest;
|
|
|
-import com.dtflys.forest.http.ForestResponse;
|
|
|
import com.fdkankan.common.constant.*;
|
|
|
import com.fdkankan.common.exception.BusinessException;
|
|
|
import com.fdkankan.common.response.Result;
|
|
@@ -38,8 +34,10 @@ import com.fdkankan.redis.util.RedisLockUtil;
|
|
|
import com.fdkankan.redis.util.RedisUtil;
|
|
|
import com.fdkankan.scene.api.dto.SceneInfoDTO;
|
|
|
import com.fdkankan.scene.bean.BoxPhotoBean;
|
|
|
+import com.fdkankan.scene.bean.IconBean;
|
|
|
import com.fdkankan.scene.bean.RequestSceneProV4;
|
|
|
import com.fdkankan.scene.bean.SceneJsonBean;
|
|
|
+import com.fdkankan.scene.bean.StyleBean;
|
|
|
import com.fdkankan.scene.bean.TagBean;
|
|
|
import com.fdkankan.scene.callback.FdkkMiniReqErrorCallback;
|
|
|
import com.fdkankan.scene.callback.FdkkMiniReqSuccessCallback;
|
|
@@ -69,7 +67,6 @@ import com.fdkankan.scene.vo.*;
|
|
|
import com.google.common.collect.Lists;
|
|
|
import com.google.errorprone.annotations.Var;
|
|
|
import java.io.File;
|
|
|
-import java.nio.charset.Charset;
|
|
|
import java.nio.charset.StandardCharsets;
|
|
|
import java.util.ArrayList;
|
|
|
import java.util.Arrays;
|
|
@@ -82,6 +79,7 @@ import java.util.Map;
|
|
|
import java.util.Map.Entry;
|
|
|
import java.util.Set;
|
|
|
import java.util.UUID;
|
|
|
+import java.util.concurrent.atomic.AtomicInteger;
|
|
|
import java.util.stream.Collectors;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.apache.commons.lang3.StringUtils;
|
|
@@ -94,7 +92,6 @@ import java.io.IOException;
|
|
|
import java.util.Calendar;
|
|
|
import java.util.Objects;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
-import org.springframework.util.ObjectUtils;
|
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
|
|
|
|
/**
|
|
@@ -241,10 +238,6 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
|
|
|
sceneEditInfoExt.setFloorPlanCompass(0f);
|
|
|
}
|
|
|
|
|
|
-// if(sceneEditControls == null){
|
|
|
-// sceneEditControls = new SceneEditControls();
|
|
|
-// }
|
|
|
-
|
|
|
//生成sceneJson
|
|
|
SceneJsonBean sceneJson = new SceneJsonBean();
|
|
|
BeanUtil.copyProperties(sceneEditInfoExt, sceneJson);
|
|
@@ -252,9 +245,6 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
|
|
|
SceneEditControlsVO sceneEditControlsVO = BeanUtil.copyProperties(sceneEditControls, SceneEditControlsVO.class);
|
|
|
sceneJson.setControls(sceneEditControlsVO);
|
|
|
sceneJson.setNum(num);
|
|
|
-// if(StrUtil.isNotEmpty(sceneEditInfo.getFloorPlanPath())){
|
|
|
-// sceneJson.setFloorPlanPaths(sceneEditInfo.getFloorPlanPath().split(","));
|
|
|
-// }
|
|
|
sceneJson.setCreateTime(scenePlus.getCreateTime());
|
|
|
|
|
|
sceneJson.setSceneResolution(scenePlusExt.getSceneResolution());
|
|
@@ -267,9 +257,8 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
|
|
|
//处理热点数据,生成hot.json
|
|
|
this.publicHotData(num, sceneEditInfo);
|
|
|
|
|
|
- // TODO: 2022/3/2 这里的逻辑放在上传球幕视频接口中做了,这里先暂时注释掉,以后要删除
|
|
|
- //处理球幕视频
|
|
|
-// this.buildVideo(sceneEditInfo, sceneProExt.getDataSource(), sceneNum);
|
|
|
+ //发布场景关联相关数据
|
|
|
+ this.publicLinkSceneData(num);
|
|
|
|
|
|
//本地写sceneJson文件
|
|
|
String localSceneJsonPath = String.format(ConstantFilePath.SCENE_DATA_PATH_V4, num) + "scene.json";
|
|
@@ -303,13 +292,6 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
|
|
|
sceneEditInfoExt.setEditInfoId(sceneEditInfo.getId());
|
|
|
sceneEditInfoExtService.saveOrUpdate(sceneEditInfoExt);
|
|
|
|
|
|
-// sceneEditControls.setEditInfoId(sceneEditInfo.getId());
|
|
|
-// if(sceneEditControls.getId() == null){
|
|
|
-// sceneEditControlsService.save(sceneEditControls);
|
|
|
-// }else{
|
|
|
-// sceneEditControlsService.updateById(sceneEditControls);
|
|
|
-// }
|
|
|
-
|
|
|
// todo 调用v3接口同步场景缩略图url---------------------------------start
|
|
|
String url = fkankanMiniHost + URL_UPGRADE_TO_V4_RESULT_SYNC;
|
|
|
fdkankanMiniClient.upgradeToV4ResultSync(url,
|
|
@@ -326,6 +308,31 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
|
|
|
return ResultData.ok();
|
|
|
}
|
|
|
|
|
|
+ public void publicLinkSceneData(String num) throws IOException {
|
|
|
+
|
|
|
+ String imgEditPath = String.format(UploadFilePath.IMG_EDIT_PATH, num);
|
|
|
+ String userEditPath = String.format(UploadFilePath.USER_EDIT_PATH, num);
|
|
|
+ String imgViewPath = String.format(UploadFilePath.IMG_VIEW_PATH, num);
|
|
|
+
|
|
|
+ //生成links.json并上传到发布目录
|
|
|
+ String linkPanKey = String.format(RedisKey.SCENE_LINKPAN_DATA, num);
|
|
|
+ Map<String, String> linkPanMap = redisUtil.hmget(linkPanKey);
|
|
|
+ if(CollUtil.isEmpty(linkPanMap)){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ JSONArray linkPanArr = new JSONArray();
|
|
|
+ linkPanMap.values().stream().forEach(linkPan->{
|
|
|
+ linkPanArr.add(JSON.parseObject(linkPan));
|
|
|
+ });
|
|
|
+ String linkScenePath = userEditPath + "links.json";
|
|
|
+ uploadToOssUtil.upload(linkPanArr.toString().getBytes(), linkScenePath);
|
|
|
+
|
|
|
+ //拷贝编辑目录到发布目录
|
|
|
+ uploadToOssUtil.deleteFile(imgViewPath + "panorama");
|
|
|
+ uploadToOssUtil.copyFiles(imgEditPath + "panorama",imgViewPath + "panorama");
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
private void buildVideo(SceneEditInfo sceneEditInfo, String path, String num) throws Exception{
|
|
|
if(CommonStatus.NO.equals(sceneEditInfo.getBuildVideoStatus())){
|
|
|
return;
|
|
@@ -1718,6 +1725,528 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
|
|
|
return ResultData.ok(result);
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ public ResultData uploadLinkPan(String num, String sid, String fileName, MultipartFile file) throws Exception {
|
|
|
+
|
|
|
+ ScenePlus scenePlus = scenePlusService.getScenePlusByNum(num);
|
|
|
+ if(scenePlus == null){
|
|
|
+ throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
|
|
|
+ }
|
|
|
+ ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
|
|
|
+
|
|
|
+ String localDataPath = String.format(ConstantFilePath.DATABUFFER_FORMAT, num);
|
|
|
+ String localImagesPath = String.format(ConstantFilePath.IMAGESBUFFER_FORMAT, num);
|
|
|
+ String path = scenePlusExt.getDataSource();
|
|
|
+ String target = localImagesPath + "panorama/" + sid;
|
|
|
+ FileUtils.deleteDirectory(target);
|
|
|
+
|
|
|
+ //文件写如本地磁盘
|
|
|
+ String filePath = target + File.separator + "extras/images" + File.separator + fileName;
|
|
|
+ File targetFile = new File(filePath);
|
|
|
+ if(!targetFile.getParentFile().exists()){
|
|
|
+ targetFile.getParentFile().mkdirs();
|
|
|
+ }
|
|
|
+ file.transferTo(targetFile);
|
|
|
+
|
|
|
+ //调用算法切全景图
|
|
|
+ FileUtils.copyFile(path + File.separator + "data.json", target + File.separator+"data.json", true);
|
|
|
+ FileUtils.copyFile(path + File.separator + "project.json", target + File.separator+"project.json", true);
|
|
|
+ JSONObject visionJson = new JSONObject();
|
|
|
+ JSONArray visionArray = new JSONArray();
|
|
|
+ visionJson.put("uuid", sid);
|
|
|
+ visionJson.put("group", 1);
|
|
|
+ visionJson.put("subgroup", 0);
|
|
|
+ visionArray.add(visionJson);
|
|
|
+ JSONObject vision = new JSONObject();
|
|
|
+ vision.put("sweepLocations", visionArray);
|
|
|
+ cn.hutool.core.io.FileUtil.writeString(vision.toString(),
|
|
|
+ target + "/extras" + File.separator + "vision.txt",
|
|
|
+ StandardCharsets.UTF_8);
|
|
|
+
|
|
|
+ //data.json增加extras为执行重建算法
|
|
|
+ String type = "4k";
|
|
|
+ String data = FileUtils.readFile(target + File.separator + "data.json");
|
|
|
+ if(data != null){
|
|
|
+ JSONObject floorplanJson = new JSONObject();
|
|
|
+ floorplanJson.put("has_source_images", true);
|
|
|
+ floorplanJson.put("has_vision_txt", true);
|
|
|
+
|
|
|
+ JSONObject dataJson = JSONObject.parseObject(data);
|
|
|
+ dataJson.put("extras", floorplanJson);
|
|
|
+ dataJson.put("split_type", "SPLIT_V8");//替换全景图算法
|
|
|
+ //V5表示不需要生成high,low文件
|
|
|
+ dataJson.put("skybox_type", "SKYBOX_V6");//默认4k minion
|
|
|
+ if(SceneFrom.PRO.code().equals(scenePlusExt.getSceneFrom())){
|
|
|
+ dataJson.put("skybox_type", "SKYBOX_V7");//pro 2k
|
|
|
+ type = "2k";
|
|
|
+ }
|
|
|
+ // TODO: 2022/6/21 这里暂时不清楚含义,可能是国际版需要,先注释---start
|
|
|
+// if(scenePlusExt.getSceneScheme() == 3){
|
|
|
+// dataJson.put("skybox_type", "SKYBOX_V4");
|
|
|
+// }
|
|
|
+ // TODO: 2022/6/21 这里暂时不清楚含义,可能是国际版需要,先注释---end
|
|
|
+ cn.hutool.core.io.FileUtil.writeString(dataJson.toString(),
|
|
|
+ target + File.separator+"data.json", StandardCharsets.UTF_8);
|
|
|
+ }
|
|
|
+
|
|
|
+ //创建文件夹软连接并且复制data.json和project.json
|
|
|
+ String capturePath = target + File.separator + "capture";
|
|
|
+ String resultPath = target + File.separator + "results";
|
|
|
+ log.info("场景关联上传全景图:capturePath={}", capturePath);
|
|
|
+ log.info("场景关联上传全景图:resultPath={}", resultPath);
|
|
|
+ if(cn.hutool.core.io.FileUtil.exist(capturePath)){
|
|
|
+ cn.hutool.core.io.FileUtil.del(capturePath);
|
|
|
+ }
|
|
|
+ if(cn.hutool.core.io.FileUtil.exist(resultPath)){
|
|
|
+ cn.hutool.core.io.FileUtil.del(resultPath);
|
|
|
+ }
|
|
|
+ //下载data.fdage
|
|
|
+ if(StorageType.AWS.code().equals(this.type)){
|
|
|
+ //亚马逊保持旧方式,超链接capture
|
|
|
+ CreateObjUtil.createSoftConnection(path + File.separator + "capture", capturePath);
|
|
|
+ }
|
|
|
+ CreateObjUtil.ossUtilCp(ConstantFilePath.OSS_PREFIX + path.replace(ConstantFilePath.BUILD_MODEL_PATH, "") + "/data.fdage", capturePath);
|
|
|
+ CreateObjUtil.build3dModel(target , "1");
|
|
|
+
|
|
|
+ //读取upload文件,获取需要上传的文件
|
|
|
+ JSONArray array = ComputerUtil.getUploadArray(resultPath + "/upload.json", this.maxCheckTimes, this.waitTime);
|
|
|
+ Map<String, String> map = new HashMap<>();
|
|
|
+ JSONObject fileJson;
|
|
|
+ String uploadFile, uploadFilePath;
|
|
|
+ String imgEditPath = String.format(UploadFilePath.IMG_EDIT_PATH, num);
|
|
|
+ for(int i = 0, len = array.size(); i < len; i++){
|
|
|
+ fileJson = array.getJSONObject(i);
|
|
|
+ uploadFile = fileJson.getString("file");
|
|
|
+ uploadFilePath = resultPath +File.separator + uploadFile;
|
|
|
+ //文件不存在抛出异常
|
|
|
+
|
|
|
+ if(!cn.hutool.core.io.FileUtil.exist(uploadFilePath)){
|
|
|
+ throw new Exception(uploadFilePath + "文件不存在");
|
|
|
+ }
|
|
|
+
|
|
|
+ Integer clazz = fileJson.getIntValue("clazz");
|
|
|
+ if(Objects.isNull(clazz)){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if(clazz == 4 || clazz == 5 || clazz == 7){
|
|
|
+ map.put(uploadFilePath, imgEditPath + "panorama/" + sid + File.separator + uploadFile);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //上传全景图
|
|
|
+ map.put(filePath, imgEditPath + "panorama/" + sid + "/high/" + fileName);
|
|
|
+
|
|
|
+ uploadToOssUtil.uploadMulFiles(map);
|
|
|
+
|
|
|
+ Map<String, String> result = new HashMap<>();
|
|
|
+ result.put("type", type);
|
|
|
+ return ResultData.ok(result);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ResultData saveLinkPan(SaveLinkPanParamVO param) throws Exception {
|
|
|
+
|
|
|
+ String num = param.getNum();
|
|
|
+ ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
|
|
|
+ if(Objects.isNull(scenePlus)){
|
|
|
+ throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
|
|
|
+ }
|
|
|
+
|
|
|
+ //添加场景关联数据
|
|
|
+ this.addOrUpdateLinPan(num, param.getLinkPans());
|
|
|
+
|
|
|
+ //添加场景关联图标
|
|
|
+ this.addOrUpdateLinkPanStyles(num, param.getStyles());
|
|
|
+
|
|
|
+ //场景关联数据备份到本地
|
|
|
+ this.writeLinkScene(num);
|
|
|
+
|
|
|
+ //更新场景关联标识、升级版本号
|
|
|
+ this.setLinkScenesAndUpgradeVersion(scenePlus.getId(), num);
|
|
|
+
|
|
|
+ return ResultData.ok();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ResultData deleteStyles(DeleteLinkSceneStylesParamVO param) throws Exception {
|
|
|
+ ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
|
|
|
+ if (scenePlus == null)
|
|
|
+ throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
|
|
|
+
|
|
|
+ List<String> sidList = param.getSidList();
|
|
|
+
|
|
|
+ this.syncLinkPanStylesFromFileToRedis(param.getNum());
|
|
|
+
|
|
|
+ String key = String.format(RedisKey.SCENE_LINKPAN_STYLES, param.getNum());
|
|
|
+ List<String> deleteList = redisUtil.hMultiGet(key, sidList);
|
|
|
+ redisUtil.hdel(key, sidList.toArray());
|
|
|
+
|
|
|
+ //写入本地文件,作为备份
|
|
|
+ this.writeLinkScene(param.getNum());
|
|
|
+
|
|
|
+ //删除oss文件
|
|
|
+ List<String> deleteFileList = deleteList.stream().map(str -> {
|
|
|
+ JSONObject parse = JSON.parseObject(str);
|
|
|
+ return parse.getString("url");
|
|
|
+ }).collect(Collectors.toList());
|
|
|
+ sceneUploadService.delete(
|
|
|
+ DeleteFileParamVO.builder()
|
|
|
+ .num(param.getNum())
|
|
|
+ .fileNames(deleteFileList)
|
|
|
+ .bizType(FileBizType.LINK_STYLE.code()).build());
|
|
|
+
|
|
|
+ return ResultData.ok();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ResultData deleteLinkPan(DeleteLinkPanParamVO param) throws Exception {
|
|
|
+
|
|
|
+ ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
|
|
|
+ if (scenePlus == null)
|
|
|
+ return ResultData.error(ErrorCode.FAILURE_CODE_5005);
|
|
|
+
|
|
|
+ List<String> deleteSidList = param.getSidList();
|
|
|
+
|
|
|
+ //处理删除状态数据
|
|
|
+ this.deletelinkPanData(param.getNum(), deleteSidList);
|
|
|
+
|
|
|
+ //写入本地文件,作为备份
|
|
|
+ this.writeLinkScene(param.getNum());
|
|
|
+
|
|
|
+ //更新场景关联标识、升级版本号
|
|
|
+ this.setLinkScenesAndUpgradeVersion(scenePlus.getId(), param.getNum());
|
|
|
+
|
|
|
+ return ResultData.ok();
|
|
|
+ }
|
|
|
+
|
|
|
+ private void deletelinkPanData(String num, List<String> deleteSidList) throws Exception {
|
|
|
+
|
|
|
+ if(CollUtil.isEmpty(deleteSidList)){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ this.syncLinPanFromFileToRedis(num);
|
|
|
+
|
|
|
+ //从redis中加载热点数据
|
|
|
+ String key = String.format(RedisKey.SCENE_LINKPAN_DATA, num);
|
|
|
+ List<String> deletDataList = redisUtil.hMultiGet(key, deleteSidList);
|
|
|
+ if(CollUtil.isEmpty(deletDataList))
|
|
|
+ return;
|
|
|
+
|
|
|
+ //从redis中移除热点数据
|
|
|
+ redisUtil.hdel(key, deleteSidList.toArray());
|
|
|
+
|
|
|
+ //删除oss文件
|
|
|
+ String imgEditPath = String.format(UploadFilePath.IMG_EDIT_PATH, num);
|
|
|
+ deleteSidList.stream().forEach(sid->{
|
|
|
+ uploadToOssUtil.deleteFile(imgEditPath + "panorama_edit/" + sid);
|
|
|
+ });
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public ResultData listLinkPan(String num) throws Exception {
|
|
|
+
|
|
|
+ this.syncLinPanFromFileToRedis(num);
|
|
|
+
|
|
|
+ this.syncLinkPanStylesFromFileToRedis(num);
|
|
|
+
|
|
|
+ JSONObject result = new JSONObject();
|
|
|
+
|
|
|
+ //查询场景关联数据
|
|
|
+ String key = String.format(RedisKey.SCENE_LINKPAN_DATA, num);
|
|
|
+ Map<String, String> allTagsMap = redisUtil.hmget(key);
|
|
|
+ List<JSONObject> tags = Lists.newArrayList();
|
|
|
+ List<TagBean> tagBeanList = new ArrayList<>();
|
|
|
+ if(CollUtil.isNotEmpty(allTagsMap)){
|
|
|
+ allTagsMap.entrySet().stream().forEach(entry -> {
|
|
|
+ JSONObject jsonObject = JSON.parseObject(entry.getValue());
|
|
|
+ tagBeanList.add(
|
|
|
+ TagBean.builder()
|
|
|
+ .createTime(jsonObject.getLong("createTime"))
|
|
|
+ .tag(jsonObject).build());
|
|
|
+ });
|
|
|
+ //按创建时间倒叙排序
|
|
|
+ tagBeanList.sort(Comparator.comparingLong(TagBean::getCreateTime).reversed());
|
|
|
+
|
|
|
+ //移除createTime字段
|
|
|
+ tags = tagBeanList.stream().map(tagBean -> {
|
|
|
+ JSONObject tag = tagBean.getTag();
|
|
|
+ tag.remove("createTime");
|
|
|
+ return tag;
|
|
|
+ }).collect(Collectors.toList());
|
|
|
+ }
|
|
|
+ result.put("tags", tags);
|
|
|
+
|
|
|
+ //封装styles数据
|
|
|
+ List<JSONObject> styles = Lists.newArrayList();
|
|
|
+ key = String.format(RedisKey.SCENE_LINKPAN_STYLES, num);
|
|
|
+ Map<String, String> styleMap = redisUtil.hmget(key);
|
|
|
+ if(CollUtil.isNotEmpty(styleMap)) {
|
|
|
+ for (String style : styleMap.values()) {
|
|
|
+ styles.add(JSON.parseObject(style));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ //图标按写入时间排序
|
|
|
+ styles = this.sortStyles(styles);
|
|
|
+
|
|
|
+ result.put("styles", styles);
|
|
|
+
|
|
|
+ return ResultData.ok(result);
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<JSONObject> sortStyles(List<JSONObject> styles){
|
|
|
+
|
|
|
+ if(CollUtil.isEmpty(styles)){
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ //统计使用频次
|
|
|
+ List<StyleBean> styleBeans = Lists.newArrayList();
|
|
|
+ for (JSONObject style : styles) {
|
|
|
+ Long createTime = style.getLong("createTime");
|
|
|
+ createTime = Objects.isNull(createTime) ? Calendar.getInstance().getTimeInMillis() : createTime;
|
|
|
+ style.remove("createTime");
|
|
|
+ styleBeans.add(
|
|
|
+ StyleBean.builder().style(style)
|
|
|
+ .createTime(createTime).build());
|
|
|
+ }
|
|
|
+
|
|
|
+ //排序
|
|
|
+ List<JSONObject> styleList = Lists.newArrayList();
|
|
|
+ if(CollUtil.isNotEmpty(styleBeans)){
|
|
|
+ styleList = styleBeans.stream().sorted(Comparator.comparing(StyleBean::getCreateTime).reversed())
|
|
|
+ .map(item -> {
|
|
|
+ return item.getStyle();
|
|
|
+ }).collect(Collectors.toList());
|
|
|
+ }
|
|
|
+
|
|
|
+ return styleList;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void setLinkScenesAndUpgradeVersion(Long scenePlusId, String num){
|
|
|
+
|
|
|
+ SceneEditInfo sceneEditInfo = this.getByScenePlusId(scenePlusId);
|
|
|
+
|
|
|
+ //查询缓存是否有场景关联数据
|
|
|
+ String key = String.format(RedisKey.SCENE_LINKPAN_DATA, num);
|
|
|
+ Map<String, String> allTagsMap = redisUtil.hmget(key);
|
|
|
+ boolean hashTags = false;
|
|
|
+ for (Entry<String, String> tagMap : allTagsMap.entrySet()) {
|
|
|
+ if(StrUtil.isEmpty(tagMap.getValue())){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ hashTags = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ //更新linkscenes字段
|
|
|
+ sceneEditInfoExtService.update(
|
|
|
+ new LambdaUpdateWrapper<SceneEditInfoExt>()
|
|
|
+ .set(SceneEditInfoExt::getLinks, hashTags ? CommonStatus.YES.code() : CommonStatus.NO.code())
|
|
|
+ .eq(SceneEditInfoExt::getEditInfoId, sceneEditInfo.getId()));
|
|
|
+
|
|
|
+ //更新场景版本
|
|
|
+ this.upgradeVersionById(sceneEditInfo.getId());
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ 热点数据保存
|
|
|
+
|
|
|
+ * </p>
|
|
|
+ * @author dengsixing
|
|
|
+ * @date 2022/3/3
|
|
|
+ **/
|
|
|
+ private void writeLinkScene(String num) throws Exception{
|
|
|
+
|
|
|
+ String dataKey = String.format(RedisKey.SCENE_LINKPAN_DATA, num);
|
|
|
+ Map<String, String> tagMap = redisUtil.hmget(dataKey);
|
|
|
+ List<String> tagList = Lists.newArrayList();
|
|
|
+ tagMap.entrySet().stream().forEach(entry->{
|
|
|
+ if(StrUtil.isNotEmpty(entry.getValue())){
|
|
|
+ tagList.add(entry.getValue());
|
|
|
+ }
|
|
|
+ });
|
|
|
+ JSONObject jsonObject = new JSONObject();
|
|
|
+ JSONArray tagJsonArr = new JSONArray();
|
|
|
+ if(CollUtil.isNotEmpty(tagList)){
|
|
|
+ tagList.stream().forEach(linkPan->{
|
|
|
+ tagJsonArr.add(JSONObject.parseObject(linkPan));
|
|
|
+ });
|
|
|
+ }
|
|
|
+ jsonObject.put("tags", tagJsonArr);
|
|
|
+
|
|
|
+ String stylesKey = String.format(RedisKey.SCENE_LINKPAN_STYLES, num);
|
|
|
+ Map<String, String> styleMap = redisUtil.hmget(stylesKey);
|
|
|
+ List<JSONObject> styleList = Lists.newArrayList();
|
|
|
+ if(CollUtil.isNotEmpty(styleMap)){
|
|
|
+ styleMap.values().stream().forEach(style->{
|
|
|
+ styleList.add(JSONObject.parseObject(style));
|
|
|
+ });
|
|
|
+ }
|
|
|
+ jsonObject.put("styles", styleList);
|
|
|
+
|
|
|
+ String linkScenePath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + "links.json";
|
|
|
+ String lockKey = String.format(RedisLockKey.LOCK_LINK_SCENE_JSON, num);
|
|
|
+ boolean lock = redisLockUtil.lock(lockKey, RedisKey.EXPIRE_TIME_1_MINUTE);
|
|
|
+ if(!lock){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try{
|
|
|
+ cn.hutool.core.io.FileUtil.writeUtf8String(jsonObject.toJSONString(), linkScenePath);
|
|
|
+ }finally {
|
|
|
+ redisLockUtil.unlockLua(lockKey);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ private void addOrUpdateLinkPanStyles(String num, List<JSONObject> styles) throws Exception{
|
|
|
+
|
|
|
+ this.syncLinkPanStylesFromFileToRedis(num);
|
|
|
+
|
|
|
+ if(CollUtil.isEmpty(styles)){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ long time = Calendar.getInstance().getTimeInMillis();
|
|
|
+ Map<String, String> styleMap = new HashMap<>();
|
|
|
+ AtomicInteger index = new AtomicInteger();
|
|
|
+ styles.stream().forEach(style->{
|
|
|
+ String id = style.getString("sid");
|
|
|
+ style.put("createTime", time + index.getAndIncrement());
|
|
|
+ styleMap.put(id, style.toJSONString());
|
|
|
+ });
|
|
|
+
|
|
|
+ String key = String.format(RedisKey.SCENE_LINKPAN_STYLES, num);
|
|
|
+ redisUtil.hmset(key, styleMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ 保证icons数据安全性,当redis宕机导致icons数据丢失时,可以从文件中读取,恢复到redis
|
|
|
+ * </p>
|
|
|
+ * @author dengsixing
|
|
|
+ * @date 2022/3/3
|
|
|
+ **/
|
|
|
+ private void syncLinkPanStylesFromFileToRedis(String num) throws Exception{
|
|
|
+
|
|
|
+ String key = String.format(RedisKey.SCENE_LINKPAN_STYLES, num);
|
|
|
+ boolean exist = redisUtil.hasKey(key);
|
|
|
+ if(exist){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ String lockKey = String.format(RedisLockKey.LOCK_LINKPAN_STYLES_SYNC, num);
|
|
|
+ boolean lock = redisLockUtil.lock(lockKey, RedisKey.EXPIRE_TIME_1_MINUTE);
|
|
|
+ if(!lock){
|
|
|
+ throw new BusinessException(ErrorCode.SYSTEM_BUSY);
|
|
|
+ }
|
|
|
+ try{
|
|
|
+ exist = redisUtil.hasKey(key);
|
|
|
+ if(exist){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ String linkSceneFilePath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num);
|
|
|
+ String linkSceneData = FileUtils.readFile(linkSceneFilePath + "links.json");
|
|
|
+ if(StrUtil.isEmpty(linkSceneData)){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ JSONObject jsonObject = JSON.parseObject(linkSceneData);
|
|
|
+ JSONArray stylesArr = jsonObject.getJSONArray("styles");
|
|
|
+ if(CollUtil.isEmpty(stylesArr)){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Map<String, String> styleMap = new HashMap<>();
|
|
|
+ for (Object style : stylesArr) {
|
|
|
+ JSONObject styleObj = (JSONObject)style;
|
|
|
+ String id = styleObj.getString("sid");
|
|
|
+ styleMap.put(id, styleObj.toJSONString());
|
|
|
+ }
|
|
|
+ redisUtil.hmset(key, styleMap);
|
|
|
+ }finally {
|
|
|
+ redisLockUtil.unlockLua(lockKey);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private void addOrUpdateLinPan(String num, List<JSONObject> linkPanList) throws Exception{
|
|
|
+ Map<String, String> addOrUpdateMap = new HashMap<>();
|
|
|
+ int i = 0;
|
|
|
+ for (JSONObject jsonObject : linkPanList) {
|
|
|
+ jsonObject.put("createTime", Calendar.getInstance().getTimeInMillis() + i++);
|
|
|
+ addOrUpdateMap.put(jsonObject.getString("sid"), jsonObject.toJSONString());
|
|
|
+ }
|
|
|
+
|
|
|
+ this.syncLinPanFromFileToRedis(num);
|
|
|
+
|
|
|
+ //处理新增和修改数据
|
|
|
+ this.addOrUpdateLinkPanHandler(num, addOrUpdateMap);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * <p>
|
|
|
+ 保证热点数据安全性,当redis宕机导致热点数据丢失时,可以从文件中读取,恢复到redis
|
|
|
+ * </p>
|
|
|
+ * @author dengsixing
|
|
|
+ * @date 2022/3/3
|
|
|
+ **/
|
|
|
+ private void syncLinPanFromFileToRedis(String num) throws Exception{
|
|
|
+
|
|
|
+ String key = String.format(RedisKey.SCENE_LINKPAN_DATA, num);
|
|
|
+ boolean exist = redisUtil.hasKey(key);
|
|
|
+ if(exist){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ String lockKey = String.format(RedisLockKey.LOCK_LINKPAN_DATA_SYNC, num);
|
|
|
+ boolean lock = redisLockUtil.lock(lockKey, RedisKey.EXPIRE_TIME_1_MINUTE);
|
|
|
+ if(!lock){
|
|
|
+ throw new BusinessException(ErrorCode.SYSTEM_BUSY);
|
|
|
+ }
|
|
|
+ try{
|
|
|
+ exist = redisUtil.hasKey(key);
|
|
|
+ if(exist){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ String linkSceneFilePath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num);
|
|
|
+ String linkSceneData = FileUtils.readFile(linkSceneFilePath + "links.json");
|
|
|
+ if(StrUtil.isEmpty(linkSceneData)){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ JSONObject jsonObject = JSON.parseObject(linkSceneData);
|
|
|
+ JSONArray tagsArr = jsonObject.getJSONArray("tags");
|
|
|
+ if(CollUtil.isEmpty(tagsArr)){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Map<String, String> map = new HashMap<>();
|
|
|
+ for (Object o : tagsArr) {
|
|
|
+ JSONObject jo = (JSONObject)o;
|
|
|
+ map.put(jo.getString("sid"), jo.toJSONString());
|
|
|
+ }
|
|
|
+ redisUtil.hmset(key, map);
|
|
|
+ }finally {
|
|
|
+ redisLockUtil.unlockLua(lockKey);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void addOrUpdateLinkPanHandler(String num, Map<String, String> addOrUpdateMap){
|
|
|
+ if(CollUtil.isEmpty(addOrUpdateMap))
|
|
|
+ return;
|
|
|
+
|
|
|
+ //数据验证,新增、修改状态,linkPan不能为空
|
|
|
+ for (String sid : addOrUpdateMap.keySet()) {
|
|
|
+ String linkPan = addOrUpdateMap.get(sid);
|
|
|
+ if(StrUtil.isEmpty(linkPan)){
|
|
|
+ throw new BusinessException(ErrorCode.FAILURE_CODE_7022);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //批量写入缓存
|
|
|
+ String key = String.format(RedisKey.SCENE_LINKPAN_DATA, num);
|
|
|
+ redisUtil.hmset(key, addOrUpdateMap);
|
|
|
+ }
|
|
|
+
|
|
|
private void updateBoxVideos(SceneEditInfo sceneEditInfo, Long scenePlusId, String boxVideos){
|
|
|
if(Objects.isNull(sceneEditInfo)){
|
|
|
sceneEditInfo = new SceneEditInfo();
|