废话不多说,先看效果图。
不知道怎么回事,简书上传图片总是失败。效果图看这里吧: 效果图
本示例重要功能点:
1、创建 Spring Boot 项目
进入 http://start.spring.io 创建 Spring Boot 项目,Spring Boot 版本为 2.7.0,选择如下依赖:
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">
<meta charset="UTF-8">
<title>Students View</title>
<style>
body {
/* 宋体 */
font-family:SimSun;
font-size: 12px;
</style>
</head>
<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">
<th>Id</th>
<th>姓名</th>
<th>性别</th>
<th>年龄</th>
<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>
</table>