diff --git a/fys-admin/src/main/resources/application.yml b/fys-admin/src/main/resources/application.yml index 21924a61..be595503 100644 --- a/fys-admin/src/main/resources/application.yml +++ b/fys-admin/src/main/resources/application.yml @@ -69,9 +69,9 @@ spring: servlet: multipart: # 单个文件大小 - max-file-size: 10MB + max-file-size: 100MB # 设置总上传的文件大小 - max-request-size: 20MB + max-request-size: 200MB mvc: # 设置静态资源路径 防止所有请求都去查静态资源 static-path-pattern: /static/** diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/dto/DeviceWithTypeExcelExportDTO.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/dto/DeviceWithTypeExcelExportDTO.java index 6ef7b5f4..0ffced9e 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/dto/DeviceWithTypeExcelExportDTO.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/domain/dto/DeviceWithTypeExcelExportDTO.java @@ -4,6 +4,7 @@ import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.write.style.ColumnWidth; import com.alibaba.excel.annotation.write.style.ContentRowHeight; import com.alibaba.excel.annotation.write.style.HeadRowHeight; +import com.fuyuanshen.equipment.converter.IgnoreFailedImageConverter; import lombok.Data; import java.net.URL; @@ -27,7 +28,8 @@ public class DeviceWithTypeExcelExportDTO { @ColumnWidth(20) private String typeName; - @ExcelProperty(value = "设备图片") + @ExcelProperty(value = "设备图片", converter = IgnoreFailedImageConverter.class) + // @ExcelProperty(value = "设备图片") @ColumnWidth(30) // 设置图片列宽度 private URL devicePic; // 使用URL类型 @@ -95,4 +97,4 @@ public class DeviceWithTypeExcelExportDTO { @ColumnWidth(20) private String pcModelDictionary; -} +} \ No newline at end of file diff --git a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceExportService.java b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceExportService.java index 4c51e7be..5133b1cf 100644 --- a/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceExportService.java +++ b/fys-modules/fys-equipment/src/main/java/com/fuyuanshen/equipment/service/impl/DeviceExportService.java @@ -11,13 +11,12 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.io.IOException; -import java.net.MalformedURLException; import java.net.URL; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; -import java.util.concurrent.Semaphore; +import java.util.concurrent.*; import java.util.stream.Collectors; /** @@ -29,6 +28,9 @@ import java.util.stream.Collectors; public class DeviceExportService { public void export(List devices, HttpServletResponse response) { + long startTime = System.currentTimeMillis(); + log.info("开始导出设备列表,设备数量: {}", devices.size()); + try { String fileName = "设备列表_" + System.currentTimeMillis() + ".xlsx"; // 使用URLEncoder进行RFC 5987编码 @@ -39,8 +41,9 @@ public class DeviceExportService { // 使用RFC 5987标准编码文件名 response.setHeader("Content-disposition", "attachment;filename*=UTF-8''" + encodedFileName); - // 转换为DTO列表 - List dtoList = devices.stream().map(device -> { + // 转换为DTO列表,使用并行流加速处理 + List dtoList = devices.parallelStream().map(device -> { + long deviceProcessStartTime = System.currentTimeMillis(); DeviceExcelExportDTO dto = new DeviceExcelExportDTO(); dto.setDeviceName(device.getDeviceName()); dto.setDeviceMac(device.getDeviceMac()); @@ -59,13 +62,22 @@ public class DeviceExportService { // 处理图片URL转换 handleDevicePic(device, dto); + long deviceProcessEndTime = System.currentTimeMillis(); + log.info("单个设备处理耗时: {} ms, 设备ID: {}", (deviceProcessEndTime - deviceProcessStartTime), device.getId()); return dto; }).collect(Collectors.toList()); // 写入Excel + long excelWriteStartTime = System.currentTimeMillis(); EasyExcel.write(response.getOutputStream(), DeviceExcelExportDTO.class).sheet("设备数据").doWrite(dtoList); + long excelWriteEndTime = System.currentTimeMillis(); + + long endTime = System.currentTimeMillis(); + log.info("设备列表导出完成,总耗时: {} ms,设备数量: {},Excel写入耗时: {} ms", + (endTime - startTime), devices.size(), (excelWriteEndTime - excelWriteStartTime)); } catch (IOException e) { + log.error("导出Excel失败", e); throw new RuntimeException("导出Excel失败", e); } } @@ -79,6 +91,9 @@ public class DeviceExportService { * @param response */ public void exportWithTypeInfo(List devices, List deviceTypes, HttpServletResponse response) { + long startTime = System.currentTimeMillis(); + log.info("开始导出设备列表(含类型详情),设备数量: {}", devices.size()); + try { String fileName = "设备列表_含类型详情_" + System.currentTimeMillis() + ".xlsx"; // 使用URLEncoder进行RFC 5987编码 @@ -93,8 +108,9 @@ public class DeviceExportService { Map deviceTypeMap = deviceTypes.stream() .collect(Collectors.toMap(DeviceType::getId, deviceType -> deviceType)); - // 转换为DTO列表 - List dtoList = devices.stream().map(device -> { + // 转换为DTO列表,使用并行流加速处理 + List dtoList = devices.parallelStream().map(device -> { + long deviceProcessStartTime = System.currentTimeMillis(); DeviceWithTypeExcelExportDTO dto = new DeviceWithTypeExcelExportDTO(); dto.setDeviceName(device.getDeviceName()); dto.setDeviceMac(device.getDeviceMac()); @@ -149,14 +165,20 @@ public class DeviceExportService { // 处理图片URL转换 handleDevicePicForTypeExport(device, dto); - return dto; }).collect(Collectors.toList()); // 写入Excel + long excelWriteStartTime = System.currentTimeMillis(); EasyExcel.write(response.getOutputStream(), DeviceWithTypeExcelExportDTO.class).sheet("设备数据含类型详情").doWrite(dtoList); + long excelWriteEndTime = System.currentTimeMillis(); + + long endTime = System.currentTimeMillis(); + log.info("设备列表(含类型详情)导出完成,总耗时: {} ms,设备数量: {},Excel写入耗时: {} ms", + (endTime - startTime), devices.size(), (excelWriteEndTime - excelWriteStartTime)); } catch (IOException e) { + log.error("导出Excel失败", e); throw new RuntimeException("导出Excel失败", e); } } @@ -224,71 +246,67 @@ public class DeviceExportService { // 在DeviceExportService中添加并发控制 - private static final Semaphore imageLoadSemaphore = new Semaphore(5); // 最多同时加载5张图片 + private static final Semaphore imageLoadSemaphore = new Semaphore(10); // 增加到最多同时加载10张图片 private void handleDevicePic(Device device, DeviceExcelExportDTO dto) { String picUrl = device.getDevicePic(); - log.debug("处理设备图片,设备ID: {}, 图片URL: {}", device.getId(), picUrl); if (picUrl != null && !picUrl.trim().isEmpty()) { try { - // 获取加载图片的许可 - imageLoadSemaphore.acquire(); + // 获取加载图片的许可,带超时控制 + if (!imageLoadSemaphore.tryAcquire(5, TimeUnit.SECONDS)) { + dto.setDevicePic(null); + return; + } try { // 自动将HTTP转换为HTTPS以避免重定向问题 if (picUrl.startsWith("http://")) { picUrl = "https://" + picUrl.substring(7); - log.debug("自动将HTTP转换为HTTPS: {}", picUrl); } // 尝试创建URL对象(会自动验证格式) URL url = new URL(picUrl); dto.setDevicePic(url); - log.debug("成功设置设备图片URL到DTO"); } finally { // 释放许可 imageLoadSemaphore.release(); } } catch (Exception e) { - log.warn("设置设备图片失败,设备ID: {}, URL: {}, 错误: {}", device.getId(), picUrl, e.getMessage()); dto.setDevicePic(null); } } else { - log.debug("设备没有设置图片,设备ID: {}", device.getId()); dto.setDevicePic(null); } } - private void handleDevicePicForTypeExport(Device device, DeviceWithTypeExcelExportDTO dto) { String picUrl = device.getDevicePic(); - log.debug("处理设备图片,设备ID: {}, 图片URL: {}", device.getId(), picUrl); if (picUrl != null && !picUrl.trim().isEmpty()) { try { - // 获取加载图片的许可 - imageLoadSemaphore.acquire(); + // 获取加载图片的许可,带超时控制 + if (!imageLoadSemaphore.tryAcquire(5, TimeUnit.SECONDS)) { + dto.setDevicePic(null); + return; + } try { picUrl = convertUrl(picUrl); - log.info("转换后的URL: {}", picUrl); // 尝试创建URL对象(会自动验证格式) URL url = new URL(picUrl); dto.setDevicePic(url); - log.debug("成功设置设备图片URL到DTO"); + } finally { // 释放许可 imageLoadSemaphore.release(); } } catch (Exception e) { - log.warn("设置设备图片失败,设备ID: {}, URL: {}, 错误: {}", device.getId(), picUrl, e.getMessage()); dto.setDevicePic(null); } } else { - log.debug("设备没有设置图片,设备ID: {}", device.getId()); dto.setDevicePic(null); } }