package com.shkpr.service.alambizplugin.components; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.global.base.log.LogLevelFlag; import com.global.base.log.LogPrintMgr; import com.shkpr.service.alambizplugin.commproperties.AsyncTaskProperties; 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.ExcelEnum; import com.shkpr.service.alambizplugin.constants.GisSurveyExcelDefine; import com.shkpr.service.alambizplugin.constants.LogFlagBusiType; import org.apache.commons.compress.archivers.ArchiveException; import org.apache.commons.io.FileUtils; import org.opengis.feature.simple.SimpleFeatureType; import org.springframework.stereotype.Component; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * 异步结果管理器 * * @author 欧阳劲驰 * @since 1.0.0 */ @Component public class AsyncResultManager { /** * 结果文件名 */ public final static String RESULT_FILE_NAME = "result.json"; /** * 临时文件夹缓存 */ private final static Map TEMP_DIR_CACHE = new ConcurrentHashMap<>(); /** * 文件分片大小 */ private final static Integer BUFFER_SIZE = 4 * 1024; /** * log */ private final String mStrClassName; private final String mBizType; private final AsyncTaskProperties asyncTaskProperties; private final TempFileProperties tempFileProperties; private final ObjectMapper objectMapper; public AsyncResultManager(AsyncTaskProperties asyncTaskProperties, TempFileProperties tempFileProperties, ObjectMapper objectMapper) { mStrClassName = "AsyncResultManager"; mBizType = LogFlagBusiType.BUSI_GIS_SURVEY.toStrValue(); this.asyncTaskProperties = asyncTaskProperties; this.tempFileProperties = tempFileProperties; this.objectMapper = objectMapper; } /** * 获取结果 * * @param flag 结果标识 * @return 检查结果 */ public T getResult(String flag, TypeReference type) { //创建文件输入流 File file = Paths.get(getResultDirPath(flag).toString(), RESULT_FILE_NAME).toFile(); if (!file.exists()) return null; try (FileInputStream fileInputStream = new FileInputStream(file)) { //获取文件通道 FileChannel channel = fileInputStream.getChannel(); //创建缓冲区 ByteBuffer byteBuffer = ByteBuffer.allocate((int) file.length()); //读取通道 int read = channel.read(byteBuffer); //输入读取信息 if (read > 0) return objectMapper.readValue(byteBuffer.array(), type); } catch (IOException e) { //打印报错信息 LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName , String.format( "监测到io异常 结果标识:%s error:%s" , flag , e ) ); return null; } return null; } /** * 获取结果文件夹路径 * * @param flag 结果标识 * @return 结果文件夹路径 */ private Path getResultDirPath(String flag) { return Paths.get(asyncTaskProperties.getResultPath().toString(), flag); } /** * 创建临时文件夹 * * @param flag 结果标识 */ public Boolean createTempDirectory(String flag) { try { //创建临时文件夹,并缓存路径 Path tempDirectory = Files.createTempDirectory(tempFileProperties.getResourcePath(), flag); TEMP_DIR_CACHE.put(flag, tempDirectory); return tempDirectory.toFile().exists(); } catch (IOException e) { //打印报错信息 LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName , String.format( "监测到io异常 结果标识:%s error:%s" , flag , e ) ); return false; } } /** * 写入json文件 * * @param data 数据 * @param flag 结果标识 * @param fileName 文件名 */ public Path writeJson(Object data, String flag, String fileName) { LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName , String.format( "开始执行写入结果文件,结果标识:%s,文件名:%s========>" , flag , fileName ) ); long begin = System.currentTimeMillis(); //写入文件 Path path = Paths.get(TEMP_DIR_CACHE.get(flag).toString(), fileName); try { //序列化数据 final byte[] bytes = objectMapper.writeValueAsBytes(data); //写入文件 int total = writeFile(bytes, path); if (total > 0) { long end = System.currentTimeMillis(); LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName , String.format( "结束执行写入结果文件,结果标识:%s,文件名:%s,用时(毫秒):%d" , flag , fileName , (end - begin) ) ); return path; } } catch (IOException e) { //打印报错信息 LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName , String.format( "监测到io异常 结果标识:%s error:%s" , flag , e ) ); } return null; } /** * 写入excel文件 * * @param heads 表头 * @param datas 数据 * @param flag 结果标识 * @param fileName 文件名 */ public Path writeExcel(Map> heads, Map>> datas, String flag, String fileName) { LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName , String.format( "开始执行写入excel文件,结果标识:%s,文件名:%s========>" , flag , fileName ) ); long begin = System.currentTimeMillis(); //写入文件 Path path = Paths.get(TEMP_DIR_CACHE.get(flag).toString(), fileName); try { ExcelUtils.writeFile(heads, datas, Files.newOutputStream(path), ExcelEnum.XLSX , GisSurveyExcelDefine.FILE_HANDLE.HEADER_ROW_NUM, GisSurveyExcelDefine.FILE_HANDLE.DATA_ROW_NUM); long end = System.currentTimeMillis(); LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName , String.format( "结束执行写入excel文件,结果标识:%s,文件名:%s,用时(毫秒):%d" , flag , fileName , (end - begin) ) ); return path; } catch (IOException e) { //打印报错信息 LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName , String.format( "监测到io异常 结果标识:%s error:%s" , flag , e ) ); return null; } } /** * 写入shape文件 * * @param data 数据 * @param flag 结果标识 * @param fileName 文件名 */ public Path writeShape(Map>> data, String flag, String fileName) { LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName , String.format( "开始执行写入shape文件,结果标识:%s,文件名:%s========>" , flag , fileName ) ); long begin = System.currentTimeMillis(); //写入文件 Path path = Paths.get(TEMP_DIR_CACHE.get(flag).toString(), fileName); try { //创建临时文件夹 Path tempDirectory = Files.createTempDirectory(tempFileProperties.getResourcePath(), flag); //导出到shape ShapeUtils.writeShape(data, tempDirectory); //压缩文件夹 Path zipPath = CompressorUtils.archivalZip(tempDirectory); //移动文件 FileUtils.moveFile(zipPath.toFile(), path.toFile()); long end = System.currentTimeMillis(); LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName , String.format( "结束执行写入shape文件,结果标识:%s,文件名:%s,用时(毫秒):%d" , flag , fileName , (end - begin) ) ); return path; } catch (IOException | ArchiveException e) { //打印报错信息 LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName , String.format( "监测到io异常 结果标识:%s error:%s" , flag , e ) ); return null; } } /** * 写文件 * * @param data 数据 * @param path 文件路径 * @return 写入数量 * @throws IOException io异常 */ private int writeFile(final byte[] data, final Path path) throws IOException { //创建文件输出流(此处会创建文件) try (FileOutputStream fileOutputStream = new FileOutputStream(path.toFile())) { //获取文件通道 FileChannel channel = fileOutputStream.getChannel(); //创建缓冲区 ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER_SIZE); //偏移量 int offset = 0; //写入总数 int total = 0; while (offset < data.length) { //分片大小 int chunkSize = Math.min(BUFFER_SIZE, data.length - offset); //重置缓冲区,存入缓冲区,翻转 byteBuffer.clear(); byteBuffer.put(data, offset, chunkSize); byteBuffer.flip(); //写入当前块 total += channel.write(byteBuffer); offset += chunkSize; } //强制写入 channel.force(true); return total; } } /** * 替换结果 * * @param flag 结果标识 * @return 替换状态 */ public boolean replaceResult(String flag) { //临时文件路径 Path path = TEMP_DIR_CACHE.get(flag); try { //替换结果目录 FileUtils.copyDirectory(path.toFile(), getResultDirPath(flag).toFile()); return true; } catch (IOException e) { //打印报错信息 LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, mBizType, mStrClassName , String.format( "监测到io异常 结果标识:%s error:%s" , flag , e ) ); } return false; } }