Freemark+itextpdf+aliyunoss实现多模版打印
最近公司项目有个需求是要求用户可以自己上传打印模版从而对相同的数据实现不同的打印排版
比如当前后台传入模版的数据为
-
name:布丁
-
age:18
-
sex:男
那么根据模版的不同就可能出现多种结果
官方模版1:
那这个时候如果有客户想想要根据现有的数据上传自己的模版
那么这个时候他就可以自己编写模版文件并且替换掉官方的模版,从而达到自己想要的效果。
所以根据这个需求我们就需要设计一个实现方式
实现方式
- 服务器获取数据和模版
- 数据和模版合成html
- html生成PDF
- 客户获取到PDF文件自行打印
使用技术
-
freemark 用户将数据和ftl模版进行合并生成html文件
-
aliyunoss 用于存储模版,也可以在本地或者替换成其他的云存储
-
itextPFD 用于将html转换成pdf进行输出的客户端
代码实现
上传模版
因为上传模版各个云存储方法都不一样,所以就不展示了。我们只需要保证最终我们可以使用一个url获取到ftl文件即可
如:https://nr-oss.oss-cn-shenzhen.aliyuncs.com/pdf/
如果我们有多个模版 如test1.ftl、test2.ftl……
因为freemark需要指定一个模版文件夹所以我们最好将文件放在一个目录下
如:
https://nr-oss.oss-cn-shenzhen.aliyuncs.com/pdf/test1.ftl
https://nr-oss.oss-cn-shenzhen.aliyuncs.com/pdf/test2.ftl
https://nr-oss.oss-cn-shenzhen.aliyuncs.com/pdf/test3.ftl
这样我们只需要将https://nr-oss.oss-cn-shenzhen.aliyuncs.com/pdf/test1.ftl设置为模版文件即可。
使用freemark获取模版
定义一个TemplateLoader用于读取URL文件
默认的freemark是读取本地的文件,所以我们需要自定一个类并且继承URLTemplateLoader来实现读取网络文件
public class MyTemlateLoad extends URLTemplateLoader {
@Override
protected URL getURL(String s) {
URL url = null;
try {
url = new URL("https://nr-oss.oss-cn-shenzhen.aliyuncs.com/pdf/" + s);
} catch (MalformedURLException e) {
e.printStackTrace();
}
return url;
}
}
定义一个字体提供类
定一个一个字体提供,用于输出中文字体 SIMYOU.TTF这个字体去百度随便一搜就有
public class MyFontProvider extends XMLWorkerFontProvider {
public MyFontProvider() {
super(null, null);
}
@Override
public Font getFont(final String fontname, String encoding, float size, final int style) {
BaseFont fontChinese = null;
try {
fontChinese = BaseFont.createFont("/Users/yuding/Desktop/SIMYOU.TTF", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Font normalFont = new Font(fontChinese, 12);
return normalFont;
}
}
全部代码
@RestController
@RequestMapping("/pdf")
public class PdfTestController {
@GetMapping("getPdf")
public void getPdf(HttpServletResponse response) throws IOException, DocumentException, TemplateException {
// 设置response格式用于返回pdf文件
response.setCharacterEncoding("utf-8");
response.setHeader("Content-type", "application/pdf;charset=utf-8");
Configuration cfg = new Configuration(Configuration.VERSION_2_3_28);
// 设置模版文件夹
cfg.setTemplateLoader(new MyTemlateLoad());
// 设置编码
cfg.setDefaultEncoding("UTF-8");
// 设置一场处理
cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
// 获取具体模版
Template temp = cfg.getTemplate("test.ftl");
// 生成PDF文档 指定页面大小 可以使用PageSize.xx 如PageSize.A4
Document document = new Document( new RectangleReadOnly(842.0F,595.0F));
// 设置写入pdf流
PdfWriter pdfWriter = PdfWriter.getInstance(document, response.getOutputStream());
// 打开一个新的PDF文件
document.open();
XMLWorkerHelper worker = XMLWorkerHelper.getInstance();
// 数据
Map root = new HashMap();
root.put("message", "freemark11测试消息");
StringWriter stringWriter = new StringWriter();
// 将ftl模版和数据进行合并html
temp.process(root, stringWriter);
// 将合并后的html转换成pdf
worker.parseXHtml(pdfWriter, document, new ByteArrayInputStream(stringWriter.getBuffer().toString().getBytes()), Charset.forName("UTF-8"), new MyFontProvider());
// 打开一个新的页面
// 继续放入内容
document.newPage();
Map root2 = new HashMap();
root2.put("message", "freemark22测试消息");
StringWriter stringWriter2 = new StringWriter();
temp.process(root2, stringWriter2);
worker.parseXHtml(pdfWriter, document, new ByteArrayInputStream(stringWriter2.getBuffer().toString().getBytes()), Charset.forName("UTF-8"), new MyFontProvider());
// 生成PDF完毕
document.close();
}
}
这样我们就可以实现由用户上传模版,根据同意的数据打印不同格式的内容了