package com.shkpr.service.alambizplugin.components; import com.global.base.log.LogLevelFlag; import com.global.base.log.LogPrintMgr; import com.shkpr.service.alambizplugin.commproperties.TempFileProperties; import com.shkpr.service.alambizplugin.commtools.CompressorUtils; import com.shkpr.service.alambizplugin.commtools.ExcelUtils; import com.shkpr.service.alambizplugin.commtools.ShapeUtils; import com.shkpr.service.alambizplugin.constants.CommAsyncStatusEnum; import com.shkpr.service.alambizplugin.constants.ExcelEnum; import com.shkpr.service.alambizplugin.constants.FileTypeEnum; import com.shkpr.service.alambizplugin.constants.GisMetadataDefine; import com.shkpr.service.alambizplugin.constants.GisSurveyExcelDefine; import com.shkpr.service.alambizplugin.constants.LogFlagBusiType; import com.shkpr.service.alambizplugin.dbdao.services.intef.GisMetadataLayerTemplateService; import com.shkpr.service.alambizplugin.dbdao.services.intef.GisSurveyLayerApplyService; import com.shkpr.service.alambizplugin.dto.CommAsyncResult; import com.shkpr.service.alambizplugin.dto.GisMetadataLayerTemplate; import com.shkpr.service.alambizplugin.dto.GisMetadataPropertyTemplate; import com.shkpr.service.alambizplugin.dto.GisSurveyLayerApply; import com.shkpr.service.alambizplugin.dto.GisSurveyPropertyValue; import org.apache.commons.compress.archivers.ArchiveException; import org.apache.commons.lang3.StringUtils; import org.locationtech.jts.geom.Geometry; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.AsyncResult; import org.springframework.stereotype.Component; import org.springframework.util.concurrent.ListenableFuture; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.time.Duration; import java.time.LocalDateTime; import java.util.Comparator; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; /** * 第三方导出执行器 * * @author 欧阳劲驰 * @since 1.0.0 */ @Component public class GisSurveyThirdExporter { /** * log */ private final String mStrClassName; private final String mBizType; private final TempFileProperties tempFileProperties; private final GisMetadataLayerTemplateService layerTemplateService; private final GisSurveyLayerApplyService gisSurveyLayerApplyService; public GisSurveyThirdExporter(TempFileProperties tempFileProperties , GisMetadataLayerTemplateService layerTemplateService, GisSurveyLayerApplyService gisSurveyLayerApplyService) { mStrClassName = "GisSurveyThirdExporter"; mBizType = LogFlagBusiType.BUSI_GIS_SURVEY.toStrValue(); this.tempFileProperties = tempFileProperties; this.layerTemplateService = layerTemplateService; this.gisSurveyLayerApplyService = gisSurveyLayerApplyService; } /** * 第三方导出任务 * * @param jobId 任务id * @param fileType 导出文件类型 * @return 导出结果 */ @Async public ListenableFuture> thirdExportTask(String jobId, FileTypeEnum fileType) { //构建返回 CommAsyncResult result = CommAsyncResult.fail(jobId); try { LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName , String.format( "开始执行第三方导出;任务id: %s" , jobId ) ); //查询点线数据 List points = gisSurveyLayerApplyService.findAllByJobIdAndKind(jobId, GisMetadataDefine.TYPE_KINE.POINT); List lines = gisSurveyLayerApplyService.findAllByJobIdAndKind(jobId, GisMetadataDefine.TYPE_KINE.LINE); //根据文件类型导出 Path resultPath = null; if (fileType == FileTypeEnum.EXCEL) resultPath = exportExcel(points, lines); if (fileType == FileTypeEnum.SHAPE_FILE) resultPath = exportShape(points, lines); //导出文件判断 if (resultPath == null || !Files.exists(resultPath)) { //打印报错信息 LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName , String.format("第三方导出文件写入失败, 任务id:%s", jobId) ); return new AsyncResult<>(result); } //导出完成 result.setStatus(CommAsyncStatusEnum.SUCCESS.getCode()); result.setCompleteTime(LocalDateTime.now()); result.setData(resultPath.getFileName().toString()); LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName , String.format( "结束第三方导出;任务id: %s, 用时(毫秒):%d" , jobId , Duration.between(result.getRequestTime(), result.getCompleteTime()).toMillis() ) ); return new AsyncResult<>(result); } catch (InterruptedException | IOException | ArchiveException e) { //打印报错信息 LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName , String.format("第三方导出异常 任务id:%s error:%s", jobId, e) ); return new AsyncResult<>(result); } } /** * 导出excel * * @param points 点 * @param lines 线 * @return excel路径 * @throws IOException io异常 */ private Path exportExcel(List points, List lines) throws IOException { //获取图层key List pointLayer = getLayerKeys(points); List lineLayer = getLayerKeys(lines); //查询点图层模版 List pointLayerTemplates = layerTemplateService.findByKeyIn(pointLayer); //查询线图层模版 List lineLayerTemplates = layerTemplateService.findByKeyIn(lineLayer); //构建excel头 Map> excelHeader = buildExcelHeader(pointLayerTemplates, lineLayerTemplates); //构建excel数据 Map>> excelData = buildExcelData(points, lines, pointLayerTemplates, lineLayerTemplates); //导出excel Path excelPath = Files.createTempFile(tempFileProperties.getResourcePath(), "third-export-", ".xlsx"); ExcelUtils.writeFile(excelHeader, excelData, Files.newOutputStream(excelPath), ExcelEnum.XLSX); return excelPath; } /** * 导出shape * * @param points 点 * @param lines 线 * @return shape路径 * @throws IOException io异常 * @throws ArchiveException 压缩异常 */ private Path exportShape(List points, List lines) throws IOException, ArchiveException { //构建shape数据 Map> shapeData = buildShapeData(points, lines); //创建临时文件夹 Path directory = Files.createTempDirectory(tempFileProperties.getResourcePath(), "third-export-"); //导出shape ShapeUtils.writeShape(shapeData, directory); //压缩文件夹 return CompressorUtils.archivalZip(directory); } /** * 获取图层key * * @param datas 数据 * @return 图层key集合 */ private List getLayerKeys(List datas) { //去重图层 return datas.parallelStream() .map(GisSurveyLayerApply::getLayer) .filter(StringUtils::isNotBlank) .distinct() .collect(Collectors.toList()); } /** * 构建excel表头 * * @param pointLayerTemplates 点图层模版 * @param lineLayerTemplates 线图层模版 * @return excel数据 */ private Map> buildExcelHeader(List pointLayerTemplates , List lineLayerTemplates) { //点excel表头 Map pointExcelHeader = new LinkedHashMap<>(); //线excel表头 Map lineExcelHeader = new LinkedHashMap<>(); //点模版表头 Map pointTemplateHeader = pointLayerTemplates.stream() .flatMap(it -> it.getPropertyTemplates().stream()) .sorted(Comparator.comparing(GisMetadataPropertyTemplate::getOrdering)) .collect(Collectors.toMap(GisMetadataPropertyTemplate::getKey, GisMetadataPropertyTemplate::getName , (it1, it2) -> it1, LinkedHashMap::new)); //线模版表头 Map lineTemplateHeader = lineLayerTemplates.stream() .flatMap(it -> it.getPropertyTemplates().stream()) .collect(Collectors.toMap(GisMetadataPropertyTemplate::getKey, GisMetadataPropertyTemplate::getName , (it1, it2) -> it1, LinkedHashMap::new)); //加入图层表头 pointExcelHeader.put(GisSurveyExcelDefine.TEMPLATE.LAYER, GisSurveyExcelDefine.FILE.POINT_LAYER); lineExcelHeader.put(GisSurveyExcelDefine.TEMPLATE.LAYER, GisSurveyExcelDefine.FILE.LINE_LAYER); //加入模版表头 pointExcelHeader.putAll(pointTemplateHeader); lineExcelHeader.putAll(lineTemplateHeader); //excel表头 Map> excelHeader = new HashMap<>(); excelHeader.put(GisMetadataDefine.TYPE_KINE.POINT, pointExcelHeader); excelHeader.put(GisMetadataDefine.TYPE_KINE.LINE, lineExcelHeader); return excelHeader; } /** * 构建excel数据 * * @param points 点元素 * @param lines 线元素 * @param pointLayerTemplates 点图层模版 * @param lineLayerTemplates 线图层模版 * @return excel数据 */ private Map>> buildExcelData(List points, List lines , List pointLayerTemplates, List lineLayerTemplates) { LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName, "开始构建excel数据 ======>"); long begin = System.currentTimeMillis(); //excel数据 Map>> excelData = new HashMap<>(); excelData.put(GisMetadataDefine.TYPE_KINE.POINT, buildExcelSheetData(points, pointLayerTemplates)); excelData.put(GisMetadataDefine.TYPE_KINE.LINE, buildExcelSheetData(lines, lineLayerTemplates)); long end = System.currentTimeMillis(); LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName , String.format( "结束构建excel数据,用时(毫秒):%d" , (end - begin) ) ); return excelData; } /** * 构建excel页数据 * * @param layerApplies 采集元素集合 * @param layerTemplates 图层模版 * @return excel数据 */ private List> buildExcelSheetData(List layerApplies, List layerTemplates) { return layerApplies.parallelStream() .map(it -> { //处理模版数据 Map rowData = it.getPropertyValues().stream() .filter(it1 -> !StringUtils.isAnyBlank(it1.getProperty(), it1.getValue())) .collect(Collectors.toMap(GisSurveyPropertyValue::getProperty, GisSurveyPropertyValue::getValue)); //处理图层数据 if (StringUtils.isNotBlank(it.getLayer())) { //获取模版 GisMetadataLayerTemplate gisMetadataLayerTemplate = layerTemplates.stream() .filter(it1 -> Objects.equals(it1.getKey(), it.getLayer())) .findFirst().orElse(null); //存入图层 if (gisMetadataLayerTemplate != null) rowData.put(GisSurveyExcelDefine.TEMPLATE.LAYER, gisMetadataLayerTemplate.getName()); } return rowData; }).collect(Collectors.toList()); } /** * 构建shape数据 * * @param points 点元素 * @param lines 线元素 * @return excel数据 */ private Map> buildShapeData(List points, List lines) { LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName, "开始构建shape数据 ======>"); long begin = System.currentTimeMillis(); //点excel数据 List pointExcelData = points.parallelStream() .map(GisSurveyLayerApply::getGis) .filter(Objects::nonNull) .collect(Collectors.toList()); //线excel数据 List lineExcelData = lines.parallelStream() .map(GisSurveyLayerApply::getGis) .filter(Objects::nonNull) .collect(Collectors.toList()); //excel数据 Map> shapeData = new HashMap<>(); shapeData.put(GisMetadataDefine.TYPE_KINE.POINT, pointExcelData); shapeData.put(GisMetadataDefine.TYPE_KINE.LINE, lineExcelData); long end = System.currentTimeMillis(); LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName , String.format( "结束构建shape数据,用时(毫秒):%d" , (end - begin) ) ); return shapeData; } }