/admin/stat/report/fuzzyReportPdfNewGET| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| checkTaskId | Integer | 是 | 检查任务ID |
| templateId | Integer | 是 | 报告模版ID |
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 到响应流
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); }
}
}
}
http://localhost:8080/admin/stat/report/fuzzyReportPdfNew?checkTaskId=1262&templateId=1
# 下载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
http://localhost:8080/admin/stat/report/fuzzyReportPdfNewcheckTaskId: 1262templateId: 1#!/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后,请检查以下内容:
可能原因:
- 转换过程中出现异常
- 响应流未正确刷新
排查步骤:
```bash
tail -f logs/application.log | grep -i "word转pdf"
ls -lh *.pdf
```
解决方案:
- 检查日志中的错误信息
- 确认 fr.opensagres.poi.xwpf.converter.pdf 依赖正常
可能原因:
- 图片格式不支持
- 图片数据在内存流中丢失
- PDF转换器限制
排查步骤:
1. 先下载Word版本,确认Word中有图片
2. 检查图片格式(应为JPG/PNG)
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
导入类(第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;
新增接口(第81-90行):
java @GetMapping("/fuzzyReportPdfNew") public void fuzzyReportPdfNew(...)
新增方法(第168-233行):
java private void downloadAsPdf(...)
如果图片仍然丢失,可以考虑使用临时文件方案:
// 使用临时文件代替内存流
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);
对于大文件,可以考虑异步生成:
@Async
public CompletableFuture<byte[]> generatePdfAsync(Integer checkTaskId, Integer templateId) {
// 异步生成PDF
}
对于相同参数的请求,可以缓存PDF结果:
@Cacheable(value = "pdfReports", key = "#checkTaskId + '_' + #templateId")
public byte[] getCachedPdf(Integer checkTaskId, Integer templateId) {
// 生成并缓存PDF
}
创建时间: 2026-01-24
接口版本: v1.0
状态: ✅ 已实现,待测试