修订记录逻辑新增,大于3条显示最后三条。且完整文件添加至附件当中
This commit is contained in:
		
							parent
							
								
									24b8bef478
								
							
						
					
					
						commit
						e0433d3faa
					
				| @ -0,0 +1,327 @@ | ||||
| package com.actionsoft.apps.coe.pal.pal.output.util; | ||||
| 
 | ||||
| import com.alibaba.fastjson.JSONArray; | ||||
| import com.alibaba.fastjson.JSONObject; | ||||
| import org.apache.poi.xwpf.usermodel.*; | ||||
| import org.openxmlformats.schemas.wordprocessingml.x2006.main.*; | ||||
| 
 | ||||
| import java.io.*; | ||||
| import java.math.BigInteger; | ||||
| 
 | ||||
| public class FileUtil { | ||||
| 
 | ||||
|     /** | ||||
|      * 生成版本历史表格的Word文档输入流 | ||||
|      * @param versionHistoryTable 版本历史数据JSONArray | ||||
|      * @return 包含表格的Word文档InputStream | ||||
|      * @throws IOException IO异常 | ||||
|      */ | ||||
|     public static InputStream generateVersionHistoryStream(JSONArray versionHistoryTable) throws IOException { | ||||
|         // 创建Word文档对象 | ||||
|         try (XWPFDocument document = new XWPFDocument(); | ||||
|              // 内存输出流,用于临时存储文档内容 | ||||
|              ByteArrayOutputStream out = new ByteArrayOutputStream()) { | ||||
| 
 | ||||
|             // 定义表格列名(与需求对应) | ||||
|             String[] columnNames = { | ||||
|                     "版本", "发布部门", "拟制人", "拟制日期", | ||||
|                     "审核人", "复核人", "审批人", "修订内容及理由" | ||||
|             }; | ||||
| 
 | ||||
|             // 创建表格:1行表头,8列 | ||||
|             XWPFTable table = document.createTable(1, columnNames.length); | ||||
|              | ||||
|             // 表格整体设置 | ||||
|             // 设置表格水平居中对齐(POI 3.17兼容方式) | ||||
|             CTTblPr tblPr = table.getCTTbl().getTblPr(); | ||||
|             if (tblPr == null) { | ||||
|                 tblPr = table.getCTTbl().addNewTblPr(); | ||||
|             } | ||||
|             CTJc jc = tblPr.isSetJc() ? tblPr.getJc() : tblPr.addNewJc(); | ||||
|             jc.setVal(STJc.CENTER); | ||||
| 
 | ||||
|             // 设置表格自动适应窗口宽度 | ||||
|             CTTblWidth tblWidth = tblPr.isSetTblW() ? tblPr.getTblW() : tblPr.addNewTblW(); | ||||
|             tblWidth.setW(new BigInteger("9000")); // 设置一个较大的宽度值 | ||||
|             tblWidth.setType(STTblWidth.DXA); | ||||
|              | ||||
|             // 设置表格布局为自动适应内容 | ||||
|             CTTblLayoutType layout = tblPr.isSetTblLayout() ? tblPr.getTblLayout() : tblPr.addNewTblLayout(); | ||||
|             layout.setType(STTblLayoutType.AUTOFIT); | ||||
|              | ||||
|             // 设置列宽 - 增大列宽值以确保内容不会缩在一起 | ||||
|             // 根据列内容性质设置不同宽度 | ||||
|             // 1. 版本 - 适中宽度 | ||||
|             // 2. 发布部门 - 较宽 | ||||
|             // 3-7. 人员信息 - 适中宽度 | ||||
|             // 8. 修订内容及理由 - 最宽 | ||||
|             int[] columnWidths = {1200, 2500, 1500, 1800, 1800, 1800, 1800, 4500}; | ||||
|             setTableColumnsWidth(table, columnWidths); | ||||
| 
 | ||||
|             // 创建表头样式 | ||||
|             XWPFTableRow headerRow = table.getRow(0); | ||||
|             // 设置为表头行 | ||||
|             // 设置固定行高20(转换为twip单位,1点≈20twip) | ||||
|             headerRow.setHeight((int) (20 * 20)); // twip单位 | ||||
| 
 | ||||
|             // 填充表头并设置样式 | ||||
|             for (int i = 0; i < columnNames.length; i++) { | ||||
|                 XWPFTableCell cell = headerRow.getCell(i); | ||||
|                 if (cell == null) { | ||||
|                     cell = headerRow.createCell(); | ||||
|                 } | ||||
|                  | ||||
|                 // 设置表头单元格样式 | ||||
|                 setHeaderCellStyle(cell); | ||||
|                 cell.setText(columnNames[i]); | ||||
|             } | ||||
| 
 | ||||
|             // 填充数据行 | ||||
|             for (int i = 0; i < versionHistoryTable.size(); i++) { | ||||
|                 JSONObject rowData = versionHistoryTable.getJSONObject(i); | ||||
|                 XWPFTableRow dataRow = table.createRow(); | ||||
| 
 | ||||
|                 // 设置数据行行高自动 | ||||
|                 dataRow.setHeight(400); | ||||
|                 // 按列顺序填充数据并设置样式(与JSON的key对应) | ||||
|                 for (int j = 0; j < columnNames.length; j++) { | ||||
|                     XWPFTableCell cell = dataRow.getCell(j); | ||||
|                     if (cell == null) { | ||||
|                         cell = dataRow.createCell(); | ||||
|                     } | ||||
|                      | ||||
|                     // 设置数据单元格样式 | ||||
|                     boolean isLastColumn = (j == 7); // 第8列(索引7) | ||||
|                     setDataCellStyle(cell, isLastColumn); | ||||
|                      | ||||
|                     // 设置对应列的数据 | ||||
|                     switch (j) { | ||||
|                         case 0: cell.setText(getSafeString(rowData, "versions")); break; | ||||
|                         case 1: cell.setText(getSafeString(rowData, "Issuing_department")); break; | ||||
|                         case 2: cell.setText(getSafeString(rowData, "Drafted_and_revised_by")); break; | ||||
|                         case 3: cell.setText(getSafeString(rowData, "Drafted_and_revised_date")); break; | ||||
|                         case 4: cell.setText(getSafeString(rowData, "auditor")); break; | ||||
|                         case 5: cell.setText(getSafeString(rowData, "reviewer")); break; | ||||
|                         case 6: cell.setText(getSafeString(rowData, "approver")); break; | ||||
|                         case 7: cell.setText(getSafeString(rowData, "Contents_and_reasons_for_revision")); break; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             // 将文档写入内存输出流 | ||||
|             document.write(out); | ||||
|             out.flush(); // 确保所有数据写入完成 | ||||
| 
 | ||||
|             // 将内存中的字节数组转换为InputStream返回 | ||||
|             return new ByteArrayInputStream(out.toByteArray()); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置表格各列宽度 | ||||
|      * @param table 表格对象 | ||||
|      * @param columnWidths 列宽数组(与列数对应) | ||||
|      */ | ||||
|     private static void setTableColumnsWidth(XWPFTable table, int[] columnWidths) { | ||||
|         // 获取或创建表格网格 | ||||
|         CTTblGrid tblGrid = table.getCTTbl().getTblGrid(); | ||||
|         if (tblGrid == null) { | ||||
|             tblGrid = table.getCTTbl().addNewTblGrid(); | ||||
|         } else { | ||||
|             // 清除原有网格列 | ||||
|             while (tblGrid.getGridColList().size() > 0) { | ||||
|                 tblGrid.removeGridCol(0); | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         // 为每一列设置宽度 | ||||
|         for (int width : columnWidths) { | ||||
|             CTTblGridCol gridCol = tblGrid.addNewGridCol(); | ||||
|             gridCol.setW(new BigInteger(String.valueOf(width))); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置表头单元格样式 | ||||
|      */ | ||||
|     private static void setHeaderCellStyle(XWPFTableCell cell) { | ||||
|         // 设置单元格垂直居中 | ||||
|         cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); | ||||
|          | ||||
|         // 设置单元格边距,确保内容不紧贴边框 | ||||
|         setCellMargins(cell); | ||||
|          | ||||
|         // 设置段落样式 | ||||
|         XWPFParagraph paragraph = cell.getParagraphs().get(0); | ||||
|         // 文字水平居中 | ||||
|         paragraph.setAlignment(ParagraphAlignment.CENTER); | ||||
|          | ||||
|         // 设置段落行距(使用兼容的方式) | ||||
|         CTP ctp = paragraph.getCTP(); | ||||
|         CTPPr pPr = ctp.isSetPPr() ? ctp.getPPr() : ctp.addNewPPr(); | ||||
|         CTSpacing spacing = pPr.isSetSpacing() ? pPr.getSpacing() : pPr.addNewSpacing(); | ||||
|         spacing.setAfter(new BigInteger("0")); | ||||
|         spacing.setBefore(new BigInteger("0")); | ||||
|         spacing.setLine(new BigInteger("240")); // 12pt 对应240 | ||||
|         spacing.setLineRule(STLineSpacingRule.EXACT); | ||||
|          | ||||
|         // 设置字体样式 | ||||
|         XWPFRun run = paragraph.getRuns().isEmpty() ? paragraph.createRun() : paragraph.getRuns().get(0); | ||||
|         run.setBold(true); // 加粗 | ||||
|         run.setFontSize(10); // 10.5号字体近似10号 | ||||
|         run.setFontFamily("宋体"); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置数据单元格样式 | ||||
|      */ | ||||
|     private static void setDataCellStyle(XWPFTableCell cell, boolean isLastColumn) { | ||||
|         // 设置单元格垂直居中 | ||||
|         cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER); | ||||
|          | ||||
|         // 设置单元格边距,确保内容不紧贴边框 | ||||
|         setCellMargins(cell); | ||||
|          | ||||
|         // 设置背景色为白色 | ||||
|         cell.setColor("FFFFFF"); | ||||
|          | ||||
|         // 设置段落样式 | ||||
|         XWPFParagraph paragraph = cell.getParagraphs().get(0); | ||||
|         // 根据是否为第8列设置水平对齐方式 | ||||
|         paragraph.setAlignment(isLastColumn ? ParagraphAlignment.LEFT : ParagraphAlignment.CENTER); | ||||
|          | ||||
|         // 设置段落行距(使用兼容的方式) | ||||
|         CTP ctp = paragraph.getCTP(); | ||||
|         CTPPr pPr = ctp.isSetPPr() ? ctp.getPPr() : ctp.addNewPPr(); | ||||
|         CTSpacing spacing = pPr.isSetSpacing() ? pPr.getSpacing() : pPr.addNewSpacing(); | ||||
|         spacing.setAfter(new BigInteger("0")); | ||||
|         spacing.setBefore(new BigInteger("0")); | ||||
|         spacing.setLine(new BigInteger("240")); // 12pt 对应240 | ||||
|         spacing.setLineRule(STLineSpacingRule.EXACT); | ||||
|          | ||||
|         // 设置字体样式 | ||||
|         XWPFRun run = paragraph.getRuns().isEmpty() ? paragraph.createRun() : paragraph.getRuns().get(0); | ||||
|         run.setFontSize(10); // 10.5号字体近似10号 | ||||
|         run.setFontFamily("宋体"); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置单元格边距 | ||||
|      */ | ||||
|     private static void setCellMargins(XWPFTableCell cell) { | ||||
|         CTTc cttc = cell.getCTTc(); | ||||
|         CTTcPr tcPr = cttc.isSetTcPr() ? cttc.getTcPr() : cttc.addNewTcPr(); | ||||
|          | ||||
|         // 设置单元格左边距 | ||||
|         CTTcMar tcMar = tcPr.isSetTcMar() ? tcPr.getTcMar() : tcPr.addNewTcMar(); | ||||
|          | ||||
|         if (!tcMar.isSetLeft()) { | ||||
|             tcMar.addNewLeft(); | ||||
|         } | ||||
|         tcMar.getLeft().setW(new BigInteger("100")); | ||||
|         tcMar.getLeft().setType(STTblWidth.DXA); | ||||
|          | ||||
|         if (!tcMar.isSetRight()) { | ||||
|             tcMar.addNewRight(); | ||||
|         } | ||||
|         tcMar.getRight().setW(new BigInteger("100")); | ||||
|         tcMar.getRight().setType(STTblWidth.DXA); | ||||
|          | ||||
|         if (!tcMar.isSetTop()) { | ||||
|             tcMar.addNewTop(); | ||||
|         } | ||||
|         tcMar.getTop().setW(new BigInteger("50")); | ||||
|         tcMar.getTop().setType(STTblWidth.DXA); | ||||
|          | ||||
|         if (!tcMar.isSetBottom()) { | ||||
|             tcMar.addNewBottom(); | ||||
|         } | ||||
|         tcMar.getBottom().setW(new BigInteger("50")); | ||||
|         tcMar.getBottom().setType(STTblWidth.DXA); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 安全获取JSON字段值(避免null) | ||||
|      */ | ||||
|     private static String getSafeString(JSONObject jsonObject, String key) { | ||||
|         return jsonObject.getString(key) == null ? "" : jsonObject.getString(key); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 将InputStream保存到本地文件 | ||||
|      * @param inputStream 输入流 | ||||
|      * @param filePath 保存路径 | ||||
|      * @throws IOException IO异常 | ||||
|      */ | ||||
|     private static void saveInputStreamToFile(InputStream inputStream, String filePath) throws IOException { | ||||
|         // 创建文件目录(如果不存在) | ||||
|         File file = new File(filePath); | ||||
|         File parentDir = file.getParentFile(); | ||||
|         if (parentDir != null && !parentDir.exists()) { | ||||
|             boolean created = parentDir.mkdirs(); | ||||
|             if (!created) { | ||||
|                 throw new IOException("无法创建目录: " + parentDir.getAbsolutePath()); | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         // 使用try-with-resources确保流正确关闭 | ||||
|         try (FileOutputStream outputStream = new FileOutputStream(file)) { | ||||
|             byte[] buffer = new byte[4096]; | ||||
|             int bytesRead; | ||||
|             while ((bytesRead = inputStream.read(buffer)) != -1) { | ||||
|                 outputStream.write(buffer, 0, bytesRead); | ||||
|             } | ||||
|             outputStream.flush(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // 使用示例 | ||||
|     public static void main(String[] args) { | ||||
|         try { | ||||
|             // 1. 构造示例JSON数据(实际使用时替换为你的versionHistoryTable) | ||||
|             JSONArray versionHistory = new JSONArray(); | ||||
| 
 | ||||
|             // 添加V1.0数据 | ||||
|             JSONObject v1 = new JSONObject(); | ||||
|             v1.put("versions", "V1.0"); | ||||
|             v1.put("Issuing_department", "总部国际业务部国贸部"); | ||||
|             v1.put("Drafted_and_revised_by", "吴赞涛"); | ||||
|             v1.put("Drafted_and_revised_by", "2023年1月1日"); | ||||
|             v1.put("auditor", "高扬,王煜"); | ||||
|             v1.put("reviewer", "王志军"); | ||||
|             v1.put("approver", "黄新峰"); | ||||
|             v1.put("Contents_and_reasons_for_revision", "初始版本创建,包含基本功能"); | ||||
|             versionHistory.add(v1); | ||||
| 
 | ||||
|             // 添加V2.0数据 | ||||
|             JSONObject v2 = new JSONObject(); | ||||
|             v2.put("版本", "V2.0"); | ||||
|             v2.put("发布部门", "总部国际业务部国贸部"); | ||||
|             v2.put("拟制人", "吴赞涛"); | ||||
|             v2.put("拟制日期", "2023年7月10日"); | ||||
|             v2.put("审核人", "高扬,王煜"); | ||||
|             v2.put("复核人", "王志军"); | ||||
|             v2.put("审批人", "齐文川"); | ||||
|             v2.put("修订内容及理由", "优化系统流程,提升用户体验,修复已知问题"); | ||||
|             versionHistory.add(v2); | ||||
| 
 | ||||
|             // 2. 生成InputStream | ||||
|             InputStream wordStream = generateVersionHistoryStream(versionHistory); | ||||
| 
 | ||||
|             // 3. 此处可使用流进行后续操作(如保存为文件、作为附件等) | ||||
|             System.out.println("InputStream生成成功,可进行后续处理"); | ||||
| 
 | ||||
|             // 将流保存到本地文件 | ||||
|             String savePath = "/Users/yuyia/Desktop/临时文件/修订记录.docx"; | ||||
|             saveInputStreamToFile(wordStream, savePath); | ||||
|             System.out.println("文件已成功保存到: " + savePath); | ||||
| 
 | ||||
|             // 注意:使用完毕后需关闭流 | ||||
|             wordStream.close(); | ||||
|         } catch (Exception e) { | ||||
|             // 捕获所有异常以提供更详细的错误信息 | ||||
|             e.printStackTrace(); | ||||
|             System.out.println("生成失败:" + e.getMessage()); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -846,7 +846,13 @@ public class OutputWordUtil { | ||||
|                             String[] header = {"版本", "发布部门","拟制人","拟制日期","审核人","复核人","审批人","修订内容及理由"}; | ||||
|                             String[][] strArray2 = new String[versionHistoryTable.size()][]; | ||||
|                             List<String[]> list = new LinkedList<>(); | ||||
|                             for (int i = 0; i < versionHistoryTable.size(); i++) { | ||||
| 
 | ||||
|                             //增加逻辑 ,修订记录大于3条时,则只保留最后三条 | ||||
|                             int startIndex = 0; | ||||
|                             if (versionHistoryTable.size() > 3) { | ||||
|                                 startIndex = versionHistoryTable.size() - 3; // 只取最后三条记录 | ||||
|                             } | ||||
|                             for (int i = startIndex; i < versionHistoryTable.size(); i++) { | ||||
|                                 JSONObject jsonObject = versionHistoryTable.getJSONObject(i); | ||||
|                                 String[] strArray = new String[8]; | ||||
| 
 | ||||
| @ -1817,6 +1823,26 @@ public class OutputWordUtil { | ||||
|                         + (b2 - b1) / 1000 + "秒"); | ||||
|             } | ||||
| 
 | ||||
|             //新增修订记录逻辑 | ||||
|             JSONArray versionHistoryTable = getVersionHistoryTable(repositoryModel); | ||||
|             if(versionHistoryTable!=null && versionHistoryTable.size()>3){ | ||||
|                 InputStream versionHistoryStream = null; | ||||
|                 try { | ||||
|                     versionHistoryStream = FileUtil.generateVersionHistoryStream(versionHistoryTable); | ||||
|                 } catch (IOException e) { | ||||
|                     throw new RuntimeException(e); | ||||
|                 } | ||||
|                 //添加段落 | ||||
|                 Paragraph paragraph5 = section.addParagraph(); | ||||
|                 //加载一个图片,它将作为外部文件的符号显示在Word文档中 | ||||
|                 //获取文件的后缀名 .jpg | ||||
|                 DocPicture pic1 = new DocPicture(doc); | ||||
|                 pic1.loadImage("../doccenter/com.awspaas.user.apps.coe.pal.output.zd/filepic/word.png"); | ||||
|                 paragraph5.appendText("修订记录.docx"); | ||||
|                 paragraph5.applyStyle(BuiltinStyle.Body_Text); //应用标题1样式 | ||||
|                 paragraph5.appendOleObject(versionHistoryStream, pic1, "docx"); | ||||
|             } | ||||
| 
 | ||||
|             try { | ||||
|                 System.out.println("Filed=================="+repositoryModel.getId()); | ||||
|                 doc.saveToFile(outFile.getPath(), FileFormat.Docx_2013); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 yujh_java
						yujh_java