ModelServiceImpl.java 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. package com.fdkankan.fusion.service.impl;
  2. import java.io.File;
  3. import java.io.IOException;
  4. import java.util.*;
  5. import java.util.concurrent.CompletableFuture;
  6. import java.util.concurrent.ExecutorService;
  7. import java.util.concurrent.ThreadPoolExecutor;
  8. import java.util.stream.Collectors;
  9. import cn.hutool.core.io.FileUtil;
  10. import cn.hutool.core.thread.ThreadUtil;
  11. import com.alibaba.fastjson.JSONArray;
  12. import com.alibaba.fastjson.JSONObject;
  13. import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  14. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  15. import com.fdkankan.fusion.common.PageInfo;
  16. import com.fdkankan.fusion.common.util.*;
  17. import com.fdkankan.fusion.common.FilePath;
  18. import com.fdkankan.fusion.common.ResultCode;
  19. import com.fdkankan.fusion.entity.*;
  20. import com.fdkankan.fusion.exception.BusinessException;
  21. import com.fdkankan.fusion.mapper.IModelMapper;
  22. import com.fdkankan.fusion.request.ModelPram;
  23. import com.fdkankan.fusion.response.SceneVo;
  24. import com.fdkankan.fusion.service.ICaseNumService;
  25. import com.fdkankan.fusion.service.ICaseService;
  26. import com.fdkankan.fusion.service.IFusionNumService;
  27. import com.fdkankan.fusion.service.IModelService;
  28. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
  29. import com.fdkankan.redis.util.RedisUtil;
  30. import lombok.SneakyThrows;
  31. import lombok.extern.slf4j.Slf4j;
  32. import org.apache.commons.io.FileUtils;
  33. import org.apache.commons.lang3.StringUtils;
  34. import org.springframework.beans.BeanUtils;
  35. import org.springframework.beans.factory.annotation.Autowired;
  36. import org.springframework.beans.factory.annotation.Value;
  37. import org.springframework.scheduling.annotation.Async;
  38. import org.springframework.stereotype.Service;
  39. import org.springframework.web.multipart.MultipartFile;
  40. /**
  41. * <p>
  42. * 服务实现类
  43. * </p>
  44. *
  45. * @author
  46. * @since 2022-08-03
  47. */
  48. @Service
  49. @Slf4j
  50. public class ModelServiceImpl extends ServiceImpl<IModelMapper, Model> implements IModelService {
  51. @Autowired
  52. UploadToOssUtil uploadToOssUtil;
  53. @Autowired
  54. UploadService uploadService;
  55. @Autowired
  56. ICaseNumService caseNumService;
  57. @Autowired
  58. ICaseService caseService;
  59. @Autowired
  60. IFusionNumService fusionNumService;
  61. @Autowired
  62. RedisUtil redisUtil;
  63. @Value("${upload.query-path}")
  64. private String queryPath;
  65. @Value("${spring.profiles.active}")
  66. private String environment;
  67. @Override
  68. public Model uploadObj(MultipartFile file, String username) throws Exception {
  69. if(file.isEmpty()){
  70. throw new BusinessException(ResultCode.UPLOAD_FILE_NO_EXIST);
  71. }
  72. if(file.getSize()>10 * 1024 * 1024 * 100){
  73. throw new BusinessException(ResultCode.UPLOAD_FILE_TO_LONG);
  74. }
  75. //获取文件名
  76. String fileName = file.getOriginalFilename();
  77. if(StringUtils.isEmpty(fileName)){
  78. throw new BusinessException(ResultCode.UPLOAD_FILE_NO_EXIST);
  79. }
  80. if(com.fdkankan.fusion.common.util.StringUtils.isChinese(fileName)){
  81. throw new BusinessException(ResultCode.UPLOAD_FILE_CHINA_NAME);
  82. }
  83. if(fileName.length() >50){
  84. throw new BusinessException(ResultCode.UPLOAD_FILE_NAME_TO_LONG);
  85. }
  86. if(!fileName.toLowerCase().endsWith(".zip")){
  87. throw new BusinessException(ResultCode.UPLOAD_FILE_TYPE_ERROR);
  88. }
  89. //获取文件后缀名
  90. String modelName = fileName.substring(0,fileName.lastIndexOf("."));
  91. Model model = new Model();
  92. model.setModelTitle(modelName);
  93. model.setModelSize(FileWriterUtil.setFileSize(file.getSize()));
  94. model.setUserName(username);
  95. this.save(model);
  96. redisUtil.set(RedisKeyUtil.modelUpload+model.getModelId(),"0");
  97. runThread(file,model,this);
  98. return model;
  99. }
  100. private void setCreateStatus(Model model,Integer status){
  101. String redisKey = RedisKeyUtil.modelCancelUpload+model.getModelId();
  102. if(redisUtil.hasKey(redisKey)){
  103. if(redisUtil.get(redisKey).equals("-2")){
  104. return;
  105. }
  106. }
  107. model.setCreateStatus(status);
  108. this.saveOrUpdate(model);
  109. if(status != 1){
  110. redisUtil.set(RedisKeyUtil.modelUpload+model.getModelId(),status.toString());
  111. }
  112. }
  113. public void runThread(MultipartFile file,Model model,IModelService modelService) throws IOException {
  114. String fileName = UUID.randomUUID().toString().replace("-","") +".zip";
  115. String objPath = String.format(FilePath.OBJ_LOCAL_PATH,environment , "modelId_"+model.getModelId()) ;
  116. log.info("uploadObj--ThreadStart-fileName:{},modeId:{}",fileName,model.getModelId());
  117. File newObjFile = new File(objPath +"/" + fileName);
  118. if(!newObjFile.getParentFile().exists()){
  119. newObjFile.getParentFile().mkdirs();
  120. }
  121. // file.transferTo(newObjFile); 异步会出现 FileNotFoundException temp.
  122. FileUtils.copyInputStreamToFile(file.getInputStream(), newObjFile);
  123. ExecutorService executor = ThreadUtil.newSingleExecutor();
  124. try {
  125. CompletableFuture.runAsync(() -> {
  126. File objPathFile = null;
  127. File mntFile = null;
  128. File b3dmFile = null;
  129. File osgbFile = null;
  130. try {
  131. // file.transferTo(newObjFile); 异步会出现 FileNotFoundException temp.
  132. FileUtils.copyInputStreamToFile(file.getInputStream(), newObjFile);
  133. if(fileName.toLowerCase().endsWith(".zip")){
  134. ShellUtil.unZip(newObjFile.getPath(),objPath);
  135. }
  136. objPathFile = new File(objPath );
  137. if(!objPathFile.isDirectory()){
  138. throw new BusinessException(-1,"解压错误");
  139. }
  140. List<File> fileList = new ArrayList<>();
  141. FileWriterUtil.getCanRunList(fileList,objPathFile);
  142. if(fileList.size() <=0){
  143. throw new BusinessException(-1,"可上传文件不存在");
  144. }
  145. File file1 = fileList.get(0);
  146. if(file1 == null){
  147. throw new BusinessException(-1,"可上传文件不存在");
  148. }
  149. if(com.fdkankan.fusion.common.util.StringUtils.isChinese(file1.getName())){
  150. throw new BusinessException(-1,"压缩包中文");
  151. }
  152. String b3dmJsonPath = null;
  153. if(file1.getName().endsWith(".b3dm") ){
  154. b3dmJsonPath = FileWriterUtil.checkB3dmTileset(objPathFile);
  155. if(b3dmJsonPath == null){
  156. throw new BusinessException(-1,"缺少tileset.json文件");
  157. }
  158. }
  159. redisUtil.set(RedisKeyUtil.modelUpload+model.getModelId(),"20");
  160. String glbOssPath = String.format(FilePath.GLB_OSS_PATH,environment, model.getModelId());
  161. String name = file1.getName();
  162. if(name.contains("obj") || name.contains("OBJ")){
  163. glbOssPath = glbOssPath.replace("mesh.glb",file1.getName().replace(".obj",".glb"));
  164. model.setModelDateType("obj");
  165. model.setModelType("glb");
  166. OBJToGLBUtil.objToGlb2(file1.getPath(), file1.getPath().replace(".obj",".glb"));
  167. redisUtil.set(RedisKeyUtil.modelUpload+model.getModelId(),"65");
  168. uploadToOssUtil.uploadOss(file1.getPath().replace(".obj",".glb"),glbOssPath);
  169. if(!uploadToOssUtil.existKey(glbOssPath)){
  170. throw new BusinessException(-1,"缺少.glb文件");
  171. }
  172. }
  173. if(name.contains(".ply")){
  174. model.setModelDateType("ply");
  175. model.setModelType("ply");
  176. }
  177. if(name.contains(".las")){
  178. model.setModelDateType("las");
  179. model.setModelType("las");
  180. }
  181. if("las".equals(model.getModelType()) || "ply".equals(model.getModelType()) ){
  182. mntFile = OBJToGLBUtil.lasOrPlyToBin(file1);
  183. glbOssPath = mntFile.getPath().replace("/mnt/","")+"/webcloud";
  184. redisUtil.set(RedisKeyUtil.modelUpload+model.getModelId(),"65");
  185. uploadToOssUtil.uploadFileOss(mntFile );
  186. if(!uploadToOssUtil.existKey(glbOssPath+"/cloud.js")){
  187. throw new BusinessException(-1,"缺少cloud.js文件");
  188. }
  189. }
  190. model.setModelGlbUrl(JSONArray.toJSONString(Arrays.asList(queryPath + glbOssPath)));
  191. String b3dmPath = objPathFile.getPath().replace(FilePath.LOCAL_BASE_PATH,"fusion/");
  192. if(name.contains(".osgb")){
  193. model.setModelDateType("b3dm");
  194. model.setModelType("b3dm");
  195. redisUtil.set(RedisKeyUtil.modelUpload+model.getModelId(),"60");
  196. String localPath = OBJToGLBUtil.OsgbToB3dm(objPathFile);
  197. osgbFile = new File(localPath.replace("mnt/fusion/b3dm","/mnt/fusion/osgb"));
  198. b3dmFile = new File(localPath);
  199. b3dmJsonPath = FileWriterUtil.checkB3dmTileset(b3dmFile);
  200. if(b3dmJsonPath == null){
  201. throw new BusinessException(-1,"缺少tileset.json文件");
  202. }
  203. redisUtil.set(RedisKeyUtil.modelUpload+model.getModelId(),"80");
  204. String replace = b3dmJsonPath.replace(FilePath.MNT_BASE_PATH, "fusion/test");
  205. File file2 = new File(replace);
  206. ShellUtil.yunUpload(localPath,file2.getParent());
  207. model.setModelGlbUrl((JSONArray.toJSONString(Arrays.asList(queryPath + replace))));
  208. }
  209. if(name.contains(".b3dm") && b3dmJsonPath != null){
  210. model.setModelDateType("b3dm");
  211. model.setModelType("b3dm");
  212. redisUtil.set(RedisKeyUtil.modelUpload+model.getModelId(),"60");
  213. ShellUtil.yunUpload(objPathFile.getPath(),b3dmPath);
  214. model.setModelGlbUrl((JSONArray.toJSONString(Arrays.asList(queryPath + b3dmJsonPath.replace(FilePath.LOCAL_BASE_PATH,"fusion/")))));
  215. }
  216. setCreateStatus(model,1);
  217. modelService.saveOrUpdate(model);
  218. redisUtil.set(RedisKeyUtil.modelUpload+model.getModelId(),"100");
  219. }catch (Exception e){
  220. setCreateStatus(model,-1);
  221. log.error("uploadObj--ThreadError-modeId:{},error:{}",model.getModelId(),e);
  222. }finally {
  223. if(newObjFile!=null){
  224. FileUtil.del(newObjFile);
  225. }
  226. if(objPathFile!=null){
  227. FileUtil.del(objPathFile);
  228. }
  229. if(mntFile!=null){
  230. FileUtil.del(mntFile.getParentFile());
  231. }
  232. if(b3dmFile != null){
  233. FileUtil.del(b3dmFile.getParentFile());
  234. }
  235. if(osgbFile != null){
  236. FileUtil.del(osgbFile.getParentFile());
  237. }
  238. }
  239. }, executor).whenComplete((reslut, e) -> {
  240. log.info("uploadObj--ThreadEnd-modeId:{}",model.getModelId());
  241. });
  242. }catch (Exception e){
  243. setCreateStatus(model,-1);
  244. log.error("uploadObj--ThreadError-modeId:{},error:{}",model.getModelId(),e);
  245. }
  246. }
  247. @Override
  248. public PageInfo pageList(ModelPram param, String token) {
  249. String username = JwtUtil.getUsername(token);
  250. LambdaQueryWrapper<Model> wrapper = new LambdaQueryWrapper<>();
  251. wrapper.eq(Model::getUserName,username);
  252. wrapper.eq(Model::getType,3);
  253. wrapper.notIn(Model::getCreateStatus,-2);
  254. if(param.getStatus()!=null){ //参数2为成功,数据库中成功为1
  255. wrapper.eq(Model::getCreateStatus,param.getStatus() == 2 ? 1 :param.getStatus());
  256. }
  257. if(StringUtils.isNotBlank(param.getModelTitle())){
  258. wrapper.like(Model::getModelTitle,param.getModelTitle());
  259. }
  260. wrapper.orderByDesc(Model::getCreateTime);
  261. Page<Model> page = this.page(new Page<>(param.getPageNum(),param.getPageSize()),wrapper);
  262. for (Model model : page.getRecords()) {
  263. if(model.getType() == 3 && StringUtils.isEmpty(model.getNum())) {
  264. model.setNum(model.getModelId().toString());
  265. }
  266. }
  267. return PageInfo.PageInfo(page);
  268. }
  269. @Override
  270. public void delete(Integer modelId) {
  271. List<CaseNumEntity> caseNumEntityList = caseNumService.getByNum(modelId.toString());
  272. List<FusionNum> fusionNumList = fusionNumService.getByNum(modelId.toString());
  273. if(caseNumEntityList.size() >0 || fusionNumList.size() >0){
  274. StringBuilder title = new StringBuilder();
  275. List<Integer> caseIdIds = caseNumEntityList.parallelStream().map(CaseNumEntity::getCaseId).collect(Collectors.toList());
  276. if(caseIdIds.size() >0){
  277. List<CaseEntity> list = caseService.getByIds(caseIdIds);
  278. List<String> collect = list.parallelStream().map(CaseEntity::getCaseTitle).collect(Collectors.toList());
  279. for (String str : collect) {
  280. title.append(str).append(",");
  281. }
  282. if(title.length()>0){
  283. title.delete(title.length()-1,title.length());
  284. }
  285. }
  286. throw new BusinessException(ResultCode.CASE_USE.code, String.format(ResultCode.CASE_USE.msg,title));
  287. }
  288. Model model = this.getById(modelId);
  289. if(model == null ){
  290. throw new BusinessException(ResultCode.MODEL_NOT_EXIST);
  291. }
  292. this.removeById(modelId);
  293. fusionNumService.deleteByModelId(modelId);
  294. if(StringUtils.isNotBlank(model.getModelGlbUrl())){
  295. uploadService.deleteOssUrl(model.getModelGlbUrl());
  296. }
  297. }
  298. @Override
  299. public List<Model> getListByNum(List<String> numList) {
  300. LambdaQueryWrapper<Model> wrapper = new LambdaQueryWrapper<>();
  301. wrapper.in(Model::getNum,numList);
  302. return this.list(wrapper);
  303. }
  304. @Override
  305. public List<Model> getListByModelIds(List<Integer> modelIds) {
  306. LambdaQueryWrapper<Model> wrapper = new LambdaQueryWrapper<>();
  307. wrapper.in(Model::getModelId,modelIds);
  308. return this.list(wrapper);
  309. }
  310. @Override
  311. public List<Model> getListByModelIdStrs(List<String> numList) {
  312. LambdaQueryWrapper<Model> wrapper = new LambdaQueryWrapper<>();
  313. wrapper.in(Model::getModelId,numList);
  314. wrapper.orderByDesc(Model::getCreateTime);
  315. return this.list(wrapper);
  316. }
  317. @Override
  318. public void deleteByNum(List<String> numList) {
  319. LambdaQueryWrapper<Model> wrapper = new LambdaQueryWrapper<>();
  320. wrapper.in(Model::getNum,numList);
  321. this.remove(wrapper);
  322. }
  323. @Override
  324. public List<Model> getByUserName(String username) {
  325. LambdaQueryWrapper<Model> wrapper = new LambdaQueryWrapper<>();
  326. wrapper.eq(Model::getUserName,username)
  327. .eq(Model::getType,3);
  328. return this.list(wrapper);
  329. }
  330. @Override
  331. public Model getIsNullNewByNum(String num,Integer type) {
  332. LambdaQueryWrapper<Model> wrapper = new LambdaQueryWrapper<>();
  333. wrapper.eq(Model::getNum,num);
  334. wrapper.eq(Model::getType,type);
  335. Model model = this.getOne(wrapper);
  336. if(model == null){
  337. model = new Model();
  338. }
  339. return model;
  340. }
  341. @Override
  342. public Object getInfo(Integer modelId) {
  343. Model model = this.getById(modelId);
  344. if(model == null){
  345. throw new BusinessException(ResultCode.SCENE_NOT_EXIST);
  346. }
  347. SceneVo sceneVo = new SceneVo();
  348. BeanUtils.copyProperties(model,sceneVo);
  349. return sceneVo;
  350. }
  351. @Override
  352. public String uploadObjProgress(Integer modelId) {
  353. String redisKey = RedisKeyUtil.modelUpload+modelId;
  354. String cancel = RedisKeyUtil.modelCancelUpload+modelId;
  355. if(redisUtil.hasKey(cancel)){
  356. return redisUtil.get(cancel);
  357. }
  358. if(redisUtil.hasKey(redisKey)){
  359. return redisUtil.get(redisKey);
  360. }
  361. return "0";
  362. }
  363. @Override
  364. public void cancelUpload(Integer modelId) {
  365. String redisKey = RedisKeyUtil.modelCancelUpload+modelId;
  366. if(redisUtil.hasKey(redisKey)){
  367. return;
  368. }
  369. Model model = this.getById(modelId);
  370. if(model == null){
  371. return;
  372. }
  373. model.setCreateStatus(-2);
  374. this.updateById(model);
  375. redisUtil.set(redisKey,"-2");
  376. }
  377. @Override
  378. public HashMap<String, Model> getMapByNum(List<String> numList) {
  379. HashMap<String,Model> map = new HashMap<>();
  380. List<Model> modelList = this.getListByNum(numList);
  381. modelList.forEach(entity-> map.put(entity.getNum() + entity.getType(),entity));
  382. return map;
  383. }
  384. }