Browse Source

pdf 下载带图片内容

ai_300
zhouhaibin 2 weeks ago
parent
commit
a278a75f8d
  1. 1
      zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/service/impl/ContractualTasksServiceImpl.java
  2. 185
      zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/service/impl/DocumentTaskResultsServiceImpl.java
  3. 28
      zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/service/impl/DocumentTasksServiceImpl.java

1
zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/service/impl/ContractualTasksServiceImpl.java

@ -96,7 +96,6 @@ public class ContractualTasksServiceImpl extends AbstractTaskProcessor<Contractu
);
}
contractualTasksVo.setTaskDuration(formattedDuration);
return contractualTasksVo;
})
.collect(java.util.stream.Collectors.toList());

185
zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/service/impl/DocumentTaskResultsServiceImpl.java

@ -308,12 +308,12 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi
for (Long taskId : ids) {
DocumentTasksVo documentTasksVo = documentTasksService.queryById(taskId);
if (documentTasksVo == null) continue;
String documentName = documentTasksVo.getDocumentName();
String taskName = documentTasksVo.getTaskName();
String taskType = documentTasksVo.getTaskType();
String label = dictTypeService.getDictLabel(taskType, taskName);
// 获取详细的任务结果
List<DocumentTaskResultVO> resultDetails = getDetailResultsByTaskId(String.valueOf(taskId));
if (resultDetails != null && !resultDetails.isEmpty()) {
@ -322,12 +322,12 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi
if (allCategory.getResults() != null && !allCategory.getResults().isEmpty()) {
// 获取任务类型对应的字段配置
List<FieldConfig> fieldConfigs = getFieldConfigsByTaskType(taskName);
// 将结果转换为Markdown
StringBuilder markdown = new StringBuilder();
for (DocumentTaskResultVO.ResultItem item : allCategory.getResults()) {
markdown.append("## ").append(item.getSerialNumber()).append(". ").append(item.getExistingIssues()).append("\n\n");
// 根据配置添加各字段内容
for (FieldConfig config : fieldConfigs) {
String fieldValue = getFieldValue(item, config.getField());
@ -335,31 +335,31 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi
markdown.append("### ").append(config.getTitle()).append("\n\n").append(fieldValue).append("\n\n");
}
}
// 添加分隔线
markdown.append("---\n\n");
}
// 为每个结果创建PDF文件
String pdfFileName = label + "_" + documentName + "_" + ".pdf";
String pdfPath = tempDir + File.separator + pdfFileName;
// 转换Markdown为PDF
convertMarkdownToPdf(markdown.toString(), pdfPath);
// 添加到ZIP
addToZip(pdfPath, pdfFileName, zos);
// 删除临时PDF文件
new File(pdfPath).delete();
}
}
}
}
// 下载ZIP文件
downloadFile(response, zipFilePath, zipFileName);
// 删除临时ZIP文件
new File(zipFilePath).delete();
} else {
@ -369,30 +369,30 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi
if (documentTasksVo == null) {
throw new RuntimeException("未找到相关任务");
}
String documentName = documentTasksVo.getDocumentName();
String taskName = documentTasksVo.getTaskName();
String taskType = documentTasksVo.getTaskType();
String label = dictTypeService.getDictLabel(taskType, taskName);
// 获取详细的任务结果
List<DocumentTaskResultVO> resultDetails = getDetailResultsByTaskId(String.valueOf(taskId));
if (resultDetails == null || resultDetails.isEmpty() ||
if (resultDetails == null || resultDetails.isEmpty() ||
resultDetails.get(0).getResults() == null || resultDetails.get(0).getResults().isEmpty()) {
throw new RuntimeException("未找到相关结果");
}
// 第一个是"全部"分类
DocumentTaskResultVO allCategory = resultDetails.get(0);
// 获取任务类型对应的字段配置
List<FieldConfig> fieldConfigs = getFieldConfigsByTaskType(taskName);
// 将结果转换为Markdown
StringBuilder markdown = new StringBuilder();
for (DocumentTaskResultVO.ResultItem item : allCategory.getResults()) {
markdown.append("## ").append(item.getSerialNumber()).append(". ").append(item.getExistingIssues()).append("\n\n");
// 根据配置添加各字段内容
for (FieldConfig config : fieldConfigs) {
String fieldValue = getFieldValue(item, config.getField());
@ -400,21 +400,21 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi
markdown.append("### ").append(config.getTitle()).append("\n\n").append(fieldValue).append("\n\n");
}
}
// 添加分隔线
markdown.append("---\n\n");
}
String pdfFileName = label + "_" + documentName + "_" + ".pdf";
String tempDir = System.getProperty("java.io.tmpdir");
String pdfPath = tempDir + File.separator + pdfFileName;
// 转换Markdown为PDF
convertMarkdownToPdf(markdown.toString(), pdfPath);
// 下载PDF文件
downloadFile(response, pdfPath, pdfFileName);
// 删除临时PDF文件
new File(pdfPath).delete();
}
@ -494,12 +494,6 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi
// Markdown转PDF方法
private void convertMarkdownToPdf(String markdown, String outputPath) throws Exception {
// 使用flexmark-java解析Markdown
// MutableDataSet options = new MutableDataSet();
// Parser parser = Parser.builder(options).build();
// HtmlRenderer renderer = HtmlRenderer.builder(options).build();
// Node document = parser.parse(markdown);
// String htmlContent = renderer.render(document);
MutableDataSet options = new MutableDataSet();
// 启用表格解析
options.set(Parser.EXTENSIONS, Arrays.asList(
@ -523,14 +517,12 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi
// 配置允许的标签
Safelist safelist = Safelist.relaxed()
// .addTags("em", "strong", "div", "span","br")
// .addAttributes(":all", "style", "class");
.addTags("em", "strong", "div", "span", "br", "table", "thead", "tbody", "tr", "th", "td")
.addTags("em", "strong", "div", "span", "br", "table", "thead", "tbody", "tr", "th", "td", "img")
.addAttributes(":all", "style", "class")
.addAttributes("table", "border", "cellpadding", "cellspacing");
.addAttributes("table", "border", "cellpadding", "cellspacing")
.addAttributes("img", "src", "alt", "width", "height"); // 允许img标签及其属性
htmlContent = Jsoup.clean(htmlContent, "", safelist, settings);
// 使用 NekoHTML 进一步处理
// 创建完整的HTML文档,使用微软雅黑
String html = String.format("""
<!DOCTYPE html>
@ -573,6 +565,14 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi
tr {
page-break-inside: avoid;
}
img {
width: 600px;
max-width: 100%%;
height: auto;
display: block;
margin: 20px auto;
page-break-inside: avoid;
}
</style>
</head>
<body>
@ -581,9 +581,8 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi
</html>
""",
htmlContent.replace("<br>", "\n"));
// 处理图片标签,将markdown的图片语法转换为HTML的img标签
html = handleImageTags(html);
// 配置Flying Saucer
ITextRenderer pdfRenderer = new ITextRenderer();
@ -610,6 +609,104 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi
}
}
/**
* 处理Markdown中的图片标签
* @param content Markdown内容
* @return 处理后的HTML内容
*/
private String handleImageTags(String content) {
// 使用非贪婪模式匹配alt文本,使用平衡组模式匹配路径
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("!\\[(.*?)\\]\\(([^()]*(?:\\([^()]*\\)[^()]*)*?)\\)");
java.util.regex.Matcher matcher = pattern.matcher(content);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
String alt = matcher.group(1);
String imagePath = matcher.group(2);
// 检查图片文件是否存在
File imageFile = new File(imagePath);
if (!imageFile.exists() && imagePath.contains("(")) {
// 如果文件不存在且路径中包含括号,尝试修正路径
String correctedPath = correctImagePath(imagePath);
imageFile = new File(correctedPath);
if (imageFile.exists()) {
imagePath = correctedPath;
}
}
if (imageFile.exists()) {
try {
// 将图片转换为Base64编码
byte[] imageBytes = Files.readAllBytes(imageFile.toPath());
String base64Image = java.util.Base64.getEncoder().encodeToString(imageBytes);
String imageType = getImageMimeType(imagePath);
// 创建data URL,使用固定的宽度来确保图片在页面内显示
String imgTag = String.format("<img src=\"data:%s;base64,%s\" alt=\"%s\" style=\"width: 600px; max-width: 100%%; height: auto; display: block; margin: 10px auto;\"/>",
imageType, base64Image, alt);
// 替换markdown图片语法为HTML img标签
matcher.appendReplacement(sb, imgTag.replace("$", "\\$"));
} catch (IOException e) {
log.error("处理图片失败: " + imagePath, e);
// 如果处理失败,保留原始文本
matcher.appendReplacement(sb, matcher.group(0).replace("$", "\\$"));
}
} else {
log.warn("图片文件不存在: " + imagePath);
// 如果图片不存在,保留原始文本
matcher.appendReplacement(sb, matcher.group(0).replace("$", "\\$"));
}
}
matcher.appendTail(sb);
return sb.toString();
}
/**
* 修正包含括号的图片路径
* @param originalPath 原始路径
* @return 修正后的路径
*/
private String correctImagePath(String originalPath) {
// 如果路径中包含多个括号,取最后一个右括号之前的内容
int lastRightBracket = originalPath.lastIndexOf(")");
if (lastRightBracket != -1) {
// 找到对应的左括号
int count = 1;
int leftBracket = lastRightBracket - 1;
while (leftBracket >= 0 && count > 0) {
if (originalPath.charAt(leftBracket) == ')') {
count++;
} else if (originalPath.charAt(leftBracket) == '(') {
count--;
}
leftBracket--;
}
if (count == 0) {
// 找到匹配的括号对,返回不包含最外层括号的路径
return originalPath.substring(0, leftBracket + 1) + originalPath.substring(lastRightBracket + 1);
}
}
return originalPath;
}
/**
* 根据文件扩展名获取MIME类型
* @param filePath 文件路径
* @return MIME类型
*/
private String getImageMimeType(String filePath) {
String extension = filePath.substring(filePath.lastIndexOf(".") + 1).toLowerCase();
return switch (extension) {
case "png" -> "image/png";
case "jpg", "jpeg" -> "image/jpeg";
case "gif" -> "image/gif";
case "bmp" -> "image/bmp";
default -> "image/jpeg";
};
}
// 添加文件到ZIP
private void addToZip(String filePath, String fileName, ZipOutputStream zos) throws IOException {
byte[] buffer = new byte[1024];
@ -770,21 +867,21 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi
private static class FieldConfig {
private String field;
private String title;
public FieldConfig(String field, String title) {
this.field = field;
this.title = title;
}
public String getField() {
return field;
}
public String getTitle() {
return title;
}
}
/**
* 根据任务类型获取对应的字段配置
*
@ -793,7 +890,7 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi
*/
private List<FieldConfig> getFieldConfigsByTaskType(String taskName) {
List<FieldConfig> configs = new java.util.ArrayList<>();
// 根据任务类型返回不同的字段配置
switch (taskName) {
case "checkCompanyName":
@ -824,10 +921,10 @@ public class DocumentTaskResultsServiceImpl implements IDocumentTaskResultsServi
configs.add(new FieldConfig("modificationDisplay", "修改情况"));
break;
}
return configs;
}
/**
* 获取对象的字段值
*

28
zaojiaManagement/zaojia-productManagement/src/main/java/org/dromara/productManagement/service/impl/DocumentTasksServiceImpl.java

@ -1,11 +1,9 @@
package org.dromara.productManagement.service.impl;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.io.FileUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import okhttp3.*;
import org.dromara.common.core.service.DictService;
import org.dromara.common.core.utils.MapstructUtils;
@ -308,28 +306,4 @@ public class DocumentTasksServiceImpl extends AbstractTaskProcessor<DocumentTask
return true;
}
// @Override
// protected Boolean processTaskItems(List<String> taskNames, BaseTaskBo bo, FileProcessResult fileResult, String taskType) {
// boolean flag = false;
// for (String taskName : taskNames) {
// DocumentTasks add = MapstructUtils.convert(bo, DocumentTasks.class);
// add.setTaskName(taskName);
// add.setDocumentName(fileResult.getFileName());
// add.setProgressStatus("PENDING");
// add.setTaskType(taskType);
//
// flag = baseMapper.insert(add) > 0;
//
// Long priority = calculatePriority(taskName);
// MyHttpUtils.sendTaskStartMessage(chatUrl + "/back/taskStart",
// add.getId(), taskName, fileResult.getFilePath(), priority);
//
// if (!flag) {
// throw new RuntimeException("新增文档任务失败");
// }
// }
// return flag;
//
// }
}

Loading…
Cancel
Save