SpringBoot通过FreeMarker生成pdf中遇到的难点记录
一、Configuration加载ftl模板
1.如果模板是放在本地盘符中
String templateName = "abc.ftl";
Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);
cfg.setDefaultEncoding("UTF-8");
cfg.setDirectoryForTemplateLoading(new File("E:/"));
Template template = cfg.getTemplate(templateName);
2如果模板是放在Springboot项目的resource路径下
String templateName = "abc.ftl";
Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);
cfg.setDefaultEncoding("UTF-8");
cfg.setClassForTemplateLoading(this.getClass(), "/");
Template template = cfg.getTemplate(templateName);
3如果生成了模板可以使用字符流接收然后转换成文件流,不需要生成到本地
private StringWriter htmHandler(String templateName,
Map paramMap) throws Exception {
Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);
// Configuration cfg = new Configuration();
cfg.setDefaultEncoding("UTF-8");
// 获取模板的路径
System.out.println("==================获取模板路径=======================");
// cfg.setClassForTemplateLoading(this.getClass(), "/");
cfg.setDirectoryForTemplateLoading(new File("E:/"));
System.out.println(cfg.getTemplateLoader().toString());
System.out.println("===================获取模板路径成功=======================");
//设置模板
Template template = cfg.getTemplate(templateName);
StringWriter out = new StringWriter();
template.process(paramMap, out);
return out;
}
二、ftl文件生成pdf,导入项目中的图片
如果直接在src中写死一个本地路径也是可以读取显示的,不过无法做到动态赋值的效果
如果使用动态赋值的方式,java中的代码只能通过uri的方式,这里使用com.itextpdf.text.Image类来接收一个url并转成uri路径
URL url = Thread.currentThread().getContextClassLoader().getResource("baidu.jpg");
Image image = Image.getInstance(url);
params.put("image", image.getUrl().toURI());
三、遇到一个需求是打印pdf时表格分页截断后需要在第二页有表头,这个纯css就可以实现。
关键样式
// 固定页面大小
@page {
margin-left: 7mm;
margin-right: 7mm;
margin-bottom: 20mm;
margin-top: 13mm;
}
表格中需要有结构
表格样式
.srv-table{
page-break-inside:auto;
-fs-table-paginate:paginate;
border-spacing:0;
word-break:break-strict;
}
.srv-table-tr{
page-break-inside:avoid;
page-break-after:auto;
}
效果
完整代码提供
/*解决html转pdf文件中文不显示的问题*/
body {
font-family: SimSun;
font-weight: bold;
font-size: 11px;
}
/*设定纸张大小*/
/* A4纸 */
/* @page{size:210mm*297mm} */
/*@page{size: 210mm 297mm}*/
/*@page{size: 210mm 297mm}*/
table {
width: 100%;
margin-top: 4mm;
}
img {
background: #fff;
box-shadow: none;
}
@page :first {
margin-top: 0mm;
}
@page {
margin-left: 7mm;
margin-right: 7mm;
margin-bottom: 20mm;
margin-top: 13mm;
}
.srv-table{
page-break-inside:auto;
-fs-table-paginate:paginate;
border-spacing:0;
word-break:break-strict;
}
.srv-table-tr{
page-break-inside:avoid;
page-break-after:auto;
}
图片
明细
NO
编码
名称
类型
作业组
价格
${arr_index + 1}
${arr.srvCode!}
${arr.srvName!?html}
${arr.srvTypeName!}
${arr.workByCode!}
¥${(arr.settlType! == 2) ? string(0, arr.sellPrice!?string(",##0.00"))}
${(arr.msuiteCode! == '')?string(arr.selfDealerSetMealCode!, arr.msuiteCode!)}
package com.pdf.gtmcafterpdf.pdf;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.BaseFont;
import com.pdf.gtmcafterpdf.Templates.SrvList;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.xhtmlrenderer.pdf.ITextRenderer;
import javax.xml.bind.DatatypeConverter;
import java.io.*;
import java.net.URL;
import java.util.*;
public class BlogPdf {
public static void main(String[] args) throws Exception {
String templateName ="blog.ftl";
Map params = new HashMap(16);
URL url = Thread.currentThread().getContextClassLoader().getResource("baidu.jpg");
Image image = Image.getInstance(url);
params.put("image", image.getUrl().toURI());
Scanner scanner = new Scanner(System.in);
System.out.println("请输入项目数量:");
if (scanner.hasNextLine()){
Integer srvNum = Integer.parseInt(scanner.nextLine());
System.out.println("目前项目数量:" + srvNum);
params.put("srvList", getSrvList(srvNum));
}else{
params.put("srvList", getSrvList(0));
}
StringWriter stringWriter = new BlogPdf().htmHandler(templateName, params);
new BlogPdf().blogPdfHandler(stringWriter);
}
public static List getSrvList(int num){
List list = new ArrayList();
for (int i = 0; i < num; i++) {
SrvList srvList = new SrvList();
srvList.setSrvCode("100000"+i);
srvList.setSrvName("作业项目");
srvList.setSrvTypeName("A");
srvList.setSettlType(2);
srvList.setSellPrice(100.00);
srvList.setSelfDealerSetMealCode("2001");
list.add(srvList);
}
return list;
}
private StringWriter htmHandler(String templateName,
Map paramMap) throws Exception {
Configuration cfg = new Configuration(Configuration.VERSION_2_3_23);
// Configuration cfg = new Configuration();
cfg.setDefaultEncoding("UTF-8");
// 获取模板的路径
System.out.println("==================获取模板路径=======================");
// cfg.setClassForTemplateLoading(this.getClass(), "/");
cfg.setDirectoryForTemplateLoading(new File("E:/"));
System.out.println(cfg.getTemplateLoader().toString());
System.out.println("===================获取模板路径成功=======================");
//设置模板
Template template = cfg.getTemplate(templateName);
StringWriter out = new StringWriter();
template.process(paramMap, out);
return out;
}
private void blogPdfHandler(StringWriter writer)throws Exception {
StringBuffer buffer = writer.getBuffer();
ByteArrayOutputStream os = new ByteArrayOutputStream();
ITextRenderer renderer = new ITextRenderer();
System.out.println(buffer.toString());
renderer.setDocumentFromString(buffer.toString());
org.xhtmlrenderer.pdf.ITextFontResolver fontResolver = renderer
.getFontResolver();
try {
System.out.println("====================================获取字体路径================================");
String path = Thread.currentThread().getContextClassLoader().getResource("simsun.ttf").toString();
System.out.println("=====================================获取字体路径成功"+path+"===========================================");
fontResolver.addFont(path, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
} catch (Exception e) {
e.printStackTrace();
}
renderer.layout();
try {
renderer.createPDF(os);
} catch (Exception e) {
e.printStackTrace();
}
os.close();
// 将文件流转成base64返回前端
String binary = printBase64Binary(os);
System.out.println(binary);
// String savePath = "E:\\";
String savePath = "E:/";
String fileName = "blog.pdf";
System.out.println("文件保存路径=>{}"+savePath+fileName);
base64ToFile(binary, fileName, savePath);
}
// 文件转成base64
public String printBase64Binary(ByteArrayOutputStream os){
byte[] bytes = os.toByteArray();
String strPDF = DatatypeConverter.printBase64Binary(bytes);
return strPDF;
}
// base64转成pdf
public void base64ToFile(String base64, String fileName, String savePath) {
File file = null;
//创建文件目录
String filePath = savePath;
File dir = new File(filePath);
if (!dir.exists() && !dir.isDirectory()) {
dir.mkdirs();
}
BufferedOutputStream bos = null;
java.io.FileOutputStream fos = null;
try {
byte[] bytes = Base64.getDecoder().decode(base64);
file=new File(filePath + fileName);
fos = new java.io.FileOutputStream(file);
bos = new BufferedOutputStream(fos);
bos.write(bytes);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (bos != null) {
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
|