Pre Merge pull request !628 from AprilWind/dev-pdf

This commit is contained in:
AprilWind 2024-12-27 03:16:38 +00:00 committed by Gitee
commit 1b98db7f4e
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
10 changed files with 322 additions and 0 deletions

14
pom.xml
View File

@ -52,6 +52,9 @@
<!--工作流配置-->
<flowable.version>7.0.1</flowable.version>
<itextpdf.version>5.5.13.4</itextpdf.version>
<itextpdf.asian.version>5.2.0</itextpdf.asian.version>
<!-- 插件版本 -->
<maven-jar-plugin.version>3.2.2</maven-jar-plugin.version>
<maven-war-plugin.version>3.2.2</maven-war-plugin.version>
@ -328,6 +331,17 @@
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>${itextpdf.asian.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>${itextpdf.version}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-system</artifactId>

View File

@ -34,6 +34,7 @@
<module>ruoyi-common-tenant</module>
<module>ruoyi-common-websocket</module>
<module>ruoyi-common-sse</module>
<module>ruoyi-common-pdf</module>
</modules>
<artifactId>ruoyi-common</artifactId>

View File

@ -82,6 +82,12 @@
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-pdf</artifactId>
<version>${revision}</version>
</dependency>
<!-- 限流 -->
<dependency>
<groupId>org.dromara</groupId>

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ruoyi-common-pdf</artifactId>
<description>
ruoyi-common-pdf pdf模块
</description>
<dependencies>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-core</artifactId>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-json</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,27 @@
package org.dromara.common.pdf.domain;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
/**
* Pdf基类
*
* @author AprilWind
*/
@Data
public class PdfEntity implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* PDF模板路径
*/
@JsonIgnore
private String templatePath;
}

View File

@ -0,0 +1,102 @@
package org.dromara.common.pdf.utils;
import com.itextpdf.text.pdf.AcroFields;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.pdf.domain.PdfEntity;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Map;
/**
* PDF操作工具类
*
* @author AprilWind
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@Slf4j
public class PdfUtils {
/**
* 根据继承自 PdfEntity 的实体对象填充 PDF 模板
*
* @param <T> 继承自 PdfEntity 的实体类型
* @param person 传入的实体对象必须是 PdfEntity 或其子类的实例
* @return 填充后的 PDF 输入流
* @throws IllegalArgumentException 如果实体类中的模板路径为空或无效
*/
public static <T extends PdfEntity> InputStream fillPdfTemplateByAlias(T person) {
String templatePath = person.getTemplatePath();
if (StringUtils.isBlank(templatePath)) {
throw new IllegalArgumentException("模板路径未指定或无效");
}
Map<String, String> fieldValues = JsonUtils.parseObject(JsonUtils.toJsonString(person), Map.class);
return fillPdfTemplate(templatePath, fieldValues);
}
/**
* 填充 PDF 模板
*
* @param templatePath 模板文件路径
* @param fieldValues 表单字段及其值的映射
* @return 填充后的 PDF 输入流
*/
private static InputStream fillPdfTemplate(String templatePath, Map<String, String> fieldValues) {
try (
InputStream templateStream = PdfUtils.class.getClassLoader().getResourceAsStream(templatePath);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()
) {
if (templateStream == null) {
throw new FileNotFoundException("PDF 模板文件未找到:" + templatePath);
}
// 读取 PDF 模板
PdfReader reader = new PdfReader(templateStream);
PdfStamper stamper = new PdfStamper(reader, outputStream);
try {
// 获取表单字段
AcroFields form = stamper.getAcroFields();
// 添加中文字体支持可选
BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
form.addSubstitutionFont(bf);
// 填充表单字段
for (Map.Entry<String, String> entry : fieldValues.entrySet()) {
String fieldName = entry.getKey();
String fieldValue = entry.getValue();
if (form.getField(fieldName) != null) {
form.setField(fieldName, fieldValue);
} else {
System.err.printf("PDF模板填充失败未找到字段 [%s],对应值为 [%s]%n", fieldName, fieldValue);
}
}
// 设置表单为不可编辑
stamper.setFormFlattening(true);
} finally {
// 确保 PDF 相关资源关闭
stamper.close();
reader.close();
}
// 返回填充后的 PDF 文件流
return new ByteArrayInputStream(outputStream.toByteArray());
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}

View File

@ -48,6 +48,11 @@
<artifactId>ruoyi-common-log</artifactId>
</dependency>
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-pdf</artifactId>
</dependency>
<!-- excel-->
<dependency>
<groupId>org.dromara</groupId>

View File

@ -0,0 +1,90 @@
package org.dromara.system.controller.system;
import cn.hutool.core.io.IoUtil;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.file.FileUtils;
import org.dromara.common.pdf.utils.PdfUtils;
import org.dromara.common.web.core.BaseController;
import org.dromara.system.domain.vo.AhhrfsPdfSampleVo;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.io.InputStream;
/**
* 下载PDF
*
* @author AprilWind
*/
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/ahhrfs/pdf")
public class AhhrfsPdfController extends BaseController {
/**
* 下载PDF对象
*/
@GetMapping("/download/{id}")
public void download(@PathVariable Long id, HttpServletResponse response) {
AhhrfsPdfSampleVo sampleVo = new AhhrfsPdfSampleVo();
sampleVo.setChdActNme("测试数据123");
sampleVo.setChdActNo("123213123123");
sampleVo.setSvsActNo("42131231231231");
try (InputStream inputStream = PdfUtils.fillPdfTemplateByAlias(sampleVo)) {
int available = inputStream.available();
IoUtil.copy(inputStream, response.getOutputStream(), available);
response.setContentLength(available);
} catch (Exception e) {
throw new ServiceException(e.getMessage());
}
}
/**
* 前端 multipart/form-data 请求
*/
@PostMapping("/download")
public void download(AhhrfsPdfSampleVo sampleVo, HttpServletResponse response) {
// AhhrfsPdfSampleVo sampleVo = new AhhrfsPdfSampleVo();
// sampleVo.setChdActNme("测试数据123");
// sampleVo.setChdActNo("123213123123");
// sampleVo.setSvsActNo("42131231231231");
String fileName = StringUtils.isBlank(sampleVo.getChdActNme()) ? "default.pdf" : sampleVo.getChdActNme();
try (InputStream inputStream = PdfUtils.fillPdfTemplateByAlias(sampleVo)) {
// 设置响应头
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=\"" + FileUtils.percentEncode(fileName) + "\"");
// PDF 数据写入响应流
IoUtil.copy(inputStream, response.getOutputStream(), inputStream.available());
response.flushBuffer();
} catch (Exception e) {
throw new ServiceException("PDF 下载失败: " + e.getMessage());
}
}
/**
* 前端 application/json 请求
*/
@PostMapping("/download2")
public void download2(@RequestBody AhhrfsPdfSampleVo sampleVo, HttpServletResponse response) {
// AhhrfsPdfSampleVo sampleVo = new AhhrfsPdfSampleVo();
// sampleVo.setChdActNme("测试数据123");
// sampleVo.setChdActNo("123213123123");
// sampleVo.setSvsActNo("42131231231231");
String fileName = StringUtils.isBlank(sampleVo.getChdActNme()) ? "default.pdf" : sampleVo.getChdActNme();
try (InputStream inputStream = PdfUtils.fillPdfTemplateByAlias(sampleVo)) {
// 设置响应头
response.setContentType("application/pdf");
response.setHeader("Content-Disposition", "attachment; filename=\"" + FileUtils.percentEncode(fileName) + "\"");
// PDF 数据写入响应流
IoUtil.copy(inputStream, response.getOutputStream(), inputStream.available());
response.flushBuffer();
} catch (Exception e) {
throw new ServiceException("PDF 下载失败: " + e.getMessage());
}
}
}

View File

@ -0,0 +1,36 @@
package org.dromara.system.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import lombok.Data;
import org.dromara.common.pdf.domain.PdfEntity;
/**
* 示例PDF
*
* @author AprilWind
*/
@Data
@ExcelIgnoreUnannotated
public class AhhrfsPdfSampleVo extends PdfEntity {
/**
* 监管账户
*/
private String svsActNo;
/**
* 子账户
*/
private String chdActNo;
/**
* 子账户名称
*/
private String chdActNme;
@Override
public String getTemplatePath() {
return "templates/sample_template.pdf";
}
}