java通過html生成pdf,支援css和圖片以及橫向列印
阿新 • • 發佈:2020-07-30
專案當中通常會有生成pdf的需求,pdf的排版尤為重要!通過html生成,最為方便.
1. 依賴
工具使用freemarker模板進行資料渲染
<dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.29</version> </dependency> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>org.xhtmlrenderer</groupId> <artifactId>flying-saucer-pdf</artifactId> <version>9.1.18</version> </dependency>
2. 工具類
import java.io.*; import java.util.Locale; import java.util.Map; import org.xhtmlrenderer.pdf.ITextRenderer; import com.lowagie.text.pdf.BaseFont; import freemarker.template.Configuration; import freemarker.template.Template; public class PdfUtil { /** * 通過模板匯出pdf檔案 * @param data 資料 * @param templateFileName 模板檔名 * @throws Exception */ public static ByteArrayOutputStream createPDF(Map<String,Object> data, String templateFileName) throws Exception { // 建立一個FreeMarker例項, 負責管理FreeMarker模板的Configuration例項 Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); // 指定FreeMarker模板檔案的位置 cfg.setClassForTemplateLoading(PdfUtil.class,"/templates"); ITextRenderer renderer = new ITextRenderer(); OutputStream out = new ByteArrayOutputStream(); try { // 設定 css中 的字型樣式(暫時僅支援宋體和黑體) 必須,不然中文不顯示 renderer.getFontResolver().addFont("/static/font/SIMSUN.TTC", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); // 設定模板的編碼格式 cfg.setEncoding(Locale.CHINA, "UTF-8"); // 獲取模板檔案 Template template = cfg.getTemplate(templateFileName, "UTF-8"); StringWriter writer = new StringWriter(); // 將資料輸出到html中 template.process(data, writer); writer.flush(); String html = writer.toString(); // 把html程式碼傳入渲染器中 renderer.setDocumentFromString(html); // 設定模板中的圖片路徑 (這裡的images在resources目錄下) 模板中img標籤src路徑需要相對路徑加圖片名 如<img src="images/xh.jpg"/> String url = PdfUtil.class.getClassLoader().getResource("static/images").toURI().toString(); renderer.getSharedContext().setBaseURL(url); renderer.layout(); renderer.createPDF(out, false); renderer.finishPDF(); out.flush(); return (ByteArrayOutputStream)out; } finally { if(out != null){ out.close(); } } } }
程式碼中需要注意路徑設定,否則會導致css和圖片引入無效
-
cfg.setClassForTemplateLoading(PdfUtil.class,"/templates");
指定FreeMarker模板檔案的位置 -
renderer.getFontResolver().addFont("/static/font/SIMSUN.TTC", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
指定字型檔案,否則中文不顯示 -
PdfUtil.class.getClassLoader().getResource("static/images").toURI().toString();
靜態資源目錄結構:
3. 使用
建議使用時,先寫一個html靜態頁面,除錯好了再複製到ftl檔案中,儲存成模板
靜態index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title></title>
<style>
.center{
width: 380px;
height: 538px;
background: url("images/zs.png") center no-repeat;
margin: 10% auto;
font-family: SimSun;
position: relative;
}
.name{
position: absolute;
top: 216px;
left: 60px;
font-size: 20px;
width: 74px;
text-align: center;
display: block;
}
</style>
</head>
<body>
<div class="center">
<span class="name">李逍遙</span>
</div>
</body>
</html>
模板zhengshu.ftl
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title></title>
<style>
.center{
width: 380px;
height: 538px;
background: url("images/zs.png") center no-repeat;
margin: 15% auto;
font-family: SimSun;
position: relative;
}
.name{
position: absolute;
top: 216px;
left: 60px;
font-size: 20px;
width: 74px;
text-align: center;
display: block;
}
</style>
</head>
<body>
<div class="center">
<span class="name">${name}</span>
</div>
</body>
</html>
把需要設定資料的地方,用freemarker語法進行佔位${}
單元測試
@Test
public void pdf() throws IOException {
ByteArrayOutputStream baos = null;
FileOutputStream out = null;
try {
Map<String,Object> data = new HashMap<>();
data.put("name", "李逍遙");
baos = PdfUtil.createPDF(data, "zhengshu.ftl");
String fileName = "獲獎證書.pdf";
File file = new File(fileName);
out = new FileOutputStream(file);
baos.writeTo(out);
} catch (Exception e) {
e.printStackTrace();
} finally {
if(baos!=null){
baos.close();
}
if(out != null){
out.close();
}
}
}
使用controller
mport java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/pdf")
public class PdfController {
@RequestMapping("/export")
public void exportPdf(HttpServletResponse response) throws Exception{
ByteArrayOutputStream baos = null;
OutputStream out = null;
try {
// 模板中的資料,實際運用從資料庫中查詢
Map<String,Object> data = new HashMap<>();
data.put("name", "李逍遙");
baos = PdfUtil.createPDF(data, "zhengshu.ftl");;
// 設定響應訊息頭,告訴瀏覽器當前響應是一個下載檔案
response.setContentType( "application/x-msdownload");
// 告訴瀏覽器,當前響應資料要求使用者干預儲存到檔案中,以及檔名是什麼 如果檔名有中文,必須URL編碼
String fileName = URLEncoder.encode("獲獎證書.pdf", "UTF-8");
response.setHeader( "Content-Disposition", "attachment;filename=" + fileName);
out = response.getOutputStream();
baos.writeTo(out);
baos.close();
} catch (Exception e) {
e.printStackTrace();
throw new Exception("匯出失敗:" + e.getMessage());
} finally{
if(baos != null){
baos.close();
}
if(out != null){
out.close();
}
}
}
}
4. 橫向列印
有時網頁比較寬時,生成的pdf寬度不夠,導致顯示內容不完整,可以通過在模板css設定@page
控制
/*設定頁面寬高 A4大小*/
@page{size:297mm 210mm;}
參考: