Commit 291db7430e54561f2e41ae2a52181295a4f8964e
1 parent
9ce96e13
险情管理导出
Showing
33 changed files
with
1966 additions
and
176 deletions
urbanops-framework/urbanops-spring-boot-starter-excel/src/main/java/com/zteits/urbanops/framework/excel/core/convert/ImageListConverter.java
| ... | ... | @@ -7,27 +7,17 @@ import cn.idev.excel.metadata.data.ImageData; |
| 7 | 7 | import cn.idev.excel.metadata.data.ReadCellData; |
| 8 | 8 | import cn.idev.excel.metadata.data.WriteCellData; |
| 9 | 9 | import cn.idev.excel.metadata.property.ExcelContentProperty; |
| 10 | -import cn.idev.excel.util.FileUtils; | |
| 11 | 10 | import cn.idev.excel.util.ListUtils; |
| 12 | 11 | import lombok.extern.slf4j.Slf4j; |
| 13 | -import org.springframework.util.StringUtils; | |
| 14 | 12 | |
| 15 | -import java.io.ByteArrayOutputStream; | |
| 16 | -import java.io.File; | |
| 17 | -import java.io.InputStream; | |
| 18 | -import java.net.HttpURLConnection; | |
| 19 | -import java.net.URL; | |
| 20 | 13 | import java.util.List; |
| 21 | 14 | |
| 22 | 15 | @Slf4j |
| 23 | -public class ImageListConverter implements Converter<List<String>> { | |
| 16 | +public class ImageListConverter implements Converter<List<byte[]>> { | |
| 24 | 17 | |
| 25 | 18 | // 横向排列:每张图片宽度 + 间距 |
| 26 | 19 | private static final int IMAGE_WIDTH = 120; |
| 27 | 20 | private static final int IMAGE_GAP = 15; |
| 28 | - private static final int MAX_IMAGE_SIZE = 10 * 1024 * 1024; | |
| 29 | - private static final int CONNECT_TIMEOUT = 5000; | |
| 30 | - private static final int READ_TIMEOUT = 10000; | |
| 31 | 21 | |
| 32 | 22 | @Override |
| 33 | 23 | public Class<?> supportJavaTypeKey() { |
| ... | ... | @@ -40,28 +30,27 @@ public class ImageListConverter implements Converter<List<String>> { |
| 40 | 30 | } |
| 41 | 31 | |
| 42 | 32 | @Override |
| 43 | - public List<String> convertToJavaData(ReadCellData readCellData, ExcelContentProperty contentProperty, | |
| 33 | + public List<byte[]> convertToJavaData(ReadCellData readCellData, ExcelContentProperty contentProperty, | |
| 44 | 34 | GlobalConfiguration globalConfiguration) { |
| 45 | 35 | return null; |
| 46 | 36 | } |
| 47 | 37 | |
| 38 | + /** | |
| 39 | + * 这里改成接收 List<byte[]> | |
| 40 | + */ | |
| 48 | 41 | @Override |
| 49 | - public WriteCellData<?> convertToExcelData(List<String> imageList, ExcelContentProperty contentProperty, | |
| 42 | + public WriteCellData<?> convertToExcelData(List<byte[]> imageByteList, ExcelContentProperty contentProperty, | |
| 50 | 43 | GlobalConfiguration globalConfiguration) { |
| 51 | 44 | try { |
| 52 | - if (imageList == null || imageList.isEmpty()) { | |
| 45 | + if (imageByteList == null || imageByteList.isEmpty()) { | |
| 53 | 46 | return new WriteCellData<>("无图片"); |
| 54 | 47 | } |
| 55 | 48 | |
| 56 | 49 | List<ImageData> imageDataList = ListUtils.newArrayList(); |
| 57 | 50 | int leftOffset = 0; // 横向偏移量 |
| 58 | 51 | |
| 59 | - for (String path : imageList) { | |
| 60 | - if (!StringUtils.hasText(path)) continue; | |
| 61 | - | |
| 62 | - byte[] imageBytes = path.startsWith("http") ? loadNetworkImage(path) : loadLocalImage(path); | |
| 63 | - if (imageBytes == null || imageBytes.length == 0 || imageBytes.length > MAX_IMAGE_SIZE) { | |
| 64 | - log.warn("跳过无效图片:{}", path); | |
| 52 | + for (byte[] imageBytes : imageByteList) { | |
| 53 | + if (imageBytes == null || imageBytes.length == 0) { | |
| 65 | 54 | continue; |
| 66 | 55 | } |
| 67 | 56 | |
| ... | ... | @@ -69,11 +58,11 @@ public class ImageListConverter implements Converter<List<String>> { |
| 69 | 58 | imageData.setImage(imageBytes); |
| 70 | 59 | imageData.setImageType(ImageData.ImageType.PICTURE_TYPE_PNG); |
| 71 | 60 | |
| 72 | - // ====================== 核心:横向偏移 ====================== | |
| 61 | + // 横向排列 | |
| 73 | 62 | imageData.setLeft(leftOffset); |
| 74 | - // ============================================================= | |
| 75 | - | |
| 76 | 63 | imageDataList.add(imageData); |
| 64 | + | |
| 65 | + // 下一张图片偏移 | |
| 77 | 66 | leftOffset += IMAGE_WIDTH + IMAGE_GAP; |
| 78 | 67 | } |
| 79 | 68 | |
| ... | ... | @@ -88,35 +77,8 @@ public class ImageListConverter implements Converter<List<String>> { |
| 88 | 77 | return writeCellData; |
| 89 | 78 | |
| 90 | 79 | } catch (Exception e) { |
| 91 | - log.error("图片导出失败", e); | |
| 80 | + log.error("图片导出异常", e); | |
| 92 | 81 | return new WriteCellData<>("图片加载失败"); |
| 93 | 82 | } |
| 94 | 83 | } |
| 95 | - | |
| 96 | - private byte[] loadLocalImage(String imagePath) throws Exception { | |
| 97 | - File file = new File(imagePath); | |
| 98 | - if (!file.exists() || !file.isFile()) { | |
| 99 | - log.warn("本地图片不存在:{}", imagePath); | |
| 100 | - return null; | |
| 101 | - } | |
| 102 | - return FileUtils.readFileToByteArray(file); | |
| 103 | - } | |
| 104 | - | |
| 105 | - private byte[] loadNetworkImage(String imageUrl) throws Exception { | |
| 106 | - URL url = new URL(imageUrl); | |
| 107 | - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); | |
| 108 | - conn.setConnectTimeout(CONNECT_TIMEOUT); | |
| 109 | - conn.setReadTimeout(READ_TIMEOUT); | |
| 110 | - try { | |
| 111 | - if (conn.getResponseCode() != 200) return null; | |
| 112 | - try (InputStream in = conn.getInputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream()) { | |
| 113 | - byte[] buffer = new byte[4096]; | |
| 114 | - int len; | |
| 115 | - while ((len = in.read(buffer)) != -1) out.write(buffer, 0, len); | |
| 116 | - return out.toByteArray(); | |
| 117 | - } | |
| 118 | - } finally { | |
| 119 | - conn.disconnect(); | |
| 120 | - } | |
| 121 | - } | |
| 122 | 84 | } | ... | ... |
urbanops-framework/urbanops-spring-boot-starter-excel/src/main/java/com/zteits/urbanops/framework/excel/core/convert/ImageStringConverter.java
0 → 100644
| 1 | +package com.zteits.urbanops.framework.excel.core.convert; | |
| 2 | + | |
| 3 | +import cn.idev.excel.converters.Converter; | |
| 4 | +import cn.idev.excel.enums.CellDataTypeEnum; | |
| 5 | +import cn.idev.excel.metadata.GlobalConfiguration; | |
| 6 | +import cn.idev.excel.metadata.data.ImageData; | |
| 7 | +import cn.idev.excel.metadata.data.ReadCellData; | |
| 8 | +import cn.idev.excel.metadata.data.WriteCellData; | |
| 9 | +import cn.idev.excel.metadata.property.ExcelContentProperty; | |
| 10 | +import lombok.extern.slf4j.Slf4j; | |
| 11 | + | |
| 12 | +@Slf4j | |
| 13 | +public class ImageStringConverter implements Converter<byte[]> { | |
| 14 | + | |
| 15 | + @Override | |
| 16 | + public Class<byte[]> supportJavaTypeKey() { | |
| 17 | + return byte[].class; | |
| 18 | + } | |
| 19 | + | |
| 20 | + @Override | |
| 21 | + public CellDataTypeEnum supportExcelTypeKey() { | |
| 22 | + return CellDataTypeEnum.EMPTY; | |
| 23 | + } | |
| 24 | + | |
| 25 | + @Override | |
| 26 | + public byte[] convertToJavaData(ReadCellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { | |
| 27 | + return null; | |
| 28 | + } | |
| 29 | + | |
| 30 | + @Override | |
| 31 | + public WriteCellData<?> convertToExcelData(byte[] imageBytes, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { | |
| 32 | + try { | |
| 33 | + if (imageBytes == null || imageBytes.length == 0) { | |
| 34 | + return new WriteCellData<>("无图片"); | |
| 35 | + } | |
| 36 | + | |
| 37 | + ImageData imageData = new ImageData(); | |
| 38 | + imageData.setImage(imageBytes); | |
| 39 | + imageData.setImageType(ImageData.ImageType.PICTURE_TYPE_PNG); | |
| 40 | + | |
| 41 | + WriteCellData<byte[]> cellData = new WriteCellData<>(); | |
| 42 | + cellData.setType(CellDataTypeEnum.EMPTY); | |
| 43 | + cellData.setImageDataList(java.util.Collections.singletonList(imageData)); | |
| 44 | + return cellData; | |
| 45 | + } catch (Exception e) { | |
| 46 | + return new WriteCellData<>("图片异常"); | |
| 47 | + } | |
| 48 | + } | |
| 49 | +} | ... | ... |
urbanops-framework/urbanops-spring-boot-starter-excel/src/main/java/com/zteits/urbanops/framework/excel/core/handler/HeadMergeHandler.java
0 → 100644
| 1 | +package com.zteits.urbanops.framework.excel.core.handler; | |
| 2 | + | |
| 3 | +import cn.idev.excel.write.handler.SheetWriteHandler; | |
| 4 | +import cn.idev.excel.write.handler.context.SheetWriteHandlerContext; | |
| 5 | +import cn.idev.excel.write.metadata.holder.WriteSheetHolder; | |
| 6 | +import org.apache.poi.ss.usermodel.Sheet; | |
| 7 | +import org.apache.poi.ss.util.CellRangeAddress; | |
| 8 | +import java.util.Arrays; | |
| 9 | +import java.util.List; | |
| 10 | + | |
| 11 | +/** | |
| 12 | + * 表头合并处理器(适配低版本 idev.excel,无 getSheet 方法) | |
| 13 | + * 纯表头场景、空数据也能正常执行,无需额外空行 | |
| 14 | + */ | |
| 15 | +public class HeadMergeHandler implements SheetWriteHandler { | |
| 16 | + | |
| 17 | + private final List<CellRangeAddress> regions; | |
| 18 | + | |
| 19 | + public HeadMergeHandler(CellRangeAddress... regions) { | |
| 20 | + this.regions = Arrays.asList(regions); | |
| 21 | + } | |
| 22 | + | |
| 23 | + @Override | |
| 24 | + public void afterSheetCreate(SheetWriteHandlerContext context) { | |
| 25 | + // 核心修正:从 WriteSheetHolder 拿 Sheet | |
| 26 | + WriteSheetHolder writeSheetHolder = context.getWriteSheetHolder(); | |
| 27 | + if (writeSheetHolder == null) { | |
| 28 | + return; | |
| 29 | + } | |
| 30 | + Sheet sheet = writeSheetHolder.getSheet(); | |
| 31 | + | |
| 32 | + for (CellRangeAddress area : regions) { | |
| 33 | + if (isValidMergedRegion(area)) { | |
| 34 | + sheet.addMergedRegionUnsafe(area); | |
| 35 | + } | |
| 36 | + } | |
| 37 | + } | |
| 38 | + | |
| 39 | + /** | |
| 40 | + * 过滤单单元格无效合并 | |
| 41 | + */ | |
| 42 | + private boolean isValidMergedRegion(CellRangeAddress area) { | |
| 43 | + int rowCnt = area.getLastRow() - area.getFirstRow() + 1; | |
| 44 | + int colCnt = area.getLastColumn() - area.getFirstColumn() + 1; | |
| 45 | + return rowCnt >= 2 || colCnt >= 2; | |
| 46 | + } | |
| 47 | +} | ... | ... |
urbanops-framework/urbanops-spring-boot-starter-excel/src/main/java/com/zteits/urbanops/framework/excel/core/util/ExcelUtils.java
| 1 | 1 | package com.zteits.urbanops.framework.excel.core.util; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.collection.CollectionUtil; | |
| 4 | +import cn.idev.excel.ExcelWriter; | |
| 3 | 5 | import cn.idev.excel.FastExcelFactory; |
| 4 | 6 | import cn.idev.excel.converters.longconverter.LongStringConverter; |
| 7 | +import cn.idev.excel.write.builder.ExcelWriterBuilder; | |
| 5 | 8 | import com.zteits.urbanops.framework.common.util.http.HttpUtils; |
| 6 | 9 | import com.zteits.urbanops.framework.excel.core.handler.ColumnWidthMatchStyleStrategy; |
| 10 | +import com.zteits.urbanops.framework.excel.core.handler.HeadMergeHandler; | |
| 7 | 11 | import com.zteits.urbanops.framework.excel.core.handler.SelectSheetWriteHandler; |
| 8 | 12 | import jakarta.servlet.http.HttpServletResponse; |
| 13 | +import org.apache.poi.ss.util.CellRangeAddress; | |
| 9 | 14 | import org.springframework.web.multipart.MultipartFile; |
| 10 | 15 | |
| 16 | +import java.io.File; | |
| 17 | +import java.io.FileOutputStream; | |
| 11 | 18 | import java.io.IOException; |
| 12 | 19 | import java.util.List; |
| 13 | 20 | |
| ... | ... | @@ -39,7 +46,8 @@ public class ExcelUtils { |
| 39 | 46 | .registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度 |
| 40 | 47 | .sheet(sheetName).doWrite(data); |
| 41 | 48 | // 设置 header 和 contentType。写在最后的原因是,避免报错时,响应 contentType 已经被修改了 |
| 42 | - response.addHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(filename)); | |
| 49 | + //response.addHeader("Content-Disposition", "attachment;filename=" + HttpUtils.encodeUtf8(filename)); | |
| 50 | + response.setHeader("Content-Disposition", "attachment;filename*=UTF-8''" + HttpUtils.encodeUtf8(filename)); | |
| 43 | 51 | response.setContentType("application/vnd.ms-excel;charset=UTF-8"); |
| 44 | 52 | } |
| 45 | 53 | |
| ... | ... | @@ -74,4 +82,82 @@ public class ExcelUtils { |
| 74 | 82 | .sheet(0) |
| 75 | 83 | .doReadSync(); |
| 76 | 84 | } |
| 85 | + | |
| 86 | + | |
| 87 | + /** | |
| 88 | + * 导出多级表头,将列表以 Excel 响应给前端 | |
| 89 | + * | |
| 90 | + * @param response 响应 | |
| 91 | + * @param filename 文件名 | |
| 92 | + * @param sheetName Excel sheet 名 | |
| 93 | + * @param head Excel head 头 | |
| 94 | + * @param data 数据列表哦 | |
| 95 | + * @param <T> 泛型,保证 head 和 data 类型的一致性 | |
| 96 | + * @throws IOException 写入失败的情况 | |
| 97 | + */ | |
| 98 | + public static <T> void writeEmergencyTask(HttpServletResponse response, String filename, String sheetName, | |
| 99 | + Class<T> head, List<T> data, List<List<String>> headList, List<CellRangeAddress> mergeList) throws IOException { | |
| 100 | + FastExcelFactory.write(response.getOutputStream()) | |
| 101 | + .head(headList) //动态自定义3行表头 | |
| 102 | + .autoCloseStream(false) // 不要自动关闭,交给 Servlet 自己处理 | |
| 103 | + .registerWriteHandler(new ColumnWidthMatchStyleStrategy()) // 基于 column 长度,自动适配。最大 255 宽度 | |
| 104 | + .registerWriteHandler(new SelectSheetWriteHandler(head)) // 基于固定 sheet 实现下拉框 | |
| 105 | + .registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度 | |
| 106 | + // 注册表头合并 | |
| 107 | + .registerWriteHandler(new HeadMergeHandler(mergeList.toArray(new CellRangeAddress[0]))) | |
| 108 | + .sheet(sheetName).doWrite(data); | |
| 109 | + // 设置 header 和 contentType。写在最后的原因是,避免报错时,响应 contentType 已经被修改了 | |
| 110 | + response.setHeader("Content-Disposition", "attachment;filename*=UTF-8''" + HttpUtils.encodeUtf8(filename)); | |
| 111 | + response.setContentType("application/vnd.ms-excel;charset=UTF-8"); | |
| 112 | + | |
| 113 | + } | |
| 114 | + | |
| 115 | + /** | |
| 116 | + * 初始化Excel、写入表头,返回全局复用的 ExcelWriter | |
| 117 | + * 不再返回 OutputStream,彻底解决多次创建写入器导致文件损坏 | |
| 118 | + */ | |
| 119 | + public static <T> ExcelWriter initEmergencyTaskExcel(File targetFile, | |
| 120 | + String fileName, | |
| 121 | + String sheetName, | |
| 122 | + Class<T> head, | |
| 123 | + List<List<String>> headList, | |
| 124 | + List<CellRangeAddress> mergeList) throws IOException { | |
| 125 | + // 目录创建逻辑不变 | |
| 126 | + File parentFile = targetFile.getParentFile(); | |
| 127 | + if (!parentFile.exists()) { | |
| 128 | + boolean mkdirs = parentFile.mkdirs(); | |
| 129 | + if (!mkdirs) { | |
| 130 | + throw new IOException("目录创建失败:" + parentFile.getAbsolutePath()); | |
| 131 | + } | |
| 132 | + } | |
| 133 | + | |
| 134 | + // 输出流交给 ExcelWriter | |
| 135 | + FileOutputStream fos = new FileOutputStream(targetFile); | |
| 136 | + ExcelWriterBuilder writeBuilder = null; | |
| 137 | + if (CollectionUtil.isNotEmpty(headList)) { | |
| 138 | + writeBuilder = FastExcelFactory.write(fos) | |
| 139 | + .head(headList) //动态自定义3行表头 | |
| 140 | + .autoCloseStream(true) // 自动关闭 | |
| 141 | + .registerWriteHandler(new ColumnWidthMatchStyleStrategy()) // 基于 column 长度,自动适配。最大 255 宽度 | |
| 142 | + .registerWriteHandler(new SelectSheetWriteHandler(head)) // 基于固定 sheet 实现下拉框 | |
| 143 | + .registerConverter(new LongStringConverter()) // 避免 Long 类型丢失精度 | |
| 144 | + .registerWriteHandler(new HeadMergeHandler(mergeList.toArray(new CellRangeAddress[0]))); | |
| 145 | + } else { | |
| 146 | + writeBuilder = FastExcelFactory.write(fos, head) | |
| 147 | + .autoCloseStream(true) // 自动关闭 | |
| 148 | + .registerWriteHandler(new ColumnWidthMatchStyleStrategy()) // 基于 column 长度,自动适配。最大 255 宽度 | |
| 149 | + .registerWriteHandler(new SelectSheetWriteHandler(head)) // 基于固定 sheet 实现下拉框 | |
| 150 | + .registerConverter(new LongStringConverter()); // 避免 Long 类型丢失精度 | |
| 151 | + } | |
| 152 | + ExcelWriter excelWriter = writeBuilder.build(); | |
| 153 | + return excelWriter; | |
| 154 | + } | |
| 155 | + /** | |
| 156 | + * 最终收尾:刷写文件尾、释放资源(替代手动close流) | |
| 157 | + */ | |
| 158 | + public static void finishExcel(ExcelWriter excelWriter) { | |
| 159 | + if (excelWriter != null) { | |
| 160 | + excelWriter.finish(); | |
| 161 | + } | |
| 162 | + } | |
| 77 | 163 | } | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/emergencytask/EmergencyTaskController.java
| 1 | 1 | package com.zteits.urbanops.module.garden.controller.admin.emergencytask; |
| 2 | 2 | |
| 3 | -import com.zteits.urbanops.framework.common.biz.system.dict.dto.DictDataRespDTO; | |
| 4 | -import org.springframework.util.CollectionUtils; | |
| 5 | -import org.springframework.web.bind.annotation.*; | |
| 3 | +import cn.hutool.core.collection.CollectionUtil; | |
| 4 | +import com.zteits.urbanops.framework.apilog.core.annotation.ApiAccessLog; | |
| 5 | +import com.zteits.urbanops.framework.common.pojo.CommonResult; | |
| 6 | +import com.zteits.urbanops.framework.common.pojo.PageParam; | |
| 7 | +import com.zteits.urbanops.framework.common.pojo.PageResult; | |
| 8 | +import com.zteits.urbanops.module.garden.controller.admin.emergencytask.vo.EmergencyTaskApprovalReqVO; | |
| 9 | +import com.zteits.urbanops.module.garden.controller.admin.emergencytask.vo.EmergencyTaskPageReqVO; | |
| 10 | +import com.zteits.urbanops.module.garden.controller.admin.emergencytask.vo.EmergencyTaskRespVO; | |
| 11 | +import com.zteits.urbanops.module.garden.controller.admin.emergencytask.vo.EmergencyTaskSaveReqVO; | |
| 12 | +import com.zteits.urbanops.module.garden.service.emergencytask.*; | |
| 13 | +import com.zteits.urbanops.module.garden.service.filedownload.ExcelExportDispatchService; | |
| 14 | +import com.zteits.urbanops.module.infra.service.file.FileConfigService; | |
| 15 | +import com.zteits.urbanops.module.infra.service.file.FileService; | |
| 16 | +import io.swagger.v3.oas.annotations.Operation; | |
| 17 | +import io.swagger.v3.oas.annotations.Parameter; | |
| 18 | +import io.swagger.v3.oas.annotations.tags.Tag; | |
| 6 | 19 | import jakarta.annotation.Resource; |
| 7 | -import org.springframework.validation.annotation.Validated; | |
| 20 | +import jakarta.validation.Valid; | |
| 21 | +import lombok.extern.slf4j.Slf4j; | |
| 8 | 22 | import org.springframework.security.access.prepost.PreAuthorize; |
| 9 | -import io.swagger.v3.oas.annotations.tags.Tag; | |
| 10 | -import io.swagger.v3.oas.annotations.Parameter; | |
| 11 | -import io.swagger.v3.oas.annotations.Operation; | |
| 12 | - | |
| 13 | -import jakarta.validation.*; | |
| 14 | -import jakarta.servlet.http.*; | |
| 15 | -import java.util.*; | |
| 16 | -import java.io.IOException; | |
| 17 | -import java.util.stream.Collectors; | |
| 23 | +import org.springframework.validation.annotation.Validated; | |
| 24 | +import org.springframework.web.bind.annotation.*; | |
| 18 | 25 | |
| 19 | -import com.zteits.urbanops.framework.common.pojo.PageParam; | |
| 20 | -import com.zteits.urbanops.framework.common.pojo.PageResult; | |
| 21 | -import com.zteits.urbanops.framework.common.pojo.CommonResult; | |
| 26 | +import java.util.List; | |
| 22 | 27 | |
| 28 | +import static com.zteits.urbanops.framework.apilog.core.enums.OperateTypeEnum.EXPORT; | |
| 23 | 29 | import static com.zteits.urbanops.framework.common.pojo.CommonResult.success; |
| 24 | 30 | |
| 25 | -import com.zteits.urbanops.framework.excel.core.util.ExcelUtils; | |
| 26 | - | |
| 27 | -import com.zteits.urbanops.framework.apilog.core.annotation.ApiAccessLog; | |
| 28 | -import static com.zteits.urbanops.framework.apilog.core.enums.OperateTypeEnum.*; | |
| 29 | - | |
| 30 | -import com.zteits.urbanops.module.garden.controller.admin.emergencytask.vo.*; | |
| 31 | -import com.zteits.urbanops.module.garden.service.emergencytask.EmergencyTaskService; | |
| 32 | - | |
| 33 | 31 | @Tag(name = "管理后台 - 抢险任务主") |
| 34 | 32 | @RestController |
| 35 | 33 | @RequestMapping("/garden/emergency-task") |
| 36 | 34 | @Validated |
| 35 | +@Slf4j | |
| 37 | 36 | public class EmergencyTaskController { |
| 38 | 37 | |
| 39 | 38 | @Resource |
| 40 | 39 | private EmergencyTaskService emergencyTaskService; |
| 40 | + @Resource | |
| 41 | + private FileService fileService; | |
| 42 | + @Resource | |
| 43 | + private FileConfigService fileConfigService; | |
| 44 | + @Resource | |
| 45 | + private ExcelExportDispatchService dispatchService; | |
| 46 | + @Resource | |
| 47 | + private EmergencyExportHandler emergencyExportHandler; | |
| 48 | + @Resource | |
| 49 | + private EmergencyExportNewHandler emergencyExportNewHandler; | |
| 41 | 50 | |
| 42 | 51 | @PostMapping("/create") |
| 43 | 52 | @Operation(summary = "创建抢险任务主") |
| ... | ... | @@ -100,81 +109,42 @@ public class EmergencyTaskController { |
| 100 | 109 | @Operation(summary = "导出抢险任务主 Excel") |
| 101 | 110 | @PreAuthorize("@ss.hasPermission('garden:emergency-task:export')") |
| 102 | 111 | @ApiAccessLog(operateType = EXPORT) |
| 103 | - public void exportEmergencyTaskExcel(@Valid EmergencyTaskPageReqVO pageReqVO, | |
| 104 | - HttpServletResponse response) throws IOException { | |
| 112 | + public CommonResult<String> exportEmergencyTaskExcel(@Valid EmergencyTaskPageReqVO pageReqVO) { | |
| 105 | 113 | pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); |
| 106 | 114 | List<EmergencyTaskRespVO> list = emergencyTaskService.getEmergencyTaskPage(pageReqVO).getList(); |
| 107 | - List<EmergencyTaskExcleRespVO> respList = new ArrayList<>(); | |
| 108 | - | |
| 109 | - //险情类型 1:树木倒伏 2:树木折枝 | |
| 110 | - List<DictDataRespDTO> dictDataList = emergencyTaskService.getDictDataList("hazard_type"); | |
| 111 | - | |
| 112 | - //险情危害 1:砸车 2:砸房 3:砸人 4:无 | |
| 113 | - List<DictDataRespDTO> hazardRiskList = emergencyTaskService.getDictDataList("hazard_risk"); | |
| 114 | - //树木权属 1:专业权属 2:街道权属 3:其他 | |
| 115 | - List<DictDataRespDTO> treePermissionsList = emergencyTaskService.getDictDataList("tree_permissions"); | |
| 116 | - //机械类型 1:三轮车;2:货车;3:挖掘机 | |
| 117 | - List<DictDataRespDTO> mechanicalTypeNameList = emergencyTaskService.getDictDataList("mechanical_type_name"); | |
| 118 | - | |
| 119 | - //案件状态 1-待提交 2-待审核 3-驳回 | |
| 120 | - List<DictDataRespDTO> rescueStatusList = emergencyTaskService.getDictDataList("rescue_status"); | |
| 121 | 115 | |
| 122 | - | |
| 123 | - list.forEach(emergencyTask -> { | |
| 124 | - EmergencyTaskExcleRespVO emergencyTaskExcleRespVO = new EmergencyTaskExcleRespVO(); | |
| 125 | - emergencyTaskExcleRespVO.setTaskNo(emergencyTask.getTaskNo()); | |
| 126 | - emergencyTaskExcleRespVO.setDiscoveryTime(emergencyTask.getDiscoveryTime()); | |
| 127 | - emergencyTaskExcleRespVO.setEmergencyTypeName(getLabel(dictDataList, emergencyTask.getEmergencyTypeId())); | |
| 128 | - emergencyTaskExcleRespVO.setEmergencyHarmName(getLabel(hazardRiskList, emergencyTask.getEmergencyHarmId())); | |
| 129 | - emergencyTaskExcleRespVO.setTreeOwnershipName(getLabel(treePermissionsList, emergencyTask.getTreeOwnershipId())); | |
| 130 | - emergencyTaskExcleRespVO.setEmergencyLocation(emergencyTask.getEmergencyLocation()); | |
| 131 | - emergencyTaskExcleRespVO.setReporter(emergencyTask.getReporter()); | |
| 132 | - emergencyTaskExcleRespVO.setContactPhone(emergencyTask.getContactPhone()); | |
| 133 | - emergencyTaskExcleRespVO.setEmergencyImg(emergencyTask.getEmergencyImg()); | |
| 134 | - emergencyTaskExcleRespVO.setTreeSpecies(emergencyTask.getTreeSpecies()); | |
| 135 | - emergencyTaskExcleRespVO.setTreeSpec(emergencyTask.getTreeSpec()); | |
| 136 | - emergencyTaskExcleRespVO.setRescueStartTime(emergencyTask.getRescueStartTime()); | |
| 137 | - emergencyTaskExcleRespVO.setRescueCompleteTime(emergencyTask.getRescueCompleteTime()); | |
| 138 | - emergencyTaskExcleRespVO.setPersonnelCount(emergencyTask.getPersonnelCount()); | |
| 139 | - emergencyTaskExcleRespVO.setEmergencyEndImg(emergencyTask.getEmergencyEndImg()); | |
| 140 | - emergencyTaskExcleRespVO.setRemarks(emergencyTask.getRemarks()); | |
| 141 | - emergencyTaskExcleRespVO.setBusiStatus(getLabel(rescueStatusList, emergencyTask.getBusiStatus())); | |
| 142 | - emergencyTaskExcleRespVO.setCompanyName(emergencyTask.getCompanyName()); | |
| 143 | - emergencyTaskExcleRespVO.setApprovalUserName(emergencyTask.getApprovalUserName()); | |
| 144 | - emergencyTaskExcleRespVO.setApprovalRemarks(emergencyTask.getApprovalRemarks()); | |
| 145 | - emergencyTaskExcleRespVO.setCreatorName(emergencyTask.getCreatorName()); | |
| 146 | - emergencyTaskExcleRespVO.setCreateTime(emergencyTask.getCreateTime()); | |
| 147 | - emergencyTaskExcleRespVO.setUpdaterName(emergencyTask.getUpdaterName()); | |
| 148 | - List<String> machineryList = new ArrayList<>(); | |
| 149 | - if(CollectionUtils.isEmpty(emergencyTask.getEmergencyMachineryList())){ | |
| 150 | - emergencyTaskExcleRespVO.setMachineryInfo(Collections.emptyList()); | |
| 151 | - }else{ | |
| 152 | - emergencyTask.getEmergencyMachineryList().forEach(emergencyMachinery -> { | |
| 153 | - String machineryName = getLabel(mechanicalTypeNameList, emergencyMachinery.getMachineryNameId()); | |
| 154 | - Integer machineryCount = emergencyMachinery.getMachineryCount(); | |
| 155 | - machineryList.add(machineryName + ":" + machineryCount); | |
| 156 | - }); | |
| 157 | - emergencyTaskExcleRespVO.setMachineryInfo(machineryList); | |
| 158 | - } | |
| 159 | - respList.add(emergencyTaskExcleRespVO); | |
| 160 | - }); | |
| 161 | - | |
| 162 | - | |
| 163 | - // 导出 Excel | |
| 164 | - ExcelUtils.write(response, "抢险任务主.xls", "数据", EmergencyTaskExcleRespVO.class, respList); | |
| 116 | + // 无数据直接返回提示 | |
| 117 | + if (CollectionUtil.isEmpty(list)) { | |
| 118 | + return CommonResult.error(1 ,"暂无数据,无法导出"); | |
| 119 | + } | |
| 120 | + // 2. 调用调度服务创建任务 | |
| 121 | + Long taskId = dispatchService.createExportTask( | |
| 122 | + "EmergencyTaskExcle", | |
| 123 | + list, | |
| 124 | + emergencyExportHandler | |
| 125 | + ); | |
| 126 | + // 直接返回成功通知 | |
| 127 | + return CommonResult.success("导出任务已提交,数据正在后台生成,请稍后下载"); | |
| 165 | 128 | } |
| 166 | 129 | |
| 167 | - private String getLabel(List<DictDataRespDTO> dictDataList, Integer id){ | |
| 168 | - if(CollectionUtils.isEmpty(dictDataList)){ | |
| 169 | - return ""; | |
| 130 | + @GetMapping("/export-excel-new") | |
| 131 | + @Operation(summary = "抢险案件表 Excel") | |
| 132 | + @PreAuthorize("@ss.hasPermission('garden:emergency-task:export')") | |
| 133 | + @ApiAccessLog(operateType = EXPORT) | |
| 134 | + public CommonResult<String> exportEmergencyTaskExcelNew(@Valid EmergencyTaskPageReqVO pageReqVO){ | |
| 135 | + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); | |
| 136 | + List<EmergencyTaskRespVO> list = emergencyTaskService.getEmergencyTaskPage(pageReqVO).getList(); | |
| 137 | + if (CollectionUtil.isEmpty(list)) { | |
| 138 | + return null; | |
| 170 | 139 | } |
| 171 | - Map<String, String> nameMap = dictDataList.stream() | |
| 172 | - .collect(Collectors.toMap( | |
| 173 | - DictDataRespDTO::getValue, // Key=id | |
| 174 | - DictDataRespDTO::getLabel // Value=name | |
| 175 | - )); | |
| 176 | - | |
| 177 | - return nameMap.get(String.valueOf( id)); | |
| 140 | + // 创建异步任务 | |
| 141 | + // 2. 调用调度服务创建任务 | |
| 142 | + Long taskId = dispatchService.createExportTask( | |
| 143 | + "EmergencyTaskExcleNew", | |
| 144 | + list, | |
| 145 | + emergencyExportNewHandler | |
| 146 | + ); | |
| 147 | + // 返回成功提示 | |
| 148 | + return success("导出任务已提交,数据正在后台生成,请稍后下载"); | |
| 178 | 149 | } |
| 179 | - | |
| 180 | 150 | } | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/emergencytask/vo/EmergencyTaskExcleNewRespVO.java
0 → 100644
| 1 | +package com.zteits.urbanops.module.garden.controller.admin.emergencytask.vo; | |
| 2 | + | |
| 3 | +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; | |
| 4 | +import cn.idev.excel.annotation.ExcelProperty; | |
| 5 | +import com.zteits.urbanops.framework.excel.core.convert.ImageStringConverter; | |
| 6 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 7 | +import lombok.Data; | |
| 8 | + | |
| 9 | +import java.time.LocalDateTime; | |
| 10 | + | |
| 11 | +@Schema(description = "管理后台 - 抢险任务主 Response VO") | |
| 12 | +@Data | |
| 13 | +@ExcelIgnoreUnannotated | |
| 14 | +public class EmergencyTaskExcleNewRespVO { | |
| 15 | + | |
| 16 | + @Schema(description = "任务编号(唯一标识,如生成规则:TASK+时间戳)", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 17 | + @ExcelProperty("案件编号") | |
| 18 | + private String taskNo; | |
| 19 | + | |
| 20 | + @Schema(description = "归属(一级部门id)", requiredMode = Schema.RequiredMode.REQUIRED, example = "20800") | |
| 21 | + @ExcelProperty("归属公司") | |
| 22 | + private String companyName; | |
| 23 | + | |
| 24 | + @Schema(description = "险情地点", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 25 | + @ExcelProperty("险情地点") | |
| 26 | + private String emergencyLocation; | |
| 27 | + | |
| 28 | + @Schema(description = "发现险情时间", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 29 | + @ExcelProperty("发现险情时间") | |
| 30 | + private LocalDateTime discoveryTime; | |
| 31 | + | |
| 32 | + @Schema(description = "险情类型(如:树木倒伏)", requiredMode = Schema.RequiredMode.REQUIRED, example = "5209") | |
| 33 | + @ExcelProperty("险情类型") | |
| 34 | + private String emergencyTypeName; | |
| 35 | + | |
| 36 | + @Schema(description = "树木权属(如:专业权属)", requiredMode = Schema.RequiredMode.REQUIRED, example = "19498") | |
| 37 | + @ExcelProperty("树木权属") | |
| 38 | + private String treeOwnershipName; | |
| 39 | + | |
| 40 | + @Schema(description = "险情危害(如:无)", requiredMode = Schema.RequiredMode.REQUIRED, example = "16325") | |
| 41 | + @ExcelProperty("险情危害") | |
| 42 | + private String emergencyHarmName; | |
| 43 | + | |
| 44 | + @Schema(description = "险情危害(如:无)", requiredMode = Schema.RequiredMode.REQUIRED, example = "16325") | |
| 45 | + @ExcelProperty("险情危害") | |
| 46 | + private Integer emergencyHarmId; | |
| 47 | + | |
| 48 | + @Schema(description = "数量/株", requiredMode = Schema.RequiredMode.REQUIRED, example = "3371") | |
| 49 | + @ExcelProperty("数量/株") | |
| 50 | + private Integer emergencyHarmNum; | |
| 51 | + | |
| 52 | + @Schema(description = "抢险开始时间", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 53 | + @ExcelProperty("抢险开始时间") | |
| 54 | + private LocalDateTime rescueStartTime; | |
| 55 | + | |
| 56 | + @Schema(description = "树种(如:国槐)") | |
| 57 | + @ExcelProperty("树种") | |
| 58 | + private String treeSpecies; | |
| 59 | + | |
| 60 | + @Schema(description = "树木规格") | |
| 61 | + @ExcelProperty("树木规格") | |
| 62 | + private String treeSpec; | |
| 63 | + | |
| 64 | + @Schema(description = "抢险完成时间", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 65 | + @ExcelProperty("抢险完成时间") | |
| 66 | + private LocalDateTime rescueCompleteTime; | |
| 67 | + | |
| 68 | + @Schema(description = "抢险中照片", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 69 | + @ExcelProperty(value = "抢险中照片", converter = ImageStringConverter.class) | |
| 70 | + private byte[] emergencyImg1; | |
| 71 | + | |
| 72 | + @Schema(description = "抢险中照片", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 73 | + @ExcelProperty(value = "抢险中照片", converter = ImageStringConverter.class) | |
| 74 | + private byte[] emergencyImg2; | |
| 75 | + | |
| 76 | + @Schema(description = "抢险中照片", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 77 | + @ExcelProperty(value = "抢险中照片", converter = ImageStringConverter.class) | |
| 78 | + private byte[] emergencyImg3; | |
| 79 | + | |
| 80 | + @Schema(description = "抢险结束照片", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 81 | + @ExcelProperty(value = "抢险结束照片", converter = ImageStringConverter.class) | |
| 82 | + private byte[] emergencyEndImg; | |
| 83 | + | |
| 84 | + @Schema(description = "预警信息") | |
| 85 | + @ExcelProperty("预警信息") | |
| 86 | + private String remarks; | |
| 87 | + | |
| 88 | +} | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/emergencytask/vo/EmergencyTaskExcleRespVO.java
| ... | ... | @@ -28,10 +28,18 @@ public class EmergencyTaskExcleRespVO { |
| 28 | 28 | @ExcelProperty("险情类型") |
| 29 | 29 | private String emergencyTypeName; |
| 30 | 30 | |
| 31 | + @Schema(description = "险情类型数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "5209") | |
| 32 | + @ExcelProperty("数量/株") | |
| 33 | + private Integer emergencyTypeNum; | |
| 34 | + | |
| 31 | 35 | @Schema(description = "险情危害(如:无)", requiredMode = Schema.RequiredMode.REQUIRED, example = "16325") |
| 32 | 36 | @ExcelProperty("险情危害") |
| 33 | 37 | private String emergencyHarmName; |
| 34 | 38 | |
| 39 | + @Schema(description = "险情危害数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "16325") | |
| 40 | + @ExcelProperty("数量") | |
| 41 | + private Integer emergencyHarmNum; | |
| 42 | + | |
| 35 | 43 | @Schema(description = "树木权属(如:专业权属)", requiredMode = Schema.RequiredMode.REQUIRED, example = "19498") |
| 36 | 44 | @ExcelProperty("树木权属") |
| 37 | 45 | private String treeOwnershipName; |
| ... | ... | @@ -40,6 +48,10 @@ public class EmergencyTaskExcleRespVO { |
| 40 | 48 | @ExcelProperty("险情地点") |
| 41 | 49 | private String emergencyLocation; |
| 42 | 50 | |
| 51 | + @Schema(description = "所属街道", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 52 | + @ExcelProperty("所属街道") | |
| 53 | + private String streetName; | |
| 54 | + | |
| 43 | 55 | @Schema(description = "上报人", requiredMode = Schema.RequiredMode.REQUIRED) |
| 44 | 56 | @ExcelProperty("上报人") |
| 45 | 57 | private String reporter; |
| ... | ... | @@ -56,7 +68,7 @@ public class EmergencyTaskExcleRespVO { |
| 56 | 68 | //@ExcelProperty(value="抢险中照片", converter = ListToStringConverter.class) |
| 57 | 69 | @ExcelProperty(value = "抢险中照片", converter = ImageListConverter.class) |
| 58 | 70 | @ColumnWidth(70) |
| 59 | - private List<String> emergencyImg; | |
| 71 | + private List<byte[]> emergencyImg; | |
| 60 | 72 | |
| 61 | 73 | @Schema(description = "树种(如:国槐)") |
| 62 | 74 | @ExcelProperty("树种") |
| ... | ... | @@ -78,7 +90,7 @@ public class EmergencyTaskExcleRespVO { |
| 78 | 90 | //@ExcelProperty(value="抢险结束照片", converter = ListToStringConverter.class) |
| 79 | 91 | @ExcelProperty(value = "抢险结束照片", converter = ImageListConverter.class) |
| 80 | 92 | @ColumnWidth(70) |
| 81 | - private List<String> emergencyEndImg; | |
| 93 | + private List<byte[]> emergencyEndImg; | |
| 82 | 94 | |
| 83 | 95 | @Schema(description = "备注") |
| 84 | 96 | @ExcelProperty("备注") |
| ... | ... | @@ -96,7 +108,6 @@ public class EmergencyTaskExcleRespVO { |
| 96 | 108 | @ExcelProperty("审批备注") |
| 97 | 109 | private String approvalRemarks; |
| 98 | 110 | |
| 99 | - | |
| 100 | 111 | @Schema(description = "创建者", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") |
| 101 | 112 | @ExcelProperty("创建者") |
| 102 | 113 | private String creatorName; | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/emergencytask/vo/EmergencyTaskPageReqVO.java
| ... | ... | @@ -46,7 +46,9 @@ public class EmergencyTaskPageReqVO extends PageParam { |
| 46 | 46 | @Schema(description = "归属(一级部门id)", example = "6353") |
| 47 | 47 | private Long companyId; |
| 48 | 48 | |
| 49 | + @Schema(description = "所在街道ID", example = "1111111") | |
| 50 | + private String streetId; | |
| 49 | 51 | |
| 50 | 52 | private List<Integer> busiStatusList; |
| 51 | 53 | |
| 52 | -} | |
| 53 | 54 | \ No newline at end of file |
| 55 | +} | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/emergencytask/vo/EmergencyTaskRespVO.java
| 1 | 1 | package com.zteits.urbanops.module.garden.controller.admin.emergencytask.vo; |
| 2 | 2 | |
| 3 | +import com.fhs.core.trans.anno.Trans; | |
| 4 | +import com.fhs.core.trans.constant.TransType; | |
| 3 | 5 | import com.zteits.urbanops.framework.excel.core.convert.ListToStringConverter; |
| 4 | 6 | import com.zteits.urbanops.module.garden.dal.dataobject.emergencytask.EmergencyMachineryDO; |
| 5 | 7 | import io.swagger.v3.oas.annotations.media.Schema; |
| 8 | +import jakarta.validation.constraints.NotEmpty; | |
| 6 | 9 | import lombok.*; |
| 7 | 10 | import java.util.*; |
| 8 | 11 | import java.time.LocalDateTime; |
| ... | ... | @@ -136,4 +139,15 @@ public class EmergencyTaskRespVO { |
| 136 | 139 | @ExcelProperty("部门") |
| 137 | 140 | private String deptName; |
| 138 | 141 | |
| 139 | -} | |
| 140 | 142 | \ No newline at end of file |
| 143 | + @Schema(description = "险情类型数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 144 | + private Integer emergencyTypeNum; | |
| 145 | + | |
| 146 | + @Schema(description = "险情危害数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 147 | + private Integer emergencyHarmNum; | |
| 148 | + | |
| 149 | + @Schema(description = "所在街道", requiredMode = Schema.RequiredMode.REQUIRED, example = "255") | |
| 150 | + private String streetId; | |
| 151 | + | |
| 152 | + @Schema(description = "所在街道", requiredMode = Schema.RequiredMode.REQUIRED, example = "255") | |
| 153 | + private String streetName; | |
| 154 | +} | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/emergencytask/vo/EmergencyTaskSaveReqVO.java
| 1 | 1 | package com.zteits.urbanops.module.garden.controller.admin.emergencytask.vo; |
| 2 | 2 | |
| 3 | +import cn.idev.excel.annotation.ExcelProperty; | |
| 3 | 4 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | 5 | import lombok.*; |
| 5 | 6 | import java.util.*; |
| 6 | 7 | import jakarta.validation.constraints.*; |
| 7 | 8 | import org.springframework.format.annotation.DateTimeFormat; |
| 8 | 9 | import java.time.LocalDateTime; |
| 10 | +import java.util.List; | |
| 9 | 11 | |
| 10 | 12 | @Schema(description = "管理后台 - 抢险任务主新增/修改 Request VO") |
| 11 | 13 | @Data |
| ... | ... | @@ -94,6 +96,16 @@ public class EmergencyTaskSaveReqVO { |
| 94 | 96 | private String approvalUserName; |
| 95 | 97 | |
| 96 | 98 | @Schema(description = "使用机械", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") |
| 97 | - private List<EmergencyMachinerySaveReqVO> emergencyMachineryList; | |
| 99 | + private List<EmergencyMachinerySaveReqVO> emergencyMachineryList; | |
| 98 | 100 | |
| 99 | -} | |
| 100 | 101 | \ No newline at end of file |
| 102 | + @Schema(description = "险情类型数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 103 | + private Integer emergencyTypeNum; | |
| 104 | + | |
| 105 | + @Schema(description = "险情危害数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") | |
| 106 | + private Integer emergencyHarmNum; | |
| 107 | + | |
| 108 | + @Schema(description = "所在街道", requiredMode = Schema.RequiredMode.REQUIRED, example = "255") | |
| 109 | + @NotEmpty(message = "所在街道") | |
| 110 | + private String streetId; | |
| 111 | + | |
| 112 | +} | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/filedownload/FileDownloadController.java
0 → 100644
| 1 | +package com.zteits.urbanops.module.garden.controller.admin.filedownload; | |
| 2 | + | |
| 3 | +import com.zteits.urbanops.framework.security.core.util.SecurityFrameworkUtils; | |
| 4 | +import jakarta.annotation.security.PermitAll; | |
| 5 | +import org.springframework.web.bind.annotation.*; | |
| 6 | +import jakarta.annotation.Resource; | |
| 7 | +import org.springframework.validation.annotation.Validated; | |
| 8 | +import org.springframework.security.access.prepost.PreAuthorize; | |
| 9 | +import io.swagger.v3.oas.annotations.tags.Tag; | |
| 10 | +import io.swagger.v3.oas.annotations.Parameter; | |
| 11 | +import io.swagger.v3.oas.annotations.Operation; | |
| 12 | + | |
| 13 | +import jakarta.validation.constraints.*; | |
| 14 | +import jakarta.validation.*; | |
| 15 | +import jakarta.servlet.http.*; | |
| 16 | + | |
| 17 | +import java.io.FileInputStream; | |
| 18 | +import java.io.OutputStream; | |
| 19 | +import java.net.URLEncoder; | |
| 20 | +import java.nio.charset.StandardCharsets; | |
| 21 | +import java.util.*; | |
| 22 | +import java.io.IOException; | |
| 23 | + | |
| 24 | +import com.zteits.urbanops.framework.common.pojo.PageParam; | |
| 25 | +import com.zteits.urbanops.framework.common.pojo.PageResult; | |
| 26 | +import com.zteits.urbanops.framework.common.pojo.CommonResult; | |
| 27 | +import com.zteits.urbanops.framework.common.util.object.BeanUtils; | |
| 28 | + | |
| 29 | +import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 30 | +import static com.zteits.urbanops.framework.common.pojo.CommonResult.success; | |
| 31 | + | |
| 32 | +import com.zteits.urbanops.framework.excel.core.util.ExcelUtils; | |
| 33 | + | |
| 34 | +import com.zteits.urbanops.framework.apilog.core.annotation.ApiAccessLog; | |
| 35 | +import static com.zteits.urbanops.framework.apilog.core.enums.OperateTypeEnum.*; | |
| 36 | +import static com.zteits.urbanops.module.garden.enums.ErrorCodeConstants.FILE_DOWNLOAD_NOT_EXISTS; | |
| 37 | +import static com.zteits.urbanops.module.infra.framework.file.core.utils.FileTypeUtils.writeAttachment; | |
| 38 | + | |
| 39 | +import com.zteits.urbanops.module.garden.controller.admin.filedownload.vo.*; | |
| 40 | +import com.zteits.urbanops.module.garden.dal.dataobject.filedownload.FileDownloadDO; | |
| 41 | +import com.zteits.urbanops.module.garden.service.filedownload.FileDownloadService; | |
| 42 | + | |
| 43 | +@Tag(name = "管理后台 - 文件异步下载任务") | |
| 44 | +@RestController | |
| 45 | +@RequestMapping("/garden/file-download") | |
| 46 | +@Validated | |
| 47 | +public class FileDownloadController { | |
| 48 | + | |
| 49 | + @Resource | |
| 50 | + private FileDownloadService fileDownloadService; | |
| 51 | + | |
| 52 | + @PostMapping("/create") | |
| 53 | + @Operation(summary = "创建文件异步下载任务") | |
| 54 | + @PreAuthorize("@ss.hasPermission('garden:file-download:create')") | |
| 55 | + public CommonResult<Long> createFileDownload(@Valid @RequestBody FileDownloadSaveReqVO createReqVO) { | |
| 56 | + return success(fileDownloadService.createFileDownload(createReqVO)); | |
| 57 | + } | |
| 58 | + | |
| 59 | + @PutMapping("/update") | |
| 60 | + @Operation(summary = "更新文件异步下载任务") | |
| 61 | + @PreAuthorize("@ss.hasPermission('garden:file-download:update')") | |
| 62 | + public CommonResult<Boolean> updateFileDownload(@Valid @RequestBody FileDownloadSaveReqVO updateReqVO) { | |
| 63 | + fileDownloadService.updateFileDownload(updateReqVO); | |
| 64 | + return success(true); | |
| 65 | + } | |
| 66 | + | |
| 67 | + @DeleteMapping("/delete") | |
| 68 | + @Operation(summary = "删除文件异步下载任务") | |
| 69 | + @Parameter(name = "id", description = "编号", required = true) | |
| 70 | + @PreAuthorize("@ss.hasPermission('garden:file-download:delete')") | |
| 71 | + public CommonResult<Boolean> deleteFileDownload(@RequestParam("id") Long id) { | |
| 72 | + fileDownloadService.deleteFileDownload(id); | |
| 73 | + return success(true); | |
| 74 | + } | |
| 75 | + | |
| 76 | + @DeleteMapping("/delete-list") | |
| 77 | + @Parameter(name = "ids", description = "编号", required = true) | |
| 78 | + @Operation(summary = "批量删除文件异步下载任务") | |
| 79 | + @PreAuthorize("@ss.hasPermission('garden:file-download:delete')") | |
| 80 | + public CommonResult<Boolean> deleteFileDownloadList(@RequestParam("ids") List<Long> ids) { | |
| 81 | + fileDownloadService.deleteFileDownloadListByIds(ids); | |
| 82 | + return success(true); | |
| 83 | + } | |
| 84 | + | |
| 85 | + @GetMapping("/get") | |
| 86 | + @Operation(summary = "获得文件异步下载任务") | |
| 87 | + @Parameter(name = "id", description = "编号", required = true, example = "1024") | |
| 88 | + @PreAuthorize("@ss.hasPermission('garden:file-download:query')") | |
| 89 | + public CommonResult<FileDownloadRespVO> getFileDownload(@RequestParam("id") Long id) { | |
| 90 | + FileDownloadDO fileDownload = fileDownloadService.getFileDownload(id); | |
| 91 | + return success(BeanUtils.toBean(fileDownload, FileDownloadRespVO.class)); | |
| 92 | + } | |
| 93 | + | |
| 94 | + @GetMapping("/page") | |
| 95 | + @Operation(summary = "获得文件异步下载任务分页") | |
| 96 | + //@PreAuthorize("@ss.hasPermission('garden:file-download:query')") | |
| 97 | + @PermitAll | |
| 98 | + public CommonResult<PageResult<FileDownloadRespVO>> getFileDownloadPage(@Valid FileDownloadPageReqVO pageReqVO) { | |
| 99 | + PageResult<FileDownloadDO> pageResult = fileDownloadService.getFileDownloadPage(pageReqVO); | |
| 100 | + return success(BeanUtils.toBean(pageResult, FileDownloadRespVO.class)); | |
| 101 | + } | |
| 102 | + | |
| 103 | + @GetMapping("/export-excel") | |
| 104 | + @Operation(summary = "导出文件异步下载任务 Excel") | |
| 105 | + @PreAuthorize("@ss.hasPermission('garden:file-download:export')") | |
| 106 | + @ApiAccessLog(operateType = EXPORT) | |
| 107 | + public void exportFileDownloadExcel(@Valid FileDownloadPageReqVO pageReqVO, | |
| 108 | + HttpServletResponse response) throws IOException { | |
| 109 | + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); | |
| 110 | + List<FileDownloadDO> list = fileDownloadService.getFileDownloadPage(pageReqVO).getList(); | |
| 111 | + // 导出 Excel | |
| 112 | + ExcelUtils.write(response, "文件异步下载任务.xls", "数据", FileDownloadRespVO.class, | |
| 113 | + BeanUtils.toBean(list, FileDownloadRespVO.class)); | |
| 114 | + } | |
| 115 | + | |
| 116 | + @GetMapping("/download") | |
| 117 | + @Operation(summary = "下载文件异步下载任务") | |
| 118 | + @Parameter(name = "id", description = "编号", required = true, example = "1024") | |
| 119 | + @PreAuthorize("@ss.hasPermission('garden:file-download:query')") | |
| 120 | + public void downloadFileDownload(@RequestParam("id") Long id, HttpServletResponse response) throws IOException { | |
| 121 | + | |
| 122 | + fileDownloadService.writeAttachment(response, id); | |
| 123 | + } | |
| 124 | +} | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/filedownload/vo/FileDownloadPageReqVO.java
0 → 100644
| 1 | +package com.zteits.urbanops.module.garden.controller.admin.filedownload.vo; | |
| 2 | + | |
| 3 | +import lombok.*; | |
| 4 | +import java.util.*; | |
| 5 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 6 | +import com.zteits.urbanops.framework.common.pojo.PageParam; | |
| 7 | +import org.springframework.format.annotation.DateTimeFormat; | |
| 8 | +import java.time.LocalDateTime; | |
| 9 | + | |
| 10 | +import static com.zteits.urbanops.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; | |
| 11 | + | |
| 12 | +@Schema(description = "管理后台 - 文件异步下载任务分页 Request VO") | |
| 13 | +@Data | |
| 14 | +public class FileDownloadPageReqVO extends PageParam { | |
| 15 | + | |
| 16 | + @Schema(description = "业务唯一编码::EmergencyTaskExcle") | |
| 17 | + private String busiCode; | |
| 18 | + | |
| 19 | + @Schema(description = "功能模块名称", example = "李四") | |
| 20 | + private String busiName; | |
| 21 | + | |
| 22 | + @Schema(description = "文件名称", example = "张三") | |
| 23 | + private String fileName; | |
| 24 | + | |
| 25 | + @Schema(description = "本地文件绝对路径") | |
| 26 | + private String filePath; | |
| 27 | + | |
| 28 | + @Schema(description = "状态:0待处理 1生成中 2成功 3失败", example = "2") | |
| 29 | + private Integer status; | |
| 30 | + | |
| 31 | + @Schema(description = "失败原因") | |
| 32 | + private String failMsg; | |
| 33 | + | |
| 34 | + @Schema(description = "文件过期时间") | |
| 35 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 36 | + private LocalDateTime[] expireTime; | |
| 37 | + | |
| 38 | + @Schema(description = "文件生成完成时间") | |
| 39 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 40 | + private LocalDateTime[] finishTime; | |
| 41 | + | |
| 42 | + @Schema(description = "文件大小(单位:字节)") | |
| 43 | + private Long fileSize; | |
| 44 | + | |
| 45 | + @Schema(description = "文件后缀:xlsx/zip/pdf") | |
| 46 | + private String fileSuffix; | |
| 47 | + | |
| 48 | + @Schema(description = "备注", example = "你猜") | |
| 49 | + private String remark; | |
| 50 | + | |
| 51 | + @Schema(description = "创建时间") | |
| 52 | + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) | |
| 53 | + private LocalDateTime[] createTime; | |
| 54 | + | |
| 55 | + @Schema(description = "创建人") | |
| 56 | + private String creator; | |
| 57 | + | |
| 58 | +} | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/filedownload/vo/FileDownloadRespVO.java
0 → 100644
| 1 | +package com.zteits.urbanops.module.garden.controller.admin.filedownload.vo; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import lombok.*; | |
| 5 | +import java.util.*; | |
| 6 | +import org.springframework.format.annotation.DateTimeFormat; | |
| 7 | +import java.time.LocalDateTime; | |
| 8 | +import cn.idev.excel.annotation.*; | |
| 9 | + | |
| 10 | +@Schema(description = "管理后台 - 文件异步下载任务 Response VO") | |
| 11 | +@Data | |
| 12 | +@ExcelIgnoreUnannotated | |
| 13 | +public class FileDownloadRespVO { | |
| 14 | + | |
| 15 | + @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "27429") | |
| 16 | + @ExcelProperty("主键ID") | |
| 17 | + private Long id; | |
| 18 | + | |
| 19 | + @Schema(description = "业务唯一编码::EmergencyTaskExcle", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 20 | + @ExcelProperty("业务唯一编码::EmergencyTaskExcle") | |
| 21 | + private String busiCode; | |
| 22 | + | |
| 23 | + @Schema(description = "功能模块名称", example = "李四") | |
| 24 | + @ExcelProperty("功能模块名称") | |
| 25 | + private String busiName; | |
| 26 | + | |
| 27 | + @Schema(description = "文件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") | |
| 28 | + @ExcelProperty("文件名称") | |
| 29 | + private String fileName; | |
| 30 | + | |
| 31 | + @Schema(description = "本地文件绝对路径") | |
| 32 | + @ExcelProperty("本地文件绝对路径") | |
| 33 | + private String filePath; | |
| 34 | + | |
| 35 | + @Schema(description = "状态:0待处理 1生成中 2成功 3失败", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | |
| 36 | + @ExcelProperty("状态:0待处理 1生成中 2成功 3失败") | |
| 37 | + private Integer status; | |
| 38 | + | |
| 39 | + @Schema(description = "失败原因") | |
| 40 | + @ExcelProperty("失败原因") | |
| 41 | + private String failMsg; | |
| 42 | + | |
| 43 | + @Schema(description = "文件过期时间") | |
| 44 | + @ExcelProperty("文件过期时间") | |
| 45 | + private LocalDateTime expireTime; | |
| 46 | + | |
| 47 | + @Schema(description = "文件生成完成时间") | |
| 48 | + @ExcelProperty("文件生成完成时间") | |
| 49 | + private LocalDateTime finishTime; | |
| 50 | + | |
| 51 | + @Schema(description = "文件大小(单位:字节)") | |
| 52 | + @ExcelProperty("文件大小(单位:字节)") | |
| 53 | + private Long fileSize; | |
| 54 | + | |
| 55 | + @Schema(description = "文件后缀:xlsx/zip/pdf") | |
| 56 | + @ExcelProperty("文件后缀:xlsx/zip/pdf") | |
| 57 | + private String fileSuffix; | |
| 58 | + | |
| 59 | + @Schema(description = "备注", example = "你猜") | |
| 60 | + @ExcelProperty("备注") | |
| 61 | + private String remark; | |
| 62 | + | |
| 63 | + @Schema(description = "创建时间") | |
| 64 | + @ExcelProperty("创建时间") | |
| 65 | + private LocalDateTime createTime; | |
| 66 | + | |
| 67 | +} | |
| 0 | 68 | \ No newline at end of file | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/controller/admin/filedownload/vo/FileDownloadSaveReqVO.java
0 → 100644
| 1 | +package com.zteits.urbanops.module.garden.controller.admin.filedownload.vo; | |
| 2 | + | |
| 3 | +import io.swagger.v3.oas.annotations.media.Schema; | |
| 4 | +import lombok.*; | |
| 5 | +import java.util.*; | |
| 6 | +import jakarta.validation.constraints.*; | |
| 7 | +import org.springframework.format.annotation.DateTimeFormat; | |
| 8 | +import java.time.LocalDateTime; | |
| 9 | + | |
| 10 | +@Schema(description = "管理后台 - 文件异步下载任务新增/修改 Request VO") | |
| 11 | +@Data | |
| 12 | +public class FileDownloadSaveReqVO { | |
| 13 | + | |
| 14 | + @Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "27429") | |
| 15 | + private Long id; | |
| 16 | + | |
| 17 | + @Schema(description = "业务唯一编码::EmergencyTaskExcle", requiredMode = Schema.RequiredMode.REQUIRED) | |
| 18 | + @NotEmpty(message = "业务唯一编码::EmergencyTaskExcle不能为空") | |
| 19 | + private String busiCode; | |
| 20 | + | |
| 21 | + @Schema(description = "功能模块名称", example = "李四") | |
| 22 | + private String busiName; | |
| 23 | + | |
| 24 | + @Schema(description = "文件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "张三") | |
| 25 | + @NotEmpty(message = "文件名称不能为空") | |
| 26 | + private String fileName; | |
| 27 | + | |
| 28 | + @Schema(description = "本地文件绝对路径") | |
| 29 | + private String filePath; | |
| 30 | + | |
| 31 | + @Schema(description = "状态:0待处理 1生成中 2成功 3失败", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") | |
| 32 | + @NotNull(message = "状态:0待处理 1生成中 2成功 3失败不能为空") | |
| 33 | + private Integer status; | |
| 34 | + | |
| 35 | + @Schema(description = "失败原因") | |
| 36 | + private String failMsg; | |
| 37 | + | |
| 38 | + @Schema(description = "文件过期时间") | |
| 39 | + private LocalDateTime expireTime; | |
| 40 | + | |
| 41 | + @Schema(description = "文件生成完成时间") | |
| 42 | + private LocalDateTime finishTime; | |
| 43 | + | |
| 44 | + @Schema(description = "文件大小(单位:字节)") | |
| 45 | + private Long fileSize; | |
| 46 | + | |
| 47 | + @Schema(description = "文件后缀:xlsx/zip/pdf") | |
| 48 | + private String fileSuffix; | |
| 49 | + | |
| 50 | + @Schema(description = "备注", example = "你猜") | |
| 51 | + private String remark; | |
| 52 | + | |
| 53 | +} | |
| 0 | 54 | \ No newline at end of file | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/dataobject/emergencytask/EmergencyTaskDO.java
| 1 | 1 | package com.zteits.urbanops.module.garden.dal.dataobject.emergencytask; |
| 2 | 2 | |
| 3 | +import com.baomidou.mybatisplus.annotation.KeySequence; | |
| 4 | +import com.baomidou.mybatisplus.annotation.TableField; | |
| 5 | +import com.baomidou.mybatisplus.annotation.TableId; | |
| 6 | +import com.baomidou.mybatisplus.annotation.TableName; | |
| 7 | +import com.zteits.urbanops.framework.mybatis.core.dataobject.BaseDO; | |
| 3 | 8 | import com.zteits.urbanops.framework.mybatis.core.type.StringArrayToListTypeHandler; |
| 4 | -import com.zteits.urbanops.framework.mybatis.core.type.StringListTypeHandler; | |
| 5 | 9 | import lombok.*; |
| 6 | -import java.util.*; | |
| 7 | -import java.time.LocalDateTime; | |
| 8 | -import java.time.LocalDateTime; | |
| 9 | -import java.time.LocalDateTime; | |
| 10 | -import java.time.LocalDateTime; | |
| 10 | + | |
| 11 | 11 | import java.time.LocalDateTime; |
| 12 | -import com.baomidou.mybatisplus.annotation.*; | |
| 13 | -import com.zteits.urbanops.framework.mybatis.core.dataobject.BaseDO; | |
| 12 | +import java.util.List; | |
| 14 | 13 | |
| 15 | 14 | /** |
| 16 | 15 | * 抢险任务主 DO |
| ... | ... | @@ -139,6 +138,16 @@ public class EmergencyTaskDO extends BaseDO { |
| 139 | 138 | * 更新者 |
| 140 | 139 | */ |
| 141 | 140 | private String updaterName; |
| 142 | - | |
| 143 | - | |
| 144 | -} | |
| 145 | 141 | \ No newline at end of file |
| 142 | + /** | |
| 143 | + * 险情类型数量 | |
| 144 | + */ | |
| 145 | + private Integer emergencyTypeNum; | |
| 146 | + /** | |
| 147 | + * 险情危害数量 | |
| 148 | + */ | |
| 149 | + private Integer emergencyHarmNum; | |
| 150 | + /** | |
| 151 | + * 所在街道ID | |
| 152 | + */ | |
| 153 | + private String streetId; | |
| 154 | +} | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/dataobject/filedownload/FileDownloadDO.java
0 → 100644
| 1 | +package com.zteits.urbanops.module.garden.dal.dataobject.filedownload; | |
| 2 | + | |
| 3 | +import lombok.*; | |
| 4 | +import java.util.*; | |
| 5 | +import java.time.LocalDateTime; | |
| 6 | +import java.time.LocalDateTime; | |
| 7 | +import java.time.LocalDateTime; | |
| 8 | +import java.time.LocalDateTime; | |
| 9 | +import com.baomidou.mybatisplus.annotation.*; | |
| 10 | +import com.zteits.urbanops.framework.mybatis.core.dataobject.BaseDO; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * 文件异步下载任务 DO | |
| 14 | + * | |
| 15 | + * @author 超级管理员 | |
| 16 | + */ | |
| 17 | +@TableName("garden_file_download") | |
| 18 | +@KeySequence("garden_file_download_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 | |
| 19 | +@Data | |
| 20 | +@EqualsAndHashCode(callSuper = true) | |
| 21 | +@ToString(callSuper = true) | |
| 22 | +@Builder | |
| 23 | +@NoArgsConstructor | |
| 24 | +@AllArgsConstructor | |
| 25 | +public class FileDownloadDO extends BaseDO { | |
| 26 | + | |
| 27 | + /** | |
| 28 | + * 主键ID | |
| 29 | + */ | |
| 30 | + @TableId | |
| 31 | + private Long id; | |
| 32 | + /** | |
| 33 | + * 业务唯一编码::EmergencyTaskExcle | |
| 34 | + */ | |
| 35 | + private String busiCode; | |
| 36 | + /** | |
| 37 | + * 功能模块名称 | |
| 38 | + */ | |
| 39 | + private String busiName; | |
| 40 | + /** | |
| 41 | + * 文件名称 | |
| 42 | + */ | |
| 43 | + private String fileName; | |
| 44 | + /** | |
| 45 | + * 本地文件绝对路径 | |
| 46 | + */ | |
| 47 | + private String filePath; | |
| 48 | + /** | |
| 49 | + * 存储类型:存储类型:LOCAL/OSS | |
| 50 | + */ | |
| 51 | + private String storageType; | |
| 52 | + /** | |
| 53 | + * 状态:0待处理 1生成中 2成功 3失败 | |
| 54 | + */ | |
| 55 | + private Integer status; | |
| 56 | + /** | |
| 57 | + * 失败原因 | |
| 58 | + */ | |
| 59 | + private String failMsg; | |
| 60 | + /** | |
| 61 | + * 文件过期时间 | |
| 62 | + */ | |
| 63 | + private LocalDateTime expireTime; | |
| 64 | + /** | |
| 65 | + * 文件生成完成时间 | |
| 66 | + */ | |
| 67 | + private LocalDateTime finishTime; | |
| 68 | + /** | |
| 69 | + * 文件大小(单位:字节) | |
| 70 | + */ | |
| 71 | + private Long fileSize; | |
| 72 | + /** | |
| 73 | + * 文件后缀:xlsx/zip/pdf | |
| 74 | + */ | |
| 75 | + private String fileSuffix; | |
| 76 | + /** | |
| 77 | + * 备注 | |
| 78 | + */ | |
| 79 | + private String remark; | |
| 80 | + | |
| 81 | + | |
| 82 | +} | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/mysql/emergencytask/EmergencyTaskMapper.java
| ... | ... | @@ -40,6 +40,7 @@ public interface EmergencyTaskMapper extends BaseMapperX<EmergencyTaskDO> { |
| 40 | 40 | .likeIfPresent(EmergencyTaskDO::getEmergencyLocation, reqVO.getEmergencyLocation()) |
| 41 | 41 | .eqIfPresent(EmergencyTaskDO::getBusiStatus, reqVO.getBusiStatus()) |
| 42 | 42 | .eqIfPresent(EmergencyTaskDO::getCompanyId, reqVO.getCompanyId()) |
| 43 | + .eqIfPresent(EmergencyTaskDO::getStreetId, reqVO.getStreetId()) | |
| 43 | 44 | .betweenIfPresent(EmergencyTaskDO::getDiscoveryTime, startDateTime, endDateTime); |
| 44 | 45 | if(!CollectionUtils.isEmpty(reqVO.getBusiStatusList())){ |
| 45 | 46 | sql.in(EmergencyTaskDO::getBusiStatus, reqVO.getBusiStatusList()); |
| ... | ... | @@ -50,4 +51,4 @@ public interface EmergencyTaskMapper extends BaseMapperX<EmergencyTaskDO> { |
| 50 | 51 | |
| 51 | 52 | int deleteByTaskNo(@Param("taskNo") String taskNo); |
| 52 | 53 | |
| 53 | -} | |
| 54 | 54 | \ No newline at end of file |
| 55 | +} | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/dal/mysql/filedownload/FileDownloadMapper.java
0 → 100644
| 1 | +package com.zteits.urbanops.module.garden.dal.mysql.filedownload; | |
| 2 | + | |
| 3 | +import java.util.*; | |
| 4 | + | |
| 5 | +import com.zteits.urbanops.framework.common.pojo.PageResult; | |
| 6 | +import com.zteits.urbanops.framework.mybatis.core.query.LambdaQueryWrapperX; | |
| 7 | +import com.zteits.urbanops.framework.mybatis.core.mapper.BaseMapperX; | |
| 8 | +import com.zteits.urbanops.module.garden.dal.dataobject.filedownload.FileDownloadDO; | |
| 9 | +import org.apache.ibatis.annotations.Mapper; | |
| 10 | +import com.zteits.urbanops.module.garden.controller.admin.filedownload.vo.*; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * 文件异步下载任务 Mapper | |
| 14 | + * | |
| 15 | + * @author 超级管理员 | |
| 16 | + */ | |
| 17 | +@Mapper | |
| 18 | +public interface FileDownloadMapper extends BaseMapperX<FileDownloadDO> { | |
| 19 | + | |
| 20 | + default PageResult<FileDownloadDO> selectPage(FileDownloadPageReqVO reqVO) { | |
| 21 | + return selectPage(reqVO, new LambdaQueryWrapperX<FileDownloadDO>() | |
| 22 | + .eqIfPresent(FileDownloadDO::getBusiCode, reqVO.getBusiCode()) | |
| 23 | + .likeIfPresent(FileDownloadDO::getBusiName, reqVO.getBusiName()) | |
| 24 | + .likeIfPresent(FileDownloadDO::getFileName, reqVO.getFileName()) | |
| 25 | + .eqIfPresent(FileDownloadDO::getFilePath, reqVO.getFilePath()) | |
| 26 | + .eqIfPresent(FileDownloadDO::getStatus, reqVO.getStatus()) | |
| 27 | + .eqIfPresent(FileDownloadDO::getFailMsg, reqVO.getFailMsg()) | |
| 28 | + .betweenIfPresent(FileDownloadDO::getExpireTime, reqVO.getExpireTime()) | |
| 29 | + .betweenIfPresent(FileDownloadDO::getFinishTime, reqVO.getFinishTime()) | |
| 30 | + .eqIfPresent(FileDownloadDO::getFileSize, reqVO.getFileSize()) | |
| 31 | + .eqIfPresent(FileDownloadDO::getFileSuffix, reqVO.getFileSuffix()) | |
| 32 | + .eqIfPresent(FileDownloadDO::getRemark, reqVO.getRemark()) | |
| 33 | + .betweenIfPresent(FileDownloadDO::getCreateTime, reqVO.getCreateTime()) | |
| 34 | + .eqIfPresent(FileDownloadDO::getCreator, reqVO.getCreator()) | |
| 35 | + .orderByDesc(FileDownloadDO::getId)); | |
| 36 | + } | |
| 37 | + | |
| 38 | +} | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/enums/ErrorCodeConstants.java
| ... | ... | @@ -155,4 +155,7 @@ public interface ErrorCodeConstants { |
| 155 | 155 | // ========== 一树一档案巡检与风险评估 1-100-008-000 ========== |
| 156 | 156 | ErrorCode TREE_INSPECTION_NOT_EXISTS = new ErrorCode(1100008001, "巡检评估记录不存在"); |
| 157 | 157 | |
| 158 | + //文件异步下载 | |
| 159 | + ErrorCode FILE_DOWNLOAD_NOT_EXISTS = new ErrorCode(1-100-000-001, "文件异步下载任务不存在"); | |
| 160 | + | |
| 158 | 161 | } | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/enums/ExportBusiCodeEnum.java
0 → 100644
| 1 | +package com.zteits.urbanops.module.garden.enums; | |
| 2 | + | |
| 3 | +import lombok.Getter; | |
| 4 | + | |
| 5 | +import java.time.LocalDateTime; | |
| 6 | +import java.time.format.DateTimeFormatter; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * 导出业务编码枚举 | |
| 10 | + */ | |
| 11 | +@Getter | |
| 12 | +public enum ExportBusiCodeEnum { | |
| 13 | + | |
| 14 | + /** 旧版抢险案件导出 */ | |
| 15 | + EMERGENCY_TASK_OLD("EmergencyTaskExcle", "险情管理", "抢险案件表", "险情案件", ".xlsx"), | |
| 16 | + /** 新版抢险案件导出 */ | |
| 17 | + EMERGENCY_TASK_NEW("EmergencyTaskExcleNew", "险情管理", "抢险案件表", "险情案件", ".xlsx"); | |
| 18 | + | |
| 19 | + /** 业务编码 */ | |
| 20 | + private final String busiCode; | |
| 21 | + /** 业务名称 */ | |
| 22 | + private final String busiName; | |
| 23 | + /** 导出文件名(不含后缀) */ | |
| 24 | + private final String fileName; | |
| 25 | + /** Excel Sheet 名称 */ | |
| 26 | + private final String sheetName; | |
| 27 | + /** 文件后缀 */ | |
| 28 | + private final String fileSuffix; | |
| 29 | + | |
| 30 | + // 时间格式化:yyyyMMddHHmmss | |
| 31 | + private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * 全参构造 | |
| 35 | + * @param busiCode 业务编码 | |
| 36 | + * @param busiName 业务名称 | |
| 37 | + * @param fileName 文件名 | |
| 38 | + * @param sheetName sheet名称 | |
| 39 | + * @param fileSuffix 文件后缀 | |
| 40 | + */ | |
| 41 | + ExportBusiCodeEnum(String busiCode, String busiName, String fileName, String sheetName, String fileSuffix) { | |
| 42 | + this.busiCode = busiCode; | |
| 43 | + this.busiName = busiName; | |
| 44 | + this.fileName = fileName; | |
| 45 | + this.sheetName = sheetName; | |
| 46 | + this.fileSuffix = fileSuffix; | |
| 47 | + } | |
| 48 | + | |
| 49 | + /** | |
| 50 | + * 根据业务编码获取枚举 | |
| 51 | + * @param busiCode 业务编码 | |
| 52 | + * @return 对应枚举,未匹配返回 null | |
| 53 | + */ | |
| 54 | + public static ExportBusiCodeEnum getByCode(String busiCode) { | |
| 55 | + if (busiCode == null) { | |
| 56 | + return null; | |
| 57 | + } | |
| 58 | + for (ExportBusiCodeEnum enumItem : values()) { | |
| 59 | + if (enumItem.getBusiCode().equals(busiCode)) { | |
| 60 | + return enumItem; | |
| 61 | + } | |
| 62 | + } | |
| 63 | + return null; | |
| 64 | + } | |
| 65 | + | |
| 66 | + /** | |
| 67 | + * 拼接完整文件名(文件名 + 后缀) | |
| 68 | + * @return 完整文件名 例:抢险案件表.xls | |
| 69 | + */ | |
| 70 | + public String getFullFileName() { | |
| 71 | + String nowTime = LocalDateTime.now().format(TIME_FORMATTER); | |
| 72 | + return String.format("%s_%s%s", this.fileName, nowTime, this.fileSuffix); | |
| 73 | + } | |
| 74 | +} | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/enums/FileTaskStatus.java
0 → 100644
| 1 | +package com.zteits.urbanops.module.garden.enums; | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * @Classname FileTaskStatus | |
| 5 | + * @Description * 文件异步任务状态 | |
| 6 | + * * 0待处理 1生成中 2成功 3失败 | |
| 7 | + * @Date 2026/6/12 15:49 | |
| 8 | + * @Created by wangqian | |
| 9 | + */ | |
| 10 | +public enum FileTaskStatus { | |
| 11 | + // FileTaskStatus 常见定义 | |
| 12 | + PENDING(0, "待处理"), // 刚创建,还没开始 | |
| 13 | + PROCESSING(1, "处理中"), // 正在分批导出 | |
| 14 | + SUCCESS(2, "成功"), // 全部分页写完 | |
| 15 | + FAIL(3, "失败"); // 中途出错 | |
| 16 | + | |
| 17 | + private final Integer code; | |
| 18 | + private final String desc; | |
| 19 | + | |
| 20 | + FileTaskStatus(Integer code, String desc) { | |
| 21 | + this.code = code; | |
| 22 | + this.desc = desc; | |
| 23 | + } | |
| 24 | + public Integer getCode() { | |
| 25 | + return code; | |
| 26 | + } | |
| 27 | + public String getDesc() { | |
| 28 | + return desc; | |
| 29 | + } | |
| 30 | +} | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/job/file/ClearExpiredFilesJob.java
0 → 100644
| 1 | +package com.zteits.urbanops.module.garden.job.file; | |
| 2 | + | |
| 3 | +import com.zteits.urbanops.framework.quartz.core.handler.JobHandler; | |
| 4 | +import com.zteits.urbanops.module.garden.service.filedownload.FileDownloadService; | |
| 5 | +import jakarta.annotation.Resource; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * @Classname ClearExpiredFilesJob | |
| 9 | + * @Description 清理过期文件 | |
| 10 | + * 1、mysql事件调度器将过期文件记录更新为 4-失效, | |
| 11 | + * 2、定时任务每天执行一次,查询到数据库中状态为4的记录,将文件删除 | |
| 12 | + * @Date 2026/6/15 12:25 | |
| 13 | + * @Created by wangqian | |
| 14 | + */ | |
| 15 | +public class ClearExpiredFilesJob implements JobHandler { | |
| 16 | + @Resource | |
| 17 | + private FileDownloadService fileDownloadService; | |
| 18 | + | |
| 19 | + @Override | |
| 20 | + public String execute(String param) throws Exception { | |
| 21 | + fileDownloadService.clearExpiredFiles(); | |
| 22 | + return "Successfully"; | |
| 23 | + } | |
| 24 | +} | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/emergencytask/EmergencyExportHandler.java
0 → 100644
| 1 | +package com.zteits.urbanops.module.garden.service.emergencytask; | |
| 2 | + | |
| 3 | +import cn.idev.excel.ExcelWriter; | |
| 4 | +import cn.idev.excel.write.metadata.WriteSheet; | |
| 5 | +import com.zteits.urbanops.framework.common.biz.system.dict.dto.DictDataRespDTO; | |
| 6 | +import com.zteits.urbanops.module.garden.controller.admin.emergencytask.vo.EmergencyTaskExcleRespVO; | |
| 7 | +import com.zteits.urbanops.module.garden.controller.admin.emergencytask.vo.EmergencyTaskRespVO; | |
| 8 | +import com.zteits.urbanops.module.garden.service.filedownload.ExcelExportHandler; | |
| 9 | +import com.zteits.urbanops.module.garden.util.ImgDownUtils; | |
| 10 | +import com.zteits.urbanops.module.infra.framework.file.core.client.FileClient; | |
| 11 | +import com.zteits.urbanops.module.infra.service.file.FileConfigService; | |
| 12 | +import lombok.extern.slf4j.Slf4j; | |
| 13 | +import org.apache.poi.ss.util.CellRangeAddress; | |
| 14 | +import org.springframework.stereotype.Service; | |
| 15 | +import org.springframework.util.CollectionUtils; | |
| 16 | + | |
| 17 | +import jakarta.annotation.Resource; | |
| 18 | +import java.util.*; | |
| 19 | +import java.util.concurrent.ConcurrentHashMap; | |
| 20 | +import java.util.stream.Collectors; | |
| 21 | + | |
| 22 | +import static com.zteits.urbanops.module.garden.service.filedownload.ExcelExportAsyncService.BATCH_SIZE; | |
| 23 | + | |
| 24 | +/** | |
| 25 | + * 应急任务导出处理器 | |
| 26 | + * 实现 ExcelExportHandler 接口,替代原抽象类继承 | |
| 27 | + */ | |
| 28 | +@Slf4j | |
| 29 | +@Service | |
| 30 | +public class EmergencyExportHandler implements ExcelExportHandler<EmergencyTaskRespVO, EmergencyTaskExcleRespVO> { | |
| 31 | + | |
| 32 | + // 字典本地缓存 | |
| 33 | + private static final Map<String, Map<String, String>> DICT_CACHE = new ConcurrentHashMap<>(); | |
| 34 | + | |
| 35 | + // 字典类型常量(避免魔法值) | |
| 36 | + private static final String DICT_HAZARD_TYPE = "hazard_type"; | |
| 37 | + private static final String DICT_HAZARD_RISK = "hazard_risk"; | |
| 38 | + private static final String DICT_TREE_PERMISSIONS = "tree_permissions"; | |
| 39 | + private static final String DICT_MECHANICAL_TYPE = "mechanical_type"; | |
| 40 | + private static final String DICT_RESCUE_STATUS = "rescue_status"; | |
| 41 | + | |
| 42 | + @Resource | |
| 43 | + private EmergencyTaskService emergencyTaskService; | |
| 44 | + @Resource | |
| 45 | + private FileConfigService fileConfigService; | |
| 46 | + | |
| 47 | + // ===================== 接口方法实现 ===================== | |
| 48 | + @Override | |
| 49 | + public List<EmergencyTaskExcleRespVO> convert(List<EmergencyTaskRespVO> batchList, int startIndex) { | |
| 50 | + | |
| 51 | + List<EmergencyTaskExcleRespVO> voList = new ArrayList<>(batchList.size()); | |
| 52 | + // 从上下文获取字典,增加空兜底 | |
| 53 | + Map<String, String> hazardTypeDict = getDictMap(DICT_HAZARD_TYPE); | |
| 54 | + Map<String, String> hazardRiskDict = getDictMap(DICT_HAZARD_RISK); | |
| 55 | + Map<String, String> treePermissionsDict = getDictMap(DICT_TREE_PERMISSIONS); | |
| 56 | + Map<String, String> mechanicalTypeDict = getDictMap(DICT_MECHANICAL_TYPE); | |
| 57 | + Map<String, String> rescueStatusDict = getDictMap(DICT_RESCUE_STATUS); | |
| 58 | + // 初始化文件客户端 | |
| 59 | + FileClient fileClient = fileConfigService.getMasterFileClient(); | |
| 60 | + | |
| 61 | + for (EmergencyTaskRespVO task : batchList) { | |
| 62 | + EmergencyTaskExcleRespVO vo = new EmergencyTaskExcleRespVO(); | |
| 63 | + vo.setTaskNo(task.getTaskNo()); | |
| 64 | + vo.setDiscoveryTime(task.getDiscoveryTime()); | |
| 65 | + vo.setReporter(task.getReporter()); | |
| 66 | + vo.setContactPhone(task.getContactPhone()); | |
| 67 | + vo.setEmergencyLocation(task.getEmergencyLocation()); | |
| 68 | + vo.setTreeSpecies(task.getTreeSpecies()); | |
| 69 | + vo.setTreeSpec(task.getTreeSpec()); | |
| 70 | + vo.setRescueStartTime(task.getRescueStartTime()); | |
| 71 | + vo.setRescueCompleteTime(task.getRescueCompleteTime()); | |
| 72 | + vo.setPersonnelCount(task.getPersonnelCount()); | |
| 73 | + vo.setRemarks(task.getRemarks()); | |
| 74 | + vo.setCompanyName(task.getCompanyName()); | |
| 75 | + vo.setApprovalUserName(task.getApprovalUserName()); | |
| 76 | + vo.setApprovalRemarks(task.getApprovalRemarks()); | |
| 77 | + vo.setCreatorName(task.getCreatorName()); | |
| 78 | + vo.setCreateTime(task.getCreateTime()); | |
| 79 | + vo.setUpdaterName(task.getUpdaterName()); | |
| 80 | + vo.setEmergencyHarmNum(task.getEmergencyHarmNum()); | |
| 81 | + vo.setEmergencyTypeNum(task.getEmergencyTypeNum()); | |
| 82 | + vo.setStreetName(task.getStreetName()); | |
| 83 | + | |
| 84 | + // 字典翻译 | |
| 85 | + vo.setEmergencyTypeName(getLabel(hazardTypeDict, task.getEmergencyTypeId())); | |
| 86 | + vo.setEmergencyHarmName(getLabel(hazardRiskDict, task.getEmergencyHarmId())); | |
| 87 | + vo.setTreeOwnershipName(getLabel(treePermissionsDict, task.getTreeOwnershipId())); | |
| 88 | + vo.setBusiStatus(getLabel(rescueStatusDict, task.getBusiStatus())); | |
| 89 | + | |
| 90 | + // 图片下载处理 | |
| 91 | + vo.setEmergencyImg(ImgDownUtils.batchDownloadImages(task.getEmergencyImg(), fileClient)); | |
| 92 | + vo.setEmergencyEndImg(ImgDownUtils.batchDownloadImages(task.getEmergencyEndImg(), fileClient)); | |
| 93 | + | |
| 94 | + // 机械设备信息拼接 | |
| 95 | + List<String> machineryInfoList = new ArrayList<>(); | |
| 96 | + if (!CollectionUtils.isEmpty(task.getEmergencyMachineryList())) { | |
| 97 | + task.getEmergencyMachineryList().forEach(machinery -> | |
| 98 | + machineryInfoList.add(getLabel(mechanicalTypeDict, machinery.getMachineryNameId()) | |
| 99 | + + ":" + machinery.getMachineryCount())); | |
| 100 | + } | |
| 101 | + vo.setMachineryInfo(machineryInfoList); | |
| 102 | + voList.add(vo); | |
| 103 | + } | |
| 104 | + return voList; | |
| 105 | + } | |
| 106 | + | |
| 107 | + @Override | |
| 108 | + public Class<EmergencyTaskExcleRespVO> getExcelVoClass() { | |
| 109 | + return EmergencyTaskExcleRespVO.class; | |
| 110 | + } | |
| 111 | + | |
| 112 | + @Override | |
| 113 | + public List<List<String>> buildHead() { | |
| 114 | + return new ArrayList<>(); | |
| 115 | + } | |
| 116 | + | |
| 117 | + @Override | |
| 118 | + public List<CellRangeAddress> buildMergeRule() { | |
| 119 | + return new ArrayList<>(); | |
| 120 | + } | |
| 121 | + // ===================== 字典工具方法 ===================== | |
| 122 | + public Map<String, String> getDictMap(String dictType) { | |
| 123 | + // 先从缓存取 | |
| 124 | + if (DICT_CACHE.containsKey(dictType)) { | |
| 125 | + return DICT_CACHE.get(dictType); | |
| 126 | + } | |
| 127 | + // 缓存不存在,查询数据库 | |
| 128 | + List<DictDataRespDTO> dictList = emergencyTaskService.getDictDataList(dictType); | |
| 129 | + Map<String, String> map = buildDictMap(dictList); | |
| 130 | + DICT_CACHE.put(dictType, map); | |
| 131 | + return map; | |
| 132 | + } | |
| 133 | + | |
| 134 | + private Map<String, String> buildDictMap(List<DictDataRespDTO> dictDataList) { | |
| 135 | + if (CollectionUtils.isEmpty(dictDataList)) { | |
| 136 | + return Collections.emptyMap(); | |
| 137 | + } | |
| 138 | + return dictDataList.stream() | |
| 139 | + .collect(Collectors.toMap( | |
| 140 | + DictDataRespDTO::getValue, | |
| 141 | + DictDataRespDTO::getLabel, | |
| 142 | + (v1, v2) -> v1 | |
| 143 | + )); | |
| 144 | + } | |
| 145 | + | |
| 146 | + private String getLabel(Map<String, String> dictMap, Integer id) { | |
| 147 | + if (dictMap == null || dictMap.isEmpty() || id == null) { | |
| 148 | + return ""; | |
| 149 | + } | |
| 150 | + return dictMap.getOrDefault(String.valueOf(id), ""); | |
| 151 | + } | |
| 152 | +} | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/emergencytask/EmergencyExportNewHandler.java
0 → 100644
| 1 | +package com.zteits.urbanops.module.garden.service.emergencytask; | |
| 2 | + | |
| 3 | +import com.zteits.urbanops.framework.common.biz.system.dict.dto.DictDataRespDTO; | |
| 4 | +import com.zteits.urbanops.module.garden.controller.admin.emergencytask.vo.EmergencyTaskExcleNewRespVO; | |
| 5 | +import com.zteits.urbanops.module.garden.controller.admin.emergencytask.vo.EmergencyTaskRespVO; | |
| 6 | +import com.zteits.urbanops.module.garden.service.filedownload.ExcelExportHandler; | |
| 7 | +import com.zteits.urbanops.module.garden.util.ImgDownUtils; | |
| 8 | +import com.zteits.urbanops.module.infra.framework.file.core.client.FileClient; | |
| 9 | +import com.zteits.urbanops.module.infra.service.file.FileConfigService; | |
| 10 | +import jakarta.annotation.Resource; | |
| 11 | +import lombok.extern.slf4j.Slf4j; | |
| 12 | +import org.apache.poi.ss.util.CellRangeAddress; | |
| 13 | +import org.springframework.stereotype.Service; | |
| 14 | +import org.springframework.util.CollectionUtils; | |
| 15 | + | |
| 16 | +import java.util.*; | |
| 17 | +import java.util.concurrent.ConcurrentHashMap; | |
| 18 | +import java.util.concurrent.atomic.AtomicInteger; | |
| 19 | +import java.util.stream.Collectors; | |
| 20 | + | |
| 21 | +import static com.zteits.urbanops.module.garden.service.filedownload.ExcelExportAsyncService.BATCH_SIZE; | |
| 22 | + | |
| 23 | +/** | |
| 24 | + * 新版应急任务导出处理器 | |
| 25 | + * 实现 ExcelExportHandler 接口 | |
| 26 | + */ | |
| 27 | +@Slf4j | |
| 28 | +@Service | |
| 29 | +public class EmergencyExportNewHandler implements ExcelExportHandler<EmergencyTaskRespVO, EmergencyTaskExcleNewRespVO> { | |
| 30 | + | |
| 31 | + // ===================== 常量定义(消除魔法值) ===================== | |
| 32 | + /** 字典类型编码 */ | |
| 33 | + private static final String DICT_HAZARD_TYPE = "hazard_type"; | |
| 34 | + private static final String DICT_HAZARD_RISK = "hazard_risk"; | |
| 35 | + private static final String DICT_TREE_PERMISSIONS = "tree_permissions"; | |
| 36 | + | |
| 37 | + /** 字典缓存:key=字典编码, value=字典映射 */ | |
| 38 | + private static final Map<String, Map<String, String>> DICT_CACHE = new ConcurrentHashMap<>(); | |
| 39 | + | |
| 40 | + @Resource | |
| 41 | + private EmergencyTaskService emergencyTaskService; | |
| 42 | + @Resource | |
| 43 | + private FileConfigService fileConfigService; | |
| 44 | + | |
| 45 | + // ===================== 接口方法实现 ===================== | |
| 46 | + @Override | |
| 47 | + public List<EmergencyTaskExcleNewRespVO> convert(List<EmergencyTaskRespVO> sourceList, int startIndex) { | |
| 48 | + if (CollectionUtils.isEmpty(sourceList)) { | |
| 49 | + return Collections.emptyList(); | |
| 50 | + } | |
| 51 | + Map<String, String> hazardTypeDict = getDictMap(DICT_HAZARD_TYPE); | |
| 52 | + Map<String, String> hazardRiskDict = getDictMap(DICT_HAZARD_RISK); | |
| 53 | + Map<String, String> treePermissionsDict = getDictMap(DICT_TREE_PERMISSIONS); | |
| 54 | + // 初始化文件客户端 | |
| 55 | + FileClient fileClient = fileConfigService.getMasterFileClient(); | |
| 56 | + | |
| 57 | + List<EmergencyTaskExcleNewRespVO> respList = new ArrayList<>(sourceList.size()); | |
| 58 | + | |
| 59 | + // 合并图片收集+下载,减少一次全量遍历 | |
| 60 | + for (EmergencyTaskRespVO task : sourceList) { | |
| 61 | + EmergencyTaskExcleNewRespVO vo = new EmergencyTaskExcleNewRespVO(); | |
| 62 | + // 全局行号,跨分片连续不重复 | |
| 63 | + vo.setTaskNo(String.valueOf(startIndex++)); | |
| 64 | + | |
| 65 | + // 基础字段赋值 | |
| 66 | + vo.setDiscoveryTime(task.getDiscoveryTime()); | |
| 67 | + vo.setEmergencyHarmId(task.getEmergencyHarmId()); | |
| 68 | + vo.setEmergencyLocation(task.getEmergencyLocation()); | |
| 69 | + vo.setTreeSpecies(task.getTreeSpecies()); | |
| 70 | + vo.setTreeSpec(task.getTreeSpec()); | |
| 71 | + vo.setRescueStartTime(task.getRescueStartTime()); | |
| 72 | + vo.setRescueCompleteTime(task.getRescueCompleteTime()); | |
| 73 | + vo.setEmergencyHarmNum(task.getEmergencyTypeNum()); | |
| 74 | + vo.setRemarks(task.getRemarks()); | |
| 75 | + vo.setCompanyName(task.getCompanyName()); | |
| 76 | + | |
| 77 | + // 字典翻译 | |
| 78 | + vo.setEmergencyTypeName(getLabel(hazardTypeDict, task.getEmergencyTypeId())); | |
| 79 | + vo.setEmergencyHarmName(getLabel(hazardRiskDict, task.getEmergencyHarmId())); | |
| 80 | + vo.setTreeOwnershipName(getLabel(treePermissionsDict, task.getTreeOwnershipId())); | |
| 81 | + | |
| 82 | + // 图片处理(一次组装、一次下载,精简逻辑) | |
| 83 | + List<String> emergencyImgs = Optional.ofNullable(task.getEmergencyImg()).orElse(Collections.emptyList()); | |
| 84 | + List<String> endImgs = Optional.ofNullable(task.getEmergencyEndImg()).orElse(Collections.emptyList()); | |
| 85 | + List<String> imgUrls = new ArrayList<>(4); | |
| 86 | + imgUrls.add(ImgDownUtils.getImgSafe(emergencyImgs, 0)); | |
| 87 | + imgUrls.add(ImgDownUtils.getImgSafe(emergencyImgs, 1)); | |
| 88 | + imgUrls.add(ImgDownUtils.getImgSafe(emergencyImgs, 2)); | |
| 89 | + imgUrls.add(ImgDownUtils.getImgSafe(endImgs, 0)); | |
| 90 | + | |
| 91 | + List<byte[]> imgBytes = ImgDownUtils.batchDownloadImages(imgUrls, fileClient); | |
| 92 | + vo.setEmergencyImg1(ImgDownUtils.getByteSafe(imgBytes, 0)); | |
| 93 | + vo.setEmergencyImg2(ImgDownUtils.getByteSafe(imgBytes, 1)); | |
| 94 | + vo.setEmergencyImg3(ImgDownUtils.getByteSafe(imgBytes, 2)); | |
| 95 | + vo.setEmergencyEndImg(ImgDownUtils.getByteSafe(imgBytes, 3)); | |
| 96 | + | |
| 97 | + respList.add(vo); | |
| 98 | + } | |
| 99 | + return respList; | |
| 100 | + } | |
| 101 | + | |
| 102 | + @Override | |
| 103 | + public Class<EmergencyTaskExcleNewRespVO> getExcelVoClass() { | |
| 104 | + return EmergencyTaskExcleNewRespVO.class; | |
| 105 | + } | |
| 106 | + | |
| 107 | + @Override | |
| 108 | + public List<List<String>> buildHead() { | |
| 109 | + List<List<String>> head = new ArrayList<>(); | |
| 110 | + head.add(Arrays.asList("抢险案件表", "", "序号")); | |
| 111 | + head.add(Arrays.asList("", "抢险前", "作业队")); | |
| 112 | + head.add(Arrays.asList("", "抢险前", "险情地点")); | |
| 113 | + head.add(Arrays.asList("", "抢险前", "发现险情时间")); | |
| 114 | + head.add(Arrays.asList("", "抢险前", "险情类型")); | |
| 115 | + head.add(Arrays.asList("", "抢险前", "树木权属")); | |
| 116 | + head.add(Arrays.asList("", "抢险前", "险情危害")); | |
| 117 | + head.add(Arrays.asList("", "抢险前", "险情危害")); | |
| 118 | + head.add(Arrays.asList("", "抢险前", "数量/株")); | |
| 119 | + head.add(Arrays.asList("", "抢险中", "抢险开始时间")); | |
| 120 | + head.add(Arrays.asList("", "抢险中", "树种")); | |
| 121 | + head.add(Arrays.asList("", "抢险中", "树木规格")); | |
| 122 | + head.add(Arrays.asList("", "抢险后", "抢险完成后时间")); | |
| 123 | + head.add(Arrays.asList("", "照片", "抢险过程照片")); | |
| 124 | + head.add(Arrays.asList("", "照片", "抢险过程照片")); | |
| 125 | + head.add(Arrays.asList("", "照片", "抢险过程照片")); | |
| 126 | + head.add(Arrays.asList("", "照片", "抢险后照片")); | |
| 127 | + head.add(Arrays.asList("", "备注", "")); | |
| 128 | + return head; | |
| 129 | + } | |
| 130 | + | |
| 131 | + @Override | |
| 132 | + public List<CellRangeAddress> buildMergeRule() { | |
| 133 | + List<CellRangeAddress> mergeList = new ArrayList<>(); | |
| 134 | + mergeList.add(new CellRangeAddress(0, 0, 0, 17)); | |
| 135 | + mergeList.add(new CellRangeAddress(1, 1, 1, 8)); | |
| 136 | + mergeList.add(new CellRangeAddress(1, 1, 9, 11)); | |
| 137 | + mergeList.add(new CellRangeAddress(1, 1, 12, 12)); | |
| 138 | + mergeList.add(new CellRangeAddress(1, 1, 13, 16)); | |
| 139 | + mergeList.add(new CellRangeAddress(1, 1, 17, 17)); | |
| 140 | + mergeList.add(new CellRangeAddress(2, 2, 6, 7)); | |
| 141 | + return mergeList; | |
| 142 | + } | |
| 143 | + | |
| 144 | + // ===================== 字典缓存工具 ===================== | |
| 145 | + /** | |
| 146 | + * 获取字典映射(优先走本地缓存) | |
| 147 | + */ | |
| 148 | + private Map<String, String> getDictMap(String dictType) { | |
| 149 | + if (DICT_CACHE.containsKey(dictType)) { | |
| 150 | + return DICT_CACHE.get(dictType); | |
| 151 | + } | |
| 152 | + List<DictDataRespDTO> dictList = emergencyTaskService.getDictDataList(dictType); | |
| 153 | + Map<String, String> map = buildDictMap(dictList); | |
| 154 | + DICT_CACHE.put(dictType, map); | |
| 155 | + log.info("加载字典[{}],数据量:{}", dictType, map.size()); | |
| 156 | + return map; | |
| 157 | + } | |
| 158 | + | |
| 159 | + /** | |
| 160 | + * 构建字典 key-value 映射 | |
| 161 | + */ | |
| 162 | + private Map<String, String> buildDictMap(List<DictDataRespDTO> dictDataList) { | |
| 163 | + if (CollectionUtils.isEmpty(dictDataList)) { | |
| 164 | + return Collections.emptyMap(); | |
| 165 | + } | |
| 166 | + return dictDataList.stream() | |
| 167 | + .collect(Collectors.toMap( | |
| 168 | + DictDataRespDTO::getValue, | |
| 169 | + DictDataRespDTO::getLabel, | |
| 170 | + (oldVal, newVal) -> oldVal | |
| 171 | + )); | |
| 172 | + } | |
| 173 | + | |
| 174 | + /** | |
| 175 | + * 字典翻译取值(防空、防NPE) | |
| 176 | + */ | |
| 177 | + private String getLabel(Map<String, String> dictMap, Integer id) { | |
| 178 | + if (dictMap == null || dictMap.isEmpty() || id == null) { | |
| 179 | + return ""; | |
| 180 | + } | |
| 181 | + return dictMap.getOrDefault(String.valueOf(id), ""); | |
| 182 | + } | |
| 183 | + | |
| 184 | +} | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/emergencytask/EmergencyTaskServiceImpl.java
| ... | ... | @@ -2,17 +2,21 @@ package com.zteits.urbanops.module.garden.service.emergencytask; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | 4 | import cn.hutool.core.collection.CollectionUtil; |
| 5 | +import cn.hutool.core.util.ObjectUtil; | |
| 5 | 6 | import cn.hutool.core.util.RandomUtil; |
| 6 | 7 | import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; |
| 7 | 8 | import com.zteits.urbanops.framework.common.biz.system.dict.dto.DictDataRespDTO; |
| 8 | 9 | import com.zteits.urbanops.framework.datapermission.core.annotation.DataPermission; |
| 9 | 10 | import com.zteits.urbanops.framework.security.core.util.SecurityFrameworkUtils; |
| 10 | 11 | import com.zteits.urbanops.module.garden.dal.dataobject.emergencytask.EmergencyMachineryDO; |
| 12 | +import com.zteits.urbanops.module.garden.dal.dataobject.road.RoadStreetDO; | |
| 11 | 13 | import com.zteits.urbanops.module.garden.dal.mysql.emergencytask.EmergencyMachineryMapper; |
| 14 | +import com.zteits.urbanops.module.garden.dal.mysql.road.RoadStreetMapper; | |
| 12 | 15 | import com.zteits.urbanops.module.system.api.dept.DeptApi; |
| 13 | 16 | import com.zteits.urbanops.module.system.api.dept.dto.DeptRespDTO; |
| 14 | 17 | import com.zteits.urbanops.module.system.api.dict.DictDataApi; |
| 15 | 18 | import org.apache.commons.lang3.StringUtils; |
| 19 | +import org.apache.poi.ss.formula.functions.T; | |
| 16 | 20 | import org.springframework.stereotype.Service; |
| 17 | 21 | import jakarta.annotation.Resource; |
| 18 | 22 | import org.springframework.util.CollectionUtils; |
| ... | ... | @@ -20,6 +24,7 @@ import org.springframework.validation.annotation.Validated; |
| 20 | 24 | import org.springframework.transaction.annotation.Transactional; |
| 21 | 25 | |
| 22 | 26 | import java.util.*; |
| 27 | +import java.util.concurrent.atomic.AtomicInteger; | |
| 23 | 28 | import java.util.stream.Collectors; |
| 24 | 29 | |
| 25 | 30 | import com.zteits.urbanops.module.garden.controller.admin.emergencytask.vo.*; |
| ... | ... | @@ -56,6 +61,9 @@ public class EmergencyTaskServiceImpl implements EmergencyTaskService { |
| 56 | 61 | @Resource |
| 57 | 62 | private DictDataApi dictDataApi; |
| 58 | 63 | |
| 64 | + @Resource | |
| 65 | + private RoadStreetMapper roadStreetMapper; | |
| 66 | + | |
| 59 | 67 | @Transactional(rollbackFor = Exception.class) |
| 60 | 68 | @Override |
| 61 | 69 | public Long createEmergencyTask(EmergencyTaskSaveReqVO createReqVO, boolean isSave) { |
| ... | ... | @@ -92,6 +100,9 @@ public class EmergencyTaskServiceImpl implements EmergencyTaskService { |
| 92 | 100 | emergencyTask.setUpdater(userId); |
| 93 | 101 | emergencyTask.setUpdaterName(userName); |
| 94 | 102 | emergencyTask.setApprovalRemarks(""); |
| 103 | + emergencyTask.setStreetId(createReqVO.getStreetId()); | |
| 104 | + emergencyTask.setEmergencyHarmNum(createReqVO.getEmergencyHarmNum()); | |
| 105 | + emergencyTask.setEmergencyTypeNum(createReqVO.getEmergencyTypeNum()); | |
| 95 | 106 | if(isSave){ |
| 96 | 107 | emergencyTask.setCreator(userId); |
| 97 | 108 | emergencyTask.setCreatorName(userName); |
| ... | ... | @@ -202,22 +213,87 @@ public class EmergencyTaskServiceImpl implements EmergencyTaskService { |
| 202 | 213 | if(companyId != null && companyId.equals(100L)){ |
| 203 | 214 | pageReqVO.setBusiStatusList(Arrays.asList(2,3,4,5)); |
| 204 | 215 | } |
| 216 | + // 2. 分页查询主表数据 | |
| 205 | 217 | PageResult<EmergencyTaskDO> page = emergencyTaskMapper.selectPage(pageReqVO); |
| 218 | + List<EmergencyTaskDO> doList = page.getList(); | |
| 219 | + if (CollectionUtil.isEmpty(doList)) { | |
| 220 | + // 无数据直接返回,跳过后续逻辑 | |
| 221 | + return new PageResult<>(Collections.emptyList(), page.getTotal()); | |
| 222 | + } | |
| 223 | + // 预定义集合容量,避免 ArrayList 扩容 | |
| 224 | + int dataSize = doList.size(); | |
| 225 | + List<String> taskNoList = new ArrayList<>(dataSize); | |
| 226 | + Set<Long> orgIdSet = new HashSet<>(dataSize); | |
| 227 | + | |
| 228 | + for (EmergencyTaskDO taskDO : doList) { | |
| 229 | + String taskNo = taskDO.getTaskNo(); | |
| 230 | + Long companyIdVal = taskDO.getCompanyId(); | |
| 231 | + Long deptIdVal = taskDO.getDeptId(); | |
| 232 | + | |
| 233 | + if (ObjectUtil.isNotEmpty(taskNo)) { | |
| 234 | + taskNoList.add(taskNo); | |
| 235 | + } | |
| 206 | 236 | |
| 207 | - List<EmergencyTaskDO> list = page.getList(); | |
| 208 | - List<EmergencyTaskRespVO> listTwo = BeanUtils.toBean(list, EmergencyTaskRespVO.class); | |
| 237 | + if (ObjectUtil.isNotNull(companyIdVal)) { | |
| 238 | + orgIdSet.add(companyIdVal); | |
| 239 | + } | |
| 240 | + if (ObjectUtil.isNotNull(deptIdVal)) { | |
| 241 | + orgIdSet.add(deptIdVal); | |
| 242 | + } | |
| 243 | + } | |
| 209 | 244 | |
| 210 | - listTwo.forEach(emergencyTaskRespVO -> { | |
| 211 | - List<EmergencyMachineryDO> detailList = emergencyMachineryMapper.selectList(EmergencyMachineryDO::getTaskNo, emergencyTaskRespVO.getTaskNo()); | |
| 212 | - if(!CollectionUtil.isEmpty(detailList)){ | |
| 213 | - emergencyTaskRespVO.setEmergencyMachineryList(detailList); | |
| 245 | + // ===================== 批量查询关联数据(彻底解决 N+1) ===================== | |
| 246 | + // 机械明细 | |
| 247 | + List<EmergencyMachineryDO> allMachineryList = emergencyMachineryMapper.selectList( | |
| 248 | + EmergencyMachineryDO::getTaskNo, taskNoList | |
| 249 | + ); | |
| 250 | + // 街道信息 | |
| 251 | + List<DictDataRespDTO> streetList = getDictDataList("street_belong"); | |
| 252 | + | |
| 253 | + // 部门/公司信息 | |
| 254 | + Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(orgIdSet); | |
| 255 | + | |
| 256 | + // ===================== 内存分组 & 映射(指定Map初始容量,规避key重复) ===================== | |
| 257 | + // taskNo -> 机械明细列表 | |
| 258 | + Map<String, List<EmergencyMachineryDO>> machineryGroupMap = allMachineryList.stream() | |
| 259 | + .collect(Collectors.groupingBy( | |
| 260 | + EmergencyMachineryDO::getTaskNo, | |
| 261 | + () -> new HashMap<>(allMachineryList.size()), | |
| 262 | + Collectors.toList() | |
| 263 | + )); | |
| 264 | + | |
| 265 | + // streetId -> 街道对象,防key重复 | |
| 266 | + Map<String, DictDataRespDTO> roadStreetMap = streetList.stream() | |
| 267 | + .collect(Collectors.toMap( | |
| 268 | + DictDataRespDTO::getValue, | |
| 269 | + item -> item, | |
| 270 | + (oldVal, newVal) -> newVal, // 重复key保留后者 | |
| 271 | + () -> new HashMap<>(streetList.size()) | |
| 272 | + )); | |
| 273 | + | |
| 274 | + // 5. DO 转 VO + 批量赋值关联数据 | |
| 275 | + List<EmergencyTaskRespVO> voList = BeanUtils.toBean(doList, EmergencyTaskRespVO.class); | |
| 276 | + for (EmergencyTaskRespVO vo : voList) { | |
| 277 | + String taskNo = vo.getTaskNo(); | |
| 278 | + List<EmergencyMachineryDO> detailList = machineryGroupMap.get(taskNo); | |
| 279 | + if (CollectionUtil.isNotEmpty(detailList)) { | |
| 280 | + vo.setEmergencyMachineryList(detailList); | |
| 214 | 281 | } |
| 215 | - }); | |
| 216 | - addDataInspectionPlan(listTwo); | |
| 282 | + DictDataRespDTO roadStreet = roadStreetMap.get(vo.getStreetId()); | |
| 283 | + if (roadStreet != null) { | |
| 284 | + vo.setStreetName(roadStreet.getLabel()); | |
| 285 | + } | |
| 286 | + DeptRespDTO company = deptMap.get(vo.getCompanyId()); | |
| 287 | + if(company != null){ | |
| 288 | + vo.setCompanyName(company.getName()); | |
| 289 | + } | |
| 290 | + } | |
| 217 | 291 | |
| 218 | - // 转换返回 | |
| 219 | - return new PageResult<>(listTwo, page.getTotal()); | |
| 292 | + // 6. 原有业务方法 | |
| 293 | + //addDataInspectionPlan(voList); | |
| 220 | 294 | |
| 295 | + // 转换返回 | |
| 296 | + return new PageResult<>(voList, page.getTotal()); | |
| 221 | 297 | } |
| 222 | 298 | |
| 223 | 299 | |
| ... | ... | @@ -257,4 +333,4 @@ public class EmergencyTaskServiceImpl implements EmergencyTaskService { |
| 257 | 333 | } |
| 258 | 334 | |
| 259 | 335 | |
| 260 | -} | |
| 261 | 336 | \ No newline at end of file |
| 337 | +} | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/filedownload/ExcelExportAsyncService.java
0 → 100644
| 1 | +package com.zteits.urbanops.module.garden.service.filedownload; | |
| 2 | + | |
| 3 | +import cn.idev.excel.EasyExcel; | |
| 4 | +import cn.idev.excel.ExcelWriter; | |
| 5 | +import cn.idev.excel.write.metadata.WriteSheet; | |
| 6 | +import com.zteits.urbanops.framework.excel.core.util.ExcelUtils; | |
| 7 | +import com.zteits.urbanops.module.garden.dal.dataobject.filedownload.FileDownloadDO; | |
| 8 | +import com.zteits.urbanops.module.garden.dal.mysql.filedownload.FileDownloadMapper; | |
| 9 | +import com.zteits.urbanops.module.garden.enums.FileTaskStatus; | |
| 10 | +import lombok.extern.slf4j.Slf4j; | |
| 11 | +import org.springframework.beans.factory.annotation.Value; | |
| 12 | +import org.springframework.scheduling.annotation.Async; | |
| 13 | +import org.springframework.stereotype.Service; | |
| 14 | +import org.springframework.util.CollectionUtils; | |
| 15 | + | |
| 16 | +import java.io.File; | |
| 17 | +import java.io.IOException; | |
| 18 | +import java.time.LocalDateTime; | |
| 19 | +import java.util.ArrayList; | |
| 20 | +import java.util.List; | |
| 21 | + | |
| 22 | +@Slf4j | |
| 23 | +@Service | |
| 24 | +public class ExcelExportAsyncService { | |
| 25 | + | |
| 26 | + @Value("${file.upload-local.path}") | |
| 27 | + private String localExcelPath; | |
| 28 | + | |
| 29 | + @Value("${file.upload-local.expire-days}") | |
| 30 | + private Integer expireDay; | |
| 31 | + | |
| 32 | + public static final int BATCH_SIZE = 500; | |
| 33 | + | |
| 34 | + private final FileDownloadMapper fileDownloadMapper; | |
| 35 | + | |
| 36 | + public ExcelExportAsyncService(FileDownloadMapper fileDownloadMapper) { | |
| 37 | + this.fileDownloadMapper = fileDownloadMapper; | |
| 38 | + } | |
| 39 | + | |
| 40 | + /** | |
| 41 | + * 异步导出入口 | |
| 42 | + */ | |
| 43 | + @Async | |
| 44 | + public <S, E> void doAsyncExport( | |
| 45 | + FileDownloadDO downloadDO, | |
| 46 | + List<S> sourceList, | |
| 47 | + String sheetName, | |
| 48 | + ExcelExportHandler<S, E> exportHandler | |
| 49 | + ) { | |
| 50 | + String busiCode = downloadDO.getBusiCode(); | |
| 51 | + ExcelWriter excelWriter = null; | |
| 52 | + File excelFile = null; | |
| 53 | + | |
| 54 | + try { | |
| 55 | + // 更新为处理中 | |
| 56 | + downloadDO.setStatus(FileTaskStatus.PROCESSING.getCode()); | |
| 57 | + fileDownloadMapper.updateById(downloadDO); | |
| 58 | + | |
| 59 | + String fullPath = buildFilePath(downloadDO); | |
| 60 | + excelFile = new File(fullPath); | |
| 61 | + File parentDir = excelFile.getParentFile(); | |
| 62 | + | |
| 63 | + if (!parentDir.exists() && !parentDir.mkdirs()) { | |
| 64 | + throw new IOException("目录创建失败:" + parentDir.getAbsolutePath()); | |
| 65 | + } | |
| 66 | + if (!parentDir.canRead() || !parentDir.canWrite()) { | |
| 67 | + throw new IOException("目录无读写权限:" + parentDir.getAbsolutePath()); | |
| 68 | + } | |
| 69 | + | |
| 70 | + // 初始化Excel | |
| 71 | + excelWriter = ExcelUtils.initEmergencyTaskExcel( | |
| 72 | + excelFile, | |
| 73 | + downloadDO.getFileName(), | |
| 74 | + sheetName, | |
| 75 | + exportHandler.getExcelVoClass(), | |
| 76 | + exportHandler.buildHead(), | |
| 77 | + exportHandler.buildMergeRule() | |
| 78 | + ); | |
| 79 | + downloadDO.setFilePath(fullPath); | |
| 80 | + fileDownloadMapper.updateById(downloadDO); | |
| 81 | + log.info("Excel初始化完成,业务编码:{},文件路径:{}", busiCode, fullPath); | |
| 82 | + | |
| 83 | + autoPageWrite(excelWriter, downloadDO, sheetName, sourceList, exportHandler); | |
| 84 | + | |
| 85 | + ExcelUtils.finishExcel(excelWriter); | |
| 86 | + excelWriter = null; | |
| 87 | + | |
| 88 | + if (excelFile.exists()) { | |
| 89 | + downloadDO.setFileSize(excelFile.length()); | |
| 90 | + } | |
| 91 | + updateSuccess(downloadDO); | |
| 92 | + log.info("导出任务执行成功,业务编码:{}", busiCode); | |
| 93 | + | |
| 94 | + } catch (IOException ioEx) { | |
| 95 | + log.error("导出IO异常,业务编码:{}", busiCode, ioEx); | |
| 96 | + updateFail(downloadDO, "文件读写异常:" + ioEx.getMessage()); | |
| 97 | + } catch (Exception e) { | |
| 98 | + log.error("导出任务异常,业务编码:{}", busiCode, e); | |
| 99 | + updateFail(downloadDO, e.getMessage()); | |
| 100 | + } finally { | |
| 101 | + ExcelUtils.finishExcel(excelWriter); | |
| 102 | + } | |
| 103 | + } | |
| 104 | + | |
| 105 | + /** 自动分片写入 */ | |
| 106 | + private <S, E> void autoPageWrite(ExcelWriter excelWriter, FileDownloadDO downloadDO, | |
| 107 | + String sheetName, List<S> sourceList, ExcelExportHandler<S, E> handler) { | |
| 108 | + if (CollectionUtils.isEmpty(sourceList)) { | |
| 109 | + log.info("导出数据为空,业务编码:{}", downloadDO.getBusiCode()); | |
| 110 | + return; | |
| 111 | + } | |
| 112 | + WriteSheet writeSheet | |
| 113 | + = EasyExcel.writerSheet(sheetName).build(); | |
| 114 | + int total = sourceList.size(); | |
| 115 | + int page = 0; | |
| 116 | + while (page * BATCH_SIZE < total) { | |
| 117 | + int start = page * BATCH_SIZE; | |
| 118 | + int end = Math.min(start + BATCH_SIZE, total); | |
| 119 | + List<S> batchData = new ArrayList<>(sourceList.subList(start, end)); | |
| 120 | + List<E> voList = handler.convert(batchData, start + 1); | |
| 121 | + excelWriter.write(voList, writeSheet); | |
| 122 | + log.info("自动分片写入完成,分片:{}, 条数:{}", page + 1, batchData.size()); | |
| 123 | + voList.clear(); | |
| 124 | + page++; | |
| 125 | + } | |
| 126 | + } | |
| 127 | + | |
| 128 | + private String buildFilePath(FileDownloadDO downloadDO) { | |
| 129 | + return new File(localExcelPath, downloadDO.getFileName()).getAbsolutePath(); | |
| 130 | + } | |
| 131 | + | |
| 132 | + private void updateSuccess(FileDownloadDO downloadDO) { | |
| 133 | + downloadDO.setStatus(FileTaskStatus.SUCCESS.getCode()); | |
| 134 | + LocalDateTime now = LocalDateTime.now(); | |
| 135 | + downloadDO.setFinishTime(now); | |
| 136 | + int days = expireDay != null ? expireDay : 30; | |
| 137 | + downloadDO.setExpireTime(now.plusDays(days)); | |
| 138 | + fileDownloadMapper.updateById(downloadDO); | |
| 139 | + } | |
| 140 | + | |
| 141 | + private void updateFail(FileDownloadDO downloadDO, String errorMsg) { | |
| 142 | + downloadDO.setStatus(FileTaskStatus.FAIL.getCode()); | |
| 143 | + String msg = errorMsg == null ? "未知异常" : errorMsg; | |
| 144 | + downloadDO.setFailMsg("导出失败:" + msg); | |
| 145 | + downloadDO.setFinishTime(LocalDateTime.now()); | |
| 146 | + fileDownloadMapper.updateById(downloadDO); | |
| 147 | + } | |
| 148 | +} | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/filedownload/ExcelExportDispatchService.java
0 → 100644
| 1 | +package com.zteits.urbanops.module.garden.service.filedownload; | |
| 2 | + | |
| 3 | +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; | |
| 4 | +import com.zteits.urbanops.module.garden.dal.dataobject.filedownload.FileDownloadDO; | |
| 5 | +import com.zteits.urbanops.module.garden.dal.mysql.filedownload.FileDownloadMapper; | |
| 6 | +import com.zteits.urbanops.module.garden.enums.ExportBusiCodeEnum; | |
| 7 | +import com.zteits.urbanops.module.garden.enums.FileTaskStatus; | |
| 8 | +import jakarta.annotation.Resource; | |
| 9 | +import lombok.RequiredArgsConstructor; | |
| 10 | +import lombok.extern.slf4j.Slf4j; | |
| 11 | +import org.springframework.stereotype.Service; | |
| 12 | +import org.springframework.util.CollectionUtils; | |
| 13 | + | |
| 14 | +import java.util.List; | |
| 15 | + | |
| 16 | +/** | |
| 17 | + * Excel导出统一调度服务 | |
| 18 | + * 统一创建导出任务、并发控制、触发异步 | |
| 19 | + */ | |
| 20 | +@Slf4j | |
| 21 | +@Service | |
| 22 | +@RequiredArgsConstructor | |
| 23 | +public class ExcelExportDispatchService { | |
| 24 | + | |
| 25 | + private final FileDownloadMapper fileDownloadMapper; | |
| 26 | + private final ExcelExportAsyncService excelExportAsyncService; | |
| 27 | + | |
| 28 | + /** | |
| 29 | + * 创建导出任务(可指定是否自动分片) | |
| 30 | + */ | |
| 31 | + public <S, E> Long createExportTask(String busiCode, List<S> sourceList, ExcelExportHandler<S, E> exportHandler) { | |
| 32 | + ExportBusiCodeEnum busiEnum = ExportBusiCodeEnum.getByCode(busiCode); | |
| 33 | + if (busiEnum == null) { | |
| 34 | + throw new IllegalArgumentException("不支持的导出业务编码:" + busiCode); | |
| 35 | + } | |
| 36 | + | |
| 37 | + // 防并发:同业务正在处理中的任务互斥 | |
| 38 | + LambdaQueryWrapper<FileDownloadDO> queryWrapper = new LambdaQueryWrapper<FileDownloadDO>() | |
| 39 | + .eq(FileDownloadDO::getBusiCode, busiCode) | |
| 40 | + .eq(FileDownloadDO::getStatus, FileTaskStatus.PROCESSING.getCode()); | |
| 41 | + List<FileDownloadDO> existTasks = fileDownloadMapper.selectList(queryWrapper); | |
| 42 | + if (!CollectionUtils.isEmpty(existTasks)) { | |
| 43 | + throw new IllegalArgumentException("当前业务导出任务正在处理中,请稍后再试"); | |
| 44 | + } | |
| 45 | + | |
| 46 | + // 新增任务记录 | |
| 47 | + FileDownloadDO downloadDO = new FileDownloadDO(); | |
| 48 | + downloadDO.setBusiCode(busiCode); | |
| 49 | + downloadDO.setBusiName(busiEnum.getBusiName()); | |
| 50 | + downloadDO.setFileName(busiEnum.getFullFileName()); | |
| 51 | + downloadDO.setFileSuffix(busiEnum.getFileSuffix()); | |
| 52 | + downloadDO.setStatus(FileTaskStatus.PENDING.getCode()); | |
| 53 | + downloadDO.setStorageType("LOCAL"); | |
| 54 | + fileDownloadMapper.insert(downloadDO); | |
| 55 | + | |
| 56 | + Long taskId = downloadDO.getId(); | |
| 57 | + | |
| 58 | + // 调用异步导出 | |
| 59 | + excelExportAsyncService.doAsyncExport( | |
| 60 | + downloadDO, | |
| 61 | + sourceList, | |
| 62 | + busiEnum.getSheetName(), | |
| 63 | + exportHandler | |
| 64 | + ); | |
| 65 | + return taskId; | |
| 66 | + } | |
| 67 | +} | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/filedownload/ExcelExportHandler.java
0 → 100644
| 1 | +package com.zteits.urbanops.module.garden.service.filedownload; | |
| 2 | + | |
| 3 | +import org.apache.poi.ss.util.CellRangeAddress; | |
| 4 | + | |
| 5 | +import java.util.List; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * Excel导出处理器接口 | |
| 9 | + * 每个导出业务实现此接口,替代原抽象类 | |
| 10 | + * @param <S> 源数据类型 | |
| 11 | + * @param <E> Excel VO类型 | |
| 12 | + */ | |
| 13 | +public interface ExcelExportHandler<S, E> { | |
| 14 | + | |
| 15 | + /** | |
| 16 | + * 源数据转换为Excel VO | |
| 17 | + */ | |
| 18 | + List<E> convert(List<S> batchList, int startIndex); | |
| 19 | + | |
| 20 | + /** | |
| 21 | + * 获取Excel VO实体Class | |
| 22 | + */ | |
| 23 | + Class<E> getExcelVoClass(); | |
| 24 | + | |
| 25 | + /** | |
| 26 | + * 构建表头 | |
| 27 | + */ | |
| 28 | + List<List<String>> buildHead(); | |
| 29 | + | |
| 30 | + /** | |
| 31 | + * 单元格合并规则 | |
| 32 | + */ | |
| 33 | + List<CellRangeAddress> buildMergeRule(); | |
| 34 | + | |
| 35 | +} | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/filedownload/FileDownloadService.java
0 → 100644
| 1 | +package com.zteits.urbanops.module.garden.service.filedownload; | |
| 2 | + | |
| 3 | +import com.zteits.urbanops.framework.common.pojo.PageResult; | |
| 4 | +import com.zteits.urbanops.module.garden.controller.admin.filedownload.vo.FileDownloadPageReqVO; | |
| 5 | +import com.zteits.urbanops.module.garden.controller.admin.filedownload.vo.FileDownloadSaveReqVO; | |
| 6 | +import com.zteits.urbanops.module.garden.dal.dataobject.filedownload.FileDownloadDO; | |
| 7 | +import jakarta.servlet.http.HttpServletResponse; | |
| 8 | +import jakarta.validation.Valid; | |
| 9 | + | |
| 10 | +import java.util.List; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * 文件异步下载任务 Service 接口 | |
| 14 | + * | |
| 15 | + * @author 超级管理员 | |
| 16 | + */ | |
| 17 | +public interface FileDownloadService { | |
| 18 | + | |
| 19 | + /** | |
| 20 | + * 创建文件异步下载任务 | |
| 21 | + * | |
| 22 | + * @param createReqVO 创建信息 | |
| 23 | + * @return 编号 | |
| 24 | + */ | |
| 25 | + Long createFileDownload(@Valid FileDownloadSaveReqVO createReqVO); | |
| 26 | + | |
| 27 | + /** | |
| 28 | + * 更新文件异步下载任务 | |
| 29 | + * | |
| 30 | + * @param updateReqVO 更新信息 | |
| 31 | + */ | |
| 32 | + void updateFileDownload(@Valid FileDownloadSaveReqVO updateReqVO); | |
| 33 | + | |
| 34 | + /** | |
| 35 | + * 删除文件异步下载任务 | |
| 36 | + * | |
| 37 | + * @param id 编号 | |
| 38 | + */ | |
| 39 | + void deleteFileDownload(Long id); | |
| 40 | + | |
| 41 | + /** | |
| 42 | + * 批量删除文件异步下载任务 | |
| 43 | + * | |
| 44 | + * @param ids 编号 | |
| 45 | + */ | |
| 46 | + void deleteFileDownloadListByIds(List<Long> ids); | |
| 47 | + | |
| 48 | + /** | |
| 49 | + * 获得文件异步下载任务 | |
| 50 | + * | |
| 51 | + * @param id 编号 | |
| 52 | + * @return 文件异步下载任务 | |
| 53 | + */ | |
| 54 | + FileDownloadDO getFileDownload(Long id); | |
| 55 | + | |
| 56 | + /** | |
| 57 | + * 获得文件异步下载任务分页 | |
| 58 | + * | |
| 59 | + * @param pageReqVO 分页查询 | |
| 60 | + * @return 文件异步下载任务分页 | |
| 61 | + */ | |
| 62 | + PageResult<FileDownloadDO> getFileDownloadPage(FileDownloadPageReqVO pageReqVO); | |
| 63 | + /** | |
| 64 | + * @Author wangqian | |
| 65 | + * @Description 文件下载 | |
| 66 | + * @Date 2026/6/15 10:19 | |
| 67 | + * @Return void | |
| 68 | + */ | |
| 69 | + void writeAttachment(HttpServletResponse response, Long id); | |
| 70 | + /** | |
| 71 | + * @Author wangqian | |
| 72 | + * @Description 清理过期文件 | |
| 73 | + * @Date 2026/6/15 12:27 | |
| 74 | + * @Return void | |
| 75 | + */ | |
| 76 | + void clearExpiredFiles(); | |
| 77 | +} | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/service/filedownload/FileDownloadServiceImpl.java
0 → 100644
| 1 | +package com.zteits.urbanops.module.garden.service.filedownload; | |
| 2 | + | |
| 3 | +import com.zteits.urbanops.framework.common.pojo.PageResult; | |
| 4 | +import com.zteits.urbanops.framework.common.util.object.BeanUtils; | |
| 5 | +import com.zteits.urbanops.module.garden.controller.admin.filedownload.vo.FileDownloadPageReqVO; | |
| 6 | +import com.zteits.urbanops.module.garden.controller.admin.filedownload.vo.FileDownloadSaveReqVO; | |
| 7 | +import com.zteits.urbanops.module.garden.dal.dataobject.filedownload.FileDownloadDO; | |
| 8 | +import com.zteits.urbanops.module.garden.dal.mysql.filedownload.FileDownloadMapper; | |
| 9 | +import jakarta.annotation.Resource; | |
| 10 | +import jakarta.servlet.http.HttpServletResponse; | |
| 11 | +import lombok.extern.slf4j.Slf4j; | |
| 12 | +import org.springframework.stereotype.Service; | |
| 13 | +import org.springframework.validation.annotation.Validated; | |
| 14 | + | |
| 15 | +import java.io.File; | |
| 16 | +import java.io.FileInputStream; | |
| 17 | +import java.io.IOException; | |
| 18 | +import java.io.OutputStream; | |
| 19 | +import java.net.URLEncoder; | |
| 20 | +import java.nio.charset.StandardCharsets; | |
| 21 | +import java.util.List; | |
| 22 | +import java.util.Objects; | |
| 23 | + | |
| 24 | +import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 25 | +import static com.zteits.urbanops.framework.common.exception.util.ServiceExceptionUtil.exception0; | |
| 26 | +import static com.zteits.urbanops.module.garden.enums.ErrorCodeConstants.FILE_DOWNLOAD_NOT_EXISTS; | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * 文件异步下载任务 Service 实现类 | |
| 30 | + * | |
| 31 | + * @author 超级管理员 | |
| 32 | + */ | |
| 33 | +@Service | |
| 34 | +@Validated | |
| 35 | +@Slf4j | |
| 36 | +public class FileDownloadServiceImpl implements FileDownloadService { | |
| 37 | + | |
| 38 | + @Resource | |
| 39 | + private FileDownloadMapper fileDownloadMapper; | |
| 40 | + | |
| 41 | + @Override | |
| 42 | + public Long createFileDownload(FileDownloadSaveReqVO createReqVO) { | |
| 43 | + // 插入 | |
| 44 | + FileDownloadDO fileDownload = BeanUtils.toBean(createReqVO, FileDownloadDO.class); | |
| 45 | + fileDownloadMapper.insert(fileDownload); | |
| 46 | + | |
| 47 | + // 返回 | |
| 48 | + return fileDownload.getId(); | |
| 49 | + } | |
| 50 | + | |
| 51 | + @Override | |
| 52 | + public void updateFileDownload(FileDownloadSaveReqVO updateReqVO) { | |
| 53 | + // 校验存在 | |
| 54 | + validateFileDownloadExists(updateReqVO.getId()); | |
| 55 | + // 更新 | |
| 56 | + FileDownloadDO updateObj = BeanUtils.toBean(updateReqVO, FileDownloadDO.class); | |
| 57 | + fileDownloadMapper.updateById(updateObj); | |
| 58 | + } | |
| 59 | + | |
| 60 | + @Override | |
| 61 | + public void deleteFileDownload(Long id) { | |
| 62 | + // 校验存在 | |
| 63 | + validateFileDownloadExists(id); | |
| 64 | + // 删除 | |
| 65 | + fileDownloadMapper.deleteById(id); | |
| 66 | + } | |
| 67 | + | |
| 68 | + @Override | |
| 69 | + public void deleteFileDownloadListByIds(List<Long> ids) { | |
| 70 | + // 删除 | |
| 71 | + fileDownloadMapper.deleteByIds(ids); | |
| 72 | + } | |
| 73 | + | |
| 74 | + | |
| 75 | + private void validateFileDownloadExists(Long id) { | |
| 76 | + if (fileDownloadMapper.selectById(id) == null) { | |
| 77 | + throw exception(FILE_DOWNLOAD_NOT_EXISTS); | |
| 78 | + } | |
| 79 | + } | |
| 80 | + | |
| 81 | + @Override | |
| 82 | + public FileDownloadDO getFileDownload(Long id) { | |
| 83 | + return fileDownloadMapper.selectById(id); | |
| 84 | + } | |
| 85 | + | |
| 86 | + @Override | |
| 87 | + public PageResult<FileDownloadDO> getFileDownloadPage(FileDownloadPageReqVO pageReqVO) { | |
| 88 | + // 当前登录用户不为空,创建人为空,则当前登录用户为创建人 | |
| 89 | + if (Objects.isNull(pageReqVO.getCreator())) { | |
| 90 | + throw exception0(400 ,"创建人不能为空"); | |
| 91 | + } | |
| 92 | + return fileDownloadMapper.selectPage(pageReqVO); | |
| 93 | + } | |
| 94 | + | |
| 95 | + @Override | |
| 96 | + public void writeAttachment(HttpServletResponse response, Long id) { | |
| 97 | + // 1. 查询下载任务记录 | |
| 98 | + FileDownloadDO fileDownload = fileDownloadMapper.selectById(id); | |
| 99 | + if (fileDownload == null) { | |
| 100 | + try { | |
| 101 | + response.setContentType("text/plain;charset=UTF-8"); | |
| 102 | + response.getWriter().write("下载任务不存在"); | |
| 103 | + } catch (IOException e) { | |
| 104 | + throw exception0( 400, e.getMessage()); | |
| 105 | + } | |
| 106 | + return; | |
| 107 | + } | |
| 108 | + | |
| 109 | + // 2. 组装文件对象(替换为你DO中实际的文件路径/文件名字段) | |
| 110 | + String filePath = fileDownload.getFilePath(); | |
| 111 | + String fileName = fileDownload.getFileName(); | |
| 112 | + File file = new File(filePath); | |
| 113 | + // 3. 校验文件合法性 | |
| 114 | + if (!file.exists() || !file.isFile()) { | |
| 115 | + try { | |
| 116 | + response.setContentType("text/plain;charset=UTF-8"); | |
| 117 | + response.getWriter().write("文件不存在或已被删除"); | |
| 118 | + } catch (IOException e) { | |
| 119 | + throw exception0( 400, e.getMessage()); | |
| 120 | + } | |
| 121 | + return; | |
| 122 | + } | |
| 123 | + | |
| 124 | + try { | |
| 125 | + // 4. 设置下载响应头,解决中文文件名乱码 | |
| 126 | + response.setContentType("application/octet-stream"); | |
| 127 | + String encodeName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()); | |
| 128 | + response.setHeader("Content-Disposition", "attachment;filename=" + encodeName); | |
| 129 | + response.setContentLength((int) file.length()); | |
| 130 | + | |
| 131 | + // 5. 流拷贝下载,try-with-resources 自动关闭流,防止资源泄漏 | |
| 132 | + byte[] buffer = new byte[8 * 1024]; | |
| 133 | + try (FileInputStream fis = new FileInputStream(file); OutputStream os = response.getOutputStream()) { | |
| 134 | + | |
| 135 | + int len; | |
| 136 | + while ((len = fis.read(buffer)) != -1) { | |
| 137 | + os.write(buffer, 0, len); | |
| 138 | + } | |
| 139 | + os.flush(); | |
| 140 | + } | |
| 141 | + } catch (IOException e) { | |
| 142 | + throw exception0( 400, e.getMessage()); | |
| 143 | + } | |
| 144 | + } | |
| 145 | + | |
| 146 | + @Override | |
| 147 | + public void clearExpiredFiles() { | |
| 148 | + log.info("[clearExpiredFiles][开始清理过期的文件]"); | |
| 149 | + List<FileDownloadDO> fileDownload = fileDownloadMapper.selectList(FileDownloadDO::getStatus, 4); | |
| 150 | + if (fileDownload.isEmpty()) { | |
| 151 | + log.info("[clearExpiredFiles][没有过期的文件]"); | |
| 152 | + return; | |
| 153 | + } | |
| 154 | + for (FileDownloadDO fileDownloadDO : fileDownload) { | |
| 155 | + log.info("[clearExpiredFiles][清理过期文件 id={}] ", fileDownloadDO.getId()); | |
| 156 | + //删除本地文件 | |
| 157 | + File file = new File(fileDownloadDO.getFilePath()); | |
| 158 | + if (file.exists()) { | |
| 159 | + file.delete(); | |
| 160 | + //log.info("[clearExpiredFiles][删除本地文件 id={}] ", fileDownloadDO.getId()); | |
| 161 | + fileDownloadMapper.deleteById(fileDownloadDO.getId()); | |
| 162 | + } | |
| 163 | + } | |
| 164 | + } | |
| 165 | + | |
| 166 | +} | ... | ... |
urbanops-module-garden/src/main/java/com/zteits/urbanops/module/garden/util/ImgDownUtils.java
0 → 100644
| 1 | +package com.zteits.urbanops.module.garden.util; | |
| 2 | + | |
| 3 | +import com.zteits.urbanops.module.infra.framework.file.core.client.FileClient; | |
| 4 | +import lombok.extern.slf4j.Slf4j; | |
| 5 | +import org.springframework.util.StringUtils; | |
| 6 | + | |
| 7 | +import java.util.ArrayList; | |
| 8 | +import java.util.List; | |
| 9 | + | |
| 10 | +/** | |
| 11 | + * @Classname FileUtils | |
| 12 | + * @Description 文件处理 | |
| 13 | + * @Date 2026/6/8 22:43 | |
| 14 | + * @Created by wangqian | |
| 15 | + */ | |
| 16 | +@Slf4j | |
| 17 | +public class ImgDownUtils { | |
| 18 | + | |
| 19 | + /** | |
| 20 | + * 获取图片 | |
| 21 | + * @param imgList | |
| 22 | + * @param index | |
| 23 | + * @return | |
| 24 | + */ | |
| 25 | + public static String getImgSafe(List<String> imgList, int index) { | |
| 26 | + if (imgList == null || imgList.size() <= index || imgList.get(index) == null) { | |
| 27 | + return ""; // 空图片返回空字符串,不报错 | |
| 28 | + } | |
| 29 | + return imgList.get(index); | |
| 30 | + } | |
| 31 | + /** | |
| 32 | + * 获取图片字节 | |
| 33 | + * @param list | |
| 34 | + * @param idx | |
| 35 | + * @return | |
| 36 | + */ | |
| 37 | + public static byte[] getByteSafe(List<byte[]> list, int idx) { | |
| 38 | + return (list == null || idx >= list.size()) ? null : list.get(idx); | |
| 39 | + } | |
| 40 | + /** | |
| 41 | + * 获取图片真实路径 | |
| 42 | + * @param fullUrl | |
| 43 | + * @return | |
| 44 | + */ | |
| 45 | + public static String getRealPath(String fullUrl) { | |
| 46 | + if (fullUrl == null) return null; | |
| 47 | + int index = fullUrl.indexOf("/quanyu/"); | |
| 48 | + return index >= 0 ? fullUrl.substring(index + 8) : fullUrl; | |
| 49 | + } | |
| 50 | + | |
| 51 | + /** | |
| 52 | + * 批量下载图片 | |
| 53 | + * @param imageUrls | |
| 54 | + * @param client | |
| 55 | + * @return | |
| 56 | + */ | |
| 57 | + public static List<byte[]> batchDownloadImages(List<String> imageUrls, FileClient client) { | |
| 58 | + List<byte[]> result = new ArrayList<>(); | |
| 59 | + if (imageUrls == null) return result; | |
| 60 | + for (String url : imageUrls) { | |
| 61 | + if (StringUtils.isEmpty(url)) { | |
| 62 | + result.add(null); | |
| 63 | + continue; | |
| 64 | + } | |
| 65 | + try { | |
| 66 | + String realPath = ImgDownUtils.getRealPath(url); | |
| 67 | + byte[] bytes = client.getContent(realPath); | |
| 68 | + result.add(bytes); | |
| 69 | + } catch (Exception e) { | |
| 70 | + log.error("[图片下载] 异常:{},路径:{}", e.getMessage(), url); | |
| 71 | + result.add(null); | |
| 72 | + } | |
| 73 | + } | |
| 74 | + return result; | |
| 75 | + } | |
| 76 | +} | ... | ... |
urbanops-server/src/main/java/com/zteits/urbanops/server/UrbanopsServerApplication.java
| ... | ... | @@ -2,6 +2,7 @@ package com.zteits.urbanops.server; |
| 2 | 2 | |
| 3 | 3 | import org.springframework.boot.SpringApplication; |
| 4 | 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; |
| 5 | +import org.springframework.scheduling.annotation.EnableAsync; | |
| 5 | 6 | |
| 6 | 7 | /** |
| 7 | 8 | * 项目的启动类 |
| ... | ... | @@ -14,6 +15,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; |
| 14 | 15 | */ |
| 15 | 16 | @SuppressWarnings("SpringComponentScan") // 忽略 IDEA 无法识别 ${urbanops.info.base-package} |
| 16 | 17 | @SpringBootApplication(scanBasePackages = {"${urbanops.info.base-package}.server", "${urbanops.info.base-package}.module"}) |
| 18 | +@EnableAsync // 开启异步线程池 | |
| 17 | 19 | public class UrbanopsServerApplication { |
| 18 | 20 | |
| 19 | 21 | public static void main(String[] args) { | ... | ... |
urbanops-server/src/main/resources/application-dev.yaml