diff --git a/com.actionsoft.apps.coe.pal/src/com/actionsoft/apps/coe/pal/pal/output/util/FileUtil.java b/com.actionsoft.apps.coe.pal/src/com/actionsoft/apps/coe/pal/pal/output/util/FileUtil.java new file mode 100644 index 00000000..230aca75 --- /dev/null +++ b/com.actionsoft.apps.coe.pal/src/com/actionsoft/apps/coe/pal/pal/output/util/FileUtil.java @@ -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()); + } + } +} \ No newline at end of file diff --git a/com.actionsoft.apps.coe.pal/src/com/actionsoft/apps/coe/pal/pal/output/util/OutputWordUtil.java b/com.actionsoft.apps.coe.pal/src/com/actionsoft/apps/coe/pal/pal/output/util/OutputWordUtil.java index 4672a450..c2b6a19c 100644 --- a/com.actionsoft.apps.coe.pal/src/com/actionsoft/apps/coe/pal/pal/output/util/OutputWordUtil.java +++ b/com.actionsoft.apps.coe.pal/src/com/actionsoft/apps/coe/pal/pal/output/util/OutputWordUtil.java @@ -846,7 +846,13 @@ public class OutputWordUtil { String[] header = {"版本", "发布部门","拟制人","拟制日期","审核人","复核人","审批人","修订内容及理由"}; String[][] strArray2 = new String[versionHistoryTable.size()][]; List 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);