Java中实现html转pdf
背景
最近项目中需要生成日报文件,日报文件的格式为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 引入依赖
<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> |
4.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 |
*/ |
@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 ""; |
} |
} |
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 |
*/ |
@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); |
} |
} |
} |
4.1.4 增加一个模板
<!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,这个变量的值通过后台来赋值
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 |
*/ |
@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); |
} |
} |
