模糊评价报告PDF下载新接口 - 使用说明

📋 接口信息

新增接口

  • 接口路径: /admin/stat/report/fuzzyReportPdfNew
  • 请求方法: GET
  • 接口描述: 模糊评价报告PDF下载(新接口)
  • 认证要求: 无需认证(@IgnoreAuth)

请求参数

参数名 类型 必填 说明
checkTaskId Integer 是 检查任务ID
templateId Integer 是 报告模版ID

响应说明

  • Content-Type: application/pdf
  • 响应方式: 文件下载
  • 文件名格式: {项目名称}_{模板名称}_模糊评价.pdf

🔄 新旧接口对比

旧接口:/fuzzyReportPdf

@GetMapping("/fuzzyReportPdf")
public void fuzzyReportPdf(Integer checkTaskId, Integer templateId, HttpServletResponse response) {
    downloadPdf(checkTaskId, templateId, response, "模糊评价", true);
}

处理流程:
1. 调用 reportService.fuzzyReportPdf()
2. 在 Service 层生成 Word 并转换为 PDF
3. 直接输出 PDF 到响应流


新接口:/fuzzyReportPdfNew

@GetMapping("/fuzzyReportPdfNew")
public void fuzzyReportPdfNew(Integer checkTaskId, Integer templateId, HttpServletResponse response) {
    try (var doc = reportService.fuzzyReport(checkTaskId, templateId)) {
        downloadAsPdf(doc, response, "模糊评价", checkTaskId, templateId);
    }
}

处理流程:
1. 调用 reportService.fuzzyReport() 获取 Word 文档
2. 在 Controller 层将 Word 转换为 PDF
3. 输出 PDF 到响应流


🎯 核心实现

downloadAsPdf 方法

private void downloadAsPdf(XWPFTemplate doc, HttpServletResponse response, String typeName,
                           Integer checkTaskId, Integer templateId) throws IOException {
    ByteArrayOutputStream docOutputStream = null;
    ByteArrayInputStream docInputStream = null;
    XWPFDocument document = null;
    OutputStream out = null;
    BufferedOutputStream bos = null;

    try {
        // 1. 获取任务和模板信息
        var checkTask = checkTaskService.get(checkTaskId, true);
        var reportTemplate = reportTemplateService.get(templateId);
        BizResultCode.TASK_NOT_FOUND.check(checkTask == null);

        // 2. 设置响应头
        var docName = checkTask.getProject().getName() + "_" + reportTemplate.getName() + "_" + typeName;
        String encodedFileName = URLEncoder.encode(docName, "UTF-8");
        response.setContentType("application/pdf");
        response.setHeader("Content-disposition", "attachment;filename=\"" + encodedFileName + ".pdf\"");

        // 3. 将Word模板写入字节数组
        docOutputStream = new ByteArrayOutputStream();
        doc.write(docOutputStream);

        // 4. 从字节数组读取Word文档
        docInputStream = new ByteArrayInputStream(docOutputStream.toByteArray());
        document = new XWPFDocument(docInputStream);

        // 5. 配置PDF选项
        PdfOptions options = PdfOptions.create();
        options.fontEncoding("UTF-8");

        // 6. 转换为PDF并写入响应流
        out = response.getOutputStream();
        bos = new BufferedOutputStream(out);
        PdfConverter.getInstance().convert(document, bos, options);

        bos.flush();
        out.flush();

    } catch (Exception e) {
        log.error("Word转PDF失败", e);
        throw new IOException("Word转PDF失败: " + e.getMessage(), e);
    } finally {
        // 7. 完善的资源清理
        if (document != null) {
            try { document.close(); }
            catch (Exception e) { log.warn("关闭Word文档失败", e); }
        }
        if (docInputStream != null) {
            try { docInputStream.close(); }
            catch (Exception e) { log.warn("关闭输入流失败", e); }
        }
        if (docOutputStream != null) {
            try { docOutputStream.close(); }
            catch (Exception e) { log.warn("关闭输出流失败", e); }
        }
    }
}

🧪 测试方法

1. 使用浏览器测试

http://localhost:8080/admin/stat/report/fuzzyReportPdfNew?checkTaskId=1262&templateId=1

2. 使用 curl 测试

# 下载PDF文件
curl -o "模糊评价报告_新接口.pdf" \
  "http://localhost:8080/admin/stat/report/fuzzyReportPdfNew?checkTaskId=1262&templateId=1"

# 检查文件大小
ls -lh 模糊评价报告_新接口.pdf

# 打开PDF文件检查内容
start 模糊评价报告_新接口.pdf  # Windows
open 模糊评价报告_新接口.pdf   # Mac
xdg-open 模糊评价报告_新接口.pdf  # Linux

3. 使用 Postman 测试

  1. 创建新的 GET 请求
  2. URL: http://localhost:8080/admin/stat/report/fuzzyReportPdfNew
  3. 添加查询参数:
  • checkTaskId: 1262
  • templateId: 1
  1. 点击 Send
  2. 在响应中选择 "Save Response" → "Save to a file"

📊 对比测试

测试脚本

#!/bin/bash

BASE_URL="http://localhost:8080/admin/stat/report"
CHECK_TASK_ID="1262"
TEMPLATE_ID="1"

echo "=========================================="
echo "新旧接口对比测试"
echo "=========================================="
echo ""

# 测试旧接口
echo "1. 测试旧接口 /fuzzyReportPdf ..."
curl -s -o "旧接口_模糊评价.pdf" \
  "$BASE_URL/fuzzyReportPdf?checkTaskId=$CHECK_TASK_ID&templateId=$TEMPLATE_ID"

if [ -f "旧接口_模糊评价.pdf" ]; then
    OLD_SIZE=$(stat -f%z "旧接口_模糊评价.pdf" 2>/dev/null || stat -c%s "旧接口_模糊评价.pdf" 2>/dev/null)
    echo "   ✓ 旧接口下载成功 (大小: $OLD_SIZE 字节)"
else
    echo "   ✗ 旧接口下载失败"
fi

echo ""

# 测试新接口
echo "2. 测试新接口 /fuzzyReportPdfNew ..."
curl -s -o "新接口_模糊评价.pdf" \
  "$BASE_URL/fuzzyReportPdfNew?checkTaskId=$CHECK_TASK_ID&templateId=$TEMPLATE_ID"

if [ -f "新接口_模糊评价.pdf" ]; then
    NEW_SIZE=$(stat -f%z "新接口_模糊评价.pdf" 2>/dev/null || stat -c%s "新接口_模糊评价.pdf" 2>/dev/null)
    echo "   ✓ 新接口下载成功 (大小: $NEW_SIZE 字节)"
else
    echo "   ✗ 新接口下载失败"
fi

echo ""
echo "=========================================="
echo "对比结果"
echo "=========================================="
echo "旧接口文件大小: $OLD_SIZE 字节"
echo "新接口文件大小: $NEW_SIZE 字节"
echo ""
echo "请手动打开两个PDF文件对比:"
echo "1. 检查图片是否显示"
echo "2. 检查内容是否完整"
echo "3. 检查格式是否正确"

✅ 验证清单

下载PDF后,请检查以下内容:

  • [ ] PDF文件能正常下载
  • [ ] PDF文件能正常打开
  • [ ] PDF文件大小合理(不为0或过小)
  • [ ] PDF包含所有应有的内容
  • [ ] 图片是否显示(重点检查)
  • [ ] 图片清晰度是否正常
  • [ ] 中文文字无乱码
  • [ ] 表格显示正常
  • [ ] 图表显示正常
  • [ ] 文件名格式正确

🔍 故障排查

问题1: 下载的PDF文件损坏或无法打开

可能原因:
- 转换过程中出现异常
- 响应流未正确刷新

排查步骤:
```bash

查看应用日志

tail -f logs/application.log | grep -i "word转pdf"

检查文件大小

ls -lh *.pdf
```

解决方案:
- 检查日志中的错误信息
- 确认 fr.opensagres.poi.xwpf.converter.pdf 依赖正常


问题2: PDF中仍然没有图片

可能原因:
- 图片格式不支持
- 图片数据在内存流中丢失
- PDF转换器限制

排查步骤:
1. 先下载Word版本,确认Word中有图片
2. 检查图片格式(应为JPG/PNG)
3. 查看日志中是否有图片加载错误

解决方案:
如果新接口仍然没有图片,可以尝试使用临时文件方案(参考之前的修改)


问题3: 中文文件名乱码

可能原因:
- URL编码问题
- 浏览器编码设置

解决方案:
java // 已使用 URLEncoder.encode(docName, "UTF-8") // 如果仍有问题,可以尝试: String encodedFileName = new String(docName.getBytes("UTF-8"), "ISO-8859-1");


📝 代码修改总结

修改的文件

admin-server/src/main/java/com/estate/expert/admin/controller/stat/ReportController.java

新增内容

  1. 导入类(第9-10行,第15行,第26-27行):
    java import fr.opensagres.poi.xwpf.converter.pdf.PdfConverter; import fr.opensagres.poi.xwpf.converter.pdf.PdfOptions; import org.apache.poi.xwpf.usermodel.XWPFDocument; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream;

  2. 新增接口(第81-90行):
    java @GetMapping("/fuzzyReportPdfNew") public void fuzzyReportPdfNew(...)

  3. 新增方法(第168-233行):
    java private void downloadAsPdf(...)

代码统计

  • 新增代码行数: 约 80 行
  • 修改文件数: 1 个
  • 新增接口数: 1 个
  • 新增方法数: 1 个

🚀 后续优化建议

1. 性能优化

如果图片仍然丢失,可以考虑使用临时文件方案:

// 使用临时文件代替内存流
Path tempDocxFile = Files.createTempFile("report_", ".docx");
try (FileOutputStream out = new FileOutputStream(tempDocxFile.toFile())) {
    doc.write(out);
}
try (FileInputStream in = new FileInputStream(tempDocxFile.toFile())) {
    document = new XWPFDocument(in);
    // 转换为PDF
}
Files.deleteIfExists(tempDocxFile);

2. 异步处理

对于大文件,可以考虑异步生成:

@Async
public CompletableFuture<byte[]> generatePdfAsync(Integer checkTaskId, Integer templateId) {
    // 异步生成PDF
}

3. 缓存机制

对于相同参数的请求,可以缓存PDF结果:

@Cacheable(value = "pdfReports", key = "#checkTaskId + '_' + #templateId")
public byte[] getCachedPdf(Integer checkTaskId, Integer templateId) {
    // 生成并缓存PDF
}

📚 相关文档


创建时间: 2026-01-24
接口版本: v1.0
状态: ✅ 已实现,待测试