SpringBoot⽣成带⽔印pdf中⽂字体问题
概述
⽣成pdf
中⽂字体问题
⼀般⽣成pdf引⽤中⽂字体有以下⼏种⽅式:
⽅法⼀:使⽤Windows系统字体(TrueType)
⽅法⼆:使⽤iTextAsian.jar中的字体
⽅法三:使⽤资源字体(ClassPath)
理论上使⽤⽅式三是最好的,但是实际使⽤过程中,itext读取字体的⽅式是接受的⽬录,不是实际的⽂件。所以当使⽤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_f", "ping_f", "ping_f", "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 = Property("user.dir");
log.info("project run path:" + systemRootPath);
//获取模板下的路径
String newFilePath = systemRootPath + File.separator + newFontPath+File.separator;
newFilePath = place("/", File.separator);
log.info("newFilePath:" + newFilePath);
File newFile = new File(newFilePath + ftlName);
if (newFile.isFile() && ists()) {
return newFilePath;
}
InputStream certStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(fontPath + ftlName); byte[] certData = ByteArray(certStream);
FileUtils.writeByteArrayToFile(newFile, certData);
return newFilePath;
} catch (IOException e) {
<("复制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>l</groupId>
<artifactId>xmlworker</artifactId>
<version>5.4.1</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
springboot中文<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,String waterMarkText){
ByteArrayOutputStream outputStream = null;
try{
outputStream = new ByteArrayOutputStream();
//设置⽂档⼤⼩
Document document = new Document(PageSize.A4);
PdfWriter writer = Instance(document, outputStream);
PDFBuilder builder = new PDFBuilder();
builder.setPresentFontSize(10);
writer.setPageEvent(builder);
//输出为PDF⽂件
convertToPDF(writer,document,htmlData,waterMarkText);
}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,String waterMarkText){ //获取字体路径
document.open();
//添加⽔印
buildDocumentWaterMark(writer, document, waterMarkText);
try {
String fontPath=getFontPath();
new Bytes()),
ResourceAsStream("/default.css"),
Charset.forName("UTF-8"),new XMLWorkerFontProvider(fontPath));
} catch (IOException e) {
e.printStackTrace();
throw new BusinessException("PDF⽂件⽣成异常",e);
}finally {
document.close();
}
}
private void buildDocumentWaterMark(PdfWriter writer,Document document,String waterMarkText){
if (StringUtils.isNotBlank(waterMarkText)) {
/
/ 加⼊⽔印
PdfContentByte waterMar = DirectContentUnder();
// 开始设置⽔印
waterMar.beginText();
// 设置⽔印透明度
PdfGState gs = new PdfGState();
// 设置填充字体不透明度为0.4f
gs.setFillOpacity(0.4f);
try {
// 设置⽔印字体参数及⼤⼩ (字体参数,字体编码格式,是否将字体信息嵌⼊到pdf中(⼀般不需要嵌⼊),字体⼤⼩) try {
waterMar.ateFont("/biz/pdf/fonts/SIMLI.TTF",BaseFont.IDENTITY_H,BaseFont.NOT_EMBEDDED), 36); } catch (DocumentException e) {
e.printStackTrace();
}
// 设置透明度
waterMar.setGState(gs);
// 设置⽔印对齐⽅式⽔印内容 X坐标 Y坐标旋转⾓度
waterMar.showTextAligned(Element.ALIGN_RIGHT, waterMarkText , 450, 630, 45);
// 设置⽔印颜⾊
waterMar.setColorFill(BaseColor.GRAY);
//结束设置
waterMar.stroke();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* @description 创建默认保存路径
*/
private String getDefaultSavePath(String fileName){
String classpath=ClassLoader().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() {
String fontPath=Resource("/").getPath()+ FontUtil.fontPath;
String systemName = Properties().getProperty("os.name");
//如果为服务器环境,jar包⽅式运⾏,取不到resource下的资源
if (!systemName.startsWith("Windows") && !systemName.startsWith("Mac")) {
fontPath = Property("user.dir")+File.separator + wFontPath+File.separator;
}
return fontPath;
}
}
ftl模板
模板⽤来⽣成html:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="/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>
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论