优化设备导出

This commit is contained in:
2025-11-19 10:55:44 +08:00
parent 3798e52ee0
commit a145c372b8
3 changed files with 47 additions and 27 deletions

View File

@ -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;
}
}

View File

@ -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<Device> 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<DeviceExcelExportDTO> dtoList = devices.stream().map(device -> {
// 转换为DTO列表,使用并行流加速处理
List<DeviceExcelExportDTO> 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<Device> devices, List<DeviceType> 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<Long, DeviceType> deviceTypeMap = deviceTypes.stream()
.collect(Collectors.toMap(DeviceType::getId, deviceType -> deviceType));
// 转换为DTO列表
List<DeviceWithTypeExcelExportDTO> dtoList = devices.stream().map(device -> {
// 转换为DTO列表,使用并行流加速处理
List<DeviceWithTypeExcelExportDTO> 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);
}
}