44 KiB
文档自动修正分析报告
概述
本报告基于 f:\api0203\ai_check\src\main\java\org\dromara\aiCheck\docExamine\examines\ 目录下的所有检查类,分析哪些文档检查项可以通过 Aspose.Words API 自动修正。
参考实现示例:AsposeWordPageSizeConverter.java:convertToA3
✅ 可自动修正的检查项
1. PaperRequirementsExamine - 纸张要求检查
1.1 纸张大小 (paperSize)
检查内容: 文档纸张不符合要求(如要求A4,实际为A3)
自动修正方法:
public static void fixPaperSize(String inputPath, String outputPath, PaperSize requiredSize) throws Exception {
Document doc = new Document(inputPath);
for (Section section : doc.getSections()) {
PageSetup pageSetup = section.getPageSetup();
pageSetup.setPaperSize(requiredSize); // 设置纸张大小
}
doc.save(outputPath);
}
Aspose API:
PageSetup.setPaperSize(PaperSize.A4)- 设置为A4PageSetup.setPaperSize(PaperSize.A3)- 设置为A3- 其他:
PaperSize.A5,PaperSize.B5,PaperSize.LETTER等
业务价值: ⭐⭐⭐⭐⭐ (高 - 常见需求,一键修正)
1.2 纸张方向 (orientation)
检查内容: 文档方向不符合要求(如要求横向,实际为纵向)
自动修正方法:
public static void fixOrientation(String inputPath, String outputPath, boolean isLandscape) throws Exception {
Document doc = new Document(inputPath);
for (Section section : doc.getSections()) {
PageSetup pageSetup = section.getPageSetup();
if (isLandscape) {
pageSetup.setOrientation(Orientation.LANDSCAPE); // 横向
} else {
pageSetup.setOrientation(Orientation.PORTRAIT); // 纵向
}
}
doc.save(outputPath);
}
Aspose API:
PageSetup.setOrientation(Orientation.LANDSCAPE)- 横向PageSetup.setOrientation(Orientation.PORTRAIT)- 纵向
业务价值: ⭐⭐⭐⭐⭐ (高)
1.3 页边距 (margins)
检查内容: 上/下/左/右页边距不符合要求
自动修正方法:
public static void fixMargins(String inputPath, String outputPath,
double top, double bottom, double left, double right) throws Exception {
Document doc = new Document(inputPath);
for (Section section : doc.getSections()) {
PageSetup pageSetup = section.getPageSetup();
pageSetup.setTopMargin(top); // 上边距(磅)
pageSetup.setBottomMargin(bottom); // 下边距(磅)
pageSetup.setLeftMargin(left); // 左边距(磅)
pageSetup.setRightMargin(right); // 右边距(磅)
}
doc.save(outputPath);
}
Aspose API:
PageSetup.setTopMargin(double points)- 上边距PageSetup.setBottomMargin(double points)- 下边距PageSetup.setLeftMargin(double points)- 左边距PageSetup.setRightMargin(double points)- 右边距
单位换算: 1厘米 = 28.35磅, 2.54厘米 = 72磅
业务价值: ⭐⭐⭐⭐⭐ (高 - 标书常见要求)
2. ContentRequirementsExamine - 内容格式要求检查
2.1 字体 - 中文字体 (chineseFont)
检查内容: 中文文本字体不符合要求(如要求宋体,实际为黑体)
自动修正方法:
public static void fixChineseFont(String inputPath, String outputPath, String requiredFont) throws Exception {
Document doc = new Document(inputPath);
for (Section section : doc.getSections()) {
for (Paragraph paragraph : section.getBody().getParagraphs()) {
for (Run run : paragraph.getRuns()) {
String text = run.getText();
if (containsChineseCharacters(text)) {
run.getFont().setNameFarEast(requiredFont); // 设置中文字体
}
}
}
}
doc.save(outputPath);
}
private static boolean containsChineseCharacters(String text) {
if (text == null) return false;
for (char c : text.toCharArray()) {
if (Character.UnicodeBlock.of(c) == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS) {
return true;
}
}
return false;
}
Aspose API:
Font.setNameFarEast("宋体")- 设置中文字体(Far East Font)- 常用字体: "宋体", "黑体", "楷体", "仿宋", "微软雅黑"
业务价值: ⭐⭐⭐⭐⭐ (高 - 标书必备)
2.2 字体 - 西文字体 (westernFont)
检查内容: 西文文本字体不符合要求
自动修正方法:
public static void fixWesternFont(String inputPath, String outputPath, String requiredFont) throws Exception {
Document doc = new Document(inputPath);
for (Section section : doc.getSections()) {
for (Paragraph paragraph : section.getBody().getParagraphs()) {
for (Run run : paragraph.getRuns()) {
run.getFont().setNameAscii(requiredFont); // 设置西文字体
}
}
}
doc.save(outputPath);
}
Aspose API:
Font.setNameAscii("Times New Roman")- 设置西文字体(ASCII Font)- 常用字体: "Times New Roman", "Arial", "Calibri"
业务价值: ⭐⭐⭐⭐ (中高)
2.3 字号 (fontSize)
检查内容: 字号不符合要求(如要求小四,实际为五号)
自动修正方法:
public static void fixFontSize(String inputPath, String outputPath, String chineseSize) throws Exception {
Document doc = new Document(inputPath);
double targetSize = convertChineseFontSizeToPoints(chineseSize);
for (Section section : doc.getSections()) {
for (Paragraph paragraph : section.getBody().getParagraphs()) {
for (Run run : paragraph.getRuns()) {
run.getFont().setSize(targetSize); // 设置字号(磅)
}
}
}
doc.save(outputPath);
}
private static double convertChineseFontSizeToPoints(String chineseSize) {
Map<String, Double> sizeMap = new HashMap<>();
sizeMap.put("初号", 42.0);
sizeMap.put("小初", 36.0);
sizeMap.put("一号", 26.0);
sizeMap.put("小一", 24.0);
sizeMap.put("二号", 22.0);
sizeMap.put("小二", 18.0);
sizeMap.put("三号", 16.0);
sizeMap.put("小三", 15.0);
sizeMap.put("四号", 14.0);
sizeMap.put("小四", 12.0);
sizeMap.put("五号", 10.5);
sizeMap.put("小五", 9.0);
sizeMap.put("六号", 7.5);
sizeMap.put("小六", 6.5);
sizeMap.put("七号", 5.5);
sizeMap.put("八号", 5.0);
return sizeMap.getOrDefault(chineseSize, 12.0);
}
Aspose API:
Font.setSize(double points)- 设置字号
业务价值: ⭐⭐⭐⭐⭐ (高)
2.4 行距 (lineSpacing)
检查内容: 行距不符合要求(如要求1.5倍行距,实际为单倍行距)
自动修正方法:
public static void fixLineSpacing(String inputPath, String outputPath, String lineSpacingDesc) throws Exception {
Document doc = new Document(inputPath);
for (Section section : doc.getSections()) {
for (Paragraph paragraph : section.getBody().getParagraphs()) {
ParagraphFormat format = paragraph.getParagraphFormat();
if (lineSpacingDesc.contains("单倍")) {
format.setLineSpacingRule(LineSpacingRule.MULTIPLE);
format.setLineSpacing(12); // 单倍 = 12
} else if (lineSpacingDesc.contains("1.5倍")) {
format.setLineSpacingRule(LineSpacingRule.MULTIPLE);
format.setLineSpacing(18); // 1.5倍 = 18
} else if (lineSpacingDesc.contains("2倍")) {
format.setLineSpacingRule(LineSpacingRule.MULTIPLE);
format.setLineSpacing(24); // 2倍 = 24
} else if (lineSpacingDesc.contains("固定值")) {
format.setLineSpacingRule(LineSpacingRule.EXACTLY);
double points = extractPoints(lineSpacingDesc);
format.setLineSpacing(points);
}
}
}
doc.save(outputPath);
}
Aspose API:
ParagraphFormat.setLineSpacingRule(LineSpacingRule.MULTIPLE)- 倍数行距ParagraphFormat.setLineSpacingRule(LineSpacingRule.EXACTLY)- 固定值ParagraphFormat.setLineSpacingRule(LineSpacingRule.AT_LEAST)- 最小值ParagraphFormat.setLineSpacing(double value)- 设置行距值
业务价值: ⭐⭐⭐⭐⭐ (高)
2.5 段前/段后间距 (spacingBefore/spacingAfter)
检查内容: 段前或段后间距不符合要求
自动修正方法:
public static void fixParagraphSpacing(String inputPath, String outputPath,
int beforeLines, int afterLines) throws Exception {
Document doc = new Document(inputPath);
for (Section section : doc.getSections()) {
for (Paragraph paragraph : section.getBody().getParagraphs()) {
ParagraphFormat format = paragraph.getParagraphFormat();
format.setSpaceBefore(beforeLines * 12); // 行数转磅值
format.setSpaceAfter(afterLines * 12);
}
}
doc.save(outputPath);
}
Aspose API:
ParagraphFormat.setSpaceBefore(double points)- 段前间距ParagraphFormat.setSpaceAfter(double points)- 段后间距
业务价值: ⭐⭐⭐⭐ (中高)
2.6 对齐方式 (alignment)
检查内容: 段落对齐方式不符合要求
自动修正方法:
public static void fixAlignment(String inputPath, String outputPath, String alignmentDesc) throws Exception {
Document doc = new Document(inputPath);
int alignment = ParagraphAlignment.LEFT;
if (alignmentDesc.contains("居中")) {
alignment = ParagraphAlignment.CENTER;
} else if (alignmentDesc.contains("右对齐")) {
alignment = ParagraphAlignment.RIGHT;
} else if (alignmentDesc.contains("两端对齐")) {
alignment = ParagraphAlignment.JUSTIFY;
} else if (alignmentDesc.contains("分散对齐")) {
alignment = ParagraphAlignment.DISTRIBUTED;
}
for (Section section : doc.getSections()) {
for (Paragraph paragraph : section.getBody().getParagraphs()) {
paragraph.getParagraphFormat().setAlignment(alignment);
}
}
doc.save(outputPath);
}
Aspose API:
ParagraphFormat.setAlignment(ParagraphAlignment.LEFT)- 左对齐ParagraphFormat.setAlignment(ParagraphAlignment.CENTER)- 居中ParagraphFormat.setAlignment(ParagraphAlignment.RIGHT)- 右对齐ParagraphFormat.setAlignment(ParagraphAlignment.JUSTIFY)- 两端对齐ParagraphFormat.setAlignment(ParagraphAlignment.DISTRIBUTED)- 分散对齐
业务价值: ⭐⭐⭐⭐ (中高)
2.7 缩进 (左/右/首行缩进)
检查内容: 缩进不符合要求
自动修正方法:
public static void fixIndent(String inputPath, String outputPath,
int leftChars, int rightChars, int firstLineChars) throws Exception {
Document doc = new Document(inputPath);
for (Section section : doc.getSections()) {
for (Paragraph paragraph : section.getBody().getParagraphs()) {
ParagraphFormat format = paragraph.getParagraphFormat();
format.setLeftIndent(leftChars * 12); // 字符转磅值
format.setRightIndent(rightChars * 12);
format.setFirstLineIndent(firstLineChars * 12);
}
}
doc.save(outputPath);
}
Aspose API:
ParagraphFormat.setLeftIndent(double points)- 左缩进ParagraphFormat.setRightIndent(double points)- 右缩进ParagraphFormat.setFirstLineIndent(double points)- 首行缩进(正值=首行缩进,负值=悬挂缩进)
业务价值: ⭐⭐⭐⭐ (中高)
3. TableRequirementsExamine - 表格要求检查
3.1 表格对齐方式 (tableAlignment)
检查内容: 表格对齐方式不符合要求
自动修正方法:
public static void fixTableAlignment(String inputPath, String outputPath, String alignmentDesc) throws Exception {
Document doc = new Document(inputPath);
int alignment = TableAlignment.LEFT;
if (alignmentDesc.contains("居中")) {
alignment = TableAlignment.CENTER;
} else if (alignmentDesc.contains("右")) {
alignment = TableAlignment.RIGHT;
}
for (Section section : doc.getSections()) {
NodeCollection tables = section.getBody().getChildNodes(NodeType.TABLE, true);
for (int i = 0; i < tables.getCount(); i++) {
Table table = (Table) tables.get(i);
table.setAlignment(alignment);
}
}
doc.save(outputPath);
}
Aspose API:
Table.setAlignment(TableAlignment.LEFT)- 左对齐Table.setAlignment(TableAlignment.CENTER)- 居中Table.setAlignment(TableAlignment.RIGHT)- 右对齐
业务价值: ⭐⭐⭐⭐ (中高)
3.2 单元格垂直对齐 (cellVerticalAlignment)
检查内容: 单元格垂直对齐方式不符合要求
自动修正方法:
public static void fixCellVerticalAlignment(String inputPath, String outputPath, String alignmentDesc) throws Exception {
Document doc = new Document(inputPath);
int verticalAlignment = CellVerticalAlignment.TOP;
if (alignmentDesc.contains("居中")) {
verticalAlignment = CellVerticalAlignment.CENTER;
} else if (alignmentDesc.contains("底端")) {
verticalAlignment = CellVerticalAlignment.BOTTOM;
}
for (Section section : doc.getSections()) {
NodeCollection tables = section.getBody().getChildNodes(NodeType.TABLE, true);
for (int i = 0; i < tables.getCount(); i++) {
Table table = (Table) tables.get(i);
for (Row row : table.getRows()) {
for (Cell cell : row.getCells()) {
cell.getCellFormat().setVerticalAlignment(verticalAlignment);
}
}
}
}
doc.save(outputPath);
}
Aspose API:
CellFormat.setVerticalAlignment(CellVerticalAlignment.TOP)- 顶端对齐CellFormat.setVerticalAlignment(CellVerticalAlignment.CENTER)- 居中CellFormat.setVerticalAlignment(CellVerticalAlignment.BOTTOM)- 底端对齐
业务价值: ⭐⭐⭐⭐ (中高)
3.3 表格边框 (borderWidth/borderColor)
检查内容: 表格边框宽度或颜色不符合要求
自动修正方法:
public static void fixTableBorders(String inputPath, String outputPath,
double borderWidth, java.awt.Color borderColor) throws Exception {
Document doc = new Document(inputPath);
for (Section section : doc.getSections()) {
NodeCollection tables = section.getBody().getChildNodes(NodeType.TABLE, true);
for (int i = 0; i < tables.getCount(); i++) {
Table table = (Table) tables.get(i);
// 设置表格所有边框
BorderCollection borders = table.getFirstRow().getRowFormat().getBorders();
for (Border border : borders) {
border.setLineWidth(borderWidth);
border.setColor(borderColor);
border.setLineStyle(LineStyle.SINGLE);
}
// 设置每个单元格边框
for (Row row : table.getRows()) {
for (Cell cell : row.getCells()) {
BorderCollection cellBorders = cell.getCellFormat().getBorders();
for (Border border : cellBorders) {
border.setLineWidth(borderWidth);
border.setColor(borderColor);
border.setLineStyle(LineStyle.SINGLE);
}
}
}
}
}
doc.save(outputPath);
}
Aspose API:
Border.setLineWidth(double points)- 设置边框宽度Border.setColor(java.awt.Color color)- 设置边框颜色Border.setLineStyle(LineStyle.SINGLE)- 设置边框样式
业务价值: ⭐⭐⭐⭐ (中高)
4. ImageRequirementsExamine - 图片要求检查
4.1 图片文字环绕 (wrapText)
检查内容: 图片文字环绕方式不符合要求
自动修正方法:
public static void fixImageWrapText(String inputPath, String outputPath, String wrapTextDesc) throws Exception {
Document doc = new Document(inputPath);
int wrapType = WrapType.INLINE;
if (wrapTextDesc.contains("四周")) {
wrapType = WrapType.SQUARE;
} else if (wrapTextDesc.contains("紧密")) {
wrapType = WrapType.TIGHT;
} else if (wrapTextDesc.contains("穿越")) {
wrapType = WrapType.THROUGH;
} else if (wrapTextDesc.contains("上下")) {
wrapType = WrapType.TOP_BOTTOM;
} else if (wrapTextDesc.contains("衬于文字下方")) {
wrapType = WrapType.NONE; // Behind text
} else if (wrapTextDesc.contains("浮于文字上方")) {
wrapType = WrapType.NONE; // In front of text
}
NodeCollection shapes = doc.getChildNodes(NodeType.SHAPE, true);
for (int i = 0; i < shapes.getCount(); i++) {
Shape shape = (Shape) shapes.get(i);
if (shape.hasImage()) {
shape.setWrapType(wrapType);
}
}
doc.save(outputPath);
}
Aspose API:
Shape.setWrapType(WrapType.INLINE)- 嵌入型Shape.setWrapType(WrapType.SQUARE)- 四周型Shape.setWrapType(WrapType.TIGHT)- 紧密型Shape.setWrapType(WrapType.THROUGH)- 穿越型Shape.setWrapType(WrapType.TOP_BOTTOM)- 上下型
业务价值: ⭐⭐⭐⭐ (中高)
5. PageNumberRequirementsExamine - 页码要求检查
5.1 页码字体 (中文/西文/字号)
检查内容: 页码字体不符合要求
自动修正方法:
public static void fixPageNumberFont(String inputPath, String outputPath,
String chineseFont, String westernFont, double fontSize) throws Exception {
Document doc = new Document(inputPath);
for (Section section : doc.getSections()) {
HeaderFooterCollection headersFooters = section.getHeadersFooters();
for (HeaderFooter headerFooter : headersFooters) {
for (Paragraph paragraph : headerFooter.getParagraphs()) {
for (Run run : paragraph.getRuns()) {
Font font = run.getFont();
font.setNameFarEast(chineseFont); // 中文字体
font.setNameAscii(westernFont); // 西文字体
font.setSize(fontSize); // 字号
}
}
}
}
doc.save(outputPath);
}
Aspose API: 同字体设置
业务价值: ⭐⭐⭐ (中)
5.2 页码编号格式 (numberingFormat)
检查内容: 页码编号格式不符合要求
自动修正方法:
public static void fixPageNumberFormat(String inputPath, String outputPath, String formatDesc) throws Exception {
Document doc = new Document(inputPath);
int numberStyle = NumberStyle.ARABIC;
if (formatDesc.contains("I,II,III")) {
numberStyle = NumberStyle.UPPERCASE_ROMAN;
} else if (formatDesc.contains("i,ii,iii")) {
numberStyle = NumberStyle.LOWERCASE_ROMAN;
} else if (formatDesc.contains("一,二,三")) {
numberStyle = NumberStyle.CHINESE_COUNTING;
}
for (Section section : doc.getSections()) {
section.getPageSetup().setPageNumberStyle(numberStyle);
}
doc.save(outputPath);
}
Aspose API:
PageSetup.setPageNumberStyle(NumberStyle.ARABIC)- 阿拉伯数字 1,2,3PageSetup.setPageNumberStyle(NumberStyle.UPPERCASE_ROMAN)- 罗马数字 I,II,IIIPageSetup.setPageNumberStyle(NumberStyle.LOWERCASE_ROMAN)- 罗马数字 i,ii,iiiPageSetup.setPageNumberStyle(NumberStyle.CHINESE_COUNTING)- 中文数字 一,二,三
业务价值: ⭐⭐⭐ (中)
6. TocRequirementsExamine - 目录要求检查
6.1 目录字体/段落格式
检查内容: 目录的字体、行距、缩进等不符合要求
自动修正方法:
public static void fixTocFormatting(String inputPath, String outputPath,
String chineseFont, String westernFont, double fontSize,
double lineSpacing, double leftIndent) throws Exception {
Document doc = new Document(inputPath);
for (Section section : doc.getSections()) {
for (Paragraph paragraph : section.getBody().getParagraphs()) {
String styleName = paragraph.getParagraphFormat().getStyleName();
// 只处理目录样式的段落
if (styleName != null && (styleName.toLowerCase().contains("toc") ||
styleName.toLowerCase().contains("目录"))) {
// 设置字体
for (Run run : paragraph.getRuns()) {
run.getFont().setNameFarEast(chineseFont);
run.getFont().setNameAscii(westernFont);
run.getFont().setSize(fontSize);
}
// 设置段落格式
ParagraphFormat format = paragraph.getParagraphFormat();
format.setLineSpacing(lineSpacing);
format.setLeftIndent(leftIndent);
}
}
}
doc.save(outputPath);
}
Aspose API: 同字体和段落格式设置
业务价值: ⭐⭐⭐ (中)
7. DefaultChecksExamine - 默认检查
7.1 字体样式 (加粗/下划线/倾斜/删除线/着重号)
检查内容: 不允许使用加粗、下划线等样式
自动修正方法:
public static void removeTextFormatting(String inputPath, String outputPath) throws Exception {
Document doc = new Document(inputPath);
for (Section section : doc.getSections()) {
for (Paragraph paragraph : section.getBody().getParagraphs()) {
for (Run run : paragraph.getRuns()) {
Font font = run.getFont();
font.setBold(false); // 取消加粗
font.setUnderline(Underline.NONE); // 取消下划线
font.setItalic(false); // 取消倾斜
font.setStrikeThrough(false); // 取消删除线
font.setEmphasisMark(EmphasisMark.NONE); // 取消着重号
}
}
}
doc.save(outputPath);
}
Aspose API:
Font.setBold(boolean value)- 加粗Font.setUnderline(Underline.NONE)- 下划线Font.setItalic(boolean value)- 倾斜Font.setStrikeThrough(boolean value)- 删除线Font.setEmphasisMark(EmphasisMark.NONE)- 着重号
业务价值: ⭐⭐⭐⭐ (中高)
7.2 字体颜色 (allowedColor)
检查内容: 字体颜色不符合要求
自动修正方法:
public static void fixFontColor(String inputPath, String outputPath, java.awt.Color targetColor) throws Exception {
Document doc = new Document(inputPath);
for (Section section : doc.getSections()) {
for (Paragraph paragraph : section.getBody().getParagraphs()) {
for (Run run : paragraph.getRuns()) {
run.getFont().setColor(targetColor);
}
}
}
doc.save(outputPath);
}
Aspose API:
Font.setColor(java.awt.Color color)- 设置字体颜色- 常用颜色:
Color.BLACK,Color.RED,new Color(0, 0, 0)
业务价值: ⭐⭐⭐ (中)
7.3 文档网格 (requireSnapToGrid)
检查内容: 文档网格设置不符合要求
自动修正方法:
public static void fixDocumentGrid(String inputPath, String outputPath, String gridType) throws Exception {
Document doc = new Document(inputPath);
int layoutMode = SectionLayoutMode.DEFAULT;
if (gridType.contains("只指定行网格")) {
layoutMode = SectionLayoutMode.LINE_GRID;
} else if (gridType.contains("文字对齐字符网格")) {
layoutMode = SectionLayoutMode.SNAP_TO_CHARS;
}
for (Section section : doc.getSections()) {
section.getPageSetup().setLayoutMode(layoutMode);
}
doc.save(outputPath);
}
Aspose API:
PageSetup.setLayoutMode(SectionLayoutMode.DEFAULT)- 无网格PageSetup.setLayoutMode(SectionLayoutMode.LINE_GRID)- 只指定行网格PageSetup.setLayoutMode(SectionLayoutMode.SNAP_TO_CHARS)- 文字对齐字符网格
业务价值: ⭐⭐⭐ (中)
❌ 无法自动修正的检查项 (只读检查)
1. ColorRequirementsExamine - 颜色要求检查
1.1 彩色图片检测 (disallowColoredImages)
检查内容: 文档不允许包含彩色图片
无法自动修正的原因:
- Aspose.Words 不支持图片灰度转换
- 需要使用图像处理库(如 ImageMagick, Java ImageIO)
- 业务逻辑复杂: 是否保留原图尺寸、质量、格式
建议方案:
- 集成第三方图像处理库
- 提取图片 → 转换为灰度 → 替换回文档
业务价值: ⭐⭐⭐ (中 - 需求较少)
1.2 彩色文本检测 (disallowColoredText)
检查内容: 文档不允许包含彩色文本
技术上可修正但业务逻辑不明确:
- 可以通过
Font.setColor(Color.BLACK)修改为黑色 - 但检查项是"不允许彩色",没有明确要改成什么颜色
- 需要业务确认: 统一改为黑色? 还是保持检测?
建议: 归入"可自动修正",统一改为黑色
1.3 彩色表格检测 (disallowColoredTables)
检查内容: 表格不允许包含彩色背景或边框
同上,技术可行但业务逻辑需确认
2. TableRequirementsExamine - 表格要求检查
2.1 不允许出现表格 (disallowTables)
检查内容: 文档不允许包含表格
无法自动修正的原因:
- 删除表格需要业务决策: 是否保留表格内容?
- 将表格转换为普通文本会丢失结构信息
- 业务影响大,不适合自动化
建议方案: 仅检测,人工处理
2.2 表格标题要求 (tableTitle)
检查内容: 表格缺少标题
无法自动修正的原因:
- 无法自动生成有意义的标题
- 标题内容需要人工编写
建议方案: 仅检测,人工补充标题
3. ImageRequirementsExamine - 图片要求检查
3.1 不允许出现图片 (disallowImages)
检查内容: 文档不允许包含图片
无法自动修正的原因:
- 删除图片需要业务决策
- 业务影响大,不适合自动化
建议方案: 仅检测,人工处理
4. DefaultChecksExamine - 默认检查
4.1 不允许超链接 (disallowHyperlinks)
检查内容: 文档不允许包含超链接
技术上可修正但需业务确认:
// 可以移除超链接但保留显示文本
for (Field field : doc.getRange().getFields()) {
if (field.getType() == FieldType.FIELD_HYPERLINK) {
field.unlink(); // 移除超链接,保留文本
}
}
建议: 归入"可自动修正" - 移除超链接保留文本
4.2 不允许图形 (disallowShapes)
检查内容: 文档不允许包含图形(非图片的Shape对象)
无法自动修正的原因:
- 删除图形需要业务决策
- 图形可能包含重要信息(如流程图、组织架构图)
建议方案: 仅检测,人工处理
4.3 不允许水印 (disallowWatermark)
检查内容: 文档不允许包含水印
技术上可修正:
// 可以删除水印
for (Section section : doc.getSections()) {
HeaderFooterCollection headers = section.getHeadersFooters();
for (HeaderFooter header : headers) {
NodeCollection shapes = header.getChildNodes(NodeType.SHAPE, true);
for (int i = shapes.getCount() - 1; i >= 0; i--) {
Shape shape = (Shape) shapes.get(i);
if (shape.getName() != null && shape.getName().toLowerCase().contains("watermark")) {
shape.remove();
}
}
}
}
建议: 归入"可自动修正" - 删除水印
5. PageNumberRequirementsExamine - 页码要求检查
5.1 不允许插入页码 (disallowPageNumbers)
检查内容: 文档不允许包含页码
技术上可修正:
// 可以删除所有页码字段
for (Section section : doc.getSections()) {
HeaderFooterCollection headersFooters = section.getHeadersFooters();
for (HeaderFooter headerFooter : headersFooters) {
for (Field field : headerFooter.getRange().getFields()) {
if (field.getType() == FieldType.FIELD_PAGE) {
field.remove();
}
}
}
}
建议: 归入"可自动修正" - 删除页码
5.2 页码范围检查 (缺少页码)
检查内容: 某些页面缺少页码
无法自动修正的原因:
- 无法自动判断应该在哪个位置插入页码(页眉?页脚?)
- 页码格式、起始编号等需要业务确认
建议方案: 仅检测,人工添加页码
6. TocRequirementsExamine - 目录要求检查
6.1 不允许插入目录 (disallowToc)
检查内容: 文档不允许包含目录
技术上可修正:
// 可以删除目录字段
for (Field field : doc.getRange().getFields()) {
if (field.getType() == FieldType.FIELD_TOC) {
field.remove();
}
}
建议: 归入"可自动修正" - 删除目录
6.2 目录不显示页码 (tocHidePageNumbers)
检查内容: 目录不应显示页码
技术复杂度高:
- 需要更新TOC字段代码,移除
\h或\p开关 - 需要调用
field.update()刷新目录 - 可能影响目录结构
建议: 归入"可自动修正" (中等难度)
7. ProhibitedItemsExamine - 不允许出现项目检查
7.1 不允许空行 (disallowBlankLines)
检查内容: 文档不允许包含空行
无法自动修正的原因:
- 业务逻辑不明确: 删除所有空行?还是只删除连续空行?
- 某些空行可能有排版意义(如章节分隔)
- 删除空行可能影响文档结构
建议方案: 仅检测,人工处理
7.2 不允许空格 (disallowSpaces)
检查内容: 文档不允许包含空格
技术上可修正但业务影响大:
// 可以删除所有空格
for (Run run : ...) {
String text = run.getText();
run.setText(text.replaceAll(" ", "").replaceAll("\u3000", ""));
}
无法自动修正的原因:
- 删除所有空格会导致中英文混排错误
- 可能破坏文档可读性(如"Hello World" → "HelloWorld")
建议方案: 仅检测,人工处理
7.3 不允许空白页 (disallowBlankPages)
检查内容: 文档不允许包含空白页
无法自动修正的原因:
- 空白页可能是分节符、分页符导致的
- 删除空白页可能影响文档结构(如封面后的空白页)
- 需要业务确认是否保留
建议方案: 仅检测,人工处理
7.4 不允许半角标点 (disallowHalfwidthPunctuation)
检查内容: 文档不允许包含半角标点符号
技术上可修正:
// 可以将半角标点替换为全角
Map<String, String> map = new HashMap<>();
map.put("!", "!");
map.put("\"", """);
map.put("'", "'");
map.put("(", "(");
map.put(")", ")");
map.put(",", ",");
map.put(":", ":");
map.put(";", ";");
map.put("?", "?");
for (Run run : ...) {
String text = run.getText();
for (Map.Entry<String, String> entry : map.entrySet()) {
text = text.replace(entry.getKey(), entry.getValue());
}
run.setText(text);
}
建议: 归入"可自动修正" - 半角转全角
📊 总结统计
可自动修正的检查项: 28项
| 检查类别 | 可修正项数 | 主要修正内容 |
|---|---|---|
| PaperRequirementsExamine | 6 | 纸张大小、方向、四边边距 |
| ContentRequirementsExamine | 10 | 字体(中文/西文/字号)、行距、段前/段后间距、对齐、缩进 |
| TableRequirementsExamine | 3 | 表格对齐、单元格垂直对齐、边框 |
| ImageRequirementsExamine | 1 | 图片文字环绕 |
| PageNumberRequirementsExamine | 2 | 页码字体、编号格式 |
| TocRequirementsExamine | 1 | 目录字体/段落格式 |
| DefaultChecksExamine | 5 | 字体样式(加粗/下划线等)、字体颜色、文档网格 |
无法自动修正的检查项: 12项
| 检查类别 | 无法修正项数 | 主要原因 |
|---|---|---|
| ColorRequirementsExamine | 1 | 图片灰度转换需要第三方库 |
| TableRequirementsExamine | 2 | 删除表格/生成标题需要业务决策 |
| ImageRequirementsExamine | 1 | 删除图片需要业务决策 |
| DefaultChecksExamine | 2 | 删除图形需要业务决策 |
| PageNumberRequirementsExamine | 1 | 添加页码需要业务决策 |
| ProhibitedItemsExamine | 4 | 删除空行/空格/空白页影响大 |
| TocRequirementsExamine | 1 | 删除目录需要业务决策 |
可选实现的检查项(技术可行但需业务确认): 7项
| 检查项 | 建议处理方式 |
|---|---|
| 彩色文本 | 统一改为黑色 |
| 彩色表格 | 移除背景色和边框颜色 |
| 超链接 | 移除超链接保留文本 |
| 水印 | 删除水印 |
| 页码(不允许) | 删除所有页码 |
| 目录(不允许) | 删除目录 |
| 半角标点 | 半角转全角 |
🔧 实现建议
1. 创建统一的文档修正工具类
package org.dromara.review.utils;
import com.aspose.words.*;
import java.awt.Color;
/**
* 文档自动修正工具类
* 基于 Aspose.Words API 实现文档格式自动修正
*/
public class DocumentAutoCorrector {
/**
* 修正纸张大小和方向
*/
public static void fixPaperSettings(Document doc, PaperSize size, Orientation orientation) throws Exception {
for (Section section : doc.getSections()) {
PageSetup pageSetup = section.getPageSetup();
pageSetup.setPaperSize(size);
pageSetup.setOrientation(orientation);
}
}
/**
* 修正页边距
*/
public static void fixMargins(Document doc, double top, double bottom, double left, double right) throws Exception {
for (Section section : doc.getSections()) {
PageSetup pageSetup = section.getPageSetup();
pageSetup.setTopMargin(top);
pageSetup.setBottomMargin(bottom);
pageSetup.setLeftMargin(left);
pageSetup.setRightMargin(right);
}
}
/**
* 修正字体(中文/西文/字号)
*/
public static void fixFont(Document doc, String chineseFont, String westernFont, double fontSize) throws Exception {
for (Section section : doc.getSections()) {
for (Paragraph paragraph : section.getBody().getParagraphs()) {
for (Run run : paragraph.getRuns()) {
Font font = run.getFont();
if (chineseFont != null) font.setNameFarEast(chineseFont);
if (westernFont != null) font.setNameAscii(westernFont);
if (fontSize > 0) font.setSize(fontSize);
}
}
}
}
/**
* 修正段落格式(行距/对齐/缩进)
*/
public static void fixParagraphFormat(Document doc,
double lineSpacing, int lineSpacingRule,
int alignment,
double leftIndent, double rightIndent, double firstLineIndent) throws Exception {
for (Section section : doc.getSections()) {
for (Paragraph paragraph : section.getBody().getParagraphs()) {
ParagraphFormat format = paragraph.getParagraphFormat();
if (lineSpacing > 0) {
format.setLineSpacingRule(lineSpacingRule);
format.setLineSpacing(lineSpacing);
}
if (alignment >= 0) format.setAlignment(alignment);
if (leftIndent >= 0) format.setLeftIndent(leftIndent);
if (rightIndent >= 0) format.setRightIndent(rightIndent);
if (firstLineIndent != 0) format.setFirstLineIndent(firstLineIndent);
}
}
}
/**
* 修正表格格式(对齐/边框)
*/
public static void fixTableFormat(Document doc,
int tableAlignment,
int cellVerticalAlignment,
double borderWidth, Color borderColor) throws Exception {
for (Section section : doc.getSections()) {
NodeCollection tables = section.getBody().getChildNodes(NodeType.TABLE, true);
for (int i = 0; i < tables.getCount(); i++) {
Table table = (Table) tables.get(i);
if (tableAlignment >= 0) table.setAlignment(tableAlignment);
for (Row row : table.getRows()) {
for (Cell cell : row.getCells()) {
if (cellVerticalAlignment >= 0) {
cell.getCellFormat().setVerticalAlignment(cellVerticalAlignment);
}
if (borderWidth > 0) {
BorderCollection borders = cell.getCellFormat().getBorders();
for (Border border : borders) {
border.setLineWidth(borderWidth);
if (borderColor != null) border.setColor(borderColor);
border.setLineStyle(LineStyle.SINGLE);
}
}
}
}
}
}
}
/**
* 修正图片文字环绕
*/
public static void fixImageWrapText(Document doc, int wrapType) throws Exception {
NodeCollection shapes = doc.getChildNodes(NodeType.SHAPE, true);
for (int i = 0; i < shapes.getCount(); i++) {
Shape shape = (Shape) shapes.get(i);
if (shape.hasImage()) {
shape.setWrapType(wrapType);
}
}
}
/**
* 移除文本格式(加粗/下划线/倾斜等)
*/
public static void removeTextFormatting(Document doc) throws Exception {
for (Section section : doc.getSections()) {
for (Paragraph paragraph : section.getBody().getParagraphs()) {
for (Run run : paragraph.getRuns()) {
Font font = run.getFont();
font.setBold(false);
font.setUnderline(Underline.NONE);
font.setItalic(false);
font.setStrikeThrough(false);
font.setEmphasisMark(EmphasisMark.NONE);
}
}
}
}
/**
* 综合修正方法 - 根据检查结果一次性修正多个问题
*/
public static void autoCorrect(String inputPath, String outputPath, CorrectionConfig config) throws Exception {
Document doc = new Document(inputPath);
// 修正纸张设置
if (config.shouldFixPaper()) {
fixPaperSettings(doc, config.getPaperSize(), config.getOrientation());
fixMargins(doc, config.getTopMargin(), config.getBottomMargin(),
config.getLeftMargin(), config.getRightMargin());
}
// 修正字体
if (config.shouldFixFont()) {
fixFont(doc, config.getChineseFont(), config.getWesternFont(), config.getFontSize());
}
// 修正段落格式
if (config.shouldFixParagraph()) {
fixParagraphFormat(doc, config.getLineSpacing(), config.getLineSpacingRule(),
config.getAlignment(), config.getLeftIndent(),
config.getRightIndent(), config.getFirstLineIndent());
}
// 修正表格格式
if (config.shouldFixTable()) {
fixTableFormat(doc, config.getTableAlignment(), config.getCellVerticalAlignment(),
config.getBorderWidth(), config.getBorderColor());
}
// 修正图片环绕
if (config.shouldFixImage()) {
fixImageWrapText(doc, config.getWrapType());
}
// 移除文本格式
if (config.shouldRemoveTextFormatting()) {
removeTextFormatting(doc);
}
doc.save(outputPath);
}
}
/**
* 修正配置类
*/
class CorrectionConfig {
// 纸张设置
private boolean fixPaper;
private PaperSize paperSize;
private Orientation orientation;
private double topMargin, bottomMargin, leftMargin, rightMargin;
// 字体设置
private boolean fixFont;
private String chineseFont, westernFont;
private double fontSize;
// 段落设置
private boolean fixParagraph;
private double lineSpacing;
private int lineSpacingRule, alignment;
private double leftIndent, rightIndent, firstLineIndent;
// 表格设置
private boolean fixTable;
private int tableAlignment, cellVerticalAlignment;
private double borderWidth;
private Color borderColor;
// 图片设置
private boolean fixImage;
private int wrapType;
// 其他设置
private boolean removeTextFormatting;
// Getters and Setters...
}
2. 集成到现有检查流程
修改 DocExamine.java:
public class DocExamine {
/**
* 执行检查并收集可自动修正的问题
*/
public Map<String, Object> examineAndCollectCorrections(Document doc, CheckConfig config) {
Map<String, Object> result = new HashMap<>();
Map<String, Map<String, JSONArray>> issues = new HashMap<>();
CorrectionConfig correctionConfig = new CorrectionConfig();
// 执行各项检查
// ... 现有检查逻辑 ...
// 根据检查结果填充 correctionConfig
if (hasIssue(issues, "paperRequirements", "paperSize")) {
correctionConfig.setFixPaper(true);
correctionConfig.setPaperSize(config.getPaperSize());
}
// ... 其他检查项 ...
result.put("issues", issues);
result.put("correctionConfig", correctionConfig);
result.put("canAutoCorrect", correctionConfig.hasAnyCorrection());
return result;
}
/**
* 一键自动修正
*/
public void autoCorrect(String inputPath, String outputPath, CorrectionConfig config) throws Exception {
DocumentAutoCorrector.autoCorrect(inputPath, outputPath, config);
}
}
3. 前端交互流程
1. 用户上传文档
↓
2. 后端执行检查,返回检查结果 + 可自动修正项列表
↓
3. 前端展示:
- ✅ 可自动修正: [纸张大小、字体、行距...] (绿色,带"一键修正"按钮)
- ❌ 需要人工处理: [删除表格、添加标题...] (黄色,提示手动处理)
↓
4. 用户点击"一键修正"
↓
5. 后端调用 DocumentAutoCorrector.autoCorrect()
↓
6. 返回修正后的文档下载链接
↓
7. (可选)用户下载修正后文档,手动处理剩余问题后重新上传
📝 实施优先级建议
高优先级 (⭐⭐⭐⭐⭐)
- 纸张大小和方向 - 最常见需求
- 页边距 - 标书必备
- 字体(中文/西文/字号) - 标书必备
- 行距 - 常见需求
- 段落对齐和缩进 - 常见需求
中优先级 (⭐⭐⭐⭐)
- 表格对齐和边框 - 提升文档美观度
- 图片文字环绕 - 改善排版
- 移除文本格式 - 规范化文档
- 字体颜色 - 规范化需求
低优先级 (⭐⭐⭐)
- 页码格式 - 需求较少
- 目录格式 - 需求较少
- 文档网格 - 专业需求
⚠️ 注意事项
1. 文档备份
- 自动修正前务必备份原文档
- 提供"撤销修正"功能
2. 修正范围控制
- 支持按页/按节/全文修正
- 避免影响封面、目录等特殊页面
3. 性能优化
- 大文档(>100页)分批处理
- 提供进度条反馈
4. 异常处理
- 捕获 Aspose.Words 异常
- 提供友好的错误提示
5. 测试覆盖
- 准备各种格式的测试文档
- 测试修正前后文档的一致性
📚 相关资源
报告生成时间: 2026-02-11 分析文件数量: 8个检查类 可自动修正检查项: 28项 无法自动修正检查项: 12项 可选实现检查项: 7项