SceneProServiceImpl.java 46 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147
  1. package com.fdkankan.scene.service.impl;
  2. import cn.hutool.core.collection.CollUtil;
  3. import cn.hutool.core.date.DateField;
  4. import cn.hutool.core.date.DateUtil;
  5. import cn.hutool.core.io.FileUtil;
  6. import cn.hutool.core.util.StrUtil;
  7. import cn.hutool.core.util.ZipUtil;
  8. import com.alibaba.fastjson.JSON;
  9. import com.alibaba.fastjson.JSONArray;
  10. import com.alibaba.fastjson.JSONObject;
  11. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  12. import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
  13. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  14. import com.fdkankan.common.constant.*;
  15. import com.fdkankan.common.exception.BusinessException;
  16. import com.fdkankan.common.util.FileUtils;
  17. import com.fdkankan.model.constants.ConstantFileName;
  18. import com.fdkankan.model.constants.ConstantFilePath;
  19. import com.fdkankan.model.constants.UploadFilePath;
  20. import com.fdkankan.common.exception.BusinessException;
  21. import com.fdkankan.scene.bean.SceneBean;
  22. import com.fdkankan.scene.config.FdkkLaserConfig;
  23. import com.fdkankan.scene.util.CmdBuildUtil;
  24. import com.fdkankan.web.response.ResultData;
  25. import com.fdkankan.model.utils.ComputerUtil;
  26. import com.fdkankan.model.utils.ConvertUtils;
  27. import com.fdkankan.model.utils.CreateObjUtil;
  28. import com.fdkankan.redis.constant.RedisKey;
  29. import com.fdkankan.redis.constant.RedisLockKey;
  30. import com.fdkankan.redis.util.RedisLockUtil;
  31. import com.fdkankan.redis.util.RedisUtil;
  32. import com.fdkankan.scene.bean.IconBean;
  33. import com.fdkankan.scene.bean.LaserSceneBean;
  34. import com.fdkankan.scene.bean.TagBean;
  35. import com.fdkankan.scene.constant.ConstantFileLocPath;
  36. import com.fdkankan.scene.entity.SceneEditInfo;
  37. import com.fdkankan.scene.entity.ScenePlus;
  38. import com.fdkankan.scene.entity.ScenePlusExt;
  39. import com.fdkankan.scene.entity.ScenePro;
  40. import com.fdkankan.scene.mapper.ISceneProMapper;
  41. import com.fdkankan.scene.oss.OssUtil;
  42. import com.fdkankan.scene.service.*;
  43. import com.fdkankan.scene.vo.*;
  44. import com.fdkankan.web.response.ResultData;
  45. import com.google.common.collect.Lists;
  46. import com.google.common.collect.Sets;
  47. import lombok.extern.slf4j.Slf4j;
  48. import org.springframework.beans.factory.annotation.Autowired;
  49. import org.springframework.beans.factory.annotation.Value;
  50. import org.springframework.stereotype.Service;
  51. import org.springframework.transaction.annotation.Transactional;
  52. import org.springframework.web.multipart.MultipartFile;
  53. import java.io.File;
  54. import java.io.IOException;
  55. import java.nio.charset.StandardCharsets;
  56. import java.util.*;
  57. import java.util.Map.Entry;
  58. import java.util.stream.Collectors;
  59. /**
  60. * <p>
  61. * pro场景表 服务实现类
  62. * </p>
  63. *
  64. * @author dengsixing
  65. * @since 2021-12-23
  66. */
  67. @Slf4j
  68. @Service
  69. public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro> implements ISceneProService {
  70. @Value("${main.url}")
  71. private String mainUrl;
  72. @Value("${scene.url}")
  73. private String sceneUrl;
  74. @Value("${scene.pro.url}")
  75. private String sceneProUrl;
  76. @Value("${scene.pro.new.url}")
  77. private String sceneProNewUrl;
  78. @Value("${ecs.checkFile.maxTimes:5}")
  79. private int maxCheckTimes;
  80. @Value("${ecs.checkFile.waitTime:5000}")
  81. private int waitTime;
  82. @Autowired
  83. private RedisLockUtil redisLockUtil;
  84. @Autowired
  85. private RedisUtil redisUtil;
  86. @Autowired
  87. private ISceneDataDownloadService sceneDataDownloadService;
  88. @Autowired
  89. private ISceneProService sceneProService;
  90. @Autowired
  91. private ISceneEditInfoService sceneEditInfoService;
  92. @Autowired
  93. private ISceneEditControlsService sceneEditControlsService;
  94. @Autowired
  95. private IScenePlusService scenePlusService;
  96. @Autowired
  97. private IScenePlusExtService scenePlusExtService;
  98. @Autowired
  99. private ISceneUploadService sceneUploadService;
  100. @Autowired
  101. private OssUtil ossUtil;
  102. @Autowired
  103. private ILaserService laserService;
  104. @Transactional
  105. @Override
  106. public ResultData saveInitialPage(FileNameAndDataParamVO param) throws Exception{
  107. ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
  108. if(scenePlus == null){
  109. throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
  110. }
  111. ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
  112. //更新缩略图url
  113. String thumbUrl = String.format(UploadFilePath.USER_EDIT_PATH, param.getNum()) + param.getFileName();
  114. scenePlusExt.setThumb(thumbUrl);
  115. scenePlusExtService.updateById(scenePlusExt);
  116. SceneEditInfo sceneEditInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId());
  117. if(sceneEditInfo == null){
  118. sceneEditInfo = new SceneEditInfo();
  119. sceneEditInfo.setScenePlusId(scenePlus.getId());
  120. sceneEditInfo.setEntry(param.getData());
  121. sceneEditInfoService.save(sceneEditInfo);
  122. }else{
  123. sceneEditInfoService.update(
  124. new LambdaUpdateWrapper<SceneEditInfo>()
  125. .set(SceneEditInfo::getEntry, param.getData())
  126. .setSql("version = version + 1")
  127. .eq(SceneEditInfo::getId, sceneEditInfo.getId()));
  128. }
  129. //修改laser场景主表的缩略图地址
  130. laserService.editScene(param.getNum(), LaserSceneBean.builder().thumb(thumbUrl).build());
  131. return ResultData.ok();
  132. }
  133. @Override
  134. public ResultData addOrUpdateTag(SaveTagsParamVO param) throws Exception {
  135. // ScenePro scenePro = this.findBySceneNum(param.getNum());
  136. ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
  137. if (scenePlus == null)
  138. return ResultData.error(ErrorCode.FAILURE_CODE_5005);
  139. this.addOrUpdateHotData(param.getNum(), param.getHotDataList());
  140. this.addOrUpdateIcons(param.getNum(), param.getIcons());
  141. //写入本地文件,作为备份
  142. this.writeHotJson(param.getNum());
  143. //保存数据库
  144. SceneEditInfo sceneEditInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId());
  145. sceneEditInfoService.saveTagsToSceneEditInfo(param.getNum(), sceneEditInfo);
  146. sceneEditInfoService.updateById(sceneEditInfo);
  147. return ResultData.ok();
  148. }
  149. private void addOrUpdateHotData(String num, List<HotParamVO> hotDataList) throws Exception{
  150. Map<String, String> addOrUpdateMap = new HashMap<>();
  151. int i = 0;
  152. for (HotParamVO hotParamVO : hotDataList) {
  153. JSONObject jsonObject = JSON.parseObject(hotParamVO.getHotData());
  154. jsonObject.put("createTime", Calendar.getInstance().getTimeInMillis() + i++);
  155. addOrUpdateMap.put(hotParamVO.getSid(), jsonObject.toJSONString());
  156. }
  157. this.syncHotFromFileToRedis(num);
  158. //处理新增和修改数据
  159. this.addOrUpdateHotDataHandler(num, addOrUpdateMap);
  160. }
  161. private void addOrUpdateIcons(String num, List<String> icons) throws Exception{
  162. if(CollUtil.isEmpty(icons)){
  163. return;
  164. }
  165. this.syncIconsFromFileToRedis(num);
  166. String key = String.format(RedisKey.SCENE_HOT_ICONS, num);
  167. redisUtil.sSet(key, icons.toArray());
  168. }
  169. @Override
  170. public ResultData deleteTag(DeleteHotParamVO param) throws Exception {
  171. // ScenePro scenePro = this.findBySceneNum(param.getNum());
  172. ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
  173. if (scenePlus == null)
  174. throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
  175. ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
  176. String bucket = scenePlusExt.getYunFileBucket();
  177. List<String> deleteSidList = param.getSidList();
  178. //处理删除状态数据
  179. this.deleteHotData(param.getNum(), deleteSidList, bucket);
  180. //删除导览中的热点数据
  181. this.deleteHotDataFromTourJson(param.getNum(), param.getSidList(), bucket);
  182. //写入本地文件,作为备份
  183. this.writeHotJson(param.getNum());
  184. //保存数据库
  185. SceneEditInfo sceneEditInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId());
  186. sceneEditInfoService.saveTagsToSceneEditInfo(param.getNum(), sceneEditInfo);
  187. sceneEditInfoService.updateById(sceneEditInfo);
  188. return ResultData.ok();
  189. }
  190. private void deleteHotDataFromTourJson(String num, List<String> sidList, String bucket){
  191. String key = String.format(UploadFilePath.USER_EDIT_PATH, num) + "tour.json";
  192. String tourJson = ossUtil.getFileContent(bucket, key);
  193. if(StrUtil.isEmpty(tourJson)){
  194. return;
  195. }
  196. JSONArray jsonArray = JSON.parseArray(tourJson);
  197. if(CollUtil.isEmpty(jsonArray)){
  198. return;
  199. }
  200. jsonArray.stream().forEach(tour->{
  201. JSONObject obj = (JSONObject) tour;
  202. JSONArray itemArra = obj.getJSONArray("list");
  203. itemArra.stream().forEach(item->{
  204. JSONObject itemObj = (JSONObject) item;
  205. String tagId = itemObj.getString("tagId");
  206. if(tagId != null && sidList.contains(tagId)){
  207. itemObj.remove("tagId");
  208. }
  209. });
  210. });
  211. ossUtil.uploadFileBytes(bucket, key, jsonArray.toJSONString().getBytes(StandardCharsets.UTF_8));
  212. }
  213. @Override
  214. public ResultData deleteIcons(DeleteHotIconParamVO param) throws Exception {
  215. ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
  216. if (scenePlus == null)
  217. throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
  218. List<String> fileNameList = param.getFileNameList();
  219. this.syncIconsFromFileToRedis(param.getNum());
  220. String key = String.format(RedisKey.SCENE_HOT_ICONS, param.getNum());
  221. redisUtil.setRemove(key, fileNameList.toArray());
  222. //写入本地文件,作为备份
  223. this.writeHotJson(param.getNum());
  224. //删除oss文件
  225. sceneUploadService.delete(
  226. DeleteFileParamVO.builder()
  227. .num(param.getNum())
  228. .fileNames(fileNameList)
  229. .bizType(FileBizType.TAG_ICON.code()).build());
  230. return ResultData.ok();
  231. }
  232. @Override
  233. public ResultData listTags(String num) throws Exception{
  234. //保证热点数据安全性,当redis宕机导致热点数据丢失时,可以从文件中读取,恢复到redis
  235. this.syncHotFromFileToRedis(num);
  236. //保证icons数据安全性,当redis宕机导致icons数据丢失时,可以从文件中读取,恢复到redis
  237. this.syncIconsFromFileToRedis(num);
  238. JSONObject result = new JSONObject();
  239. //查询缓存是否包含热点数据
  240. String key = String.format(RedisKey.SCENE_HOT_DATA, num);
  241. Map<String, String> allTagsMap = redisUtil.hmget(key);
  242. List<JSONObject> tags = Lists.newArrayList();
  243. List<TagBean> tagBeanList = new ArrayList<>();
  244. if(CollUtil.isNotEmpty(allTagsMap)){
  245. allTagsMap.entrySet().stream().forEach(entry -> {
  246. JSONObject jsonObject = JSON.parseObject(entry.getValue());
  247. tagBeanList.add(
  248. TagBean.builder()
  249. .createTime(jsonObject.getLong("createTime"))
  250. .tag(jsonObject).build());
  251. });
  252. //按创建时间倒叙排序
  253. tagBeanList.sort(Comparator.comparingLong(TagBean::getCreateTime).reversed());
  254. //移除createTime字段
  255. tags = tagBeanList.stream().map(tagBean -> {
  256. JSONObject tag = tagBean.getTag();
  257. tag.remove("createTime");
  258. return tag;
  259. }).collect(Collectors.toList());
  260. }
  261. result.put("tags", tags);
  262. //查询缓存是否包含icons
  263. key = String.format(RedisKey.SCENE_HOT_ICONS, num);
  264. Set<String> icons = redisUtil.sGet(key);
  265. if(icons == null){
  266. icons = Sets.newHashSet();
  267. }
  268. List<String> iconList = this.sortIcons(tags, icons);
  269. result.put("icons", iconList);
  270. return ResultData.ok(result);
  271. }
  272. private List<String> sortIcons(List<JSONObject> tags, Set<String> icons){
  273. //统计使用频次
  274. List<IconBean> iconBeans = Lists.newArrayList();
  275. for (String icon : icons) {
  276. int count = 0;
  277. for (JSONObject tag : tags) {
  278. String sid = tag.getString("icon");
  279. if(StrUtil.isEmpty(sid) || !icon.equals(sid)){
  280. continue;
  281. }
  282. ++count;
  283. }
  284. iconBeans.add(IconBean.builder().icon(icon).count(count).build());
  285. }
  286. //排序
  287. List<String> iconList = iconBeans.stream().sorted(Comparator.comparing(IconBean::getCount).reversed())
  288. .map(item -> {
  289. return item.getIcon();
  290. }).collect(Collectors.toList());
  291. return iconList;
  292. }
  293. /**
  294. * <p>
  295. 保证热点数据安全性,当redis宕机导致热点数据丢失时,可以从文件中读取,恢复到redis
  296. * </p>
  297. * @author dengsixing
  298. * @date 2022/3/3
  299. **/
  300. private void syncHotFromFileToRedis(String num) throws Exception{
  301. String key = String.format(RedisKey.SCENE_HOT_DATA, num);
  302. boolean exist = redisUtil.hasKey(key);
  303. if(exist){
  304. return;
  305. }
  306. String lockKey = String.format(RedisLockKey.LOCK_HOT_DATA_SYNC, num);
  307. String lockVal = cn.hutool.core.lang.UUID.randomUUID().toString();
  308. boolean lock = redisLockUtil.lock(lockKey, lockVal, RedisKey.EXPIRE_TIME_1_MINUTE);
  309. if(!lock){
  310. throw new BusinessException(ErrorCode.SYSTEM_BUSY);
  311. }
  312. try{
  313. exist = redisUtil.hasKey(key);
  314. if(exist){
  315. return;
  316. }
  317. String tagsFilePath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + "hot.json";
  318. String tagsData = FileUtils.readUtf8String(tagsFilePath);
  319. if(StrUtil.isEmpty(tagsData)){
  320. return;
  321. }
  322. JSONObject jsonObject = JSON.parseObject(tagsData);
  323. JSONArray tagsArr = jsonObject.getJSONArray("tags");
  324. if(CollUtil.isEmpty(tagsArr)){
  325. return;
  326. }
  327. Map<String, String> map = new HashMap<>();
  328. for (Object o : tagsArr) {
  329. JSONObject jo = (JSONObject)o;
  330. map.put(jo.getString("sid"), jo.toJSONString());
  331. }
  332. redisUtil.hmset(key, map);
  333. }finally {
  334. redisLockUtil.unlockLua(lockKey, lockVal);
  335. }
  336. }
  337. /**
  338. * <p>
  339. 保证icons数据安全性,当redis宕机导致icons数据丢失时,可以从文件中读取,恢复到redis
  340. * </p>
  341. * @author dengsixing
  342. * @date 2022/3/3
  343. **/
  344. private void syncIconsFromFileToRedis(String num) throws Exception{
  345. String key = String.format(RedisKey.SCENE_HOT_ICONS, num);
  346. boolean exist = redisUtil.hasKey(key);
  347. if(exist){
  348. return;
  349. }
  350. String lockKey = String.format(RedisLockKey.LOCK_HOT_ICONS_SYNC, num);
  351. String lockVal = cn.hutool.core.lang.UUID.randomUUID().toString();
  352. boolean lock = redisLockUtil.lock(lockKey, lockVal, RedisKey.EXPIRE_TIME_1_MINUTE);
  353. if(!lock){
  354. throw new BusinessException(ErrorCode.SYSTEM_BUSY);
  355. }
  356. try{
  357. exist = redisUtil.hasKey(key);
  358. if(exist){
  359. return;
  360. }
  361. String tagsFilePath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + "hot.json";
  362. String tagsData = FileUtils.readUtf8String(tagsFilePath);
  363. if(StrUtil.isEmpty(tagsData)){
  364. return;
  365. }
  366. JSONObject jsonObject = JSON.parseObject(tagsData);
  367. JSONArray iconArr = jsonObject.getJSONArray("icons");
  368. if(CollUtil.isEmpty(iconArr)){
  369. return;
  370. }
  371. redisUtil.sSet(key, iconArr.toJavaList(String.class).toArray());
  372. }finally {
  373. redisLockUtil.unlockLua(lockKey, lockVal);
  374. }
  375. }
  376. /**
  377. * <p>
  378. 热点数据保存
  379. * </p>
  380. * @author dengsixing
  381. * @date 2022/3/3
  382. **/
  383. private void writeHotJson(String num) throws Exception{
  384. String dataKey = String.format(RedisKey.SCENE_HOT_DATA, num);
  385. Map<String, String> tagMap = redisUtil.hmget(dataKey);
  386. List<String> tagList = Lists.newArrayList();
  387. tagMap.entrySet().stream().forEach(entry->{
  388. if(StrUtil.isNotEmpty(entry.getValue())){
  389. tagList.add(entry.getValue());
  390. }
  391. });
  392. JSONObject jsonObject = new JSONObject();
  393. JSONArray tagJsonArr = new JSONArray();
  394. if(CollUtil.isNotEmpty(tagList)){
  395. tagList.stream().forEach(hot->{
  396. tagJsonArr.add(JSONObject.parseObject(hot));
  397. });
  398. }
  399. jsonObject.put("tags", tagJsonArr);
  400. String iconsKey = String.format(RedisKey.SCENE_HOT_ICONS, num);
  401. Set<String> iconList = redisUtil.sGet(iconsKey);
  402. jsonObject.put("icons", iconList);
  403. String hotJsonPath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + "hot.json";
  404. String lockKey = String.format(RedisLockKey.LOCK_HOT_JSON, num);
  405. String lockVal = cn.hutool.core.lang.UUID.randomUUID().toString();
  406. boolean lock = redisLockUtil.lock(lockKey, lockVal, RedisKey.EXPIRE_TIME_1_MINUTE);
  407. if(!lock){
  408. return;
  409. }
  410. try{
  411. FileUtils.writeFile(hotJsonPath, jsonObject.toJSONString());
  412. }finally {
  413. redisLockUtil.unlockLua(lockKey, lockVal);
  414. }
  415. }
  416. private void addOrUpdateHotDataHandler(String num, Map<String, String> addOrUpdateMap){
  417. if(CollUtil.isEmpty(addOrUpdateMap))
  418. return;
  419. //数据验证,新增、修改状态,hotdata不能为空
  420. for (String sid : addOrUpdateMap.keySet()) {
  421. String hotData = addOrUpdateMap.get(sid);
  422. if(StrUtil.isEmpty(hotData)){
  423. throw new BusinessException(ErrorCode.FAILURE_CODE_7004);
  424. }
  425. }
  426. //批量写入缓存
  427. String key = String.format(RedisKey.SCENE_HOT_DATA, num);
  428. redisUtil.hmset(key, addOrUpdateMap);
  429. }
  430. private void deleteHotData(String num, List<String> deleteSidList, String bucket) throws Exception {
  431. this.syncHotFromFileToRedis(num);
  432. if(CollUtil.isEmpty(deleteSidList)){
  433. return;
  434. }
  435. //从redis中加载热点数据
  436. String key = String.format(RedisKey.SCENE_HOT_DATA, num);
  437. List<String> deletDataList = redisUtil.hMultiGet(key, deleteSidList);
  438. if(CollUtil.isEmpty(deletDataList))
  439. return;
  440. String userDataPath = String.format(UploadFilePath.USER_EDIT_PATH, num);
  441. //删除图片音频视频等资源文件
  442. for (String data : deletDataList) {
  443. if(StrUtil.isBlank(data)){
  444. continue;
  445. }
  446. JSONObject jsonObject = JSON.parseObject(data);
  447. String sid = jsonObject.getString("sid");
  448. if(jsonObject.containsKey("media")){
  449. String fileType = jsonObject.getString("media");
  450. if(fileType.contains("photo"))
  451. {
  452. ossUtil.deleteObject(bucket, userDataPath + "hot"+sid+".jpg");
  453. }
  454. if(fileType.contains("audio") || fileType.contains("voice"))
  455. {
  456. ossUtil.deleteObject(bucket,userDataPath + "hot"+sid+".mp3");
  457. }
  458. if(fileType.contains("video"))
  459. {
  460. ossUtil.deleteObject(bucket,userDataPath + "hot"+sid+".mp4");
  461. }
  462. }
  463. }
  464. //从redis中移除热点数据
  465. redisUtil.hdel(key, deleteSidList.toArray());
  466. }
  467. @Override
  468. public ResultData saveTagsVisible(SaveTagsVisibleParamVO param) throws Exception {
  469. ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
  470. if (scenePlus == null ) {
  471. return ResultData.error(ErrorCode.FAILURE_CODE_5005);
  472. }
  473. JSONArray visiblePanos = JSONArray.parseArray(param.getData());
  474. //如果redis找不到,就从本地文件中reload
  475. this.syncHotFromFileToRedis(param.getNum());
  476. //从缓存中获取热点数据,如果为空,抛出异常
  477. String key = String.format(RedisKey.SCENE_HOT_DATA, param.getNum());
  478. Map<String, String> map = redisUtil.hmget(key);
  479. if (CollUtil.isEmpty(map)) {
  480. throw new BusinessException(ErrorCode.FAILURE_CODE_7005);
  481. }
  482. List<Entry<String, String>> allTags = map.entrySet().stream().filter(item -> {
  483. if (StrUtil.isBlank(item.getValue())) {
  484. return false;
  485. }
  486. return true;
  487. }).collect(Collectors.toList());
  488. if (CollUtil.isEmpty(allTags)) {
  489. throw new BusinessException(ErrorCode.FAILURE_CODE_7005);
  490. }
  491. allTags.stream().forEach(entry->{
  492. JSONObject hot = JSON.parseObject(entry.getValue());
  493. visiblePanos.stream().forEach(item->{
  494. if (hot.getString("sid").equals(((JSONObject) item).getString("sid"))) {
  495. hot.put("visiblePanos", ((JSONObject) item).getJSONArray("value"));
  496. hot.put("isHidden", ((JSONObject) item).getBoolean("isHidden"));
  497. entry.setValue(hot.toJSONString());
  498. }
  499. });
  500. });
  501. //更新版本号
  502. SceneEditInfo editInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId());
  503. sceneEditInfoService.upgradeVersionById(editInfo.getId());
  504. //放入缓存
  505. Map<String, String> finalMap = new HashMap<>();
  506. allTags.stream().forEach(entry->{
  507. finalMap.put(entry.getKey(), entry.getValue());
  508. });
  509. redisUtil.hmset(key, finalMap);
  510. //写入本地文件,作为备份,以防redis数据丢失
  511. this.writeHotJson(param.getNum());
  512. return ResultData.ok();
  513. }
  514. @Override
  515. public ResultData saveRoam(BaseDataParamVO param) throws Exception {
  516. // ScenePro scenePro = this.findBySceneNum(param.getNum());
  517. ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
  518. if (scenePlus == null ) {
  519. return ResultData.error(ErrorCode.FAILURE_CODE_5005);
  520. }
  521. ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
  522. String bucket = scenePlusExt.getYunFileBucket();
  523. JSONArray inputData = JSONObject.parseArray(param.getData());
  524. String localDataPath = String.format(scenePlusExt.getDataSource()+ ConstantFileLocPath.SCENE_DATA_PATH_V4, param.getNum());
  525. File directory = new File(localDataPath);
  526. if (!directory.exists()) {
  527. directory.mkdirs();
  528. }
  529. //如果是云存储,将vision.modeldata下载到本地,如果是本地存储,场景计算完就已经将这个文件拷贝到编辑目录了存在这个文件了,不需要再下载
  530. String viewImagesPath = String.format(UploadFilePath.IMG_VIEW_PATH, param.getNum());
  531. ossUtil.downloadFile(bucket,viewImagesPath + "vision.modeldata", localDataPath + "vision.modeldata");
  532. //检查vision.modeldata本地是否存在,不存在抛出异常
  533. File file = new File(localDataPath + "vision.modeldata");
  534. if(!file.exists()) {
  535. return ResultData.error(ErrorCode.FAILURE_CODE_5012);
  536. }
  537. //将vision.modeldata解压缩至vision.json
  538. ConvertUtils.convertVisionModelDataToTxt(localDataPath + "vision.modeldata", localDataPath + "vision.json");
  539. String str = FileUtils.readFile(localDataPath + "vision.json");
  540. JSONObject json = JSONObject.parseObject(str);
  541. JSONArray panos = json.getJSONArray("sweepLocations");
  542. for (int i = 0; i < panos.size(); ++i) {
  543. JSONObject pano = panos.getJSONObject(i);
  544. for (int j = 0; j < inputData.size(); ++j) {
  545. JSONObject jo = inputData.getJSONObject(j);
  546. String currentPanoId = jo.getString("panoID");
  547. JSONArray visibles = jo.getJSONArray("visibles");
  548. JSONArray visibles3 = jo.getJSONArray("visibles3");
  549. if (pano.getString("uuid").equals(currentPanoId)) {
  550. pano.put("visibles", visibles);
  551. pano.put("visibles3", visibles3);
  552. }
  553. }
  554. }
  555. FileUtils.deleteFile(localDataPath + "vision.json");
  556. FileUtils.deleteFile(localDataPath + "vision.modeldata");
  557. FileUtils.writeFile(localDataPath + "vision.json", json.toString());
  558. ConvertUtils.convertTxtToVisionModelData(localDataPath + "vision.json", localDataPath + "vision.modeldata");
  559. ossUtil.uploadFile(bucket,viewImagesPath + "vision.modeldata", localDataPath + "vision.modeldata", false);
  560. //更新版本号
  561. SceneEditInfo editInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId());
  562. if(Objects.isNull(editInfo)){
  563. editInfo = new SceneEditInfo();
  564. editInfo.setScenePlusId(scenePlus.getId());
  565. sceneEditInfoService.save(editInfo);
  566. }else{
  567. sceneEditInfoService.upgradeVersionAndImgVersionById(editInfo.getId());
  568. //更新scenejson缓存和oss文件版本号
  569. sceneEditInfoService.upgradeSceneJsonVersion(param.getNum(), editInfo.getVersion() + 1, editInfo.getImgVersion() + 1, bucket);
  570. }
  571. return ResultData.ok();
  572. }
  573. @Override
  574. public void updateUserIdByCameraId(Long userId, Long cameraId) {
  575. this.update(new LambdaUpdateWrapper<ScenePro>()
  576. .eq(ScenePro::getCameraId, cameraId)
  577. .set(ScenePro::getUserId, userId));
  578. }
  579. @Override
  580. public ResultData uploadObjAndImg(String num, MultipartFile file) throws Exception{
  581. if(StrUtil.isEmpty(num)){
  582. throw new BusinessException(ServerCode.PARAM_REQUIRED, "num");
  583. }
  584. if(!file.getOriginalFilename().endsWith(".zip")){
  585. throw new BusinessException(ErrorCode.FAILURE_CODE_7015);
  586. }
  587. ScenePlus scenePlus = scenePlusService.getScenePlusByNum(num);
  588. if(scenePlus == null){
  589. throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
  590. }
  591. ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
  592. String bucket = scenePlusExt.getYunFileBucket();
  593. if(ModelKind.THREE_D_TILE.code().equals(scenePlusExt.getModelKind())){
  594. this.buildModel43dtiles(num, bucket, scenePlusExt.getDataSource(), file);
  595. }else{
  596. this.buildModel4Dam(num, bucket, scenePlusExt.getDataSource(), scenePlusExt.getBuildType(), file);
  597. }
  598. //更新版本信息
  599. SceneEditInfo sceneEditInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId());
  600. if(Objects.isNull(sceneEditInfo)){
  601. sceneEditInfo = new SceneEditInfo();
  602. sceneEditInfo.setScenePlusId(scenePlus.getId());
  603. sceneEditInfo.setFloorPublishVer(1);
  604. sceneEditInfo.setFloorEditVer(1);
  605. sceneEditInfo.setIsUploadObj(CommonStatus.YES.code());
  606. sceneEditInfoService.save(sceneEditInfo);
  607. }else{
  608. sceneEditInfoService.update(
  609. new LambdaUpdateWrapper<SceneEditInfo>()
  610. .setSql("version = version + 1")
  611. .setSql("floor_edit_ver = floor_edit_ver + 1")
  612. .setSql("floor_publish_ver = floor_publish_ver + 1")
  613. .setSql("img_version = img_version + 1")
  614. .set(SceneEditInfo::getIsUploadObj, CommonStatus.YES.code())
  615. .eq(SceneEditInfo::getId, sceneEditInfo.getId()));
  616. sceneEditInfoService.upgradeSceneJsonVersion(num, sceneEditInfo.getVersion() + 1, sceneEditInfo.getImgVersion() + 1, bucket);
  617. }
  618. return ResultData.ok();
  619. }
  620. /**
  621. * 老算法(dam)上传模型逻辑
  622. * @param num
  623. * @param bucket
  624. * @param dataSource
  625. * @param buildType
  626. * @throws Exception
  627. */
  628. private void buildModel4Dam(String num, String bucket, String dataSource, String buildType, MultipartFile file) throws Exception {
  629. //文件上传的位置可以自定义
  630. String path = dataSource + "_obj2txt";
  631. String zipPath = path + "/zip/";
  632. String filePath = path + "/extras/";
  633. String resultPath = path + "/results/";
  634. //压缩文件处理:解压缩,解压缩后复制等操作
  635. this.objAndImgFileHandler(resultPath, filePath, zipPath, file);
  636. //创建data.json
  637. this.writeDataJson(path);
  638. //调用算法,不同的类型调用不同的算法
  639. if("V2".equals(buildType)){
  640. CreateObjUtil.objToTxt(path , "1");
  641. }
  642. if("V3".equals(buildType)){
  643. CmdBuildUtil.BuildModelCommand(path);
  644. }
  645. //算法计算完后,生成压缩文件,上传到oss
  646. this.uploadFileofterRebuildPanoram(path, filePath, num, bucket);
  647. }
  648. /**
  649. * 新算法(3dtiles)上传模型逻辑
  650. * @param num
  651. * @param bucket
  652. * @param dataSource
  653. * @throws Exception
  654. */
  655. private void buildModel43dtiles(String num, String bucket, String dataSource, MultipartFile file) throws Exception {
  656. //文件上传的位置可以自定义
  657. String path = dataSource + "_obj2Tiles" + File.separator;
  658. String meshPath = path + "mesh";
  659. String zipPath = path + "zip" + File.separator;
  660. String zipFilePath = zipPath + file.getOriginalFilename();
  661. //压缩文件处理:解压缩,解压缩后复制等操作
  662. FileUtil.del(path);
  663. FileUtil.mkdir(zipPath);
  664. File zipFile = new File(zipFilePath);
  665. file.transferTo(zipFile);
  666. ZipUtil.unzip(zipFilePath, meshPath);
  667. //检测文件
  668. String floorsJsonPath = meshPath + File.separator + "floors.json";
  669. if(!FileUtil.exist(floorsJsonPath)){
  670. throw new BusinessException(ErrorCode.FAILURE_CODE_5068);
  671. }
  672. String floorsJsonStr = FileUtil.readUtf8String(floorsJsonPath);
  673. JSONObject floorsJsonObj = JSON.parseObject(floorsJsonStr);
  674. JSONArray floorArr = floorsJsonObj.getJSONArray("floors");
  675. if(CollUtil.isEmpty(floorArr)){
  676. throw new BusinessException(ErrorCode.FAILURE_CODE_5069);
  677. }
  678. Set<String> floorNameSet = new HashSet<>();
  679. floorArr.stream().forEach(item->{
  680. JSONObject itemObj = (JSONObject) item;
  681. //楼层目录是否存在
  682. String name = itemObj.getString("name");
  683. if(StrUtil.isEmpty(name) || !FileUtil.exist(meshPath + File.separator + name)){
  684. throw new BusinessException(ErrorCode.FAILURE_CODE_5070);
  685. }
  686. //检测obj文件是否存在
  687. String objPath = itemObj.getString("objPath");
  688. if(StrUtil.isEmpty(objPath) || !FileUtil.exist(path + objPath)){
  689. throw new BusinessException(ErrorCode.FAILURE_CODE_5070);
  690. }
  691. if(floorNameSet.contains(name)){
  692. throw new BusinessException(ErrorCode.FAILURE_CODE_5069);
  693. }
  694. floorNameSet.add(name);
  695. });
  696. //读取oss上的floors.jsoon用于校验用户上传的模型楼层数是否一一对应
  697. String ossFloorsJson = ossUtil.getFileContent(bucket,String.format(UploadFilePath.DATA_VIEW_PATH, num) + "mesh/floors.json");
  698. JSONObject orginFloorsJsonObj = JSON.parseObject(ossFloorsJson);
  699. JSONArray orginFloorArr = orginFloorsJsonObj.getJSONArray("floors");
  700. Set<String> orginFloorNameSet = orginFloorArr.stream().map(item -> {
  701. JSONObject itemObj = (JSONObject) item;
  702. return itemObj.getString("name");
  703. }).collect(Collectors.toSet());
  704. if(floorNameSet.size() != orginFloorNameSet.size()){
  705. throw new BusinessException(ErrorCode.FAILURE_CODE_5070);
  706. }
  707. orginFloorNameSet.stream().forEach(orginName->{
  708. if(!floorNameSet.contains(orginName)){
  709. throw new BusinessException(ErrorCode.FAILURE_CODE_5070);
  710. }
  711. });
  712. //调用算法
  713. String command = "bash /home/ubuntu/bin/Obj2Tiles.sh " + path;
  714. log.info("上传3dtiles模型开始, num:{}, targetPath:{}", num, path);
  715. CmdBuildUtil.Build3dtilesModel(path);
  716. log.info("上传3dtiles模型结束, num:{}, targetPath:{}", num, path);
  717. //检测计算结果
  718. String tilesPath = path + "3dtiles";
  719. String tilesetJsonPath = tilesPath + File.separator + "tileset.json";
  720. boolean success = ComputerUtil.checkComputeCompleted(tilesetJsonPath, maxCheckTimes, waitTime);
  721. if(!success){
  722. throw new BusinessException(ErrorCode.FAILURE_CODE_7013);
  723. }
  724. //删除logs
  725. FileUtil.del(tilesPath + File.separator + "logs");
  726. //算法计算完后,生成压缩文件,上传到oss
  727. //上传3dtiles
  728. ossUtil.deleteObject(bucket,String.format(UploadFilePath.IMG_VIEW_PATH, num) + "3dtiles");
  729. FileUtil.copyContent(
  730. FileUtil.file(tilesPath),
  731. FileUtil.file(FdkkLaserConfig.getProfile(bucket) + File.separator + String.format(UploadFilePath.IMG_VIEW_PATH, num) + "3dtiles"),
  732. true);
  733. //上传mesh
  734. ossUtil.deleteObject(bucket,String.format(UploadFilePath.DATA_VIEW_PATH, num) + "mesh");
  735. FileUtil.copyContent(
  736. FileUtil.file(meshPath),
  737. FileUtil.file(FdkkLaserConfig.getProfile(bucket) + File.separator + String.format(UploadFilePath.DATA_VIEW_PATH, num) + "mesh"),
  738. true);
  739. }
  740. private void uploadFileofterRebuildPanoram(String path, String filePath, String sceneNum, String bucket) throws Exception {
  741. //因为共享目录有延迟,这里循环检测算法是否计算完毕3次,每次隔五秒
  742. String uploadJsonPath = path + File.separator + "results" +File.separator+"upload.json";
  743. boolean exist = ComputerUtil.checkComputeCompleted(uploadJsonPath, maxCheckTimes, waitTime);
  744. if(!exist){
  745. throw new BusinessException(ErrorCode.FAILURE_CODE_7013);
  746. }
  747. String uploadData = FileUtils.readFile(uploadJsonPath);
  748. JSONObject uploadJson = null;
  749. JSONArray array = null;
  750. if(uploadData!=null) {
  751. uploadJson = JSONObject.parseObject(uploadData);
  752. array = uploadJson.getJSONArray("upload");
  753. }
  754. Map<String,String> map = new HashMap<String,String>();
  755. JSONObject fileJson = null;
  756. String fileName = "";
  757. String imgViewPath = String.format(UploadFilePath.IMG_VIEW_PATH, sceneNum);
  758. for(int i = 0, len = array.size(); i < len; i++) {
  759. fileJson = array.getJSONObject(i);
  760. fileName = fileJson.getString("file");
  761. //文件不存在抛出异常
  762. if (!new File(path + File.separator + "results" + File.separator + fileName).exists()) {
  763. throw new Exception(path + File.separator + "results" + File.separator + fileName + "文件不存在");
  764. }
  765. //tex文件夹
  766. if (fileJson.getIntValue("clazz") == 15) {
  767. map.put(path + File.separator + "results" + File.separator + fileName,
  768. imgViewPath + ConstantFileName.modelUUID + "_50k_texture_jpg_high1/" + fileName.replace("tex/", ""));
  769. continue;
  770. }
  771. }
  772. String damPath = path + File.separator + "results" +File.separator+ ConstantFileName.modelUUID+"_50k.dam";
  773. CreateObjUtil.convertTxtToDam( path + File.separator + "results" +File.separator+"modeldata.txt", damPath);
  774. boolean existDam = ComputerUtil.checkComputeCompleted(damPath, 5, 2);
  775. if(!existDam){
  776. throw new BusinessException(ErrorCode.FAILURE_CODE_7013);
  777. }
  778. // CreateObjUtil.convertDamToLzma(path + File.separator + "results");
  779. // CreateObjUtil.convertTxtToDam( path + File.separator + "results" +File.separator+"modeldata.txt", path + File.separator + "results" + File.separator+ConstantFileName.modelUUID+"_50k.dam");
  780. // map.put(path + File.separator + "results" +File.separator+ConstantFileName.modelUUID+"_50k.dam.lzma", imgViewPath +ConstantFileName.modelUUID+"_50k.dam.lzma");
  781. map.put(path + File.separator + "results" +File.separator+ConstantFileName.modelUUID+"_50k.dam", imgViewPath+ConstantFileName.modelUUID+"_50k.dam");
  782. String ossMeshPath = String.format(UploadFilePath.DATA_VIEW_PATH, sceneNum) + "mesh";
  783. //删除oss中的mesh
  784. ossUtil.deleteObject(bucket, ossMeshPath);
  785. //上传obj相关文件
  786. List<String> fileNames = FileUtil.listFileNames(filePath);
  787. fileNames.stream().forEach(name->{
  788. ossUtil.uploadFile(bucket,ossMeshPath + File.separator + name, filePath + name, false);
  789. });
  790. }
  791. private void writeDataJson(String path) throws IOException {
  792. JSONObject dataJson = new JSONObject();
  793. dataJson.put("obj2txt", true);
  794. dataJson.put("split_type", "SPLIT_V6");
  795. dataJson.put("data_describe", "double spherical");
  796. dataJson.put("skybox_type", "SKYBOX_V5");
  797. FileUtils.writeFile(path + "/data.json", dataJson.toString());
  798. }
  799. private void objAndImgFileHandler(String resultPath, String filePath, String zipPath, MultipartFile file)
  800. throws Exception {
  801. FileUtils.delAllFile(resultPath);
  802. File targetFile = new File(filePath);
  803. if (!targetFile.exists()) {
  804. targetFile.mkdirs();
  805. }else {
  806. FileUtils.delAllFile(filePath);
  807. }
  808. targetFile = new File(zipPath);
  809. if (!targetFile.exists()) {
  810. targetFile.mkdirs();
  811. }else {
  812. FileUtils.delAllFile(zipPath);
  813. }
  814. targetFile = new File(zipPath + file.getOriginalFilename());
  815. if(!targetFile.getParentFile().exists()){
  816. targetFile.getParentFile().mkdirs();
  817. }
  818. // 保存压缩包到本地
  819. if(targetFile.exists())
  820. {
  821. FileUtils.deleteFile(zipPath + file.getOriginalFilename());
  822. }
  823. file.transferTo(targetFile);
  824. ZipUtil.unzip(zipPath + file.getOriginalFilename(), zipPath + "data/");
  825. //源文件数据,判断是否有多个文件夹,有多个就提示错误,有一个就将文件夹里数据迁移到extras目录,无直接迁移到extras目录
  826. boolean flag = false;
  827. //目录名称,如果不为空,则压缩文件第一层是目录
  828. String targetName = "";
  829. File dataFile = new File(zipPath + "data/");
  830. for(File data : dataFile.listFiles()){
  831. if(data.isDirectory() && flag){
  832. throw new BusinessException(ErrorCode.FAILURE_CODE_5018);
  833. }
  834. if(data.isDirectory() && !flag){
  835. flag = true;
  836. targetName = data.getName();
  837. }
  838. }
  839. //是否包含obj文件
  840. boolean objFlag = false;
  841. //是否包含mtl文件
  842. boolean mtlFlag = false;
  843. File[] files = null;
  844. String dataPath = null;
  845. if(StrUtil.isEmpty(targetName)){
  846. files = dataFile.listFiles();
  847. dataPath = zipPath + "data/";
  848. }else{
  849. files = new File(zipPath + "data/" + targetName).listFiles();
  850. dataPath = zipPath + "data/" + targetName + File.separator;
  851. }
  852. for(File data : files){
  853. if(data.isDirectory()){
  854. throw new BusinessException(ErrorCode.FAILURE_CODE_5018);
  855. }
  856. if(data.getName().endsWith(".jpg") || data.getName().endsWith(".png")){
  857. if(!FileUtils.checkFileSizeIsLimit(data.length(), 1.5, "M")){
  858. throw new BusinessException(ErrorCode.FAILURE_CODE_5020);
  859. }
  860. }
  861. if(data.getName().endsWith(".obj")){
  862. if(objFlag){
  863. throw new BusinessException(ErrorCode.FAILURE_CODE_5019);
  864. }
  865. if(!data.getName().equals("mesh.obj")){
  866. throw new BusinessException(ErrorCode.FAILURE_CODE_5060);
  867. }
  868. if(!FileUtils.checkFileSizeIsLimit(data.length(), 20, "M")){
  869. throw new BusinessException(ErrorCode.FAILURE_CODE_5020);
  870. }
  871. objFlag = true;
  872. FileUtils.copyFile(dataPath + data.getName(), filePath + "mesh.obj", true);
  873. continue;
  874. }
  875. if(data.getName().endsWith(".mtl")){
  876. mtlFlag = true;
  877. }
  878. FileUtils.copyFile(dataPath + data.getName(), filePath + data.getName(), true);
  879. }
  880. //压缩文件中必须有且仅有一个obj和mtl文件,否则抛出异常
  881. if(!mtlFlag || !objFlag){
  882. throw new BusinessException(ErrorCode.FAILURE_CODE_5059);
  883. }
  884. }
  885. public ResultData downloadTexData(String num) throws Exception {
  886. if(StrUtil.isEmpty(num)){
  887. throw new BusinessException(ErrorCode.PARAM_REQUIRED);
  888. }
  889. ScenePlus scenePlus = scenePlusService.getScenePlusByNum(num);
  890. if(scenePlus == null){
  891. throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
  892. }
  893. ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
  894. String bucket = scenePlusExt.getYunFileBucket();
  895. SceneEditInfo sceneEditInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId());
  896. if(ModelKind.THREE_D_TILE.code().equals(scenePlusExt.getModelKind())){
  897. return this.downloadModel43dtiles(num, bucket, scenePlusExt, sceneEditInfo);
  898. }
  899. return this.downloadModel4Dam(num, bucket);
  900. }
  901. @Override
  902. public ScenePro getByNum(String num) {
  903. return this.getOne(new LambdaQueryWrapper<ScenePro>().eq(ScenePro::getNum, num));
  904. }
  905. private ResultData downloadModel43dtiles(String num, String bucket, ScenePlusExt scenePlusExt, SceneEditInfo sceneEditInfo){
  906. //下载mesh到本地
  907. String meshOssPath = String.format(UploadFilePath.DATA_VIEW_PATH, num) + "mesh/";
  908. String meshLocalPath = String.format(ConstantFilePath.SCENE_DATA_PATH_V4, num);
  909. String zipName = num + "_mesh.zip";
  910. String zipFilePath = String.format(ConstantFilePath.SCENE_DATA_PATH_V4, num) + zipName;
  911. //下载
  912. ossUtil.downloadFile(bucket, meshOssPath, meshLocalPath);
  913. //打包
  914. ZipUtil.zip(meshLocalPath.concat("mesh") ,zipFilePath);
  915. //上传压缩包
  916. ossUtil.uploadFile(bucket,"downloads/extras/" + zipName, zipFilePath, false);
  917. //删除本地文件
  918. FileUtil.del(meshLocalPath.concat("mesh"));
  919. FileUtil.del(zipFilePath);
  920. String url = "downloads/extras/" + zipName + "?t=" + Calendar.getInstance().getTimeInMillis();
  921. return ResultData.ok(url);
  922. }
  923. public static void main(String[] args) {
  924. File copy = FileUtil.copy(new File("D:\\4DMega\\4DKK_PROGRAM_STATIC\\scene_view_data/1680825957743071232/data/mesh/"),
  925. new File("/mnt/4Dkankan/scene_v4/1680825957743071232/data"), true);
  926. }
  927. private ResultData downloadModel4Dam(String num, String bucket){
  928. String localImagePath = String.format(ConstantFilePath.IMAGESBUFFER_FORMAT, num);
  929. if(!new File(localImagePath).exists()){
  930. new File(localImagePath).mkdirs();
  931. }
  932. String zipName = num + "_extras.zip";
  933. String zipPath = localImagePath + zipName;
  934. String dataViewPath = String.format(UploadFilePath.DATA_VIEW_PATH, num);
  935. //V3版本去oss下载2048模型
  936. String meshPath = String.format(ConstantFilePath.DATABUFFER_FORMAT, num) + "mesh";
  937. FileUtils.deleteDirectory(meshPath);
  938. ossUtil.downloadFile(bucket, dataViewPath + "mesh", meshPath);
  939. log.info("meshPath="+meshPath);
  940. if(!new File(meshPath).exists() || new File(meshPath).listFiles().length < 1){
  941. throw new BusinessException(ErrorCode.FAILURE_CODE_7006);
  942. }
  943. for(File file : new File(meshPath).listFiles()){
  944. if(file.isDirectory()){
  945. for (File item : file.listFiles()) {
  946. if(item.getName().endsWith(".obj") && !"output.house.obj".equals(item.getName()) &&
  947. !"mesh.obj".equals(item.getName())){
  948. item.delete();
  949. }
  950. if(item.getName().endsWith(".mtl") && !"output.house.mtl".equals(item.getName()) &&
  951. !"mesh.mtl".equals(item.getName())){
  952. item.delete();
  953. }
  954. }
  955. continue;
  956. }
  957. if(file.getName().endsWith(".obj") && !"output.house.obj".equals(file.getName()) &&
  958. !"mesh.obj".equals(file.getName())){
  959. file.delete();
  960. }
  961. if(file.getName().endsWith(".mtl") && !"output.house.mtl".equals(file.getName()) &&
  962. !"mesh.mtl".equals(file.getName())){
  963. file.delete();
  964. }
  965. }
  966. //打包
  967. ZipUtil.zip(meshPath, zipPath);
  968. //上传压缩包
  969. ossUtil.uploadFile(bucket,"downloads/extras/" + zipName, zipPath, false);
  970. String url = "downloads/extras/" + zipName + "?t=" + Calendar.getInstance().getTimeInMillis();
  971. FileUtil.del(zipPath);
  972. return ResultData.ok(url);
  973. }
  974. @Override
  975. public List<SceneBean> listCleanOrigScene(int cleanOrigMonth) {
  976. Date time = Calendar.getInstance().getTime();
  977. time = DateUtil.beginOfDay(DateUtil.offset(time, DateField.MONTH, -cleanOrigMonth));
  978. return this.baseMapper.selectCleanOrigScene(time);
  979. }
  980. @Override
  981. public List<SceneBean> listCleanOss4DeletedScene(int month) {
  982. Date time = Calendar.getInstance().getTime();
  983. time = DateUtil.beginOfDay(DateUtil.offset(time, DateField.MONTH, -month));
  984. return this.baseMapper.listCleanOss4DeletedScene(time);
  985. }
  986. @Override
  987. public List<SceneBean> listCleanOss4TestCamera(Set<Long> cameraIds, int month) {
  988. Date time = Calendar.getInstance().getTime();
  989. time = DateUtil.beginOfDay(DateUtil.offset(time, DateField.MONTH, -month));
  990. return this.baseMapper.listCleanOss4TestCamera(cameraIds, time);
  991. }
  992. @Override
  993. public List<SceneBean> listColdStorageScene(int cleanOrigMonth) {
  994. Date time = Calendar.getInstance().getTime();
  995. time = DateUtil.beginOfDay(DateUtil.offset(time, DateField.MONTH, -cleanOrigMonth));
  996. return this.baseMapper.selectColdStorageScene(time);
  997. }
  998. }