freemarker根據靜態模板和動態模板生成PDF與Word
背景介紹:最近在做老舊專案的二次開發,所以用到了freemarker去生成PDF和Word,涉及到列印靜態模板與動態模板。檢視了這方面的資料發現大都不全,似是而非。廢話不多說,上案例。
freemarker版本號:<freemarker.version>2.3.26-incubating</freemarker.version>
這個無所謂,我也沒用最新的標籤。
一、靜態模板生成Word:
public void submitPrint(HttpServletRequest request, HttpServletResponse response ){
try {
String fileName = "***.doc";
// 設定response型別
String userAgent = request.getHeader("user-agent").toLowerCase();
if (userAgent.contains("msie") || userAgent.contains("like gecko")) {
fileName = URLEncoder.encode(fileName, "UTF-8");
} else {
fileName = new String(fileName.getBytes("UTF-8"), "iso-8859-1");
}
response.setCharacterEncoding("utf-8");
response.setHeader("Content-Disposition", "attachment;" + " filename=" + fileName);
response.setContentType("application/octet-stream");
// 獲取資料,設定資料
Map<String,Object> dataMap = new LinkedHashMap<>(2);
dataMap.put("st1Name","張三");
dataMap.put("st1Content","李四");
Writer out = response.getWriter();
//模板所在路徑
String templateFolder = request.getSession().getServletContext().getRealPath("/template/reins/makeslip");
//判斷使用哪個模板
createDoc(out, dataMap, "***模板名.ftl",templateFolder);
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private void createDoc(Writer out, Map<String, Object> dataMap, String ftlName,String templateFolder) {
try {
configuration.setDirectoryForTemplateLoading(new File(templateFolder));
Template t = null;
t = configuration.getTemplate(ftlName,"UTF-8");
t.process(dataMap, out);
} catch (TemplateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
class Template<T> {
private String id;
private String value;
private String label;
private String parentId;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getParentId() {
return parentId;
}
public void setParentId(String parentId) {
this.parentId = parentId;
}
}
class ToCreateDoc {
private Configuration configuration = null;
public ToCreateDoc() {
configuration = new Configuration();
configuration.setDefaultEncoding("UTF-8");
}
public void createDoc(Writer out, Map<String, Object> dataMap, String ftlName,String templateFolder) {
try {
configuration.setDirectoryForTemplateLoading(new File(templateFolder));
Template t = null;
t = configuration.getTemplate(ftlName,"UTF-8");
t.process(dataMap, out);
} catch (TemplateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/*模板:只粘出關鍵程式碼*/
<w:tr w:rsidR="00CF02E7" w:rsidRPr="00573DB1" w:rsidTr="003477DD">
<w:trPr>
<w:trHeight w:val="737"/>
</w:trPr>
<w:tc>
<w:tcPr>
<w:tcW w:w="2283" w:type="dxa"/>
</w:tcPr>
<w:p w:rsidR="00CF02E7" w:rsidRDefault="00CF02E7" w:rsidP="00CF02E7">
<w:pPr>
<w:widowControl/>
<w:jc w:val="left"/>
<w:rPr>
<w:b/>
<w:bCs/>
<w:color w:val="000000"/>
<w:kern w:val="0"/>
<w:sz w:val="24"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:b/>
<w:bCs/>
<w:color w:val="000000"/>
<w:kern w:val="0"/>
<w:sz w:val="24"/>
</w:rPr>
<w:t>${st1Name!}</w:t>
</w:r>
<w:r>
<w:rPr>
<w:color w:val="000000"/>
<w:kern w:val="0"/>
<w:sz w:val="24"/>
</w:rPr>
<w:t xml:space="preserve"> </w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="7371" w:type="dxa"/>
</w:tcPr>
<w:p w:rsidR="00CF02E7" w:rsidRDefault="00CF02E7" w:rsidP="00CF02E7">
<w:pPr>
<w:widowControl/>
<w:rPr>
<w:color w:val="000000"/>
<w:kern w:val="0"/>
<w:sz w:val="24"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:rFonts w:hint="eastAsia"/>
<w:color w:val="000000"/>
<w:kern w:val="0"/>
<w:sz w:val="24"/>
</w:rPr>
<w:t>${st1Content!}</w:t>
</w:r>
</w:p>
</w:tc>
</w:tr>
二、動態生成Word:
/*1、資料格式為:list<String>*/
List<String> pringDataOneList = new LinkedList<>(20);
for (int i = 0; i < 20; i++) {
pringDataOneList.add("張三"+(i+1));
}
Map<String,Object> resultMap = new HashMap<>(1);
resultMap.put("printlist",pringDataOneList);
因為模板資料規定為map,在list外面套了一層map。
模板如下:
<!--printlist:map的key -->
<#if printlist?exists>
<!--遍歷list -->
<#list printlist as key>
<w:tr w:rsidR="00CF02E7" w:rsidRPr="00573DB1" w:rsidTr="003477DD">
<w:trPr>
<w:trHeight w:val="737"/>
</w:trPr>
<w:tc>
<w:tcPr>
<w:tcW w:w="2283" w:type="dxa"/>
</w:tcPr>
<w:p w:rsidR="00CF02E7" w:rsidRDefault="00CF02E7" w:rsidP="00CF02E7">
<w:pPr>
<w:widowControl/>
<w:jc w:val="left"/>
<w:rPr>
<w:b/>
<w:bCs/>
<w:color w:val="000000"/>
<w:kern w:val="0"/>
<w:sz w:val="24"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:b/>
<w:bCs/>
<w:color w:val="000000"/>
<w:kern w:val="0"/>
<w:sz w:val="24"/>
</w:rPr>
<!--列印陣列下邊並判斷非空-->
<w:t>${(key_index)!}</w:t>
<!--列印陣列內容並判斷非空-->
<w:t>${(key)!}</w:t>
</w:r>
<w:r>
<w:rPr>
<w:color w:val="000000"/>
<w:kern w:val="0"/>
<w:sz w:val="24"/>
</w:rPr>
<w:t xml:space="preserve"> </w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="7371" w:type="dxa"/>
</w:tcPr>
<w:p w:rsidR="00CF02E7" w:rsidRDefault="00CF02E7" w:rsidP="00CF02E7">
<w:pPr>
<w:widowControl/>
<w:rPr>
<w:color w:val="000000"/>
<w:kern w:val="0"/>
<w:sz w:val="24"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:rFonts w:hint="eastAsia"/>
<w:color w:val="000000"/>
<w:kern w:val="0"/>
<w:sz w:val="24"/>
</w:rPr>
<w:t>${(key_index)!}</w:t>
<w:t>${(key)!}</w:t>
</w:r>
</w:p>
</w:tc>
</w:tr>
</#list>
</#if>
----------------------------------------------------------------------------------------------------------------------------
/*2、資料格式為:Map<String,List<Entity>>*/
// 獲取資料,設定資料
List<Entity> printWordList = new LinkedList<>(20);
for (int i = 0; i < 20; i++) {
printWordList.add(new Entity("st"+(i+1)+"Name","st"+(i+1)+"Content"));
}
Map<String, Object> dataMap = new HashMap<>(1);
dataMap.put("printlist",printWordList);
class Entity{
private String name;
private String content;
public Entity (String name,String content){
this.name = name;
this.content = content;
}
@Override
public String toString() {
return "Entity{" +
"name='" + name + '\'' +
", content='" + content + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
/*其他程式碼與固定模板程式碼一致。*/
/*模板:*/
<!--先判斷printlist的值存在,取值得到printWordList-->
<#if printlist?exists>
<!--遍歷list-->
<#list printlist as mapa>
<w:tr w:rsidR="00CF02E7" w:rsidRPr="00573DB1" w:rsidTr="003477DD">
<w:trPr>
<w:trHeight w:val="737"/>
</w:trPr>
<w:tc>
<w:tcPr>
<w:tcW w:w="2283" w:type="dxa"/>
</w:tcPr>
<w:p w:rsidR="00CF02E7" w:rsidRDefault="00CF02E7" w:rsidP="00CF02E7">
<w:pPr>
<w:widowControl/>
<w:jc w:val="left"/>
<w:rPr>
<w:b/>
<w:bCs/>
<w:color w:val="000000"/>
<w:kern w:val="0"/>
<w:sz w:val="24"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:b/>
<w:bCs/>
<w:color w:val="000000"/>
<w:kern w:val="0"/>
<w:sz w:val="24"/>
</w:rPr>
<!--取list中的entity的name值-->
<w:t>${(mapa.name)!}</w:t>
</w:r>
<w:r>
<w:rPr>
<w:color w:val="000000"/>
<w:kern w:val="0"/>
<w:sz w:val="24"/>
</w:rPr>
<w:t xml:space="preserve"> </w:t>
</w:r>
</w:p>
</w:tc>
<w:tc>
<w:tcPr>
<w:tcW w:w="7371" w:type="dxa"/>
</w:tcPr>
<w:p w:rsidR="00CF02E7" w:rsidRDefault="00CF02E7" w:rsidP="00CF02E7">
<w:pPr>
<w:widowControl/>
<w:rPr>
<w:color w:val="000000"/>
<w:kern w:val="0"/>
<w:sz w:val="24"/>
</w:rPr>
</w:pPr>
<w:r>
<w:rPr>
<w:rFonts w:hint="eastAsia"/>
<w:color w:val="000000"/>
<w:kern w:val="0"/>
<w:sz w:val="24"/>
</w:rPr>
<!--取list中的entity的content值-->
<w:t>${(mapa.content)!}</w:t>
</w:r>
</w:p>
</w:tc>
</w:tr>
</#list>
</#if>
三、靜態模板生成PDF:
/*java程式碼:*/
public void printMarineNote(HttpServletResponse response){
String html = null;
Map<String,Object> map = new LinkedHashMap<>(4);
map.put("st1Name","張三");
map.put("st1Content","張三的java從入門到放棄");
map.put("st2Name","李四");
map.put("st2Content","李四的java從入門到放棄");
response.setCharacterEncoding("UTF-8");
html = getHtml("**模板名稱",map);
//輸出PDF檔名
response.setHeader("Content-Disposition","attachment;filename=" +
URLEncoder.encode("***.pdf","UTF-8"));
PdfUtils.createPdfForBsDebitNote(response, html);
}
private String getHtml(String fileName,Map<String,Object> map) throws Exception {
String freemarkerPath="templates\\modules\\freemarkermodle\\";
Resource resource = new ClassPathResource(freemarkerPath);
map.put("basePath", resource.getFile().getAbsoluteFile());
Template template = configuration.getTemplate(fileName);
StringWriter writer = new StringWriter();
template.process(map,writer);
writer.flush();
writer.close();
String html=writer.toString();
writer.close();
return html;
}
/*模板:*/
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>***</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
body {
font-family: Microsoft YaHei;
font-size: 2px;
}
@page {
size: A4;
}
</style>
</head>
<body bgcolor="#FFFFFF" leftmargin="0" topmargin="0" marginwidth="0" marginheight="0">
<table style="width: 100%; border-collapse: collapse;">
<tr>
<td style="width: 100%;height:35px;font-size:20px;text-align:center;"><strong>***</strong></td>
</tr>
</table>
<table style="width: 100%; border-collapse: collapse; font-size: 12px;">
<tr>
<td style="width: 580px; height: 400px;padding-left: 20px">
<table style="font-size: 12px;padding-left: 20px">
<tr>
<td style="width: 20%;padding-left: 60px; float: left; height: auto;padding-top: 10px;padding- buttom:10px;">${st1Name?if_exists}</td>
<td style="width: 30%;float: left; height: auto;padding-top: 10px;padding-buttom:10px;">${st1Content?if_exists}</td>
<td style="width: 20%;padding-left: 60px; float: left; height: auto;padding-top: 10px;padding-buttom:10px;">${st2Name?if_exists}</td>
<td style="width: 30%;float: left; height: auto;padding-top: 10px;padding-buttom:10px;">${st2Content?if_exists}</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
四、動態生成PDF:其實動態模板和上面的Word一樣。這裡我用的其他方式,畢竟條條大路通羅馬。
/**
*資料格式
* Map<String,Map<String,Object>> map = new HashMap<>();
*/
public void printMarineNote(HttpServletRequest request, HttpServletResponse response) throws Exception {
String html = null;
Map<String,Object> map = new HashMap<>();
Map<String,Object> map1 = new LinkedHashMap<>(20);
for (int i = 0; i < 20; i++) {
map1.put(i+"name",i+"content");
}
map.put("printMap",map1);
for (int i = 0; i < 2; i++) {
map.put(i+"dynamicMap",map1);
}
if(map.size()>1){
html = getDynamicHtml("***.ftl","***.ftl",map);
}else{
html = getDynamicHtml("***.ftl",null,map);
}
response.setHeader("Content-Disposition","attachment;filename=" +
URLEncoder.encode("***.pdf","UTF-8"));
createPdfForBsDebitNote(response, html);
}
public static void createPdfForBsDebitNote(HttpServletResponse response,String html) throws Exception{
Document doc = new Document(PageSize.A4,0,0,0,0);
OutputStream stream = response.getOutputStream();
PdfWriter pdfWriter = PdfWriter.getInstance(doc,stream);
pdfWriter.setPageEvent(new PdfPageEventHelper(){
@Override
public void onEndPage(PdfWriter writer, Document document) {
PdfContentByte cb = writer.getDirectContent();
try{
cb.setFontAndSize(BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED),6);
} catch (com.itextpdf.text.DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
cb.saveState();
cb.beginText();
cb.endText();
cb.restoreState();
}
});
doc.setMargins(10, 10, 10, 10);
doc.open();
ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(html.getBytes());
XMLWorkerHelper.getInstance().parseXHtml(pdfWriter,doc,byteArrayInputStream);
doc.close();
stream.close();
}
private String getDynamicHtml(String fileName,String fileName1,Map<String,Object> map) throws Exception {
String freemarkerPath="templates\\modules\\freemarkermodle\\";
Resource resource = new ClassPathResource(freemarkerPath);
StringWriter writer = new StringWriter();
String html1;
String html2 = null;
Map<String,Object> map1 = (Map<String, Object>) map.get("printMap");
Template template = configuration.getTemplate(fileName);
template.process(map1,writer);
writer.flush();
writer.close();
html1=writer.toString();
writer.close();
if(StringUtils.isNotBlank(fileName1)){
int i = 0;
if(map.size()>1){
for(String key : map.keySet()){
StringWriter writer1 = new StringWriter();
if(!"printMap".equals(key)){
Map<String,Object> map2 = (Map<String, Object>) map.get(i+"dynamicMap");
Template template1 = configuration.getTemplate(fileName1);
template1.process(map2,writer1);
writer1.flush();
writer1.close();
String html3=writer1.toString();
writer1.close();
html2+=html3;
i++;
}
}
}
}
String html = html1 + html2;
return html;
}
/*模板同上*/
freemarker中文文件如下:http://freemarker.foofun.cn/ref_builtins_alphaidx.html
完整的Word模板如下:
相關文章
- DocTemplateTool - 可根據模板生成word或pdf檔案的工具
- spring boot itextPdf根據模板生成pdf檔案Spring Boot
- Java 根據模板生成 PDF 檔案 以及 excel 檔案JavaExcel
- SpringBoot2 整合FreeMarker模板,完成頁面靜態化處理Spring Boot
- 靜態主席樹模板
- Java使用FreeMarker模版技術動態生成word實踐Java
- cmake:生成靜態庫和動態庫
- FreeMarker模板引擎
- 動態主席樹模板
- 模板 - 動態規劃動態規劃
- 關於Docx動態控制word模板檔案的資料
- 實現一個程式碼自動生成(一):模板引擎Freemarker
- 偽靜態、靜態和動態的區別
- Java模板引擎之FreeMarkerJava
- 關於FreeMarker模板注入
- 靜態庫與動態庫
- Springboot如何利用模板,快速生成word文件?Spring Boot
- 靜態路由和動態路由路由
- 靜態代理和動態代理
- 聊聊elasticsearch7.8的模板和動態對映Elasticsearch
- 關於靜態檔案目錄與模板引用和Nginx location塊的適配設定Nginx
- 基於 Svelte 的通用靜態網站開發模板網站
- 一個後臺靜態模板,自帶excel,print,cvsExcel
- JVM 模板直譯器之如何根據位元組碼生成彙編碼?JVM
- 靜態庫生成
- ios靜態庫和動態庫iOS
- 洛谷 - P3690 【模板】Link Cut Tree (動態樹)(LCT模板)
- docxtpl - word模板
- vue自定義表單生成器,可根據json引數動態生成表單VueJSON
- 利用FreeSql.Generator自動根據資料庫表動態生成實體類SQL資料庫
- 靜態域與靜態方法
- Excel模板匯出之動態匯出Excel
- echarts之靜態與動態地圖Echarts地圖
- 動態註冊和靜態註冊
- 靜態合批和動態合批
- Spring Boot (三)模板引擎FreeMarker整合Spring Boot
- SAST 與 DAST:靜態和動態應用程式安全測試AST
- BIRT 中如何根據引數動態拼接 SQLSQL