Spring Boot | 将 html 页面转化为 pdf 文件

废话不多说,先看效果图。

不知道怎么回事,简书上传图片总是失败。效果图看这里吧:效果图

本示例重要功能点:

  • 访问 url 直接下载 pdf 文件,前后端分离的项目可能通过这种方式下载 pdf 文件;
  • 将 html 页面转换成 pdf 文件,支持中文、图片

1、创建 Spring Boot 项目

进入 http://start.spring.io 创建 Spring Boot 项目,Spring Boot 版本为 2.7.0,选择如下依赖:

  • Starter:spring-boot-starter-web
  • spring-boot-starter-thymeleaf
  • lombok

2、修改 pom.xml 文件,添加将 html 页面转换成 pdf 文件需要的依赖:

<dependency>
    <groupId>org.xhtmlrenderer</groupId>
    <artifactId>flying-saucer-pdf</artifactId>
    <version>9.1.22</version>
</dependency>
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.11.0</version>
</dependency>
<dependency>
    <groupId>ognl</groupId>
    <artifactId>ognl</artifactId>
    <version>3.1.29</version>
</dependency>
<dependency>
    <groupId>com.github.jtidy</groupId>
    <artifactId>jtidy</artifactId>
    <version>1.0.2</version>
</dependency>

3、创建演示数据需要的实体类 —— Student.java

import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class Student {
    private Integer id;
    private String name;
    private String gender;
    private Integer age;
}

4、创建具体的业务处理类 —— PdfService.java

import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.BaseFont;
import com.wangc.downloadpdf.entity.Student;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import org.w3c.tidy.Tidy;
import org.xhtmlrenderer.pdf.ITextRenderer;

import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.util.List;

@Slf4j
@Service
public class PdfService {

    @Resource
    private TemplateEngine templateEngine;

    public ByteArrayInputStream exportPdf(String template, List<Student> students) throws Exception {
        Context context = new Context();
        context.setVariable("students", students);
        String content = convertToXhtml(templateEngine.process(template, context));

        ByteArrayInputStream byteArrayInputStream = null;
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ITextRenderer renderer = new ITextRenderer();
            renderer.getFontResolver().addFont("c:/Windows/Fonts/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
            renderer.setDocumentFromString(content);
            renderer.layout();
            renderer.createPDF(byteArrayOutputStream, false);
            renderer.finishPDF();
            byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        } catch (DocumentException e) {
            log.error(e.getMessage(), e);
        }

        return byteArrayInputStream;
    }

    private String convertToXhtml(String htmlContent) throws UnsupportedEncodingException {
        Tidy tidy = new Tidy();
        tidy.setInputEncoding("UTF-8");
        tidy.setOutputEncoding("UTF-8");
        tidy.setXHTML(true);
        ByteArrayInputStream inputStream = new ByteArrayInputStream(htmlContent.getBytes(StandardCharsets.UTF_8));
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        tidy.parseDOM(inputStream, outputStream);
        return outputStream.toString("UTF-8");
    }

}

5、创建控制器 —— PdfController.java

import com.wangc.downloadpdf.entity.Student;
import com.wangc.downloadpdf.service.PdfService;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Controller
public class PdfController {

    @Resource
    private PdfService pdfService;

    @GetMapping("/downloadPdf")
    public void downloadPdf(HttpServletResponse response) throws Exception {
        List<Student> students = createTestData();
        ByteArrayInputStream byteArrayInputStream = pdfService.exportPdf("students", students);

        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attachment; filename=receipt.pdf");
        IOUtils.copy(byteArrayInputStream, response.getOutputStream());
    }

    // 效果预览
    @GetMapping("/view")
    public ModelAndView view() throws Exception {
        List<Student> students = createTestData();

        ModelAndView mv = new ModelAndView();
        mv.setViewName("students");
        mv.addObject("students", students);
        return mv;
    }

    // 测试数据
    private List<Student> createTestData() {
        final List<Student> students = IntStream.range(1, 10)
                .mapToObj(v -> Student.builder()
                        .id(v)
                        .name("学生" + v)
                        .age(16)
                        .gender(v % 2 == 0 ? "男" : "女")
                        .build())
                .collect(Collectors.toList());
        return students;
    }
}

6、创建 html 模板 —— students.html

<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Students View</title>
    <style>
        body {
            /* 宋体 */
            font-family:SimSun;
            font-size: 12px;
        }
    </style>
</head>
<body>
<div class="container">
    <img src="http://127.0.0.1:9090/image-01.png" />

    <h1 th:text="'Students / Count:' + ${#lists.size(students)}"></h1>

    <div class="table-responsive">
        <table class="table">
            <tr>
                <th>Id</th>
                <th>姓名</th>
                <th>性别</th>
                <th>年龄</th>
            </tr>
            <tr th:each="student : ${students}">
                <td th:text="${student.id}"></td>
                <td th:text="${student.name}"></td>
                <td th:text="${student.gender}"></td>
                <td th:text="${student.age}"></td>
            </tr>
        </table>
    </div>
</div>

</body>
</html>

7、启动项目

访问 http://localhost:9090/view 查看 html 页面效果。访问 http://localhost:9090/downloadPdf 下载 pdf 文件。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容