修订记录逻辑新增,大于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[] header = {"版本", "发布部门","拟制人","拟制日期","审核人","复核人","审批人","修订内容及理由"};
|
||||||
String[][] strArray2 = new String[versionHistoryTable.size()][];
|
String[][] strArray2 = new String[versionHistoryTable.size()][];
|
||||||
List<String[]> list = new LinkedList<>();
|
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);
|
JSONObject jsonObject = versionHistoryTable.getJSONObject(i);
|
||||||
String[] strArray = new String[8];
|
String[] strArray = new String[8];
|
||||||
|
|
||||||
@ -1817,6 +1823,26 @@ public class OutputWordUtil {
|
|||||||
+ (b2 - b1) / 1000 + "秒");
|
+ (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 {
|
try {
|
||||||
System.out.println("Filed=================="+repositoryModel.getId());
|
System.out.println("Filed=================="+repositoryModel.getId());
|
||||||
doc.saveToFile(outFile.getPath(), FileFormat.Docx_2013);
|
doc.saveToFile(outFile.getPath(), FileFormat.Docx_2013);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user