From 4ed42b06fb033407d8ff01f391b56fe547df0e85 Mon Sep 17 00:00:00 2001 From: yu Date: Wed, 13 Nov 2024 17:12:16 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=9F=E8=AE=A1=E5=88=86=E6=9E=90-=E5=AF=BC?= =?UTF-8?q?=E5=87=BAExcel=E5=B9=B6=E7=94=9F=E6=88=90=E5=9B=BE=E8=A1=A8;?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../constant/StatisticalAnalysisConstant.java | 14 ++ .../impl/StatisticalAnalysisServiceImpl.java | 207 ++++++++++++------ 2 files changed, 153 insertions(+), 68 deletions(-) create mode 100644 das/src/main/java/com/das/common/constant/StatisticalAnalysisConstant.java diff --git a/das/src/main/java/com/das/common/constant/StatisticalAnalysisConstant.java b/das/src/main/java/com/das/common/constant/StatisticalAnalysisConstant.java new file mode 100644 index 00000000..a1ba8fa7 --- /dev/null +++ b/das/src/main/java/com/das/common/constant/StatisticalAnalysisConstant.java @@ -0,0 +1,14 @@ +package com.das.common.constant; + +/** + * 统计分析 + */ +public interface StatisticalAnalysisConstant { + + + String TREND_ANALYSE = "趋势分析"; + + String POWER_CURVE = "功率曲线"; + + String TREND_CONTRAST = "趋势对比"; +} diff --git a/das/src/main/java/com/das/modules/page/service/impl/StatisticalAnalysisServiceImpl.java b/das/src/main/java/com/das/modules/page/service/impl/StatisticalAnalysisServiceImpl.java index 3b1d80f1..1da74722 100644 --- a/das/src/main/java/com/das/modules/page/service/impl/StatisticalAnalysisServiceImpl.java +++ b/das/src/main/java/com/das/modules/page/service/impl/StatisticalAnalysisServiceImpl.java @@ -5,6 +5,7 @@ import cn.hutool.core.util.RandomUtil; import cn.hutool.poi.excel.ExcelUtil; import cn.hutool.poi.excel.ExcelWriter; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.das.common.constant.StatisticalAnalysisConstant; import com.das.common.exceptions.ServiceException; import com.das.common.utils.BeanCopyUtils; import com.das.modules.curve.domain.entity.CurveItemEntity; @@ -20,9 +21,13 @@ import com.das.modules.page.service.StatisticalAnalysisService; import jakarta.servlet.ServletOutputStream; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.apache.poi.ss.usermodel.ClientAnchor; import org.apache.poi.ss.usermodel.HorizontalAlignment; import org.apache.poi.ss.usermodel.VerticalAlignment; import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.xddf.usermodel.chart.*; +import org.apache.poi.xssf.usermodel.XSSFChart; import org.apache.poi.xssf.usermodel.XSSFClientAnchor; import org.apache.poi.xssf.usermodel.XSSFDrawing; import org.apache.poi.xssf.usermodel.XSSFSheet; @@ -82,19 +87,22 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic //获取Excel的列 LinkedHashMap map = getTrendColumnName(param); List> dataList = new ArrayList<>(); - //图表数据集 - DefaultCategoryDataset dataset = new DefaultCategoryDataset(); - // 遍历数据,填充Excel和图表数据集 - setTrendAnalyseExcelValue(mapsList, dataList, map, dataset); + // 遍历数据,填充Excel数据集 + setTrendAnalyseExcelValue(mapsList, dataList); + //获取图表类别集 + List chartKey = getCharKey(map); ExcelWriter writer = ExcelUtil.getWriter(RandomUtil.randomInt(100, 1000) + "statistics" + ".xlsx"); //设置Excel样式 setExcelStyle(writer, map, dataList); - // 使用JFreeChart生成折线图 - createChart(dataList, writer, dataset, "趋势分析"); + //生成折线图 + addChartToExcel(writer,dataList,StatisticalAnalysisConstant.TREND_ANALYSE,chartKey); //下载Excel - downloadExcel(response, writer,"趋势分析"); + downloadExcel(response, writer,StatisticalAnalysisConstant.TREND_ANALYSE); } + + + /** * 功率曲线Excel导出 * @@ -114,15 +122,15 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic setPowerCurveExcelValue(resultMap, dataList, curveItemEntitieList); //获取功率曲线的列 LinkedHashMap map = getPowerCurveColumnName(); - //获取图表数据集 - DefaultCategoryDataset dataset = getDefaultCategoryDataset(dataList); + //获取图表类别集 + List chartKey = getCharKey(map); ExcelWriter writer = ExcelUtil.getWriter(RandomUtil.randomInt(100, 1000) + "statistics" + ".xlsx"); //设置Excel样式 setExcelStyle(writer, map, dataList); - //使用JFreeChart生成图表 - createChart(dataList, writer, dataset, "功率曲线分析"); + //生成折线图 + addChartToExcel(writer,dataList,StatisticalAnalysisConstant.POWER_CURVE,chartKey); //下载Excel - downloadExcel(response, writer,"功率曲线分析"); + downloadExcel(response, writer,StatisticalAnalysisConstant.POWER_CURVE); } @@ -140,44 +148,19 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic //自定义别名 别名的key和实体类中的名称要对应上! LinkedHashMap map = gettrendContrastColumnName(param); List> dataList = new ArrayList<>(); - //图表数据集 - DefaultCategoryDataset dataset = new DefaultCategoryDataset(); + //图表类别集 + List charKey = getCharKey(map); // 遍历数据,将数据添加到dataList中 - setTrendContrastExcelValue(maps, dataList, map, dataset); + setTrendContrastExcelValue(maps, dataList); ExcelWriter writer = ExcelUtil.getWriter(RandomUtil.randomInt(100, 1000) + "statistics" + ".xlsx"); //设置Excel样式 setExcelStyle(writer, map, dataList); - // 使用JFreeChart生成折线图 - createChart(dataList, writer, dataset, "趋势对比"); + //生成折线图 + addChartToExcel(writer,dataList,StatisticalAnalysisConstant.TREND_CONTRAST,charKey); //下载Excel - downloadExcel(response, writer,"趋势对比"); + downloadExcel(response, writer,StatisticalAnalysisConstant.TREND_CONTRAST); } - /** - * 获取图表数据集 - * - * @param dataList 数据集 - * @return 图表数据集 - */ - private DefaultCategoryDataset getDefaultCategoryDataset(List> dataList) { - DefaultCategoryDataset dataset = new DefaultCategoryDataset(); - for (Map mapData : dataList) { - Object time = mapData.get("time"); - Object speed = mapData.get("iWindSpeed"); - Object power = mapData.get("iGenPower"); - Object theorySpeed = mapData.get("theoryIWindSpeed"); - Object theoryPower = mapData.get("theoryIGenPower"); - if (speed != null && power != null) { - dataset.addValue((Float) speed, "风速实际值", (String) time); - dataset.addValue((Float) power, "功率实际值", (String) time); - } - if (theorySpeed != null && theoryPower != null) { - dataset.addValue((Float) theorySpeed, "风速理论值", (String) time); - dataset.addValue((Float) theoryPower, "功率理论值", (String) time); - } - } - return dataset; - } /** @@ -200,15 +183,11 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic /** * 趋势分析-遍历数据,填充Excel和图表数据集 - * * @param mapsList 测点历史数据 * @param dataList Excel数据集 - * @param map 表格的列 - * @param dataset 图表数据集 */ private void setTrendAnalyseExcelValue(List>>> mapsList, - List> dataList, - LinkedHashMap map, DefaultCategoryDataset dataset) { + List> dataList) { for (int i = 0; i < mapsList.size(); i++) { List timesListstr = new ArrayList<>(); List valuesList = new ArrayList<>(); @@ -237,10 +216,6 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic } String pointNameKey = pointName + num; String timeKey = "time" + num; - //添加图表的数据集 - for (int j = 0; j < timesListstr.size(); j++) { - dataset.addValue(valuesList.get(j), map.get(pointNameKey), timesListstr.get(j)); - } if (i == 0) { for (int j = 0; j < timesListstr.size(); j++) { Map dataMap = new HashMap<>(); @@ -258,16 +233,31 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic } } + /** + * 获取图表类别集 + * @param map Excel的列 + * @return 图表类别集 + */ + private List getCharKey(LinkedHashMap map) { + //获取图表类别集 + List chartKey = new ArrayList<>(); + for (Map.Entry stringStringEntry : map.entrySet()) { + String value = stringStringEntry.getValue(); + if (!value.contains("时间")){ + chartKey.add(value); + } + } + return chartKey; + } + /** * 趋势对比填充Excel数据集 * * @param dataList Excel数据集 - * @param map 表格的列 - * @param dataset Excel数据集 + * @param maps 测点数据 */ private void setTrendContrastExcelValue(Map>> maps, - List> dataList, - LinkedHashMap map, DefaultCategoryDataset dataset) { + List> dataList) { for (Map.Entry>> stringMapEntry : maps.entrySet()) { int flagNum = 0; for (Map.Entry> mapEntry : stringMapEntry.getValue().entrySet()) { @@ -303,19 +293,12 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic } } flagNum++; - //生成图表的数据集 - for (int j = 0; j < timesListstr.size(); j++) { - dataset.addValue(valuesList.get(j), map.get(key), timesListstr.get(j)); - } } } - } /** * 趋势-获取表格的列 - * * - * * @param param 查询条件 * @return 表格的列 */ @@ -360,8 +343,7 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic /** * 获取功率曲线的列 - * - * @return + * @return Excel的列 */ private LinkedHashMap getPowerCurveColumnName() { LinkedHashMap map = new LinkedHashMap<>(); @@ -458,6 +440,7 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic * * @param response 响应对象 * @param writer Excel对象 + * @param title 标题 */ private void downloadExcel(HttpServletResponse response, ExcelWriter writer,String title) { response.setCharacterEncoding(StandardCharsets.UTF_8.name()); @@ -468,7 +451,7 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic response.setDateHeader("Expires", 0); try { // 设置请求头属性 - response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(title+".xls", StandardCharsets.UTF_8)); + response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(title+"-"+System.currentTimeMillis()+".xls", StandardCharsets.UTF_8)); ServletOutputStream out = response.getOutputStream(); // 写出到文件 writer.flush(out, true); @@ -482,8 +465,7 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic } /** - * 使用JFreeChart生成折线图 - * + * 使用JFreeChart生成折线图(图片),已弃用 * @param data excel数据集 * @param writer excel对象 * @param dataset 图表数据集 @@ -554,6 +536,95 @@ public class StatisticalAnalysisServiceImpl implements StatisticalAnalysisServic } + /** + * 生成折线图,并插入到Excel中 + * @param writer Sheet对象 + * @param data 测点数据集合 + * @param titleText 标题 + * @param chartKey 类别数据集 + */ + private static void addChartToExcel(ExcelWriter writer, List> data, + String titleText,List chartKey) { + try { + // 获取Sheet对象 + XSSFSheet sheet = (XSSFSheet) writer.getSheet(); + // 创建绘图区域 + XSSFDrawing drawing = sheet.createDrawingPatriarch(); + int columnCount = sheet.getRow(0).getPhysicalNumberOfCells() + 1; + //图表位置,插入到最后一列+1 + ClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, columnCount, 0, 15, 15); + // 创建图表 + XSSFChart xssfChart = drawing.createChart(anchor); + // 设置图表标题 + xssfChart.setTitleText(titleText); + // 创建数据系列 + XDDFChartLegend legend = xssfChart.getOrAddLegend(); + legend.setPosition(LegendPosition.TOP_RIGHT); + XDDFCategoryAxis bottomAxis = xssfChart.createCategoryAxis(AxisPosition.BOTTOM); + XDDFValueAxis leftAxis = xssfChart.createValueAxis(AxisPosition.LEFT); + leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN); + XDDFLineChartData chartData = (XDDFLineChartData) xssfChart.createData(ChartTypes.LINE, bottomAxis, leftAxis); + // 遍历每个系列并添加数据 + setChartData(data, titleText, chartKey, chartData, sheet); + xssfChart.plot(chartData); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + /** + * 给每个类别,添加数据 + * @param data 测点数据 + * @param titleText 标题 + * @param chartKey 类别key + * @param chartData 图表数据 + * @param sheet sheet对象 + */ + private static void setChartData(List> data, String titleText, List chartKey, XDDFLineChartData chartData, XSSFSheet sheet) { + if (titleText.equals(StatisticalAnalysisConstant.TREND_ANALYSE)) { + int strStartRow = 0; + int strEndCol = 0; + int numStartRow = 1; + int numEndCol = 1; + for (int i = 0; i < chartKey.size(); i++) { + XDDFLineChartData.Series series = (XDDFLineChartData.Series) chartData.addSeries( + createStringDataReference(sheet, 1, data.size(), strStartRow, strEndCol), // 类别(X轴) + createNumericDataReference(sheet, 1, data.size(), numStartRow, numEndCol) // 值(Y轴) + ); + series.setTitle(chartKey.get(i), null); + strStartRow += 2; + strEndCol += 2; + numStartRow += 2; + numEndCol += 2; + } + } else { + for (int i = 0; i < chartKey.size(); i++) { + XDDFLineChartData.Series series = (XDDFLineChartData.Series) chartData.addSeries( + createStringDataReference(sheet, 1, data.size(), 0, 0), // 类别(X轴) + createNumericDataReference(sheet, 1, data.size(), i + 1, i + 1) // 值(Y轴) + ); + series.setTitle(chartKey.get(i), null); + } + } + + } + + /** + * 创建字符串数据引用 + * @return XDDFDataSource + */ + private static XDDFDataSource createStringDataReference(XSSFSheet sheet, int startRow, int endRow, int startCol, int endCol) { + CellRangeAddress ref = new CellRangeAddress(startRow, endRow, startCol, endCol); + return XDDFDataSourcesFactory.fromStringCellRange(sheet, ref); + } + + /** + * 创建值数据引用 + * @return XDDFNumericalDataSource + */ + private static XDDFNumericalDataSource createNumericDataReference(XSSFSheet sheet, int startRow, int endRow, int startCol, int endCol) { + CellRangeAddress ref = new CellRangeAddress(startRow, endRow, startCol, endCol); + return XDDFDataSourcesFactory.fromNumericCellRange(sheet, ref); + } }