package com.fdkankan.fusion.service.impl; import java.io.File; import java.io.IOException; import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.ThreadPoolExecutor; import java.util.stream.Collectors; import cn.hutool.core.io.FileUtil; import cn.hutool.core.thread.ThreadUtil; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.fdkankan.fusion.common.PageInfo; import com.fdkankan.fusion.common.util.*; import com.fdkankan.fusion.common.FilePath; import com.fdkankan.fusion.common.ResultCode; import com.fdkankan.fusion.entity.*; import com.fdkankan.fusion.exception.BusinessException; import com.fdkankan.fusion.mapper.IModelMapper; import com.fdkankan.fusion.request.ModelPram; import com.fdkankan.fusion.response.SceneVo; import com.fdkankan.fusion.service.ICaseNumService; import com.fdkankan.fusion.service.ICaseService; import com.fdkankan.fusion.service.IFusionNumService; import com.fdkankan.fusion.service.IModelService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.fdkankan.redis.util.RedisUtil; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; /** *

* 服务实现类 *

* * @author * @since 2022-08-03 */ @Service @Slf4j public class ModelServiceImpl extends ServiceImpl implements IModelService { @Autowired UploadToOssUtil uploadToOssUtil; @Autowired UploadService uploadService; @Autowired ICaseNumService caseNumService; @Autowired ICaseService caseService; @Autowired IFusionNumService fusionNumService; @Autowired RedisUtil redisUtil; @Value("${upload.query-path}") private String queryPath; @Value("${spring.profiles.active}") private String environment; @Override public Model uploadObj(MultipartFile file, String username) throws Exception { if(file.isEmpty()){ throw new BusinessException(ResultCode.UPLOAD_FILE_NO_EXIST); } if(file.getSize()>10 * 1024 * 1024 * 100){ throw new BusinessException(ResultCode.UPLOAD_FILE_TO_LONG); } //获取文件名 String fileName = file.getOriginalFilename(); if(StringUtils.isEmpty(fileName)){ throw new BusinessException(ResultCode.UPLOAD_FILE_NO_EXIST); } if(com.fdkankan.fusion.common.util.StringUtils.isChinese(fileName)){ throw new BusinessException(ResultCode.UPLOAD_FILE_CHINA_NAME); } if(fileName.length() >50){ throw new BusinessException(ResultCode.UPLOAD_FILE_NAME_TO_LONG); } if(!fileName.toLowerCase().endsWith(".zip")){ throw new BusinessException(ResultCode.UPLOAD_FILE_TYPE_ERROR); } //获取文件后缀名 String modelName = fileName.substring(0,fileName.lastIndexOf(".")); Model model = new Model(); model.setModelTitle(modelName); model.setModelSize(FileWriterUtil.setFileSize(file.getSize())); model.setUserName(username); this.save(model); redisUtil.set(RedisKeyUtil.modelUpload+model.getModelId(),"0"); runThread(file,model,this); return model; } private void setCreateStatus(Model model,Integer status){ String redisKey = RedisKeyUtil.modelCancelUpload+model.getModelId(); if(redisUtil.hasKey(redisKey)){ if(redisUtil.get(redisKey).equals("-2")){ return; } } model.setCreateStatus(status); this.saveOrUpdate(model); if(status != 1){ redisUtil.set(RedisKeyUtil.modelUpload+model.getModelId(),status.toString()); } } public void runThread(MultipartFile file,Model model,IModelService modelService){ ExecutorService executor = ThreadUtil.newSingleExecutor(); try { CompletableFuture.runAsync(() -> { File newObjFile = null; File objPathFile = null; File mntFile = null; try { String fileName = UUID.randomUUID().toString().replace("-","") +".zip"; String objPath = String.format(FilePath.OBJ_LOCAL_PATH,environment , "modelId_"+model.getModelId()) ; log.info("uploadObj--ThreadStart-fileName:{},modeId:{}",fileName,model.getModelId()); newObjFile = new File(objPath +"/" + fileName); if(!newObjFile.getParentFile().exists()){ newObjFile.mkdirs(); } file.transferTo(newObjFile); if(fileName.toLowerCase().endsWith(".zip")){ ShellUtil.unZip(newObjFile.getPath(),objPath); } objPathFile = new File(objPath ); if(!objPathFile.isDirectory()){ throw new BusinessException(-1,"解压错误"); } List fileList = new ArrayList<>(); FileWriterUtil.getCanRunList(fileList,objPathFile); if(fileList.size() <=0){ throw new BusinessException(-1,"可上传文件不存在"); } File file1 = fileList.get(0); if(file1 == null){ throw new BusinessException(-1,"可上传文件不存在"); } if(com.fdkankan.fusion.common.util.StringUtils.isChinese(file1.getName())){ throw new BusinessException(-1,"压缩包中文"); } String b3dmJsonPath = null; if(file1.getName().endsWith(".b3dm") ){ b3dmJsonPath = FileWriterUtil.checkB3dmTileset(objPathFile); if(b3dmJsonPath == null){ throw new BusinessException(-1,"缺少tileset.json文件"); } } redisUtil.set(RedisKeyUtil.modelUpload+model.getModelId(),"20"); String glbOssPath = String.format(FilePath.GLB_OSS_PATH,environment, model.getModelId()); String name = file1.getName(); if(name.contains("obj") || name.contains("OBJ")){ glbOssPath = glbOssPath.replace("mesh.glb",file1.getName().replace(".obj",".glb")); model.setModelDateType("obj"); model.setModelType("glb"); OBJToGLBUtil.objToGlb2(file1.getPath(), file1.getPath().replace(".obj",".glb")); redisUtil.set(RedisKeyUtil.modelUpload+model.getModelId(),"65"); uploadToOssUtil.uploadOss(file1.getPath().replace(".obj",".glb"),glbOssPath); if(!uploadToOssUtil.existKey(glbOssPath)){ throw new BusinessException(-1,"缺少.glb文件"); } } if(name.contains(".ply")){ model.setModelDateType("ply"); model.setModelType("ply"); } if(name.contains(".las")){ model.setModelDateType("las"); model.setModelType("las"); } if("las".equals(model.getModelType()) || "ply".equals(model.getModelType()) ){ mntFile = OBJToGLBUtil.lasOrPlyToBin(file1); glbOssPath = mntFile.getPath().replace("/mnt/","")+"/webcloud"; redisUtil.set(RedisKeyUtil.modelUpload+model.getModelId(),"65"); uploadToOssUtil.uploadFileOss(mntFile ); if(!uploadToOssUtil.existKey(glbOssPath+"/cloud.js")){ throw new BusinessException(-1,"缺少cloud.js文件"); } } model.setModelGlbUrl(JSONArray.toJSONString(Arrays.asList(queryPath + glbOssPath))); String b3dmPath = objPathFile.getPath().replace(FilePath.LOCAL_BASE_PATH,"fusion/"); if(name.contains(".osgb")){ model.setModelDateType("osgb"); model.setModelType("b3dm"); redisUtil.set(RedisKeyUtil.modelUpload+model.getModelId(),"60"); String localPath = OBJToGLBUtil.OsgbToB3dm(objPathFile); String jsonPath = null; jsonPath = FileWriterUtil.checkB3dmTileset(objPathFile); if(jsonPath == null){ throw new BusinessException(-1,"缺少tileset.json文件"); } redisUtil.set(RedisKeyUtil.modelUpload+model.getModelId(),"80"); ShellUtil.yunUpload(localPath,b3dmPath); model.setModelGlbUrl((JSONArray.toJSONString(Arrays.asList(queryPath + jsonPath.replace(FilePath.LOCAL_BASE_PATH,"fusion/"))))); //FileUtil.del(localPath); } if(name.contains(".b3dm") && b3dmJsonPath != null){ model.setModelDateType("b3dm"); model.setModelType("b3dm"); redisUtil.set(RedisKeyUtil.modelUpload+model.getModelId(),"60"); ShellUtil.yunUpload(objPathFile.getPath(),b3dmPath); model.setModelGlbUrl((JSONArray.toJSONString(Arrays.asList(queryPath + b3dmJsonPath.replace(FilePath.LOCAL_BASE_PATH,"fusion/"))))); } setCreateStatus(model,1); modelService.saveOrUpdate(model); redisUtil.set(RedisKeyUtil.modelUpload+model.getModelId(),"100"); }catch (Exception e){ setCreateStatus(model,-1); log.error("uploadObj--ThreadError-modeId:{},error:{}",model.getModelId(),e); }finally { if(newObjFile!=null){ FileUtil.del(newObjFile); } if(objPathFile!=null){ FileUtil.del(objPathFile); } if(mntFile!=null){ FileUtil.del(mntFile.getParentFile()); } } }, executor).whenComplete((reslut, e) -> { log.info("uploadObj--ThreadEnd-modeId:{}",model.getModelId()); }); }catch (Exception e){ setCreateStatus(model,-1); log.error("uploadObj--ThreadError-modeId:{},error:{}",model.getModelId(),e); } } @Override public PageInfo pageList(ModelPram param, String token) { String username = JwtUtil.getUsername(token); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Model::getUserName,username); wrapper.eq(Model::getType,3); wrapper.notIn(Model::getCreateStatus,-2); if(param.getStatus()!=null){ //参数2为成功,数据库中成功为1 wrapper.eq(Model::getCreateStatus,param.getStatus() == 2 ? 1 :param.getStatus()); } if(StringUtils.isNotBlank(param.getModelTitle())){ wrapper.like(Model::getModelTitle,param.getModelTitle()); } wrapper.orderByDesc(Model::getCreateTime); Page page = this.page(new Page<>(param.getPageNum(),param.getPageSize()),wrapper); for (Model model : page.getRecords()) { if(model.getType() == 3 && StringUtils.isEmpty(model.getNum())) { model.setNum(model.getModelId().toString()); } } return PageInfo.PageInfo(page); } @Override public void delete(Integer modelId) { List caseNumEntityList = caseNumService.getByNum(modelId.toString()); List fusionNumList = fusionNumService.getByNum(modelId.toString()); if(caseNumEntityList.size() >0 || fusionNumList.size() >0){ StringBuilder title = new StringBuilder(); List caseIdIds = caseNumEntityList.parallelStream().map(CaseNumEntity::getCaseId).collect(Collectors.toList()); if(caseIdIds.size() >0){ List list = caseService.getByIds(caseIdIds); List collect = list.parallelStream().map(CaseEntity::getCaseTitle).collect(Collectors.toList()); for (String str : collect) { title.append(str).append(","); } if(title.length()>0){ title.delete(title.length()-1,title.length()); } } throw new BusinessException(ResultCode.CASE_USE.code, String.format(ResultCode.CASE_USE.msg,title)); } Model model = this.getById(modelId); if(model == null ){ throw new BusinessException(ResultCode.MODEL_NOT_EXIST); } this.removeById(modelId); fusionNumService.deleteByModelId(modelId); if(StringUtils.isNotBlank(model.getModelGlbUrl())){ uploadService.deleteOssUrl(model.getModelGlbUrl()); } } @Override public List getListByNum(List numList) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.in(Model::getNum,numList); return this.list(wrapper); } @Override public List getListByModelIds(List modelIds) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.in(Model::getModelId,modelIds); return this.list(wrapper); } @Override public List getListByModelIdStrs(List numList) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.in(Model::getModelId,numList); wrapper.orderByDesc(Model::getCreateTime); return this.list(wrapper); } @Override public void deleteByNum(List numList) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.in(Model::getNum,numList); this.remove(wrapper); } @Override public List getByUserName(String username) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Model::getUserName,username) .eq(Model::getType,3); return this.list(wrapper); } @Override public Model getIsNullNewByNum(String num,Integer type) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(Model::getNum,num); wrapper.eq(Model::getType,type); Model model = this.getOne(wrapper); if(model == null){ model = new Model(); } return model; } @Override public Object getInfo(Integer modelId) { Model model = this.getById(modelId); if(model == null){ throw new BusinessException(ResultCode.SCENE_NOT_EXIST); } SceneVo sceneVo = new SceneVo(); BeanUtils.copyProperties(model,sceneVo); return sceneVo; } @Override public String uploadObjProgress(Integer modelId) { String redisKey = RedisKeyUtil.modelUpload+modelId; String cancel = RedisKeyUtil.modelCancelUpload+modelId; if(redisUtil.hasKey(cancel)){ return redisUtil.get(cancel); } if(redisUtil.hasKey(redisKey)){ return redisUtil.get(redisKey); } return "0"; } @Override public void cancelUpload(Integer modelId) { String redisKey = RedisKeyUtil.modelCancelUpload+modelId; if(redisUtil.hasKey(redisKey)){ return; } Model model = this.getById(modelId); if(model == null){ return; } model.setCreateStatus(-2); this.updateById(model); redisUtil.set(redisKey,"-2"); } @Override public HashMap getMapByNum(List numList) { HashMap map = new HashMap<>(); List modelList = this.getListByNum(numList); modelList.forEach(entity-> map.put(entity.getNum() + entity.getType(),entity)); return map; } }