package com.ots.project.tool.report.APIFan.chart; import com.ots.framework.config.EssConfig; 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.ooxml.POIXMLDocument; import org.apache.poi.ooxml.POIXMLDocumentPart; import org.apache.poi.util.Units; 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.*; import org.openxmlformats.schemas.drawingml.x2006.chart.*; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; /** *@ClassName APIFanChart *@Description 柱形图数据替换 */ @Slf4j public class APIFanChart { //region 图形变量定义 private static String p_total;//工作表现预测分数 private static String p_retent09;//留职预测分数 private static String p_social01;//1.社交性 private static String p_cooper02;//2.合作性 private static String p_analth03;//3.问题解决和适应性 private static String p_initia04;//4.主动性 private static String p_persis05;//5.坚韧性 private static String p_depend06;//6.可靠性 private static String p_emotct07;//7.情绪的自我控制 private static String p_stress08;//8.压力的容忍度 //自我认知准确度 private static String p_sdecepT1; private static String p_sdecep10; //自我阐述的真实度 private static String p_impmgT1; private static String p_impmg11; //直接撒谎 private static String bst1; private static String bst2; //endregion public static void main(String[] args) throws IOException { try ( OutputStream os = new FileOutputStream("C:\\Users\\mac\\Desktop\\API_Fan_IA_CN_222.docx"); XWPFDocument document = new XWPFDocument(POIXMLDocument.openPackage("C:\\Users\\mac\\Desktop\\API_Fan_IA_CN.docx"))) { Map textMap = new HashMap(); textMap.put("P_Total","52"); textMap.put("P_Retent09","53"); textMap.put("P_Social01","54"); textMap.put("P_Cooper02","55"); textMap.put("P_Analth03","56"); textMap.put("P_Initia04","57"); textMap.put("P_Persis05","58"); textMap.put("P_Depend06","59"); textMap.put("P_Emotct07","60"); textMap.put("P_Stress08","61"); textMap.put("P_SdecepT1","62"); textMap.put("P_Sdecep10","63"); textMap.put("P_ImpmgT1","64"); textMap.put("P_Impmg11","65"); textMap.put("BST1","66"); textMap.put("BST2","67"); textMap.put("box","1"); changeChart(document,textMap); document.write(os); }catch (Exception e){ e.printStackTrace(); } } /** * 替换Excel图表数据 * @param document 文档对象 * @param textMap 报告字典键值对 * @return */ public static boolean changeChart(XWPFDocument document, Map textMap){ List seriesDatas = initData(textMap); if(seriesDatas == null){ log.error("替换APIFan图表数据,初始化数据失败!"); return false; } //图表数据 changeAPIFanChart(document,seriesDatas); //替换图片 try{ // 获取所有段落 List paragraphs = document.getParagraphs(); //获取图片路径 String selectedPic = EssConfig.getReportTemplates()+"apifanSelected.png"; String defaultPic =EssConfig.getReportTemplates()+"apifanDefalut.png"; // 遍历段落进行替换操作 synchronized (paragraphs) { for (XWPFParagraph paragraph : paragraphs) { String text = paragraph.getText(); //用%%号在前面被替换了 if (text.contains("{{box0}}")) { // 检查是否包含要替换的文字变量 String picturePath = ""; // 图片路径 String Box = (String) textMap.get("box"); int box = Integer.parseInt(Box); if(box== 0) { picturePath =selectedPic; } else { picturePath = defaultPic; } // 创建新的图片段落 // XWPFParagraph paragraph = document.createParagraph(); // 获取所有运行的列表 List runs = paragraph.getRuns(); // 移除所有运行 for (int i = runs.size() - 1; i >= 0 ; i--) { paragraph.removeRun(i); } // 创建图片对象 XWPFRun run = paragraph.createRun(); int pictureType = Document.PICTURE_TYPE_PNG; // 图片类型 // 将图片插入到段落中 int width = Units.toEMU(20); // 图片宽度 int height = Units.toEMU(20); // 图片高度 run.addPicture(new FileInputStream(picturePath), pictureType, "image.png", width, height); run.setText("结果可信,可以直接解读(测试中未发现明显的“伪装好”倾向)"); } if (text.contains("{{box1}}")) { // 检查是否包含要替换的文字变量 String picturePath = ""; // 图片路径 String Box = (String) textMap.get("box"); int box = Integer.parseInt(Box); if(box== 1) { picturePath =selectedPic; } else { picturePath = defaultPic; } // 创建新的图片段落 // XWPFParagraph paragraph = document.createParagraph(); // 获取所有运行的列表 List runs = paragraph.getRuns(); // 移除所有运行 for (int i = runs.size() - 1; i >= 0 ; i--) { paragraph.removeRun(i); } // 创建图片对象 XWPFRun run = paragraph.createRun(); int pictureType = Document.PICTURE_TYPE_PNG; // 图片类型 // 将图片插入到段落中 int width = Units.toEMU(20); // 图片宽度 int height = Units.toEMU(20); // 图片高度 run.addPicture(new FileInputStream(picturePath), pictureType, "image.png", width, height); run.setText("结果不可信(测试中有明显的“伪装好”倾向)"); } if (text.contains("{{box2}}")) { // 检查是否包含要替换的文字变量 String picturePath = ""; // 图片路径 String Box = (String) textMap.get("box"); int box = Integer.parseInt(Box); if(box== 2) { picturePath =selectedPic; } else { picturePath = defaultPic; } // 创建新的图片段落 // XWPFParagraph paragraph = document.createParagraph(); // 获取所有运行的列表 List runs = paragraph.getRuns(); // 移除所有运行 for (int i = runs.size() - 1; i >= 0 ; i--) { paragraph.removeRun(i); } // 创建图片对象 XWPFRun run = paragraph.createRun(); int pictureType = Document.PICTURE_TYPE_PNG; // 图片类型 // 将图片插入到段落中 int width = Units.toEMU(20); // 图片宽度 int height = Units.toEMU(20); // 图片高度 run.addPicture(new FileInputStream(picturePath), pictureType, "image.png", width, height); run.setText("结果可能可信,解读时要谨慎(测试中有一定的“伪装好倾向”)"); } } } } catch (Exception ex) { System.out.println(ex.getMessage()); } return true; } /** * 判断是否为空 * @param value * @return */ public static boolean checkParamsIsNull(String... value) { for (int i = 0; i < value.length; i++) { if (Objects.isNull(value[i])) { return true; } } return false; } /** * 初始化报告数据 * @param textMap * @return */ public static List initData(Map textMap){ //region 获取命中数值 p_total = (String) textMap.get("P_Total"); p_retent09 = (String) textMap.get("P_Retent09"); p_social01 = (String) textMap.get("P_Social01"); p_cooper02 = (String) textMap.get("P_Cooper02"); p_analth03 = (String) textMap.get("P_Analth03"); p_initia04 = (String) textMap.get("P_Initia04"); p_persis05 = (String) textMap.get("P_Persis05"); p_depend06 = (String) textMap.get("P_Depend06"); p_emotct07 = (String) textMap.get("P_Emotct07"); p_stress08 = (String) textMap.get("P_Stress08"); p_sdecepT1 = (String) textMap.get("P_SdecepT1"); p_sdecep10 = (String) textMap.get("P_Sdecep10"); p_impmgT1 = (String) textMap.get("P_ImpmgT1"); p_impmg11 = (String) textMap.get("P_Impmg11"); bst1 = (String) textMap.get("BST1"); bst2 = (String) textMap.get("BST2"); String[] paramValue = new String[]{p_total, p_retent09, p_social01,p_cooper02,p_analth03,p_initia04, p_persis05,p_depend06,p_emotct07,p_stress08,p_sdecepT1, p_sdecep10,p_impmgT1,p_impmg11,bst1,bst2}; //判断是否为空 if (checkParamsIsNull(paramValue)) { return null; } //endregion Double P_Total = Double.valueOf(p_total); Double P_Retent09 = Double.valueOf(p_retent09); Double P_Social01 = Double.valueOf(p_social01); Double P_Cooper02 = Double.valueOf(p_cooper02); Double P_Analth03 = Double.valueOf(p_analth03); Double P_Initia04 = Double.valueOf(p_initia04); Double P_Persis05 = Double.valueOf(p_persis05); Double P_Depend06 = Double.valueOf(p_depend06); Double P_Emotct07 = Double.valueOf(p_emotct07); Double P_Stress08 = Double.valueOf(p_stress08); Double P_SdecepT1 = Double.valueOf(p_sdecepT1); Double P_Sdecep10 = Double.valueOf(p_sdecep10); Double P_ImpmgT1 = Double.valueOf(p_impmgT1); Double P_Impmg11 = Double.valueOf(p_impmg11); Double BST1 = Double.valueOf(bst1); Double BST2 = Double.valueOf(bst2); // 测试数据 List seriesDatas = Arrays.asList( new SeriesData("留职预测分数", Arrays.asList( new RowData("留职预测分数", P_Retent09) )), new SeriesData("人格剖像", Arrays.asList( new RowData("人格剖像", P_Social01), new RowData("人格剖像", P_Cooper02), new RowData("人格剖像", P_Analth03), new RowData("人格剖像", P_Initia04), new RowData("人格剖像", P_Persis05), new RowData("人格剖像", P_Depend06), new RowData("人格剖像", P_Emotct07), new RowData("人格剖像", P_Stress08) )), new SeriesData("自我认知的准确度", Arrays.asList( new RowData("自我认知的准确度", P_Sdecep10),//顺序要倒置 new RowData("自我认知的准确度", P_SdecepT1)//顺序要倒置 )), new SeriesData("自我阐述的真实度", Arrays.asList( new RowData("自我阐述的真实度", P_Impmg11),//顺序要倒置 new RowData("自我阐述的真实度", P_ImpmgT1)//顺序要倒置 )), new SeriesData("直接撒谎", Arrays.asList( new RowData("直接撒谎", BST2),//顺序要倒置 new RowData("直接撒谎", BST1)//顺序要倒置 )), new SeriesData("工作表现预测分数", Arrays.asList( new RowData("工作表现预测分数", P_Total) )) ); return seriesDatas; } /** * 替换word图表 散点图跟柱形图组合图形 * @param doc * @param seriesDatas */ public static void changeAPIFanChart(XWPFDocument doc,List seriesDatas) { try { //动态刷新图表 List relations = doc.getRelations(); int k=0; for (POIXMLDocumentPart part : relations) { if (part instanceof XWPFChart) { // 图表元素 XWPFChart chart = (XWPFChart) part; // 查看里面的图表数据,才能知道是什么图表 CTPlotArea plot = chart.getCTChart().getPlotArea(); // excel内置表格 XSSFWorkbook workbook = chart.getWorkbook(); XSSFSheet sheet = workbook.getSheetAt(0); String sheetName = sheet.getSheetName(); //柱形图 if (!plot.getBarChartList().isEmpty()) { CTBarChart barChart = plot.getBarChartArray(0); //刷新内置excel数据 List excelData = new ArrayList<>(); //excelData.add(seriesDatas.get(k)); //通过sheetName来解决匹配多表的问题 SeriesData seriesData = seriesDatas.stream() .filter(item -> item.getName().equals(sheetName)) .findFirst() .orElse(null); excelData.add(seriesData); refreshExcel(excelData, workbook, sheet); workbook.write(chart.getPackagePart().getOutputStream()); //柱形图数据源 // List barDatas = seriesDatas; int i = 0; for (CTBarSer ser : barChart.getSerList()) { //更新柱形图数据缓存 updateBarChart(seriesData, ser.getVal()); ++i; } ++k; } } } } catch (Exception e) { e.printStackTrace(); log.error("API-fan柱形图图形失败:{}",e); } } /** * 更新图表的关联 excel * * @param seriesDatas * @param workbook * @param sheet */ protected static void refreshExcel(List seriesDatas, XSSFWorkbook workbook, 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()) { // 第2行标题 XSSFCell cell = title.getCell(i+1); 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); //第2列开始赋值 XSSFCell cell = row.getCell(i+1); if (cell == null) { cell = row.createCell(i+1); } cell.setCellValue(cellValu.value); } //删除多余行数 // int lastRowNum = sheet.getLastRowNum(); // if (lastRowNum > size) { // for (int idx = lastRowNum; idx > size; idx--) { // sheet.removeRow(sheet.getRow(idx)); // } // } } } /** * 更新 柱形图 的缓存数据 * * @param seriesDatas 数据 * @param numDataSource 数据的缓存 */ protected static void updateBarChart(SeriesData seriesDatas, CTNumDataSource numDataSource) { //获取柱形图数据数量 long ptNumCnt = numDataSource.getNumRef().getNumCache().getPtCount().getVal(); int dataSize = seriesDatas.value.size(); for (int i = 0; i < dataSize; i++) { RowData cellValu = seriesDatas.value.get(i); CTNumVal val = ptNumCnt > i ? numDataSource.getNumRef().getNumCache().getPtArray(i) : numDataSource.getNumRef().getNumCache().addNewPt(); val.setIdx(i); val.setV(String.format("%.0f", cellValu.value)); } // 更新对应excel的范围 numDataSource.getNumRef().setF( replaceRowEnd(numDataSource.getNumRef().getF(), ptNumCnt, dataSize)); // 删除多的 if (ptNumCnt > dataSize) { for (int idx = dataSize; idx < ptNumCnt; idx++) { numDataSource.getNumRef().getNumCache().removePt(dataSize); } } // 更新个数 numDataSource.getNumRef().getNumCache().getPtCount().setVal(dataSize); } /** * 替换 形如: 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()+"}"); } } }