From 3f77d30cfda1d605f01138a4b6d35195e7690c78 Mon Sep 17 00:00:00 2001 From: wr <1754607820@qq.com> Date: Wed, 28 Jan 2026 11:26:52 +0800 Subject: [PATCH] =?UTF-8?q?1.=E7=9B=91=E6=B5=8B=E7=82=B9=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E6=8A=A5=E8=A1=A8=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pq/pojo/vo/dataClean/DataVerifyExcel.java | 33 ++- .../pq/utils/FixedDynamicExcelExport.java | 206 ++++++++++++++++++ .../impl/PqDataVerifyBakServiceImpl.java | 18 +- .../mapper/mapping/TerminalMaintainMapper.xml | 18 +- 4 files changed, 259 insertions(+), 16 deletions(-) create mode 100644 pqs-device/pq-device/pq-device-api/src/main/java/com/njcn/device/pq/utils/FixedDynamicExcelExport.java diff --git a/pqs-device/pq-device/pq-device-api/src/main/java/com/njcn/device/pq/pojo/vo/dataClean/DataVerifyExcel.java b/pqs-device/pq-device/pq-device-api/src/main/java/com/njcn/device/pq/pojo/vo/dataClean/DataVerifyExcel.java index 5cf984ec2..a7aba528b 100644 --- a/pqs-device/pq-device/pq-device-api/src/main/java/com/njcn/device/pq/pojo/vo/dataClean/DataVerifyExcel.java +++ b/pqs-device/pq-device/pq-device-api/src/main/java/com/njcn/device/pq/pojo/vo/dataClean/DataVerifyExcel.java @@ -8,6 +8,8 @@ import lombok.Getter; import lombok.Setter; import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; /** * @version 1.0.0 @@ -72,7 +74,7 @@ public class DataVerifyExcel implements Serializable { @ColumnWidth(20) @ExcelProperty(value = "总指标异常时间") - @Excel(name = "总") + @Excel(name = "总指标异常时间") private Integer allTime; @ColumnWidth(20) @@ -191,4 +193,33 @@ public class DataVerifyExcel implements Serializable { private Integer riseTime; + // 字段名 ↔ Excel列名 映射 + public static final Map FIELD_COLUMN_MAP = new HashMap<>(); + static { + // 按代码中字段顺序整理,确保一一对应 + FIELD_COLUMN_MAP.put("freqTime", "频率"); + FIELD_COLUMN_MAP.put("freqDevTime", "频率偏差"); + FIELD_COLUMN_MAP.put("vRmsTime", "相电压有效值"); + FIELD_COLUMN_MAP.put("vPosTime", "正序电压"); + FIELD_COLUMN_MAP.put("vNegTime", "负序电压"); + FIELD_COLUMN_MAP.put("vZeroTime", "零序电压"); + FIELD_COLUMN_MAP.put("vUnbalanceTime", "电压不平衡度"); + FIELD_COLUMN_MAP.put("rmsLvrTime", "线电压有效值"); + FIELD_COLUMN_MAP.put("vuDevTime", "电压正偏差"); + FIELD_COLUMN_MAP.put("vlDevTime", "电压负偏差"); + FIELD_COLUMN_MAP.put("vThdTime", "电压总谐波畸变率"); + FIELD_COLUMN_MAP.put("vTime", "相电压基波有效值"); + FIELD_COLUMN_MAP.put("iRmsTime", "电流有效值"); + FIELD_COLUMN_MAP.put("pltTime", "长时闪变"); + FIELD_COLUMN_MAP.put("vInharmTime", "间谐波电压含有率"); + FIELD_COLUMN_MAP.put("vHarmTime", "谐波电压含有率"); + FIELD_COLUMN_MAP.put("pfTime", "功率因数"); + FIELD_COLUMN_MAP.put("vPhasicTime", "谐波电压相角"); + FIELD_COLUMN_MAP.put("v1PhasicTime", "谐波电压基波相角"); + FIELD_COLUMN_MAP.put("flucTime", "电压波动"); + FIELD_COLUMN_MAP.put("pstTime", "短时闪变"); + FIELD_COLUMN_MAP.put("dipTime", "电压暂降"); + FIELD_COLUMN_MAP.put("riseTime", "电压暂升"); + } + } diff --git a/pqs-device/pq-device/pq-device-api/src/main/java/com/njcn/device/pq/utils/FixedDynamicExcelExport.java b/pqs-device/pq-device/pq-device-api/src/main/java/com/njcn/device/pq/utils/FixedDynamicExcelExport.java new file mode 100644 index 000000000..9b75b0510 --- /dev/null +++ b/pqs-device/pq-device/pq-device-api/src/main/java/com/njcn/device/pq/utils/FixedDynamicExcelExport.java @@ -0,0 +1,206 @@ +package com.njcn.device.pq.utils; + +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.write.handler.SheetWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; +import com.alibaba.excel.write.style.column.SimpleColumnWidthStyleStrategy; +import com.njcn.device.pq.pojo.vo.dataClean.DataVerifyExcel; +import org.apache.poi.ss.usermodel.Sheet; + +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.lang.reflect.Field; +import java.util.*; + +/** + * 修复版:按数据量动态排序Excel列,解决列挤在一行的问题 + * 关键改动:表头构建方式 + 列宽匹配逻辑 + */ +public class FixedDynamicExcelExport { + + + public static void main(String[] args) throws Exception { + // 1. 模拟测试数据(相电压数据量最多,频率次之,频率偏差最少) + List dataList = EasyExcel.read("F:\\usr\\response.xlsx") + .head(DataVerifyExcel.class) + .doReadAllSync(); + // 2. 导出Excel(替换为你的本地路径,比如桌面) + dataList.sort(Comparator.comparing((DataVerifyExcel item) -> item.getCity() + "_" + item.getStationName()+"_"+item.getDevName()) + .thenComparing(DataVerifyExcel::getAllTime, Comparator.reverseOrder()) + ); + exportExcelByDataSize(dataList, "D:/dynamic_excel_fixed.xlsx"); + System.out.println("导出完成!打开桌面的「测试导出.xlsx」查看效果"); + } + + /** + * 核心方法:按数据量排序导出Excel + */ + public static void exportExcelByDataSize(List dataList, String outputPath) throws Exception { + // 步骤1:统计每个字段的有效数据量 + Map fieldCount = countValidData(dataList); + // 步骤2:按数据量降序排序字段名 + List sortedFields = sortFields(fieldCount); + // 步骤3:构建正确的动态表头 + List> head = buildCorrectHead(sortedFields); + // 步骤4:构建对应顺序的行数据 + List> data = buildRowData(dataList, sortedFields); + + // 步骤5:导出Excel(含列宽设置) + try (FileOutputStream out = new FileOutputStream(outputPath)) { + EasyExcel.write(out) + .head(head) + .registerWriteHandler(new SimpleColumnWidthStyleStrategy(20)) + .registerWriteHandler(new FreezeHeaderHandler()) // 用修复后的表头 + .sheet("数据统计") + .doWrite(data); + } + } + + public static void exportExcelByDataSize(List dataList, OutputStream outputStream) { + // 步骤1:统计每个字段的有效数据量 + Map fieldCount = countValidData(dataList); + // 步骤2:按数据量降序排序字段名 + List sortedFields = sortFields(fieldCount); + // 步骤3:构建正确的动态表头 + List> head = buildCorrectHead(sortedFields); + // 步骤4:构建对应顺序的行数据 + List> data = buildRowData(dataList, sortedFields); + + // 步骤5:导出Excel(含列宽设置) + EasyExcel.write(outputStream) + .head(head) + .registerWriteHandler(new SimpleColumnWidthStyleStrategy(20)) + .registerWriteHandler(new FreezeHeaderHandler()) // 用修复后的表头 + .sheet("数据统计") + .doWrite(data); + } + + public static class FreezeHeaderHandler implements SheetWriteHandler { + @Override + public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { + // 表格创建前无需操作 + } + + @Override + public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { + Sheet sheet = writeSheetHolder.getSheet(); + // freezePane(c, r):c=冻结列数,r=冻结行数;这里r=1表示冻结第1行(表头),c=0表示不冻结列 + // 比如 freezePane(1, 1) 表示冻结第一列+第一行 + sheet.createFreezePane(0, 1); + } + } + + // ★ 修复点1:构建正确的表头(每个列名独立成List) + private static List> buildCorrectHead(List allFields) { + List> head = new ArrayList<>(); + head.add(Collections.singletonList("供电公司")); + head.add(Collections.singletonList("所属变电站")); + head.add(Collections.singletonList("终端名称")); + head.add(Collections.singletonList("监测点名称")); + head.add(Collections.singletonList("IP")); + head.add(Collections.singletonList("干扰源类型")); + head.add(Collections.singletonList("监测对象名称")); + head.add(Collections.singletonList("电网侧变电站")); + head.add(Collections.singletonList("厂商")); + head.add(Collections.singletonList("总指标异常时间")); + List sortedFields = allFields.subList(10, allFields.size()); + for (String field : sortedFields) { + // 每个列名单独封装成List,EasyExcel才能识别为不同列 + head.add(Collections.singletonList(DataVerifyExcel.FIELD_COLUMN_MAP.get(field))); + } + return head; + } + + + // 统计有效数据量(无改动,保留) + private static Map countValidData(List dataList) { + // 1. 初始化计数字典(反射自动提取所有Time结尾的Integer字段,初始值0) + Map countMap = initCountMap(); + // 2. 判空,避免空指针异常 + if (dataList == null || dataList.isEmpty()) { + return countMap; + } + // 3. 获取DataStatistic类的所有字段 + Field[] fields = DataVerifyExcel.class.getDeclaredFields(); + try { + // 4. 遍历每个数据对象 + for (DataVerifyExcel data : dataList) { + // 5. 遍历每个字段,累加数值 + for (Field field : fields) { + // 过滤条件:Integer类型 + 以Time结尾 + if (field.getType() == Integer.class && field.getName().endsWith("Time") ) { + if(!field.getName().equals("allTime")){ + // 设置可访问私有字段 + field.setAccessible(true); + // 获取当前对象的该字段值 + Integer value = (Integer) field.get(data); + // 非空则累加 + if (value != null) { + String fieldName = field.getName(); + countMap.put(fieldName, countMap.get(fieldName) + value); + } + } + } + } + } + } catch (IllegalAccessException e) { + // 捕获反射访问异常,便于排查问题 + throw new RuntimeException("统计字段时反射访问失败", e); + } + return countMap; + } + + // 反射初始化计数字典(复用之前的逻辑) + private static Map initCountMap() { + Map countMap = new HashMap<>(); + Field[] fields = DataVerifyExcel.class.getDeclaredFields(); + for (Field field : fields) { + if (field.getType() == Integer.class && field.getName().endsWith("Time")) { + if(!field.getName().equals("allTime")){ + countMap.put(field.getName(), 0); + } + } + } + return countMap; + } + + + // 按数据量排序字段(无改动,保留) + private static List sortFields(Map fieldCount) { + List fields = new ArrayList<>(fieldCount.keySet()); + fields.sort((f1, f2) -> fieldCount.get(f2) - fieldCount.get(f1)); // 降序 + List fieldAlls=new ArrayList<>(); + fieldAlls.add("city"); + fieldAlls.add("stationName"); + fieldAlls.add("devName"); + fieldAlls.add("lineName"); + fieldAlls.add("ip"); + fieldAlls.add("loadType"); + fieldAlls.add("objName"); + fieldAlls.add("powerSubstationName"); + fieldAlls.add("manufacturer"); + fieldAlls.add("allTime"); + fieldAlls.addAll(fields); + return fieldAlls; + } + + // 构建行数据(无改动,保留) + private static List> buildRowData(List dataList, List sortedFields) { + List> rows = new ArrayList<>(); + for (DataVerifyExcel data : dataList) { + List row = new ArrayList<>(); + for (String field : sortedFields) { + try { + Field f = DataVerifyExcel.class.getDeclaredField(field); + f.setAccessible(true); + row.add(f.get(data)); + } catch (Exception e) { + throw new RuntimeException("导出异常数据转换异常:"+e); + } + } + rows.add(row); + } + return rows; + } +} \ No newline at end of file diff --git a/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/service/impl/PqDataVerifyBakServiceImpl.java b/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/service/impl/PqDataVerifyBakServiceImpl.java index e42d89164..4a9a17e05 100644 --- a/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/service/impl/PqDataVerifyBakServiceImpl.java +++ b/pqs-device/pq-device/pq-device-boot/src/main/java/com/njcn/device/pq/service/impl/PqDataVerifyBakServiceImpl.java @@ -51,6 +51,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +import static com.njcn.device.pq.utils.FixedDynamicExcelExport.exportExcelByDataSize; + /** *

* 服务实现类 @@ -392,14 +394,16 @@ public class PqDataVerifyBakServiceImpl extends ServiceImpl excludeColumnFiledNames = new HashSet<>(1); - excludeColumnFiledNames.add("lineId"); - dataVerifyExcels.sort(Comparator.comparing((DataVerifyExcel item) -> item.getCity() + "_" + item.getStationName()+"_"+item.getDevName()) - .thenComparing(DataVerifyExcel::getAllTime, Comparator.reverseOrder()) + dataVerifyExcels.sort(Comparator + .comparing(DataVerifyExcel::getAllTime, Comparator.reverseOrder()) + .thenComparing((DataVerifyExcel item) -> item.getCity() + "_" + item.getStationName()+"_"+item.getDevName()) ); - EasyExcel.write(response.getOutputStream(), DataVerifyExcel.class) - .excludeColumnFiledNames(excludeColumnFiledNames).sheet("sheet") - .doWrite(dataVerifyExcels); + exportExcelByDataSize(dataVerifyExcels,response.getOutputStream()); +// Set excludeColumnFiledNames = new HashSet<>(1); +// excludeColumnFiledNames.add("lineId"); +// EasyExcel.write(response.getOutputStream(), DataVerifyExcel.class) +// .excludeColumnFiledNames(excludeColumnFiledNames).sheet("sheet") +// .doWrite(dataVerifyExcels); } diff --git a/pqs-device/pq-device/pq-device-com/src/main/java/com/njcn/device/terminal/mapper/mapping/TerminalMaintainMapper.xml b/pqs-device/pq-device/pq-device-com/src/main/java/com/njcn/device/terminal/mapper/mapping/TerminalMaintainMapper.xml index ad8b31a6f..7b25d4671 100644 --- a/pqs-device/pq-device/pq-device-com/src/main/java/com/njcn/device/terminal/mapper/mapping/TerminalMaintainMapper.xml +++ b/pqs-device/pq-device/pq-device-com/src/main/java/com/njcn/device/terminal/mapper/mapping/TerminalMaintainMapper.xml @@ -148,7 +148,7 @@