Pre Merge pull request !628 from AprilWind/dev-pdf
This commit is contained in:
commit
1b98db7f4e
14
pom.xml
14
pom.xml
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
41
ruoyi-common/ruoyi-common-pdf/pom.xml
Normal file
41
ruoyi-common/ruoyi-common-pdf/pom.xml
Normal 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>
|
@ -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;
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Binary file not shown.
@ -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>
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user