Files
ai_dify_plat_api/文档自动修正分析报告.md
2026-06-01 16:31:17 +08:00

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) - 设置为A4
  • PageSetup.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,3
  • PageSetup.setPageNumberStyle(NumberStyle.UPPERCASE_ROMAN) - 罗马数字 I,II,III
  • PageSetup.setPageNumberStyle(NumberStyle.LOWERCASE_ROMAN) - 罗马数字 i,ii,iii
  • PageSetup.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 - 默认检查

检查内容: 文档不允许包含超链接

技术上可修正但需业务确认:

// 可以移除超链接但保留显示文本
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. 字体(中文/西文/字号) - 标书必备
  4. 行距 - 常见需求
  5. 段落对齐和缩进 - 常见需求

中优先级 ()

  1. 表格对齐和边框 - 提升文档美观度
  2. 图片文字环绕 - 改善排版
  3. 移除文本格式 - 规范化文档
  4. 字体颜色 - 规范化需求

低优先级 ()

  1. 页码格式 - 需求较少
  2. 目录格式 - 需求较少
  3. 文档网格 - 专业需求

⚠️ 注意事项

1. 文档备份

  • 自动修正前务必备份原文档
  • 提供"撤销修正"功能

2. 修正范围控制

  • 支持按页/按节/全文修正
  • 避免影响封面、目录等特殊页面

3. 性能优化

  • 大文档(>100页)分批处理
  • 提供进度条反馈

4. 异常处理

  • 捕获 Aspose.Words 异常
  • 提供友好的错误提示

5. 测试覆盖

  • 准备各种格式的测试文档
  • 测试修正前后文档的一致性

📚 相关资源


报告生成时间: 2026-02-11 分析文件数量: 8个检查类 可自动修正检查项: 28项 无法自动修正检查项: 12项 可选实现检查项: 7项