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

1425 lines
44 KiB
Markdown

# 文档自动修正分析报告
## 概述
本报告基于 `f:\api0203\ai_check\src\main\java\org\dromara\aiCheck\docExamine\examines\` 目录下的所有检查类,分析哪些文档检查项可以通过 Aspose.Words API 自动修正。
参考实现示例:[AsposeWordPageSizeConverter.java](ruoyi-modules/ai-intelligent-review/src/main/java/org/dromara/review/utils/AsposeWordPageSizeConverter.java):convertToA3
---
## ✅ 可自动修正的检查项
### 1. PaperRequirementsExamine - 纸张要求检查
#### 1.1 纸张大小 (paperSize)
**检查内容**: 文档纸张不符合要求(如要求A4,实际为A3)
**自动修正方法**:
```java
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)
**检查内容**: 文档方向不符合要求(如要求横向,实际为纵向)
**自动修正方法**:
```java
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)
**检查内容**: 上/下/左/右页边距不符合要求
**自动修正方法**:
```java
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)
**检查内容**: 中文文本字体不符合要求(如要求宋体,实际为黑体)
**自动修正方法**:
```java
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)
**检查内容**: 西文文本字体不符合要求
**自动修正方法**:
```java
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)
**检查内容**: 字号不符合要求(如要求小四,实际为五号)
**自动修正方法**:
```java
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倍行距,实际为单倍行距)
**自动修正方法**:
```java
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)
**检查内容**: 段前或段后间距不符合要求
**自动修正方法**:
```java
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)
**检查内容**: 段落对齐方式不符合要求
**自动修正方法**:
```java
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 缩进 (左/右/首行缩进)
**检查内容**: 缩进不符合要求
**自动修正方法**:
```java
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)
**检查内容**: 表格对齐方式不符合要求
**自动修正方法**:
```java
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)
**检查内容**: 单元格垂直对齐方式不符合要求
**自动修正方法**:
```java
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)
**检查内容**: 表格边框宽度或颜色不符合要求
**自动修正方法**:
```java
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)
**检查内容**: 图片文字环绕方式不符合要求
**自动修正方法**:
```java
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 页码字体 (中文/西文/字号)
**检查内容**: 页码字体不符合要求
**自动修正方法**:
```java
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)
**检查内容**: 页码编号格式不符合要求
**自动修正方法**:
```java
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 目录字体/段落格式
**检查内容**: 目录的字体、行距、缩进等不符合要求
**自动修正方法**:
```java
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 字体样式 (加粗/下划线/倾斜/删除线/着重号)
**检查内容**: 不允许使用加粗、下划线等样式
**自动修正方法**:
```java
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)
**检查内容**: 字体颜色不符合要求
**自动修正方法**:
```java
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)
**检查内容**: 文档网格设置不符合要求
**自动修正方法**:
```java
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)
**检查内容**: 文档不允许包含超链接
**技术上可修正但需业务确认**:
```java
// 可以移除超链接但保留显示文本
for (Field field : doc.getRange().getFields()) {
if (field.getType() == FieldType.FIELD_HYPERLINK) {
field.unlink(); // 移除超链接,保留文本
}
}
```
**建议**: 归入"可自动修正" - 移除超链接保留文本
---
#### 4.2 不允许图形 (disallowShapes)
**检查内容**: 文档不允许包含图形(非图片的Shape对象)
**无法自动修正的原因**:
- 删除图形需要业务决策
- 图形可能包含重要信息(如流程图、组织架构图)
**建议方案**: 仅检测,人工处理
---
#### 4.3 不允许水印 (disallowWatermark)
**检查内容**: 文档不允许包含水印
**技术上可修正**:
```java
// 可以删除水印
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)
**检查内容**: 文档不允许包含页码
**技术上可修正**:
```java
// 可以删除所有页码字段
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)
**检查内容**: 文档不允许包含目录
**技术上可修正**:
```java
// 可以删除目录字段
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)
**检查内容**: 文档不允许包含空格
**技术上可修正但业务影响大**:
```java
// 可以删除所有空格
for (Run run : ...) {
String text = run.getText();
run.setText(text.replaceAll(" ", "").replaceAll("\u3000", ""));
}
```
**无法自动修正的原因**:
- 删除所有空格会导致中英文混排错误
- 可能破坏文档可读性(如"Hello World" → "HelloWorld")
**建议方案**: 仅检测,人工处理
---
#### 7.3 不允许空白页 (disallowBlankPages)
**检查内容**: 文档不允许包含空白页
**无法自动修正的原因**:
- 空白页可能是分节符、分页符导致的
- 删除空白页可能影响文档结构(如封面后的空白页)
- 需要业务确认是否保留
**建议方案**: 仅检测,人工处理
---
#### 7.4 不允许半角标点 (disallowHalfwidthPunctuation)
**检查内容**: 文档不允许包含半角标点符号
**技术上可修正**:
```java
// 可以将半角标点替换为全角
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. 创建统一的文档修正工具类
```java
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`:
```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. **段落对齐和缩进** - 常见需求
### 中优先级 (⭐⭐⭐⭐)
6. **表格对齐和边框** - 提升文档美观度
7. **图片文字环绕** - 改善排版
8. **移除文本格式** - 规范化文档
9. **字体颜色** - 规范化需求
### 低优先级 (⭐⭐⭐)
10. **页码格式** - 需求较少
11. **目录格式** - 需求较少
12. **文档网格** - 专业需求
---
## ⚠️ 注意事项
### 1. 文档备份
- 自动修正前务必备份原文档
- 提供"撤销修正"功能
### 2. 修正范围控制
- 支持按页/按节/全文修正
- 避免影响封面、目录等特殊页面
### 3. 性能优化
- 大文档(>100页)分批处理
- 提供进度条反馈
### 4. 异常处理
- 捕获 Aspose.Words 异常
- 提供友好的错误提示
### 5. 测试覆盖
- 准备各种格式的测试文档
- 测试修正前后文档的一致性
---
## 📚 相关资源
- [Aspose.Words Java API 文档](https://reference.aspose.com/words/java/)
- [PageSetup 类参考](https://reference.aspose.com/words/java/com.aspose.words/pagesetup/)
- [Font 类参考](https://reference.aspose.com/words/java/com.aspose.words/font/)
- [ParagraphFormat 类参考](https://reference.aspose.com/words/java/com.aspose.words/paragraphformat/)
- [Table 类参考](https://reference.aspose.com/words/java/com.aspose.words/table/)
---
**报告生成时间**: 2026-02-11
**分析文件数量**: 8个检查类
**可自动修正检查项**: 28项
**无法自动修正检查项**: 12项
**可选实现检查项**: 7项