我是不会告诉你,关注公众号《andyqian》,回复pdf,会给你整个工程代码的!
前言
这是一篇以前的文章,最近做了优化处理,决定分享在这里,没有时间阅读全文的童鞋,可直接拖到最后一章节。进入主题,今天介绍的是电子凭证(pdf)生成的解决方案,会从几个常用的工具来介绍,也会对比一下几者之间的性能。
iText是什么?
在官网中 http://itextpdf.com/描述:
iText, the world's preferred PDF library,iText is a software developer toolkit that allows users to integrate PDF functionalities within their applications, processes or products
iText,是世界上首选的PDF库,iText是一个软件开发人员工具包,允许用户将PDF功能集成到其他应用程序,流程或者产品中。 其特点有:
- 支持表格
- 图片,
- 定制字体
- 支持合并pdf 等。
准备工作
在使用iTex时,我们需要添加Maven依赖,如下:
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.11</version>
</dependency>
入门实例
代码:
/**
* 生成pdf文件
*/
@Test
public void testCreatePdf(){
try{
// 1. new Document
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream(DEST));
// 2. 打开document
document.open();
// 3. 添加内容
document.add(new Paragraph("hello world!"));
// 4. 关闭 (如果未关闭则会生成无效的pdf文件)
document.close();
}catch(DocumentException ex){
ex.printStackTrace();
}catch (FileNotFoundException ex){
ex.printStackTrace();
}
}
效果:
iText字体
iText内置支持多种字体,我们可以通过FontFactory类找到iText的内置字体:
Courier;
Courier-Bold;
Courier-Oblique;
Courier-BoldOblique;
Helvetica;
Helvetica-Bold;
Helvetica-Oblique;
Helvetica-BoldOblique;
Symbol;
Times;
Times-Roman;
Times-Bold;
Times-Italic;
Times-BoldItalic;
ZapfDingbats;
同样,iText也允许自定义字体,itext默认字体不支持中文,这时,我们就可以通过自定义字体来解决这个问题,代码如下所示:
@Test
public void testChineseFontPdf(){
try {
//1. new document
Document document = new Document();
PdfWriter.getInstance(document, new FileOutputStream("/tmp/pdf/2017/1.pdf"));
//2. open document
document.open();
BaseFont bf = BaseFont.createFont(path()+"fonts/SIMKAI.TTF", BaseFont.IDENTITY_H,BaseFont.EMBEDDED);
//3. 注册字体
Font font = new Font(bf,30);
//3. 添加段落,并设置字体
document.add(new Paragraph("hello world(中文,)",font));
//4. close document
document.close();
}catch(FileNotFoundException ex){
ex.printStackTrace();
}catch(DocumentException ex){
ex.printStackTrace();
}catch(IOException ex){
ex.printStackTrace();
}
}
/**
* 获取资源的路径
* @return
*/
private String path(){
String path = this.getClass().getResource("/").getPath();
return path;
}
效果如下:
表格
通常我们会在pdf文件中生成表格,来展示数据,在iText中也是非常方便的,代码如下:
/**
* 生成表格
*/
@Test
public void testTablePdf(){
try {
//1.new document
Document document = new Document();
PdfWriter.getInstance(document,new FileOutputStream("/tmp/pdf/2017/1.pdf"));
//2 open document
document.open();
//3.添加pdf tables 3表示列数,
PdfPTable pdfPTable = new PdfPTable(3);
// cell表示单元格,(12表示12个单元格,3列,12个单元格就形成来一个4行3列的表格)
for (int i = 0; i < 12; i++) {
pdfPTable.addCell("cell" + i);
}
document.add(pdfPTable);
//4. 关闭document
document.close();
}catch(DocumentException ex){
ex.printStackTrace();
}catch(FileNotFoundException ex){
ex.printStackTrace();
}
}
生成效果如下所示:
图片
代码:
/**
* 生成image
*/
@Test
public void testImagePdf(){
try {
//1.new document
Document document = new Document();
PdfWriter.getInstance(document,new FileOutputStream("/tmp/pdf/2017/1.pdf"));
//2 open document
document.open();
document.add(new Paragraph("Hello world!"));
//3.添加image
Image image = Image.getInstance(path()+"/images/timg.jpg");
image.scaleAbsolute(PageSize.A4.rotate());
document.add(image);
//4. 关闭document
document.close();
}catch(DocumentException ex){
ex.printStackTrace();
}catch(FileNotFoundException ex){
ex.printStackTrace();
}catch (IOException ex){
ex.printStackTrace();
}
}
效果:
html转换pdf
我们在实际项目中,需要将html格式的文档转换为pdf工具,在iText中,默认是不直接支持html格式文档的,我们可以借助com.itextpdf.tool来生成 首先添加maven
<dependency>
<groupId>com.itextpdf.tool</groupId>
<artifactId>xmlworker</artifactId>
<version>5.5.11</version>
</dependency>
代码如下所示:
/**
* author: andy
* date: 17-5-30
* blog: www.andyqian.com
* version: 0.0.1
* description: 生成html格式內容的工具類
*/
public class CreateHtmlPdfTest {
/**
* html内容路径
*/
private static final String HTML_PATH= "/html/helloworld.html";
private static final String FONT_PATH="/fonts/SIMKAI.TTF";
/**
* 生成pdf格式的內容
*/
@Test
public void testHtml(){
try {
//1. new document
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("/tmp/pdf/2017/1.pdf"));
//2.open document
document.open();
//3. 设置字体
XMLWorkerFontProvider xmlWorkerFontProvider = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
xmlWorkerFontProvider.register(getContextPath()+FONT_PATH);
//4. 文件
FileInputStream fileInputStream = new FileInputStream(getContextPath()+HTML_PATH);
XMLWorkerHelper.getInstance().parseXHtml(writer, document,fileInputStream, Charset.forName("UTF-8"),xmlWorkerFontProvider);
//3. close document
document.close();
}catch(Exception ex){
ex.printStackTrace();
}
}
/**
* 获取上下文路径
* @return
*/
private String getContextPath(){
return this.getClass().getResource("/").getPath();
}
}
html代码内容:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>标题</title>
</head>
<style>
*{
font-family: KaiTi_GB2312;
}
</style>
<body>
hello world! XMLWorkerHelper [这是带有中文的html格式内容]
</body>
</html>
代码结构为:效果如下所示:
7.iText+Freemarker
首先添加Freemarker Maven依赖如下所示:
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.23</version>
</dependency>
代码如下所示:
/**
* author: andy
* date: 17-5-30
* blog: www.andyqian.com
* version: 0.0.1
* description: 通过feemarker工具类生成pdf
*/
public class CreateFeemarkerPdfTest {
private static final String FONT_PATH="/fonts/SIMKAI.TTF";
private static final String HTML_PATH="/html/feemarker.html";
@Test
public void testCreatePdf(){
try {
//1. new document
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("/tmp/pdf/2017/1.pdf"));
//2.open document
document.open();
//3. 设置字体
XMLWorkerFontProvider xmlWorkerFontProvider = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
xmlWorkerFontProvider.register(getContextPath()+FONT_PATH);
//4. 设置模板内容
Map<String,Object> params = new HashMap<String,Object>();
params.put("name","鞠骞");
params.put("career","软件开发");
params.put("blog","http://www.andyqian.com");
String content = getFreeMarkerText(htmlContent(),params);
//4. 文件
InputStream inputStream = new ByteArrayInputStream(content.getBytes("utf-8"));
XMLWorkerHelper.getInstance().parseXHtml(writer, document,inputStream, Charset.forName("UTF-8"),xmlWorkerFontProvider);
//3. close document
document.close();
}catch(Exception ex){
ex.printStackTrace();
}
}
/**
* 获取上下文路径
* @return
*/
private String getContextPath(){
return this.getClass().getResource("/").getPath();
}
/**
* freemarker模板方法
* @param templateTxt 模板文本
* @param map 模板参数
* @return
* @throws Exception
*/
public static String getFreeMarkerText(String templateTxt, Map<String, Object> map) throws Exception {
String result = null;
Configuration config = new Configuration(Configuration.VERSION_2_3_23);
try {
StringTemplateLoader e = new StringTemplateLoader();
e.putTemplate("t", templateTxt);
config.setTemplateLoader(e);
config.setDefaultEncoding("UTF-8");
Template template = config.getTemplate("t", "UTF-8");
StringWriter out = new StringWriter();
template.process(map, out);
result = out.toString();
return result;
} catch (IOException iex) {
throw new Exception("获取freemark模版出错", iex);
} catch (TemplateException ex) {
throw new Exception("freemark模版处理异常", ex);
}
}
/**
* 获取html内容
* @return
*/
private String htmlContent(){
String result = "";
try {
FileInputStream fileInputStream = new FileInputStream(getContextPath() + HTML_PATH);
int len=0;
byte[] array = new byte[1024];
StringBuffer stringBuffer = new StringBuffer();
while((len=fileInputStream.read(array))!=-1){
stringBuffer.append(new String(array,0,len));
}
result = stringBuffer.toString();
}catch(Exception ex){
ex.printStackTrace();
}
return result;
}
}
效果如下:
其实上面,在windows平台下还是有些问题的,字体路径会加载不到,处理方案,请看下一章节。
福利时间 | 现成代码
我是不会告诉你,关注公众号《andyqian》,回复pdf,会给你整个工程代码的!
如果想拷贝代码直接使用,也可以使用下面代码
public class PdfUtils {
private static final Logger logger = LoggerFactory.getLogger(PdfUtils.class);
/**
* 通过html生成文件
* @param htmlContent html格式内容
* @param file 输出文件file
*/
public static void createdPdfByItextHtml(String htmlContent,File file){
InputStream inputStream = null;
FileOutputStream outputStream = null;
PdfWriter writer = null;
try {
// 1. 获取生成pdf的html内容
inputStream= new ByteArrayInputStream(htmlContent.getBytes("utf-8"));
outputStream = new FileOutputStream(file);
Document document = new Document();
writer = PdfWriter.getInstance(document, outputStream);
document.open();
// 2. 添加字体
XMLWorkerFontProvider fontImp = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
fontImp.register(getFontPath());
// 3. 设置编码
XMLWorkerHelper.getInstance().parseXHtml(writer, document, inputStream, Charset.forName("UTF-8"),fontImp);
// 4. 关闭,(不关闭则会生成无效pdf)
document.close();
} catch (Exception ex) {
ex.printStackTrace();
}finally {
try {
if(writer!=null){
writer.close();
}
if (outputStream != null) {
outputStream.close();
}
if (inputStream != null) {
inputStream.close();
}
}catch(IOException ex){
ex.printStackTrace();
}
}
}
/**
* 应用场景:
* 1.在windows下,使用Thread.currentThread()获取路径时,出现空对象,导致不能使用
* 2.在linux下,使用PdfUtils.class获取路径为null,
* 获取字体路径
* @return
*/
private static String getFontPath(){
String path="";
// 1.
ClassLoader classLoader= Thread.currentThread().getContextClassLoader();
URL url = (classLoader==null)?null:classLoader.getResource("/");
String threadCurrentPath = (url==null)?"":url.getPath();
// 2. 如果线程获取为null,则使用当前PdfUtils.class加载路径
if(StringUtil.isBlank(threadCurrentPath)){
path = PdfUtils.class.getClass().getResource("/").getPath();
}
// 3.拼接字体路径
StringBuffer stringBuffer = new StringBuffer(path);
stringBuffer.append("/fonts/SIMKAI.TTF");
path = stringBuffer.toString();
logger.info("getFontPath threadCurrentPath: {} path: {}",threadCurrentPath,path);
return path;
}
上面getFontPath()方法中,对linux以及windows平台做了字体加载路径做了兼容处理。
参考资料
小结
本文从iText最基本的用法,分别介绍从表格,图片,HTML,Feemarker来介绍iText,希望能够帮助到你。
有任何问题,都可以在公众号下留言哦,在线提供帮助!
扫码关注,一起进步
个人博客: http://www.andyqian.com