# 模糊评价报告PDF下载新接口 - 使用说明 ## 📋 接口信息 ### 新增接口 - **接口路径**: `/admin/stat/report/fuzzyReportPdfNew` - **请求方法**: `GET` - **接口描述**: 模糊评价报告PDF下载(新接口) - **认证要求**: 无需认证(@IgnoreAuth) ### 请求参数 | 参数名 | 类型 | 必填 | 说明 | |--------|------|------|------| | checkTaskId | Integer | 是 | 检查任务ID | | templateId | Integer | 是 | 报告模版ID | ### 响应说明 - **Content-Type**: `application/pdf` - **响应方式**: 文件下载 - **文件名格式**: `{项目名称}_{模板名称}_模糊评价.pdf` --- ## 🔄 新旧接口对比 ### 旧接口:`/fuzzyReportPdf` ```java @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` ```java @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 方法 ```java 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 测试 ```bash # 下载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 4. 点击 Send 5. 在响应中选择 "Save Response" → "Save to a file" --- ## 📊 对比测试 ### 测试脚本 ```bash #!/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. 性能优化 如果图片仍然丢失,可以考虑使用临时文件方案: ```java // 使用临时文件代替内存流 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. 异步处理 对于大文件,可以考虑异步生成: ```java @Async public CompletableFuture generatePdfAsync(Integer checkTaskId, Integer templateId) { // 异步生成PDF } ``` ### 3. 缓存机制 对于相同参数的请求,可以缓存PDF结果: ```java @Cacheable(value = "pdfReports", key = "#checkTaskId + '_' + #templateId") public byte[] getCachedPdf(Integer checkTaskId, Integer templateId) { // 生成并缓存PDF } ``` --- ## 📚 相关文档 - [Apache POI 官方文档](https://poi.apache.org/) - [OpenSagres XDocReport](https://github.com/opensagres/xdocreport) - [poi-tl 文档](http://deepoove.com/poi-tl/) --- **创建时间**: 2026-01-24 **接口版本**: v1.0 **状态**: ✅ 已实现,待测试