概述
生成pdf
SpringBoot部署方式以jar包方式運行,在獲取字體的時候獲取不到,因爲在服務器上讀取的字體路徑爲jar包中的路徑:
file:/root/startup/za-minos-ms.jar!/BOOT-INF/classes!/
如上圖,這種路徑是無法正確讀取文件的,所以合理的解決方案是通過流讀取,然後在服務器上創建新的文件。
讀取和創建新文件的代碼:
/**
* Created by zhangshukang on 2019/7/25.
*/
@Slf4j
@Component
public class FontUtil {
public static String[] fontNames = {"ping_fang_bold.ttf", "ping_fang_light.ttf", "ping_fang_regular.ttf", "SIMLI.TTF"};
public static String fontPath = "biz/pdf/fonts/";
public static String newFontPath = "resources";
private static String sourceTemplatePath;
static {
//靜態方法調用一次
sourceTemplatePath = createFtlFileByFtlArray();
}
public static String createFtlFileByFtlArray() {
String path = "";
for (int i = 0; i < fontNames.length; i++) {
path = createNewFile(fontPath, fontNames[i]);
if (null == path) {
log.info("ftl not copy success:" + fontNames[i]);
}
}
return path;
}
private static String createNewFile(String fontPath, String ftlName) {
try {
String systemRootPath = System.getProperty("user.dir");
log.info("project run path:" + systemRootPath);
//獲取模板下的路徑
String newFilePath = systemRootPath + File.separator + newFontPath+File.separator;
newFilePath = newFilePath.replace("/", File.separator);
log.info("newFilePath:" + newFilePath);
File newFile = new File(newFilePath + ftlName);
if (newFile.isFile() && newFile.exists()) {
return newFilePath;
}
InputStream certStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(fontPath + ftlName);
byte[] certData = IOUtils.toByteArray(certStream);
FileUtils.writeByteArrayToFile(newFile, certData);
return newFilePath;
} catch (IOException e) {
log.error("複製new文件失敗--> 異常信息:" + e);
}
return null;
}
}
在項目啓動的時候會將字體文件通過流讀取,生成新的文件,目錄爲jar包所在目錄。
生成pdf工具類
maven 依賴:
<!--pdf生成 itext-->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.4.2</version>
</dependency>
<dependency>
<groupId>com.itextpdf.tool</groupId>
<artifactId>xmlworker</artifactId>
<version>5.4.1</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf</artifactId>
<version>9.0.3</version>
</dependency>
/**
* Created by zsk on 2019/7/24.
*
*/
@Slf4j
public class PDFKit {
public ByteArrayOutputStream exportToFile(String htmlData){
ByteArrayOutputStream outputStream = null;
try{
outputStream = new ByteArrayOutputStream();
//設置文檔大小
Document document = new Document(PageSize.A4);
PdfWriter writer = PdfWriter.getInstance(document, outputStream);
PDFBuilder builder = new PDFBuilder();
builder.setPresentFontSize(10);
writer.setPageEvent(builder);
//輸出爲PDF文件
convertToPDF(writer,document,htmlData);
}catch(Exception ex){
throw new BusinessException("PDF export to File fail",ex);
}finally{
IOUtils.closeQuietly(outputStream);
}
return outputStream;
}
/**
* @description PDF文件生成
*/
private void convertToPDF(PdfWriter writer,Document document,String htmlString){
//獲取字體路徑
document.open();
try {
String fontPath=getFontPath();
XMLWorkerHelper.getInstance().parseXHtml(writer,document,
new ByteArrayInputStream(htmlString.getBytes()),
XMLWorkerHelper.class.getResourceAsStream("/default.css"),
Charset.forName("UTF-8"),new XMLWorkerFontProvider(fontPath));
} catch (IOException e) {
e.printStackTrace();
throw new BusinessException("PDF文件生成異常",e);
}finally {
document.close();
}
}
/**
* @description 創建默認保存路徑
*/
private String getDefaultSavePath(String fileName){
String classpath=PDFKit.class.getClassLoader().getResource("").getPath();
String saveFilePath=classpath+"biz/pdf/"+fileName;
File f=new File(saveFilePath);
if(!f.getParentFile().exists()){
f.mkdirs();
}
return saveFilePath;
}
/**
* @description 獲取字體設置路徑
*/
public static String getFontPath() {
FontUtil fontUtil = new FontUtil();
fontUtil.createFtlFileByFtlArray();
String fontPath=PDFKit.class.getResource("/").getPath()+ FontUtil.fontPath;
String systemName = System.getProperties().getProperty("os.name");
//如果爲服務器環境,jar包方式運行,取不到resource下的資源
//這裏讀取的是上面創建的新的字體文件
if (!systemName.startsWith("Windows") && !systemName.startsWith("Mac")) {
fontPath = System.getProperty("user.dir")+File.separator + FontUtil.newFontPath+File.separator;
}
return fontPath;
}
}
ftl模板
模板用來生成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>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta http-equiv="Content-Style-Type" content="text/css"/>
<title></title>
<style type="text/css">
body {
font-family: pingfang sc light;
}
.center{
text-align: center;
width: 100%;
}
</style>
</head>
<body>
<div class="page" >
<div class="center"><p>覈保諮詢保全信息確認函</p></div>
<div><p>保單號:${policyNo}</p></div>
<div><p>批單類型:${busType}</p></div>
<div><p>是否同意:${customerDecision}</p></div>
<div><p>生效日期:${effectiveDate}</p></div>
<div><p>二核人員:${(lockId)!}</p></div>
<div><p>是否退費:${(isRefund)!}</p></div>
<div><p>退費金額:${(refundAmount)!}</p></div>
</div>
</body>
</html>