文章目录

前言一、准备模板二、代码实现三、源代码总结

前言

在有些场景下我们可能需要根据指定的模板来生成 PDF,比如说合同、收据、发票等等。因为 PDF 是不可编辑的,所以用代码直接对 PDF 文件进行修改是很不方便的,这里我是通过 itext 和 Adobe Acrobat 来实现的,以下就是具体实现方法。

一、准备模板

Adobe Acrobat 是由 Adobe 公司开发的一款 PDF(Portable Document Format,便携式文档格式)编辑软件。借助它,你可以以 PDF 格式制作和保存文档 ,以便于浏览和打印,或使用更高级的功能。

说白一点就是 Adobe Acrobat 可以让你的 PDF 文件编程可编辑文件,PDF 文件可编辑的话,使用代码去修改就会方便很多。

adobe 中文官网:https://www.adobe.com/cn/

Adobe Acrobat 中文官网:https://www.adobe.com/cn/acrobat.html

如果你之前没有使用过这个软件,可以在上面我提供的官网里面去下载

PS:不过这个软件是收费的,但是可以注册一个账号申请免费试用,然后按照提示去下载该软件,大概有一周左右的使用期限

下载完,打开该软件大概是这个样子的

软件有了之后就是准备模板,这里我以 劳动合同模板 为例:

以上一个为 PDF 的劳动合同模板,使用 Adobe Acrobat 软件中的 准备表单 工具将该 .pdf 文件导入进来

进入到 工具 栏,选择 准备表单,点击 打开

选择模板文件

再点击 开始

进来之后就可以对 PDF 文件进行编辑,那些需要填入的值的地方,可以 添加文本域,之后通过代码设置的值就会直接填入到文本域当中

双击文本域,可编辑文本域的信息

其中最重要的就是 名称,如果想要在这个位置上赋值的话,就需要绑定该名称,类似于给 Map 赋值需要知道 key 一样,虽然说在添加文本域的时候就会生成一个名称,但是还是建议最好自己取一个见名知意的名称。

模板各文本域名称和备注如下:

{

"companyName":"用人单位名称",

"legalPerson":"法人",

"companyAddress":"用人单位地址",

"companyPhone":"用人单位联系方式",

"term":"合同期限",

"startYear":"起始时间-年",

"startMonth":"起始时间-月",

"startDay":"起始时间-日",

"endYear":"终止时间-年",

"endMonth":"终止时间-月",

"endDay":"终止时间-日",

"probationPeriodStartYear":"试用期起始时间-年",

"probationPeriodStartMonth":"试用期起始时间-月",

"probationPeriodStartDay":"试用期起始时间-日",

"probationPeriodEndYear":"试用期终止时间-年",

"probationPeriodEndMonth":"试用期终止时间-月",

"probationPeriodEndDay":"试用期终止时间-日",

"probationPeriodTerm":"试用期期限",

"post":"岗位",

"salary":"薪资",

"probationPeriodSalary":"试用期薪资",

"salaryGrant":"薪资发放时间"

}

同时还能够设置其它一些属性,比如说字体大小、字体、对齐方式等等,这里我是把字体大小都设置为 10,字体设置为宋体,居中对齐

然后保存即可,再打开该 PDF 文件时,该文件就已成为可编辑文件了,模板到此准备完成

二、代码实现

导入 itext 相关的依赖:

com.itextpdf

itextpdf

5.4.2

com.itextpdf

itext-asian

5.2.0

org.apache.pdfbox

pdfbox

2.0.13

接口编写:

PdfController.java

import com.mike.server.system.service.PdfService;

import io.swagger.annotations.Api;

import io.swagger.annotations.ApiOperation;

import lombok.RequiredArgsConstructor;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.*;

import java.util.Map;

@Slf4j

@RestController

@RequestMapping("/test")

@Api(tags = "【PDF-管理】")

@RequiredArgsConstructor(onConstructor = @__(@Autowired))

@CrossOrigin(origins = "*", methods = {RequestMethod.POST, RequestMethod.GET})

public class PdfController {

private final PdfService pdfService;

@PostMapping(value = "/generate-pdf")

@ApiOperation(value = "生成PDF", produces = "application/octet-stream")

public void generatePdf(@RequestBody Map params) {

pdfService.generatePdf(params);

}

}

PdfService.java

import java.util.Map;

public interface PdfService {

void generatePdf(Map params);

}

PdfServiceImpl.java

import com.itextpdf.text.DocumentException;

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 com.mike.common.core.utils.ServletUtils;

import com.mike.server.system.service.PdfService;

import lombok.RequiredArgsConstructor;

import lombok.SneakyThrows;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.core.io.ClassPathResource;

import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.util.Map;

@Slf4j

@Service

@RequiredArgsConstructor(onConstructor = @__(@Autowired))

public class PdfServiceImpl implements PdfService {

private final HttpServletResponse response;

@Override

@SneakyThrows

public void generatePdf(Map params) {

// 读取资源文件夹下的模板

ClassPathResource resource = new ClassPathResource("pdf-template/简单劳动合同模板.pdf");

InputStream inputStream = resource.getInputStream();

/*

* 或者通过 url 从网上下载 pdf 模板文件

*

// 获取文件地址

String urlPath = "模板资源文件链接-url";

// 下载文件

URL url = new URL(urlPath);

URLConnection connection = url.openConnection();

// 设置请求超时时长为 5 秒

connection.setConnectTimeout(5*1000);

// 读取数据

InputStream inputStream = connection.getInputStream();

*/

PdfReader reader = null;

ByteArrayOutputStream bos = null;

try {

reader = new PdfReader(inputStream);

bos = new ByteArrayOutputStream();

PdfStamper pdfStamper = new PdfStamper(reader, bos);

AcroFields acroFields = pdfStamper.getAcroFields();

// 中文字体

BaseFont font = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);

for (Map.Entry param : params.entrySet()) {

// 设置文本域的字体为中文字体

acroFields.setFieldProperty(param.getKey(), "textfont", font,null);

// 将 map 中的值写到 pdf 模板对应的文本域中

acroFields.setField(param.getKey(), param.getValue());

}

// 如果为false那么生成的PDF文件还能编辑,所以一定要设为true

pdfStamper.setFormFlattening(true);

pdfStamper.close();

// 返回文件

ServletUtils.writeAttachment(response, "劳动合同.pdf", bos.toByteArray());

} catch (IOException | DocumentException e) {

e.printStackTrace();

} finally {

try {

assert bos != null;

bos.close();

reader.close();

} catch (IOException e) {

e.printStackTrace();

}

}

}

}

ServletUtils.java 工具类部分代码:

import cn.hutool.core.io.IoUtil;

import org.springframework.http.MediaType;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

import java.net.URLEncoder;

/**

* 客户端工具类

*

* @author system

*/

public class ServletUtils {

...

/**

* 返回附件

*

* @param response 响应

* @param filename 文件名

* @param content 附件内容

*/

public static void writeAttachment(HttpServletResponse response, String filename, byte[] content) throws IOException {

// 设置 header 和 contentType

response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));

response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);

// 输出附件

IoUtil.write(response.getOutputStream(), false, content);

}

...

}

请求接口:

参数:

{

"companyName": "xxxx科技有限公司",

"legalPerson": "米大傻",

"companyAddress": "广州xxxxxxx",

"companyPhone": "18274563214",

"term": "3",

"startYear": "2023",

"startMonth": "9",

"startDay": "15",

"endYear": "2026",

"endMonth": "9",

"endDay": "15",

"probationPeriodStartYear": "2023",

"probationPeriodStartMonth": "9",

"probationPeriodStartDay": "15",

"probationPeriodEndYear": "2023",

"probationPeriodEndMonth": "11",

"probationPeriodEndDay": "15",

"probationPeriodTerm": "2",

"post": "JAVA工程师",

"salary": "23000",

"probationPeriodSalary": "18000",

"salaryGrant": "15"

}

效果:

三、源代码

------------------项目下载------------------ 链接:百度网盘 提取码:ihyo -------------------------------------------

总结

个人觉得代码实现起来不是很难,关键是要知道如何使用 Adobe Acrobat 工具设置 PDF 模板以及 itext 的一些 API 的使用,以后有时间我会出一篇关于 iText 的博客,主要介绍 iText 在日常开发中的主要应用。

itextpdf-接口文档:https://api.itextpdf.com/iText5/java/5.5.9/

itext 生成 PDF(一):https://blog.csdn.net/lcczpp/article/details/125424395

为何选择iText?java PDF开源库选择与iText发展历史:https://zhuanlan.zhihu.com/p/375700748

使用itext填充静态PDF模板,生成PDF新文件:https://www.cnblogs.com/hunter-space/p/static_pdf.html

好文链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。