当前位置: 代码网 > it编程>编程语言>Java > 基于Java编写一个html转pdf的工具类

基于Java编写一个html转pdf的工具类

2025年09月29日 Java 我要评论
1、背景最近项目中需要生成日报文件,日报文件的格式为pdf,且日报的样式相对而言比较复杂,存在多段文字,存在多个表格,且存在样式。目前想到的解决办法是 先生成html文件,让后将html文件转换成pd

1、背景

最近项目中需要生成日报文件,日报文件的格式为pdf,且日报的样式相对而言比较复杂,存在多段文字,存在多个表格,且存在样式。目前想到的解决办法是 先生成html文件,让后将html文件转换成pdf文件。通过网上搜索,发现openhtmltopdf可以实现我们的需求,此处记录一下。

2、需求

生成的pdf需要支持中文。

生成的pdf支持简单的样式。(此处可以使用css样式来解决,但不是所有的css样式都支持)

生成的pdf存在表格,每行应完整地出现在同一页,不要一半在上一页、一半在下一页。

生成的pdf可以自己指定到分页,比如某个表格的数据渲染完之后,需要单独开启一页。

生成的pdf支持密码加密。

生成的pdf可以支持纸张规格,比如是a3还是a4,并且还可设置横向还是纵向。

3、思路

1、html的生成,我们可以通过freemarker来实现。

2、html转pdf,通过openhtmltopdf来实现。

4、实现步骤

4.1 搭建一个简单的工程

首先搭建一个简单的可运行的程序,可实现freemarker渲染模板,然后生成pdf文件

引入依赖

<dependencies>
    <dependency>
        <groupid>org.springframework.boot</groupid>
        <artifactid>spring-boot-starter-web</artifactid>
        <version>2.6.0</version>
    </dependency>
    <!-- 模板引擎,用于渲染html -->
    <dependency>
        <groupid>org.freemarker</groupid>
        <artifactid>freemarker</artifactid>
        <version>2.3.30</version>
    </dependency>
    <!-- 用于将html转换成pdf -->
    <dependency>
        <groupid>com.openhtmltopdf</groupid>
        <artifactid>openhtmltopdf-pdfbox</artifactid>
        <version>1.0.10</version>
    </dependency>
    <dependency>
        <groupid>org.projectlombok</groupid>
        <artifactid>lombok</artifactid>
        <version>1.18.36</version>
    </dependency>
</dependencies>

编写freemarker工具类

加载程序中src/main/resources/templates/ftls目录下的模板文件,然后渲染成html内容。

package com.huan.pdf.utils;

import freemarker.cache.classtemplateloader;
import freemarker.template.configuration;
import freemarker.template.template;
import freemarker.template.templateexceptionhandler;
import lombok.extern.slf4j.slf4j;

import java.io.stringwriter;
import java.util.map;

/**
 * freemarker 工具类
 *
 * @author admin
 */
@slf4j
public class freemarkerutils {
    /**
     * 模板文件夹路径
     */
    private static final string template_dir = "/templates/ftls";
    private static final configuration configuration;

    static {
        configuration = new configuration(configuration.version_2_3_30);
        configuration.settemplateloader(new classtemplateloader(freemarkerutils.class, template_dir));
        configuration.setdefaultencoding("utf-8");
        configuration.settemplateexceptionhandler(templateexceptionhandler.rethrow_handler);
        configuration.setlogtemplateexceptions(false);
        configuration.setwrapuncheckedexceptions(true);
    }

    /**
     * 根据模板名称和数据模型生成字符串
     *
     * @param templatename 模板名称
     * @param datamodel    数据模型
     * @return 生成的字符串
     */
    public static string processtemplate(string templatename, map<string, object> datamodel) {
        try {
            template template = configuration.gettemplate(templatename);
            stringwriter writer = new stringwriter();
            template.process(datamodel, writer);
            return writer.tostring();
        } catch (exception e) {
            log.error("解析模板出现问题", e);
        }
        return "";
    }
}

编写pdf工具类

编写pdf工具类,用于将html内容渲染成pdf文件,此处只是简单实现,后期该类还需要修改

package com.huan.pdf.utils;

import com.openhtmltopdf.pdfboxout.pdfrendererbuilder;
import lombok.extern.slf4j.slf4j;

import javax.servlet.http.httpservletresponse;
import java.io.ioexception;
import java.io.outputstream;
import java.util.uuid;

/**
 * pdf工具类
 *
 * @author admin
 */
@slf4j
public class pdfutils {

    /**
     * 生成pdf文件
     *
     * @param pdftemplate pdf模板
     * @param response    http response
     */
    public static void generatepdf(string pdftemplate, httpservletresponse response) {
        // 设置响应头
        string filename = uuid.randomuuid() + ".pdf";
        response.setcontenttype("application/pdf");
        response.setheader("content-disposition", "attachment; filename=" + filename);

        try (outputstream os = response.getoutputstream()) {
            pdfrendererbuilder builder = new pdfrendererbuilder();
            builder.withhtmlcontent(pdftemplate, null);
            builder.tostream(os);
            builder.run();
        } catch (ioexception e) {
            log.error("生成pdf文件失败", e);
            throw new runtimeexception("生成pdf文件失败", e);
        }
    }
}

增加一个模板

<!doctype html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title>生成pdf</title>
        <style>
            .main-title { text-align: center; font-size:25px; }
        </style>
    </head>
    <body>
        <div class="main-title">${maintitle}</div>
    </body>
</html>

该模板中存在变量maintitle,这个变量的值通过后台来赋值

增加一个控制层

package com.huan.pdf.controller;

import com.huan.pdf.utils.freemarkerutils;
import com.huan.pdf.utils.pdfutils;
import org.springframework.web.bind.annotation.getmapping;
import org.springframework.web.bind.annotation.restcontroller;

import javax.servlet.http.httpservletresponse;
import java.time.localdatetime;
import java.time.format.datetimeformatter;
import java.util.hashmap;
import java.util.map;

/**
 * pdf控制器
 *
 * @author admin
 */
@restcontroller
public class pdfcontroller {

    @getmapping("pdf")
    public void pdf(httpservletresponse response) {

        map<string, object> params = new hashmap<>(16);
        params.put("maintitle", "这是一个标题 - " + localdatetime.now().format(datetimeformatter.ofpattern("yyyy-mm-dd hh:mm:ss")));

        // 渲染模板
        string htmlcontent = freemarkerutils.processtemplate("pdf.ftl", params);
        // 生成pdf
        pdfutils.generatepdf(htmlcontent, response);
    }
}

注意:此处的maintitle中存在中文,生产的pdf会乱码待会儿在处理

运行

可以看到可以正常的生成pdf了,但是中文乱码了。 至此我们一个简单的程序就搭建完成了,下面让我们来完善功能。

4.2 功能完善

生成的pdf需要支持中文

默认情况下生成的pdf,中文是乱码的,若需要解决这个问题,就需要引入中文字体。此处我们使用宋体

1.程序中引入宋体

在程序的src/main/resources/fonts目录下,引入宋体(simsun.ttf)

2.pdf工具类中增加使用中文字体

builder.usefont(() -> pdfutils.class.getclassloader().getresourceasstream("fonts/simsun.ttf"), "simsun");

3.freemarker模板中使用中文字体

<style>
   body { font-family: "simsun";  font-size: 16px; line-height: 1.5; color: #000;}
</style>

4.运行

从上图中可以看到,现在已经可以展示中文了。

生成的pdf支持简单的样式

此处实现将生成的pdf中的 这是一个标题-时间 这句话的字体修改成红色

1.freemarker模板中使用css样式

.main-title { text-align: center; font-size:25px; color:#ff0000; }

2.运行

通过上图可知,样式已经生效了。

表格的某一行不要出现跨页

1.freemarker模板中增加一个表格

<style>
     table { border-collapse: collapse; }
     td { border: 1px solid black; padding: 70px;}
</style>

<table>
    <tr><td>序号</td></tr>
    <tr><td>1</td></tr>
    <tr><td>2</td></tr>
    <tr><td>3</td></tr>
    <tr><td>4</td></tr>
    <tr><td>5</td></tr>
</table>

2.查看效果

从上图可以看到,生成的pdf,内容跨了2页,那么如何解决这个问题呢?通过css样式解决

3.css解决

 table { border-collapse: collapse; page-break-inside: auto;}
 tr { page-break-inside: avoid;}

4.查看效果

单独开启一页pdf

1.freemarker模板修改

通过css样式page-break-before:always开启新的一页pdf。

2.查看效果

指定pdf页面的规格

默认情况是a4 纵向,现在我想修改成a3 横向。这个指定对所有的页面都生效,不可只对某一个页面生效,若想对某一个页面生效,可以生成多个pdf文件,然后进行pdf文件的合并操作。

css样式指定页面规则

@page{ size:a3 landscape; }

查看效果

从上图中可知 正好是a3横向

pdf 加密

实现思路:通过pdfbox生成加密的密码,此处给默认密码a0nin13s

1.修改pdf生成的工具类

/**
 * 生成带密码的 pdf 文件(用户密码 a0min13s)
 *
 * @param pdftemplate html 模板字符串
 * @param response    http 响应
 */
public static void generatepdf(string pdftemplate, httpservletresponse response) {
    string filename = uuid.randomuuid() + ".pdf";
    response.setcontenttype("application/pdf");
    response.setheader("content-disposition", "attachment; filename=" + filename);

    // 1. 先用 openhtmltopdf 生成未加密 pdf(内存)
    bytearrayoutputstream temp = new bytearrayoutputstream();
    try {
        pdfrendererbuilder builder = new pdfrendererbuilder();
        builder.usefont(() -> pdfutils.class.getclassloader().getresourceasstream("fonts/simsun.ttf"), "simsun");
        builder.withhtmlcontent(pdftemplate, null);
        builder.tostream(temp);
        // 完成渲染
        builder.run();
    } catch (ioexception e) {
        log.error("生成pdf失败", e);
        throw new runtimeexception("生成pdf失败");
    }

    // 用 pdfbox 加载并加密
    try (pddocument doc = pddocument.load(temp.tobytearray());
         outputstream os = response.getoutputstream()) {

        accesspermission ap = new accesspermission();
        // 可选:禁止打印、复制等
        ap.setcanprint(false);
        ap.setcanextractcontent(false);

        // 用户密码,所有者密码一样即可(也可设不同)
        standardprotectionpolicy policy =
                // ownerpwd  userpwd
                new standardprotectionpolicy("a0min13s", "a0min13s", ap);
        // 128 位 aes
        policy.setencryptionkeylength(128);
        policy.setpermissions(ap);
        // 执行加密
        doc.protect(policy);
        // 写给浏览器
        doc.save(os);
        // 确保全部送出
        os.flush();
    } catch (ioexception e) {
        log.error("pdf加密输出失败", e);
        throw new runtimeexception("pdf加密输出失败");
    }
}

2.查看效果

完整代码:https://gitee.com/huan1993/spring-cloud-parent/tree/master/pdf/openhtmltopdf

以上就是基于java编写一个html转pdf的工具类的详细内容,更多关于java html转pdf的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com