package com.fdkankan.fusion.down; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IORuntimeException; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.deepoove.poi.XWPFTemplate; import com.fdkankan.fusion.common.FilePath; import com.fdkankan.fusion.common.ResultCode; import com.fdkankan.fusion.common.ResultData; import com.fdkankan.fusion.common.util.DateUtils; import com.fdkankan.fusion.common.util.ShellUtil; import com.fdkankan.fusion.common.util.LocalToOssUtil; import com.fdkankan.fusion.config.CacheUtil; import com.fdkankan.fusion.entity.*; import com.fdkankan.fusion.exception.BusinessException; import com.fdkankan.fusion.httpClient.LaserService; import com.fdkankan.fusion.httpClient.response.FdkkResponse; import com.fdkankan.fusion.request.CaseParam; import com.fdkankan.fusion.response.DownVo; import com.fdkankan.fusion.response.DownloadProcessVo; import com.fdkankan.fusion.response.FusionNumVo; import com.fdkankan.fusion.response.SceneVo; import com.fdkankan.fusion.service.*; import com.fdkankan.fusion.service.impl.DownService; import com.fdkankan.redis.util.RedisUtil; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.FactoryBean; 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 java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Date; import java.util.HashSet; import java.util.List; @Service @Slf4j public class CaseDownService { @Value("${server.servlet.context-path}") String basePath; public static String jsonDataName = "data.json"; public static String caseInfo = "/case/getInfo?caseId="; public static String caseSettingsInfo = "/caseSettings/info?caseId="; public static String hostIcon = "/edit/hotIcon/list?caseId="; public static String caseView = "/caseView/allList?caseId="; public static String caseFiles = "/caseFiles/allList?caseId="; public static String caseFilesType = "/caseFilesType/allList?caseId="; public static String caseScene = "/case/sceneList?caseId="; public static String caseFusion = "/caseFusion/list?caseId="; public static String caseVideoFolder = "/caseVideoFolder/allList?caseId="; public static String caseVideo = "/caseVideo/allList?folderId="; public static String caseTag = "/caseTag/allList?caseId="; public static String caseTagPoint = "/caseTagPoint/allList?tagId="; public static String caseInquest = "/caseInquest/info?caseId="; public static String caseExtractDetail = "/caseExtractDetail/info?caseId="; public static String fusionGuide = "/fusionGuide/allList?caseId="; public static String fusionGuidePath = "/fusionGuidePath/allList?guideId="; public static String fusionMeter = "/fusionMeter/allList?fusionId="; public static String model = "/model/getInfo?modelId="; public static String caseImg = "/caseImg/getFfmpegImage?caseId="; public static String inquestInfoUrl = "/caseInquestInfo/info?caseId="; public static String casePathInfoUrl = "/casePath/info?caseId="; public static String laserData = "/laser/dataset/%s/getDataSet"; public static String laserDataSetAndControlPoint = "/laser/4dage/%s/getDataSetAndControlPoint"; public static String laserDataQuery = "/laser/filter/%s/query?datasetId=%s"; @Autowired ICaseService caseService; @Autowired ICaseSettingsService caseSettingsService; @Autowired IFusionNumService fusionNumService; @Autowired ICaseViewService caseViewService; @Autowired ICaseVideoFolderService caseVideoFolderService; @Autowired ICaseVideoService caseVideoService; @Autowired ICaseFilesService caseFilesService; @Autowired ICaseFilesTypeService caseFilesTypeService; @Autowired IHotIconService hotIconService; @Autowired ICaseTagService caseTagService; @Autowired ICaseTagPointService caseTagPointService; @Autowired IFusionGuideService fusionGuideService; @Autowired IFusionGuidePathService fusionGuidePathService; @Autowired ICaseInquestService caseInquestService; @Autowired ICaseExtractDetailService caseExtractDetailService; @Autowired IFusionMeterService fusionMeterService; @Autowired IModelService modelService; @Autowired LaserService laserService; @Autowired ICaseOfflineService caseOfflineService; @Autowired ICaseImgService caseImgService; @Autowired ICaseInquestInfoService caseInquestInfoService; @Autowired ICasePathService casePathService; @Autowired RedisUtil redisUtil; public static String downProcessKey = "fusion:down:offline:process:caseId:%s"; public static String downProcessKey2 = "fusion:down:process:caseId:%s"; public static String buildSceneKey = "fusion:build:scene:"; public static final String BUILD_SCENE_OFFLINE_CASE = "BUILD:SCENE:OFFLINE:CASE"; public DownVo checkDown(Integer caseId) { DownVo downVo = new DownVo(); // CaseOffline byCaseId = caseOfflineService.getByCaseId(caseId); // if(byCaseId != null){ // downVo.setDownloadStatus(3); // downVo.setDownloadUrl(byCaseId.getOfflineUrl()); // } return downVo; } @Async public void downOffline(Integer caseId,String zipPath){ String caseOffPath = null; redisUtil.set(BUILD_SCENE_OFFLINE_CASE,caseId+"",60 * 60 * 24); try { String redisKey = String.format(downProcessKey, caseId); if( redisUtil.hasKey(redisKey)){ String res = redisUtil.get(redisKey); DownloadProcessVo downloadProcessVo = JSONObject.parseObject(res, DownloadProcessVo.class); if(downloadProcessVo.getStatus() ==1000 && (downloadProcessVo.getPercent()== null || downloadProcessVo.getPercent() != 100)){ return; } } String timeKey = DateUtils.dateStr(); caseOffPath = zipPath+"offline_"+caseId+"_"+timeKey ; caseService.updateOfflineStatus(caseId,1,zipPath); setRedisProcess(caseId,0); //复制前端资源 cpIndexHtml(caseId,caseOffPath); setRedisProcess(caseId,10); //创建data.json并下载资源 createDataJson(caseId,caseOffPath); //打包zip //caseOfflineService.saveByCase(caseId,caseOffPath); setRedisProcess(caseId,100,caseOffPath); caseService.updateOfflineStatus(caseId,2,caseOffPath); }catch (IOException e){ log.info("down-offline-IOException:{}",caseId,e); setRedisProcess(caseId,0,null,1004); caseService.updateOfflineStatus(caseId,1004,caseOffPath); }catch (IORuntimeException e){ log.info("down-offline-IORuntimeException:{}",caseId,e); setRedisProcess(caseId,0,null,1004); caseService.updateOfflineStatus(caseId,1004,caseOffPath); }catch (Exception e){ log.info("down-offline-Exception:{}",caseId,e); setRedisProcess(caseId,0,null,1003); caseService.updateOfflineStatus(caseId,1003,caseOffPath); }finally { redisUtil.del(BUILD_SCENE_OFFLINE_CASE); } } public void setRedisProcess(Integer caseId,Integer num){ setRedisProcess(caseId,num,null,1000); if(num ==0){ String redisKey2 = String.format(downProcessKey2, caseId); redisUtil.set(redisKey2,"1",60); } } public void setRedisProcess(Integer caseId,Integer num,String url){ setRedisProcess(caseId,num,url,1000); } public void setRedisProcess(Integer caseId,Integer num,String url,Integer status){ String redisKey = String.format(downProcessKey, caseId); log.info("down-offline-process:{},{},{}",caseId,num,url); DownloadProcessVo processVo = new DownloadProcessVo(); processVo.setStatus(status); processVo.setPercent(num); processVo.setUrl( url); processVo.setCaseId( caseId); redisUtil.set(redisKey,JSONObject.toJSONString(processVo),60 * 60 * 24); } public DownloadProcessVo process(Integer caseId) { DownloadProcessVo downVo = new DownloadProcessVo(); String redisKey = String.format(downProcessKey, caseId); String redisKey2 = String.format(downProcessKey2, caseId); if(redisUtil.hasKey(redisKey)){ DownloadProcessVo downloadProcessVo = JSONObject.parseObject(redisUtil.get(redisKey), DownloadProcessVo.class); if(redisUtil.hasKey(redisKey2)){ redisUtil.set(redisKey2,String.valueOf(Integer.parseInt(redisUtil.get(redisKey2)) + 1),60); }else { redisUtil.set(redisKey2,"1",60); } if(downloadProcessVo.getPercent() == 100){ downloadProcessVo.setPercent(100); }else{ Integer percent = Integer.parseInt(redisUtil.get(redisKey2)) <100 ? Integer.parseInt(redisUtil.get(redisKey2)) : 99; downloadProcessVo.setPercent(percent); } return downloadProcessVo; } return downVo; } public void createDataJson(Integer caseId,String caseOffPath){ log.info("down-offline-createDataJson:{}",caseOffPath); JSONObject jsonObject = new JSONObject(); CaseParam param = new CaseParam(); param.setCaseId(caseId); //设置案件信息 jsonObject.put(basePath+inquestInfoUrl+caseId, ResultData.ok(caseInquestInfoService.getByCaseId(caseId))); jsonObject.put(basePath+caseInfo+caseId, ResultData.ok(caseService.getInfo(caseId))); List caseSettings = caseSettingsService.getByFusionId(caseId); jsonObject.put(basePath+caseSettingsInfo+caseId, ResultData.ok(caseSettings)); for (CaseSettings caseSetting : caseSettings) { downResource(caseId,caseSetting.getBack(),caseOffPath); downResource(caseId,caseSetting.getCover(),caseOffPath); } List listByCaseId = fusionNumService.getListByCaseId(caseId,null); jsonObject.put(basePath+caseFusion+caseId, ResultData.ok(listByCaseId)); for (FusionNumVo fusion : listByCaseId) { jsonObject.put(basePath+fusionMeter+fusion.getFusionId(), ResultData.ok(fusionMeterService.getListByFusionId(fusion.getFusionId(),null))); } for (FusionNumVo fusionNumVo : listByCaseId) { //下载媒体库模型 if(fusionNumVo.getSceneData() != null){ if(fusionNumVo.getSceneData().getType() ==3 && StringUtils.isNotBlank(fusionNumVo.getSceneData().getModelGlbUrl()) ){ downModel(caseId,fusionNumVo.getSceneData().getModelGlbUrl(),caseOffPath); } } } List sceneVos = caseService.sceneList(param); for (SceneVo sceneData : sceneVos) { //下载模型 if(StringUtils.isNotBlank(sceneData.getModelGlbUrl())){ downModel(caseId,sceneData.getModelGlbUrl(),caseOffPath); } if(sceneData.getType() != 3){ //下载场景离线包 downSwkk(caseId,sceneData.getNum(),sceneData.getType(),caseOffPath); } if(sceneData.getType() == 2 || sceneData.getType() == 5){ FdkkResponse sceneInfo = laserService.getSceneInfo(sceneData.getNum()); HashSet dataSetIds = new HashSet<>(); if(sceneInfo != null){ JSONArray jsonArray = JSONArray.parseArray(JSONArray.toJSONString(sceneInfo.getData())); JSONArray newJsonArray = new JSONArray(); for (Object object : jsonArray) { JSONObject sceneInfoObj = (JSONObject) object; String newPath = String.format(FilePath.OFFLINE_LASER_OSS_PATH, sceneData.getNum(), sceneData.getNum()); String mapping = sceneInfoObj.getString("mapping"); String oldPath = sceneInfoObj.getString("webBin"); String webBin = null; if(StringUtils.isNotBlank(mapping)){ webBin =newPath + mapping+ File.separator+ oldPath; }else { webBin = newPath+ oldPath; } sceneInfoObj.put("oldWebBin",oldPath); sceneInfoObj.put("webBin",webBin); newJsonArray.add(sceneInfoObj); dataSetIds.add( sceneInfoObj.getString("id")); } sceneInfo.setData(newJsonArray); jsonObject.put(String.format(laserData,sceneData.getNum()),sceneInfo); if(!dataSetIds.isEmpty()){ for (String dataSetId : dataSetIds) { FdkkResponse sceneInfo2 = laserService.getSceneInfoQuery(sceneData.getNum(),dataSetId); jsonObject.put(String.format(laserDataQuery,sceneData.getNum(),dataSetId),sceneInfo2); } } } FdkkResponse dataSetAndControlPoint = laserService.getDataSetAndControlPoint(sceneData.getNum()); if(dataSetAndControlPoint !=null){ jsonObject.put(String.format(laserDataSetAndControlPoint,sceneData.getNum()),dataSetAndControlPoint); } } if(sceneData.getModelId() != null){ jsonObject.put(basePath+model+sceneData.getModelId(), ResultData.ok(modelService.getInfo(sceneData.getModelId()))); } } jsonObject.put(basePath+caseScene+caseId, ResultData.ok(sceneVos)); List caseViews = caseViewService.allList(caseId, null, null, null, null); jsonObject.put(basePath+caseView+caseId, ResultData.ok(caseViews)); for (CaseView view : caseViews) { downResource(caseId,view.getViewImg(),caseOffPath); downResource(caseId,view.getViewImgSmall(),caseOffPath); } List videoFolders = caseVideoFolderService.getAllList(caseId); jsonObject.put(basePath+caseVideoFolder+caseId, ResultData.ok(videoFolders)); for (CaseVideoFolder videoFolder : videoFolders) { downResource(caseId,videoFolder.getVideoFolderCover(),caseOffPath); downResource(caseId,videoFolder.getVideoMergeUrl(),caseOffPath); List allList = caseVideoService.getAllList(videoFolder.getVideoFolderId()); for (CaseVideo video : allList) { downResource(caseId,video.getVideoCover(),caseOffPath); downResource(caseId,video.getVideoPath(),caseOffPath); } jsonObject.put(basePath+caseVideo+videoFolder.getVideoFolderId(), ResultData.ok(allList)); } List caseFilesList = caseFilesService.allList(caseId, null); for (CaseFiles files : caseFilesList) { downResource(caseId,files.getFilesUrl(),caseOffPath); } jsonObject.put(basePath+caseFiles+caseId, ResultData.ok(caseFilesList)); jsonObject.put(basePath+caseFilesType+caseId, ResultData.ok(caseFilesTypeService.list())); List hotIconList = hotIconService.getListByFusionId(caseId); for (HotIcon hotIcon : hotIconList) { downResource(caseId,hotIcon.getIconUrl(),caseOffPath); } jsonObject.put(basePath+hostIcon+caseId, ResultData.ok(hotIconList)); List caseTagList = caseTagService.getListByFusionId(caseId); jsonObject.put(basePath+caseTag+caseId, ResultData.ok(caseTagList)); for (CaseTag tag : caseTagList) { jsonObject.put(basePath+caseTagPoint+tag.getTagId(), ResultData.ok(caseTagPointService.allList(tag.getTagId()))); downResources(caseId,tag.getTagImgUrl(),caseOffPath); downResource(caseId,tag.getHotIconUrl(),caseOffPath); downResource(caseId,tag.getAudio(),caseOffPath); } jsonObject.put(basePath+casePathInfoUrl+caseId, ResultData.ok(casePathService.getByFusionId(caseId))); List fusionGuides = fusionGuideService.getByFusionId(caseId); jsonObject.put(basePath+fusionGuide+caseId, ResultData.ok(fusionGuides)); for (FusionGuide guide : fusionGuides) { downResource(caseId,guide.getCover(),caseOffPath); List listByGuideId = fusionGuidePathService.getListByGuideId(guide.getFusionGuideId()); for (FusionGuidePath guidePath : listByGuideId) { downResource(caseId,guidePath.getCover(),caseOffPath); } jsonObject.put(basePath+fusionGuidePath+guide.getFusionGuideId(), ResultData.ok(listByGuideId)); } CaseInquest caseInquest1 = caseInquestService.getByCaseId(caseId); if(caseInquest1 != null){ XWPFTemplate inquestTemp = caseInquestService.getWordByTemplate(caseInquest1); downWordByTemplate(caseId,inquestTemp,"caseInquest.doc",caseOffPath); } jsonObject.put(basePath+caseInquest+caseId, ResultData.ok(caseInquest1)); CaseExtractDetail caseExtractDetail1 = caseExtractDetailService.getByCaseId(caseId); if(caseExtractDetail1 != null){ XWPFTemplate detailTemp = caseExtractDetailService.getWordByTemplate(caseExtractDetail1); downWordByTemplate(caseId,detailTemp,"caseExtractDetail.doc",caseOffPath); } jsonObject.put(basePath+caseExtractDetail+caseId, ResultData.ok(caseExtractDetail1)); List caseImgList = caseImgService.getByCaseId(caseId, 1); for (CaseImg img : caseImgList) { downResource(img.getCaseId(),img.getImgUrl(),caseOffPath); } jsonObject.put(basePath+caseImg+caseId, ResultData.ok(caseImgList)); FileUtil.writeString(JSON.toJSONString(jsonObject), caseOffPath+"/www/package/"+jsonDataName,"UTF-8"); } //http://127.0.0.1:8080/offline.html?caseId=362&app=1&share=1#/show/summary static String batName = "start-browser.bat"; public void cpIndexHtml(Integer caseId,String caseOffPath) throws IOException { log.info("down-offline-cpIndexHtml:{}",caseOffPath); FileUtil.copyContent(new File(FilePath.OFFLINE_TEMPLATE_PATH),new File(caseOffPath),true); String s = FileUtil.readString(caseOffPath + File.separator + batName, StandardCharsets.UTF_8); String s1 = s.replaceAll("@caseId", String.valueOf(caseId)); if(CacheUtil.settingEntity.getGa()){ s1 = s.replaceAll("@caseId", String.valueOf(caseId)+"^&ga=true"); } FileUtil.writeString(s1, caseOffPath + File.separator + batName,"UTF-8"); } @Autowired DownService downService; @Autowired LocalToOssUtil localToOssUtil; public void downSwkk(Integer caseId,String num,Integer type,String offPath){ String swkkPath = offPath+ "/www/swkk"; String swssPath = offPath + "/www/swss"; String numPath = swkkPath; Boolean isLaser = false; if(type == 2 || type == 5){ isLaser = true; numPath = swssPath; } Boolean wita = true; Long startTime = new Date().getTime(); Long outTime = new Date().getTime(); Long wiatTime = 10000L; JSONObject jsonObject = getSceneInfo(num); Integer sceneId = jsonObject.getInteger("id"); laserService.rebuildOffline( isLaser ? swssPath : swkkPath,isLaser,sceneId); while (wita){ Long nowTime = new Date().getTime(); if(nowTime - startTime < wiatTime){ continue; } if(nowTime - outTime > 1000 * 60 * 60 * 2){ //下载单个场景超时时间 throw new BusinessException(ResultCode.SYSTEM_ERROR); } startTime = nowTime; jsonObject = getSceneInfo(num); sceneId = jsonObject.getInteger("id"); Boolean meshStatus = jsonObject.getBoolean("meshRebuildOffline"); Boolean laserStatus = jsonObject.getBoolean("rebuildOffline"); String meshOfflineFolder = jsonObject.getString("meshOfflineFolder"); String laserOfflineFolder = jsonObject.getString("offlineFolder"); //1 生成成功 ,0:正在生成 1,初次生成 2,下载失败 Integer laserOffStatus = jsonObject.getInteger("buildOfflineStatus"); //1 生成成功,0:正在生成 1,初次生成 2,下载失败 Integer meshBuildOfflineStatus = jsonObject.getInteger("meshBuildOfflineStatus"); wita = downSceneOffline(num,sceneId, isLaser, isLaser ? swssPath : swkkPath, isLaser ? laserStatus : meshStatus, isLaser ? laserOfflineFolder : meshOfflineFolder, isLaser ? laserOffStatus : meshBuildOfflineStatus ); } File file = new File(numPath + File.separator + num); if(!file.exists()){ log.info("场景下载失败-num:{}",num); throw new BusinessException(ResultCode.SCENE_DOWN_ERROR); } } private JSONObject getSceneInfo(String num){ FdkkResponse fdkkResponse = laserService.sceneLocInfo(num); if(fdkkResponse.getCode() != 200){ throw new BusinessException(ResultCode.SYSTEM_ERROR); } return (JSONObject) fdkkResponse.getData(); } /** * @param buildOfflineStatus //1 生成成功,0:正在生成 1,初次生成 2,下载失败 */ private Boolean downSceneOffline(String num,Integer sceneId, Boolean isLaser, String offPath, Boolean rebuildOffline, String offlineFolder, Integer buildOfflineStatus) { if(buildOfflineStatus == null|| buildOfflineStatus == 1 || buildOfflineStatus == -1 || buildOfflineStatus ==2){ return false; } return true; } @Value("${upload.query-path}") private String queryPath; public void downZip(Integer type ,String uri,String kkzipPath,String kknumPath,String sszipPath,String ssNumPath){ try { if(type != 2 && type != 5){ //深时点云 if(uri.contains("?")){ uri = uri.split("[?]")[0]; } ShellUtil.yunDownload(uri.replace(queryPath, ""), kkzipPath); ShellUtil.unZip(kkzipPath,kknumPath); FileUtil.del(kkzipPath); }else { ShellUtil.yunDownloadSs(uri.replace(queryPath, ""), sszipPath); ShellUtil.unZip(sszipPath,ssNumPath); FileUtil.del(sszipPath); } }catch (Exception e){ log.info("下载场景离线包失败:{}",uri,e); } } public void downModel(Integer caseId, String modelGlbUrl,String offPath) { String path = offPath +FilePath.OFFLINE_OSS_PATH; JSONArray jsonArray = JSONArray.parseArray(modelGlbUrl); for (Object object : jsonArray) { String res = (String) object; log.info("下载模型:{}",res); if(res.contains(".json") || res.contains(".obj")){ res = new File(res).getParentFile().getPath(); } localToOssUtil.downForm(res,path+queryPath+res); } } public void downResources(Integer caseId,String urls,String offPath) { JSONArray jsonArray = JSONArray.parseArray(urls); for (Object object : jsonArray) { String res = (String) object; downResource(caseId,res,offPath); } } public void downResource(Integer caseId,String url,String offPath) { if(StringUtils.isBlank(url) ){ return; } if("none".equals(url)){ return; } if("map".equals(url)){ return; } String path = offPath + FilePath.OFFLINE_OSS_PATH; localToOssUtil.downForm(url,path+queryPath+url); } public void downWordByTemplate(Integer caseId,XWPFTemplate template,String name,String offPath){ // 指定输出文件的路径 String outputPath = offPath +FilePath.OFFLINE_RESOURCE_PACKAGE_PATH + name; try { FileOutputStream out = new FileOutputStream(outputPath); template.write(out); out.close(); log.info("文档已成功写入到: " + outputPath); } catch (Exception e) { log.info("写出文档失败:{},{}",caseId,name,e); throw new BusinessException(ResultCode.SYSTEM_ERROR); } } }