背景最近项目中需要生成日报文件日报文件的格式为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文件4.1.1 引入依赖dependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactIdversion2.6.0/version/dependency!-- 模板引擎用于渲染html --dependencygroupIdorg.freemarker/groupIdartifactIdfreemarker/artifactIdversion2.3.30/version/dependency!-- 用于将html转换成pdf --dependencygroupIdcom.openhtmltopdf/groupIdartifactIdopenhtmltopdf-pdfbox/artifactIdversion1.0.10/version/dependencydependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdversion1.18.36/version/dependency/dependencies4.1.2 编写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*/Slf4jpublic 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, MapString, 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 ;}}4.1.3 编写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*/Slf4jpublic 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);}}}4.1.4 增加一个模板!DOCTYPE htmlhtml langenheadmeta charsetUTF-8 /title生成pdf/titlestyle.main-title { text-align: center; font-size:25px; }/style/headbodydiv classmain-title${mainTitle}/div/body/html该模板中存在变量mainTitle,这个变量的值通过后台来赋值4.1.5 增加一个控制层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*/RestControllerpublic class PdfController {GetMapping(pdf)public void pdf(HttpServletResponse response) {MapString, 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);// 生成pdfPdfUtils.generatePdf(htmlContent, response);}}