基于chromium的,Java生成PDF

280 阅读1分钟

实现方式: thymeleaf + jvppeteer

基于chromium实现,所见即所得,html在浏览器上什么样子,生成的PDF就是什么样子。不需要花费额外的时间调样式。

POM文件 :

<!-- springboot-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.2.7.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    <version>2.2.7.RELEASE</version>
</dependency>

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>

<!-- lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.22</version>
    <scope>compile</scope>
</dependency>

<!-- thymeleaf -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
    <version>2.2.7.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.thymeleaf</groupId>
    <artifactId>thymeleaf-spring5</artifactId>
    <version>3.0.15.RELEASE</version>
</dependency>


<!-- jvppeteer -->
<dependency>
    <groupId>io.github.fanyong920</groupId>
    <artifactId>jvppeteer</artifactId>
    <version>1.1.6</version>
</dependency>

配置文件:

server:
  port: 9182
spring:
  profiles:
    active: @profiles.active@
  thymeleaf:
    #模版文件存放目录
    prefix: classpath:/templates/
    suffix: .html
    mode: HTML
    encoding: UTF-8
    cache: false
puppeteer:
    # 临时文件存放目录
    tmp: /app/home/tmp
    # chrome地址
    chrome: /usr/bin/chromium-browser

核心代码:

@Autowired
private TemplateEngine templateEngine;

    private String htmlGenerate(String template, JSONObject param) {
        Context context = new Context();
        param.forEach(context::setVariable);
        //获取html文件
        String htmlContent = templateEngine.process(template, context);
        String tmpHtmlPath = tmpPath + "/" +UUID.randomUUID()+".html";
        log.info("html临时存放目录 = {}",tmpHtmlPath);
        File htmlFile = new File(tmpHtmlPath);
        //1. 保存html到临时目录
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(htmlFile))) {
            writer.write(htmlContent);
            writer.flush();
        } catch (IOException e) {
            log.error(e.toString(),e);
            log.error("保存html到临时文件失败!");
            return null;
        }
        return tmpHtmlPath;
    }
    private byte[] htmlToPdf(String htmlPath) {
        //生成pdf必须在无头模式下才能生效
        ArrayList<String> arrayList = new ArrayList<>();
        LaunchOptions options = new LaunchOptionsBuilder()
                .withArgs(arrayList)
                .withHeadless(true)
                .withExecutablePath(chromeUrl)
                .build();
        arrayList.add("--no-sandbox");
        arrayList.add("--disable-setuid-sandbox");
        Page page = null;
        Browser browser = null;
        try {
            browser = Puppeteer.launch(options);
            page = browser.newPage();
            page.goTo("file://" + htmlPath);
            PDFOptions pdfOptions = new PDFOptions();
            //位置
//            pdfOptions.setPath("");
            //大小
            pdfOptions.setFormat("A4");
            //边框
            Margin margin =  new Margin();
            margin.setTop("20mm");
            margin.setBottom("20mm");
            pdfOptions.setMargin(margin);
            //开启背景图片
            pdfOptions.setPrintBackground(true);
            //开启页眉页脚
            pdfOptions.setDisplayHeaderFooter(true);
            pdfOptions.setHeaderTemplate("<div></div>");
            pdfOptions.setFooterTemplate("<div style=\"font-size: 10px; width: 100%; text-align: center; padding: 10px;\">\n" +
                    "                共 <span class=\"totalPages\"></span> 页,第 <span class=\"pageNumber\"></span> 页 \n" +
                    "            </div>");

            return page.pdf(pdfOptions);

        } catch (InterruptedException | IOException e) {
            log.error(e.getMessage(),e);
            return null;
        }finally {
            if (page != null){
                try {
                    page.close();
                } catch (InterruptedException e) {
                    log.error(e.getMessage());
                }
            }
            if (browser != null){
                browser.close();
            }
        }
    }

centos7.9 安装chromium

sudo yum install epel-release 
sudo yum install https://forensics.cert.org/cert-forensics-tools-release-el7.rpm 
sudo yum install chromium

安装中文字体

sudo yum install wqy-microhei-fonts