Springboot整合FlyingSaucer + thymeleaf 實現模板文件轉pdf打印

前言

最近,接到一個模板打印pdf的任務,後來網上找了很多案例,本文做下記錄。

如何開始

添加依賴包

<code>
<dependency>
<groupid>org.springframework.boot/<groupid>
<artifactid>spring-boot-starter-thymeleaf/<artifactid>
/<dependency>

<dependency>
<groupid>org.xhtmlrenderer/<groupid>
<artifactid>flying-saucer-pdf/<artifactid>
<version>9.1.9/<version>
/<dependency>/<code>

yml配置(可選,不配置默認也可)

<code>spring:
# thymeleaf
thymeleaf:
prefix: classpath:/templates/
check-template-location: true
suffix: .html
encoding: UTF-8
mode: HTML
cache: false
servlet:
content-type: text/html/<code>

模板文件

如下文件放置位置

Springboot整合FlyingSaucer + thymeleaf 實現模板文件轉pdf打印

​pdfPage模板文件:

<code>


<title>Spring Boot Demo - PDF/<title>





1.標題-中文



2.按鈕:按鈕的邊框需要寫css渲染

<button> click me t-p/<button>


3.普通div

Alice's Adventures in Wonderland


4.圖片 絕對定位到左上角(注意:圖片必須用全路徑或者http://開頭的路徑,否則無法顯示)



5.普通table表格


<table>

1
2
2
2
2


1
2
2
2
2


1
2

2
2
2

/<table>



6.input控件,邊框需要寫css渲染 (在模板中一般不用input,因為不存在輸入操作)


<label>姓名:/<label>



/<code>

避坑:

測試的時候,模板文件中一定至少有一個:th:text="${xxx}",否則會報模板不存在

圖片路徑需絕對路徑,如:http://localhost:8088/hu/imgs/sg.jpg

核心處理類

工具類

<code>/**
* pdf處理工具類

*
* @author gourd.hu
* @version 1.0
*/
@Slf4j
public class PdfUtil {
private PdfUtil() {
}


/**
* 按模板和參數生成html字符串,再轉換為flying-saucer識別的Document
*
* @param templateName freemarker模板名稱
* @param variables freemarker模板參數
* @return Document
*/
private static Document generateDoc(TemplateEngine templateEngine, String templateName, Map<string> variables) {
// 聲明一個上下文對象,裡面放入要存到模板裡面的數據
final Context context = new Context();
context.setVariables(variables);
StringWriter stringWriter = new StringWriter();
try(BufferedWriter writer = new BufferedWriter(stringWriter)) {
templateEngine.process(templateName,context, writer);
writer.flush();
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
return builder.parse(new ByteArrayInputStream(stringWriter.toString().getBytes()));
}catch (Exception e){
log.error(e.getMessage(), e);
return null;
}
}

/**
* 核心: 根據freemarker模板生成pdf文檔
*
* @param templateEngine 配置
* @param templateName 模板名稱
* @param out 輸出流
* @param listVars 模板參數
* @throws Exception 模板無法找到、模板語法錯誤、IO異常
*/

private static void generateAll(TemplateEngine templateEngine, String templateName, OutputStream out, List> listVars) throws Exception {
if (CollectionUtils.isEmpty(listVars)) {
log.warn("警告:模板參數為空!");
return;
}

ITextRenderer renderer = new ITextRenderer();
//設置字符集(宋體),此處必須與模板中的一致,區分大小寫,不能寫成漢字"宋體"
ITextFontResolver fontResolver = renderer.getFontResolver();
//避免中文為空設置系統字體
fontResolver.addFont("static/fonts/simsun.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
fontResolver.addFont("static/fonts/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);

//根據參數集個數循環調用模板,追加到同一個pdf文檔中
//(注意:此處從1開始,因為第0是創建pdf,從1往後則向pdf中追加內容)
for (int i = 0; i < listVars.size(); i++) {
Document docAppend = generateDoc(templateEngine, templateName, listVars.get(i));
renderer.setDocument(docAppend, null);
//展現和輸出pdf
renderer.layout();
if(i==0){
renderer.createPDF(out, false);
}else {
//寫下一個pdf頁面
renderer.writeNextDocument();
}

}
renderer.finishPDF(); //完成pdf寫入
}

/**
* pdf下載
*
* @param templateEngine 配置
* @param templateName 模板名稱(帶後綴.ftl)
* @param listVars 模板參數集

* @param response HttpServletResponse
* @param fileName 下載文件名稱(帶文件擴展名後綴)
*/
public static void download(TemplateEngine templateEngine, String templateName, List> listVars, HttpServletResponse response, String fileName) {
// 設置編碼、文件ContentType類型、文件頭、下載文件名
response.setCharacterEncoding("utf-8");
response.setContentType("multipart/form-data");
try {
response.setHeader("Content-Disposition", "attachment;fileName=" +
new String(fileName.getBytes("gb2312"), "ISO8859-1"));
} catch (UnsupportedEncodingException e) {
log.error(e.getMessage(), e);
}
try (ServletOutputStream out = response.getOutputStream()) {
generateAll(templateEngine, templateName, out, listVars);
out.flush();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}

/**
* pdf預覽
*
* @param templateEngine 配置
* @param templateName 模板名稱(帶後綴.ftl)
* @param listVars 模板參數集
* @param response HttpServletResponse
*/
public static void preview(TemplateEngine templateEngine, String templateName, List> listVars, HttpServletResponse response) {
try (ServletOutputStream out = response.getOutputStream()) {
generateAll(templateEngine, templateName, out, listVars);
out.flush();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
}
/<string>/<code>

Controller

<code>/**
* pdf預覽、下載
*
* @author gourd.hu
* @version 1.0
*/
@RestController
@RequestMapping(value = "/pdf")
@Api(tags = "pdf", description = "pdf功能")
public class PdfController {

@Autowired
private TemplateEngine templateEngine;

/**
* pdf預覽
*
* @param response HttpServletResponse
*/
@GetMapping(value = "/preview")
@ApiOperation(value="pdf預覽")
public void preview(HttpServletResponse response) {
// 構造freemarker模板引擎參數,listVars.size()個數對應pdf頁數
List> listVars = new ArrayList<>();
Map<string> variables = new HashMap<>(4);
variables.put("title","測試預覽PDF!");
Map<string> variables2 = new HashMap<>(4);
variables2.put("title","測試預覽PDF2!");
listVars.add(variables);
listVars.add(variables2);

PdfUtil.preview(templateEngine,"pdfPage",listVars,response);
}

/**
* pdf下載
*
* @param response HttpServletResponse
*/
@GetMapping(value = "/download")
@ApiOperation(value="pdf下載")
public void download(HttpServletResponse response) {
List> listVars = new ArrayList<>();

Map<string> variables = new HashMap<>(4);
variables.put("title","測試下載PDF!");
listVars.add(variables);
PdfUtil.download(templateEngine,"pdfPage",listVars,response,"測試打印.pdf");
}
}/<string>
/<string>/<string>
/<code>

演示效果

Springboot整合FlyingSaucer + thymeleaf 實現模板文件轉pdf打印

​結語

至此,pdf打印功能就完成了,如果本文有錯誤的地方,歡迎評論指正。

===============================================

代碼均已上傳至本人的開源項目

Springboot整合FlyingSaucer + thymeleaf 實現模板文件轉pdf打印

​葫蘆胡:


分享到:


相關文章: