| New file |
| | |
| | | package com.ots.project.tool.report.MAQTR.chart; |
| | | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.ots.common.utils.StringUtils; |
| | | import com.ots.project.tool.report.MAQ.base.RowData; |
| | | import com.ots.project.tool.report.MAQ.base.SeriesData; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.poi.hssf.usermodel.HSSFWorkbook; |
| | | import org.apache.poi.ooxml.POIXMLDocument; |
| | | import org.apache.poi.ooxml.POIXMLDocumentPart; |
| | | import org.apache.poi.ss.usermodel.CellType; |
| | | import org.apache.poi.xssf.usermodel.XSSFCell; |
| | | import org.apache.poi.xssf.usermodel.XSSFRow; |
| | | import org.apache.poi.xssf.usermodel.XSSFSheet; |
| | | import org.apache.poi.xssf.usermodel.XSSFWorkbook; |
| | | import org.apache.poi.xwpf.usermodel.XWPFChart; |
| | | import org.apache.poi.xwpf.usermodel.XWPFDocument; |
| | | import org.openxmlformats.schemas.drawingml.x2006.chart.*; |
| | | |
| | | import java.io.*; |
| | | import java.util.*; |
| | | import java.util.regex.Matcher; |
| | | import java.util.regex.Pattern; |
| | | |
| | | /** |
| | | * @description: MAQTR图表 带直线和数据标记散点图数据变更 |
| | | * @author: zhijie |
| | | * @create: 2022-06-16 22:01 |
| | | **/ |
| | | @Slf4j |
| | | public class MAQTRChart { |
| | | |
| | | |
| | | public static void main(String[] args) throws IOException { |
| | | try { |
| | | OutputStream os = new FileOutputStream("C:\\Users\\大头\\Desktop\\MAQ组别报告\\林_PAQ_IA_CN1.docx"); |
| | | XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage("C:\\Users\\大头\\Desktop\\MAQ组别报告\\终稿【0607中文版】MAQ组别对比报告.docx")); |
| | | |
| | | String fileName = "C:\\Users\\大头\\Desktop\\MAQ组别报告\\MAQ组别导入数据模板.xlsx"; |
| | | //变更图表数据 |
| | | changeMAQTRChart(document,fileName); |
| | | document.write(os); |
| | | }catch (Exception e){ |
| | | e.printStackTrace(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 初始化报告数据 |
| | | * @param fileName 数据源文件名 |
| | | * @param index 模板sheet索引 |
| | | * @return |
| | | */ |
| | | public static List<SeriesData> initData(String fileName,Integer index){ |
| | | List<SeriesData> seriesDatas = new ArrayList<>(); |
| | | try { |
| | | XSSFWorkbook wb = new XSSFWorkbook(new FileInputStream(fileName)); |
| | | XSSFSheet sheet1 = wb.getSheetAt(index); |
| | | |
| | | //数据处理 先获取表头长度 遍历表头行数、一一对应放进表头集合里 |
| | | Map<Integer,SeriesData> map = new HashMap<>(); |
| | | XSSFRow row = sheet1.getRow(0); |
| | | for (int i = 0; i < row.getLastCellNum(); i++) { |
| | | //为空忽略 |
| | | /*if(StringUtils.isEmpty(getName(row.getCell(i)))){ |
| | | continue; |
| | | }*/ |
| | | SeriesData seriesData = new SeriesData(getName(row.getCell(i))); |
| | | map.put(i,seriesData); |
| | | //读取每一行每一列 |
| | | for (int j = 1; j <= sheet1.getLastRowNum(); j++) { |
| | | //每一行 |
| | | XSSFRow row1 = sheet1.getRow(j); |
| | | RowData rowData = new RowData(); |
| | | if(seriesData.getValue() == null){ |
| | | List<RowData> rowDatas = new ArrayList<>(); |
| | | //设置表头 |
| | | rowData.setName(getName(row.getCell(i))); |
| | | //根据类型判断赋值 |
| | | switch (row1.getCell(i).getCellType()) { |
| | | case STRING: |
| | | rowData.setValueStr(row1.getCell(i).getStringCellValue()); |
| | | break; |
| | | case NUMERIC: |
| | | rowData.setValue(row1.getCell(i).getNumericCellValue()); |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | rowDatas.add(rowData); |
| | | seriesData.setValue(rowDatas); |
| | | }else{ |
| | | //设置表头 |
| | | rowData.setName(getName(row.getCell(i))); |
| | | //根据类型判断赋值 |
| | | switch (row1.getCell(i).getCellType()) { |
| | | case STRING: |
| | | rowData.setValueStr(row1.getCell(i).getStringCellValue()); |
| | | break; |
| | | case NUMERIC: |
| | | rowData.setValue(row1.getCell(i).getNumericCellValue()); |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | seriesData.getValue().add(rowData); |
| | | } |
| | | } |
| | | seriesDatas.add(seriesData); |
| | | } |
| | | }catch (Exception e){ |
| | | e.printStackTrace(); |
| | | } |
| | | return seriesDatas; |
| | | } |
| | | |
| | | /** |
| | | * 根据单元格类型取值 |
| | | * @return 返回字符值 |
| | | */ |
| | | private static String getName(XSSFCell cell){ |
| | | String name = null; |
| | | switch (cell.getCellType()) { |
| | | case STRING: |
| | | name = cell.getStringCellValue(); |
| | | break; |
| | | case NUMERIC: |
| | | name = cell.getNumericCellValue()+""; |
| | | break; |
| | | } |
| | | return name; |
| | | } |
| | | |
| | | /** |
| | | * 替换MAQTR图表数据 |
| | | * @param document 文档对象 |
| | | * @param fileName 数据源excel |
| | | */ |
| | | public static void changeMAQTRChart(XWPFDocument document,String fileName) { |
| | | if(StringUtils.isEmpty(fileName)){ |
| | | return; |
| | | } |
| | | try { |
| | | List<POIXMLDocumentPart> relations = document.getRelations(); |
| | | for (POIXMLDocumentPart part : relations) { |
| | | if (part instanceof XWPFChart) { |
| | | // 图表元素 |
| | | XWPFChart chart = (XWPFChart) part; |
| | | String partName = chart.getPackagePart().getPartName().getName(); |
| | | |
| | | Integer index = 0; |
| | | if(partName.contains("chart1.xml")){ |
| | | index = 0; |
| | | }else if(partName.contains("chart2.xml")){ |
| | | index = 1; |
| | | } |
| | | //获取模板数据 |
| | | List<SeriesData> seriesDatas = initData(fileName,index); |
| | | //数据长度 |
| | | int size = seriesDatas.size(); |
| | | // 查看里面的图表数据,才能知道是什么图表 |
| | | CTPlotArea plot = chart.getCTChart().getPlotArea(); |
| | | // excel内置表格 |
| | | XSSFWorkbook workbook = chart.getWorkbook(); |
| | | XSSFSheet sheet = workbook.getSheetAt(0); |
| | | |
| | | //散点图 |
| | | if (!plot.getScatterChartList().isEmpty()) { |
| | | CTScatterChart scatterChart = plot.getScatterChartArray(0); |
| | | |
| | | //去除多余数据源 |
| | | int remain = 8 - size; |
| | | if(remain != 0){ |
| | | for (int j = 1; j <= remain; j++) { |
| | | int removeSize = scatterChart.getSerList().size() - j - 1; |
| | | scatterChart.getSerList().remove(removeSize); |
| | | //删除excel多余列 |
| | | //deleteColumn(sheet,8 - remain); |
| | | } |
| | | } |
| | | |
| | | //刷新内置excel数据 |
| | | refreshExcel(seriesDatas, sheet); |
| | | workbook.write(chart.getPackagePart().getOutputStream()); |
| | | |
| | | //散点图数据源 XY坐标 |
| | | for (int i = 0; i < scatterChart.getSerList().size(); i++) { |
| | | //根据图表数据线获取对应数据源 数值是X轴 辅助Y轴 |
| | | List<SeriesData> scatterDatas = new ArrayList<SeriesData>(); |
| | | //最后一个数据源需拿取最后一列0000 作为x轴 |
| | | if((i+1) == size-2){ |
| | | scatterDatas.add(seriesDatas.get(size-1)); |
| | | scatterDatas.add(seriesDatas.get(size-2)); |
| | | }else{ |
| | | scatterDatas.add(seriesDatas.get(i+1)); |
| | | scatterDatas.add(seriesDatas.get(size-2)); |
| | | } |
| | | |
| | | CTScatterSer ser = scatterChart.getSerList().get(i); |
| | | updateScatterChart(scatterDatas, ser.getXVal(), ser.getYVal()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | log.error("MAQTR替换word图表 散点图图形失败:{}",e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 删除列 |
| | | * @param sheet |
| | | * @param columnToDelete |
| | | */ |
| | | public static void deleteColumn(XSSFSheet sheet, int columnToDelete) { |
| | | for (int r = 0; r <= sheet.getLastRowNum(); r++) { |
| | | XSSFRow row = sheet.getRow(r); |
| | | for (int c = columnToDelete; c <= row.getLastCellNum(); c++) { |
| | | XSSFCell cOld = row.getCell(c); |
| | | if (cOld != null) { |
| | | row.removeCell(cOld); |
| | | } |
| | | XSSFCell cNext = row.getCell(c + 1); |
| | | if (cNext != null) { |
| | | XSSFCell cNew = row.createCell(c, cNext.getCellType()); |
| | | cloneCell(cNew, cNext); |
| | | if (r == 0) { |
| | | sheet.setColumnWidth(c, sheet.getColumnWidth(c + 1)); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 右边列左移,样式值设置 |
| | | * @param cNew |
| | | * @param cOld |
| | | */ |
| | | private static void cloneCell(XSSFCell cNew, XSSFCell cOld) { |
| | | cNew.setCellComment(cOld.getCellComment()); |
| | | cNew.setCellStyle(cOld.getCellStyle()); |
| | | if (CellType.BOOLEAN == cNew.getCellType()) { |
| | | cNew.setCellValue(cOld.getBooleanCellValue()); |
| | | } else if (CellType.NUMERIC == cNew.getCellType()) { |
| | | cNew.setCellValue(cOld.getNumericCellValue()); |
| | | } else if (CellType.STRING == cNew.getCellType()) { |
| | | cNew.setCellValue(cOld.getStringCellValue()); |
| | | } else if (CellType.ERROR == cNew.getCellType()) { |
| | | cNew.setCellValue(cOld.getErrorCellValue()); |
| | | } else if (CellType.FORMULA == cNew.getCellType()) { |
| | | cNew.setCellValue(cOld.getCellFormula()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 更新图表的关联 excel |
| | | * |
| | | * @param seriesDatas |
| | | * @param sheet |
| | | */ |
| | | protected static void refreshExcel(List<SeriesData> seriesDatas, XSSFSheet sheet) { |
| | | XSSFRow title = sheet.getRow(0); |
| | | //遍历数据数组进行excel赋值 |
| | | for (int i = 0; i < seriesDatas.size(); i++) { |
| | | SeriesData data = seriesDatas.get(i); |
| | | if (data.name != null && !data.name.isEmpty()) { |
| | | // 第一行标题 |
| | | XSSFCell cell = title.getCell(i); |
| | | if (cell == null) { |
| | | cell = title.createCell(i + 1); |
| | | } |
| | | cell.setCellValue(data.name); |
| | | } |
| | | int size = data.value.size(); |
| | | //遍历数据进行赋值 |
| | | for (int j = 0; j < size; j++) { |
| | | //从第二行开始赋值 |
| | | XSSFRow row = sheet.getRow(j + 1); |
| | | if (row == null) { |
| | | row = sheet.createRow(j + 1); |
| | | } |
| | | RowData cellValu = data.value.get(j); |
| | | |
| | | //第一列开始赋值 |
| | | XSSFCell cell = row.getCell(i); |
| | | if (cell == null) { |
| | | cell = row.createCell(i); |
| | | } |
| | | //优先使用字符串值 |
| | | if(StringUtils.isNotEmpty(cellValu.valueStr)){ |
| | | cell.setCellValue(cellValu.valueStr); |
| | | }else{ |
| | | cell.setCellValue(cellValu.value); |
| | | } |
| | | |
| | | } |
| | | //删除多余行数 |
| | | int lastRowNum = sheet.getLastRowNum(); |
| | | //log.error("lastRowNum:{},size:{}",lastRowNum,size); |
| | | if (lastRowNum > size) { |
| | | for (int idx = lastRowNum; idx > size; idx--) { |
| | | sheet.removeRow(sheet.getRow(idx)); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 更新 散点图 缓存数据 |
| | | * |
| | | * @param seriesDatas 数据 |
| | | * @param xDataSource X坐标数据缓存 |
| | | * @param yDataSource Y坐标数据缓存 |
| | | */ |
| | | protected static void updateScatterChart(List<SeriesData> seriesDatas, CTAxDataSource xDataSource, |
| | | CTNumDataSource yDataSource) { |
| | | |
| | | //获取xy坐标数据条数 |
| | | long xNumCnt = xDataSource.getNumRef().getNumCache().getPtCount().getVal(); |
| | | long yNumCnt = yDataSource.getNumRef().getNumCache().getPtCount().getVal(); |
| | | |
| | | //获取XY最新数据 |
| | | List<RowData> xRowDatas = seriesDatas.get(0).getValue(); |
| | | int xRowDataSize = xRowDatas.size(); |
| | | List<RowData> yRowDatas = seriesDatas.get(1).getValue(); |
| | | int yRowDataSize = yRowDatas.size(); |
| | | |
| | | //更新X坐标缓存 |
| | | for (int i = 0; i < xRowDatas.size(); i++) { |
| | | RowData cellValu = xRowDatas.get(i); |
| | | CTNumVal val = xNumCnt > i ? xDataSource.getNumRef().getNumCache().getPtArray(i) |
| | | : xDataSource.getNumRef().getNumCache().addNewPt(); |
| | | val.setIdx(i); |
| | | val.setV(String.format("%.0f", cellValu.value)); |
| | | } |
| | | |
| | | //更新Y坐标缓存 |
| | | for (int i = 0; i < yRowDatas.size(); i++) { |
| | | RowData cellValu = yRowDatas.get(i); |
| | | CTNumVal val = yNumCnt > i ? yDataSource.getNumRef().getNumCache().getPtArray(i) |
| | | : yDataSource.getNumRef().getNumCache().addNewPt(); |
| | | val.setIdx(i); |
| | | val.setV(String.format("%.0f", cellValu.value)); |
| | | } |
| | | |
| | | // 更新对应excel的范围 |
| | | xDataSource.getNumRef().setF( |
| | | replaceRowEnd(xDataSource.getNumRef().getF(), |
| | | xNumCnt, |
| | | xRowDataSize)); |
| | | yDataSource.getNumRef().setF( |
| | | replaceRowEnd(yDataSource.getNumRef().getF(), |
| | | yNumCnt, |
| | | yRowDataSize)); |
| | | |
| | | // 删除多的 |
| | | if (xNumCnt > xRowDataSize) { |
| | | for (int idx = xRowDataSize; idx < xNumCnt; idx++) { |
| | | xDataSource.getNumRef().getNumCache().removePt(xRowDataSize); |
| | | } |
| | | } |
| | | if (yNumCnt > yRowDataSize) { |
| | | for (int idx = yRowDataSize; idx < yNumCnt; idx++) { |
| | | yDataSource.getNumRef().getNumCache().removePt(yRowDataSize); |
| | | } |
| | | } |
| | | // 更新个数 |
| | | xDataSource.getNumRef().getNumCache().getPtCount().setVal(xRowDataSize); |
| | | // 更新个数 |
| | | yDataSource.getNumRef().getNumCache().getPtCount().setVal(yRowDataSize); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 替换 形如: Sheet1!$A$2:$A$4 的字符 |
| | | * |
| | | * @param range |
| | | * @return |
| | | */ |
| | | public static String replaceRowEnd(String range, long oldSize, long newSize) { |
| | | Pattern pattern = Pattern.compile("(:\\$[A-Z]+\\$)(\\d+)"); |
| | | Matcher matcher = pattern.matcher(range); |
| | | if (matcher.find()) { |
| | | long old = Long.parseLong(matcher.group(2)); |
| | | return range.replaceAll("(:\\$[A-Z]+\\$)(\\d+)", "$1" + Long.toString(old - oldSize + newSize)); |
| | | } |
| | | return range; |
| | | } |
| | | |
| | | /** |
| | | * 获取图表有哪些类型 |
| | | * @param part |
| | | */ |
| | | public static void getChartType(POIXMLDocumentPart part){ |
| | | XWPFChart chart = (XWPFChart) part; |
| | | //根据属性第一列名称切换数据类型 |
| | | CTChart ctChart = chart.getCTChart(); |
| | | CTPlotArea plotArea = ctChart.getPlotArea(); |
| | | |
| | | if (!plotArea.getBarChartList().isEmpty()) { |
| | | System.out.println("柱状图{"+plotArea.getBarChartList().size()+"}"); |
| | | } |
| | | if (!plotArea.getPieChartList().isEmpty()) { |
| | | System.out.println("饼图{"+plotArea.getPieChartList().size()+"}"); |
| | | } |
| | | if (!plotArea.getLineChartList().isEmpty()) { |
| | | System.out.println("线形图{"+plotArea.getLineChartList().size()+"}"); |
| | | } |
| | | if (!plotArea.getBar3DChartList().isEmpty()) { |
| | | System.out.println("柱状图3D{"+plotArea.getBar3DChartList().size()+"}"); |
| | | } |
| | | if (!plotArea.getScatterChartList().isEmpty()) { |
| | | System.out.println("散点图{"+plotArea.getScatterChartList().size()+"}"); |
| | | } |
| | | } |
| | | |
| | | } |