使用Java输出PDF文件
内容纲要

场景

最近跟进的 温氏拍照检测上报管理系统 项目中拥有一个需求是 自动将做完实验后的实验板拍照检测后将结果输出为PDF文件并且加上水印上传 防止实验作假。因此系统需要一个功能来实现 将实验结果动态生成为PDF文件并且输出

解决方案

1.制作PDF模板

(1)在Word内制作模板

因为PDF常用的软件不支持编辑,所以先用Word工具,如WPS或者Office新建一个空白Word文档,里面制作出自己想要的样式。

(2)将Word转换为PDF保存起来

(2)利用 Adobe Acrobat DC 编辑保存好的PDF文件

Adobe Acrobat DC 是一个专业的PDF文件处理软件,不是免费的,但可以免费试用7天。

点击准备表单按钮。

详细配置所需要的数据源(注意,配置的数据源字段必须与Java中的实体类对象的字段名保持一致),若要显示图像,在要显示图像的区域,点击鼠标右键,选择文本域,设定好图像的显示位置,并指定数据源字段。

配置完成后保存作为模板使用。

2.代码实现

(1)创建一个 SpringBoot 项目,导入以下依赖

  <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.13</version>
        </dependency>

        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
            <version>2.1.0</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <dependency>
            <groupId>io.swagger</groupId>
            <artifactId>swagger-annotations</artifactId>
            <version>1.5.22</version>
        </dependency>

        <dependency>
            <groupId>com.spring4all</groupId>
            <artifactId>swagger-spring-boot-starter</artifactId>
            <version>1.9.0.RELEASE</version>
        </dependency>

(2)编写Swagger配置文件

在项目中创建 resource 目录,创建 bootstrap.yml 文件,输入swagger配置信息,具体配置信息根据个人项目而定,模板如下。

swagger:
  title: "PDF生成系统"
  description: "PDF生成"
  base-package: cn.loungexi
  enabled: true
  version: 1.0.0

在 SpringBoot 启动类上面添加 Swagger 启动注解。

@EnableSwagger2Doc

(2)编写pojo层代码

import lombok.Data;

@Data
public class Result {
    private String experimenter;
    private String experimentalResult;
    private String experimentalResultImage;
}

(3)编写service层代码

import cn.loungexi.pojo.Result;

import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;

public interface OutputPdfService {

    void generatorPdf(Result result, HttpServletResponse response) throws UnsupportedEncodingException;

}
import cn.loungexi.pojo.Result;
import cn.loungexi.service.OutputPdfService;
import com.itextpdf.text.Document;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class OutputPdfServiceImpl implements OutputPdfService {
    @Override
    public void generatorPdf(Result result, HttpServletResponse response) throws UnsupportedEncodingException {
        // 模板名称
        String templateName = "检测结果打印模板.pdf";
        String path = "";
        // 获取操作系统名称,根据系统名称确定模板存放的路径
        String systemName = System.getProperty("os.name");
        if (systemName.toUpperCase().startsWith("WIN")) {
            path = "D:/桌面/JAVA/JavaOutputPDF/";//改成自己的模板路径
        } else {
            path = "/usr/local/JAVA/JavaOutputPDF/";//改成自己的模板路径
        }
        // 生成导出PDF的文件名称
        String fileName = result.getExperimenter() + "实验结果.pdf";
        fileName = URLEncoder.encode(fileName, "UTF-8");
        // 设置响应头
        response.setContentType("application/force-download");
        response.setHeader("Content-Disposition", "attachment;fileName=" + fileName);
        OutputStream out = null;
        ByteArrayOutputStream bos = null;
        PdfStamper stamper = null;
        PdfReader reader = null;
        try {
            // 输出到浏览器端
            out = response.getOutputStream();
            // 读取PDF模板表单
            reader = new PdfReader(path + templateName);
            // 字节数组流,用来缓存文件流
            bos = new ByteArrayOutputStream();
            // 根据模板表单生成一个新的PDF
            stamper = new PdfStamper(reader, bos);
            // 获取新生成的PDF表单
            AcroFields form = stamper.getAcroFields();
            // 给表单生成中文字体,这里采用系统字体,不设置的话,中文显示会有问题
            BaseFont font = BaseFont.createFont("C:/WINDOWS/Fonts/SIMSUN.TTC,1", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
            form.addSubstitutionFont(font);
            // 装配数据
            Map<String, Object> data = new HashMap<>(15);
            data.put("experimenter", result.getExperimenter());
            data.put("experimentalResult", result.getExperimentalResult());
            data.put("experimentalResultImage", result.getExperimentalResultImage());
            // 遍历data,给pdf表单赋值
            for (String key : data.keySet()) {
                // 图片要单独处理
                if ("experimentalResultImage".equals(key)) {
                    int pageNo = form.getFieldPositions(key).get(0).page;
                    Rectangle signRect = form.getFieldPositions(key).get(0).position;
                    float x = signRect.getLeft();
                    float y = signRect.getBottom();
                    String resultImage = data.get(key).toString();
                    //根据路径或Url读取图片
                    Image image = Image.getInstance(resultImage);
                    //获取图片页面
                    PdfContentByte under = stamper.getOverContent(pageNo);
                    //图片大小自适应
                    image.scaleToFit(signRect.getWidth(), signRect.getHeight());
                    //添加图片
                    image.setAbsolutePosition(x, y);
                    under.addImage(image);
                }
                // 设置普通文本数据
                else {
                    form.setField(key, data.get(key).toString());
                }
            }
            // 表明该PDF不可修改
            stamper.setFormFlattening(true);
            // 关闭资源
            stamper.close();
            // 将ByteArray字节数组中的流输出到out中(即输出到浏览器)
            Document doc = new Document();
            PdfCopy copy = new PdfCopy(doc, out);
            doc.open();
            PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), 1);
            copy.addPage(importPage);
            doc.close();
            log.info("*****************************PDF导出成功*********************************");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.flush();
                    out.close();
                }
                if (reader != null) {
                    reader.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

(4)编写controller层代码

import cn.loungexi.pojo.Result;
import cn.loungexi.service.OutputPdfService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;

@RestController
@Api(value = "PDF相关操作接口",tags = "PDF相关操作接口")
@RequestMapping("/pdf")
public class PdfController {
    @Autowired
    private OutputPdfService outputPdfService;
    @ApiOperation(value = "导出PDF")
    @PostMapping("/outresult")
    public void generatorPdf(@RequestBody Result result, HttpServletResponse response){
        try {
            outputPdfService.generatorPdf(result, response);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    }

}

3.测试接口

利用 Swagger 请求接口。

SpingBoot 启动后默认端口为8080,利用 http://localhost:8080/swagger-ui.html 进入Swagger 面板。若在配置文件中改动了默认启动端口,则在 url 中改为自己的端口即可。

进入 PDF相关操作接口

点击 Try it out 后将要上传的 Json 数据补充完整,注意图片一行需要填写正确的图片路径,否则会报 400 错误,尽量将 "\" 换成 "/" 填写路径,填写完毕后点击 Execute

点击 Download file 下载生成的 PDF 文件,浏览器可能响应比较慢,耐心等待。

打开下载的 PDF 文件。

导出正常,显示正常,至此需求完成。

2023.07.06更新:完成项目需求pdf导出的最终版本如下。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇
隐藏
变装