在做单位OA项目的时候有个功能,合同打印的功能,之前的想法是打印PDF。既然是打印PDF就需要用到PDF插件,java比较常用方便的插件有几种,我选择了IText,当然IText版本众多,也让我走了不少的弯路。
要说实现方式IText有三种方式来生成pdf:
1、绘制
2、PDF模板
3、html转PDF
这三种方法各有千秋,从我试验的顺序开始说起
适用场景:
适用于内容较少的文字、表格或者图片生成PDF
优点:
可以做成多样结构的PDF,书写方便、不需要模板。
缺点:
对于复杂的多样PDF不适合、写样式会累死人。
实现:
1、初始化pdf
// 设置纸张的大小
Document document = new Document(PageSize.A4, 80, 80, 20, 36);
try {
PdfWriter.getInstance(document, new FileOutputStream(distDir));
document.open();
Paragraph p = TemplateUtil.paragraphFonts("员工日常费用报销流程", Font.BOLD, 14);
p.setAlignment(Element.ALIGN_CENTER);
document.add(p);
PdfPTable table = createTable(gaFlowNormalExpenseInfo,gaDetails,flowOpnions);
document.add(table);
} catch (Exception e) {
e.printStackTrace();
}
2、绘制表格
public PdfPTable createTable(GaFlowNormalExpenseInfo gaFlowNormalExpenseInfo,List gaDetails,List flowOpnions){
PdfPTable table = new PdfPTable(4);
table.setWidthPercentage(100);// 设置表格宽度为100%
table.setSpacingBefore(15f);// 设置段落前间距
table.setSpacingAfter(10f);
table.setFooterRows(2);
PdfPCell cell = TemplateUtil.customCell("员工日常费用报销", Font.BOLD);
cell.setBackgroundColor(Color.LIGHT_GRAY);
cell.setColspan(4);
table.addCell(cell);
cell = TemplateUtil.customCell("业务编号");
table.addCell(cell);
cell = TemplateUtil.customCell(gaFlowNormalExpenseInfo.getCode(),false,Font.NORMAL,7);
cell.setColspan(3);
table.addCell(cell);
……
for(GaFlowNormalExpenseDetail detail : gaDetails){
cell = TemplateUtil.customCell("发票时间");
table.addCell(cell);
cell = TemplateUtil.customCell(DateUtils.dateTimeToString(detail.getInvoiceTime()));
table.addCell(cell);
……
}
return table;
}
代码结构比较简单,但是打印出来的样子如果想做的特别美观需要慢慢的去写!
应用场景:适合模板文本较多,动态内容较少的,只需要填写个别的空,空的内容较少
优点:样子美观,开发容易便捷
缺点:针对于循环,或者大文本上不适合,不易于扩展
实现:
需要准备下载地址:链接:http://pan.baidu.com/s/1kVbRyPD 密码:k8ky
首先用word编辑好需要的样式
然后转成PDF再用这个软件打开
点击编辑表单
这里就会留出一个个坑,然后我们将这里的坑编好编号
//将需要填入模板的字段扔到Map(dataMap)里,distDir:生成的位置
ITextUtil.genPdfByTemplate("pdftemp/CLFBX_TEMPLETE_10.pdf", distDir,dataMap);
ITextUtil.java
package com.yinker.oa.sys.util;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.AcroFields;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfCopy;
import com.lowagie.text.pdf.PdfGState;
import com.lowagie.text.pdf.PdfImportedPage;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfStamper;
import com.lowagie.text.pdf.PdfWriter;
public class ITextUtil {
// 所有者密码
private static final String OWNERPASSWORD = "123123";
private static final Logger logger = LoggerFactory.getLogger(ITextUtil.class);
/**
* 使用场景:同一个模板,打印多份,每份填充不同的内容
*
* @例如:《共有人声明》,有几个共有人则打几份,虽然使用同一个模板,但是每一份都填充不同的信息。
* @实现方式:先生成多个临时文件,然后复制过去
* @param srcFile
* @param distFile
* @param dataList
*/
public static void genPdfByTemplate(String srcFile, String distFile, List
实现思路:
利用volicity模板引擎生成HTML代码(适应各种复杂结构的变化),然后利用IText将HTML文件转成PDF文件
优点:方便,快捷,使用样式比较复杂的输出,适用于网页另存为pdf的转存方式
缺点:对中文的支持需要替换一下jar包
实现:
1、所需maven
<dependency>
<groupId>com.lowagie.textgroupId>
<artifactId>iTextAsianartifactId>
<version>1.0version>
dependency>
<dependency>
<groupId>com.lowagiegroupId>
<artifactId>itextartifactId>
<version>2.0.8version>
dependency>
<dependency>
<groupId>org.xhtmlrenderergroupId>
<artifactId>core-rendererartifactId>
<version>R8version>
dependency>
2、volicity模板生成方法
private String createHtml(GaFlowContractExamineApply GaFlowContractExamineApply,List opnions,String distFileName){
PmParamService pmParamService = (PmParamService)SpringBeanContext.getBean("pmParamService");
PmParam pmParam = pmParamService.selectByCode("tempFilePath");
Properties p = new Properties();
p.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, "");
p.setProperty(Velocity.ENCODING_DEFAULT, "UTF-8");
p.setProperty(Velocity.INPUT_ENCODING, "UTF-8");
p.setProperty(Velocity.OUTPUT_ENCODING, "UTF-8");
String htmlPath="";
try {
String path =ServletActionContext.getServletContext().getRealPath("/pdfjs-dist/web/");
Velocity.init(p);
Template template = Velocity.getTemplate(path+"/vm/HTSPSQ.vm");
VelocityContext context = new VelocityContext();
context=putContext(GaFlowContractExamineApply, opnions);
String fileLocation = pmParam.getValue() + "/htmltemp/";
try {
if (!(new File(fileLocation).isDirectory())) {
new File(fileLocation).mkdir();
}
} catch (SecurityException e) {
e.printStackTrace();
}
FileOutputStream fos = new FileOutputStream(fileLocation +distFileName + ".html");
htmlPath=fileLocation +distFileName + ".html";
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos, "UTF-8"));//设置写入的文件编码,解决中文问题
template.merge(context, writer);
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
return htmlPath;
}
volicity模板。ps:图片路径我是从后台传过来的
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8" />
<title>Documenttitle>
<style>
*{margin: 0;padding: 0;}
body{
font-family:"Microsoft YaHei";
width:664px;
margin:0 auto;
}
h5{
width: 100%;
font-weight: 900;
text-align: center;
font-size: 26px;
padding: 16px 0;
background: url($basePath) no-repeat 0 8px;
background-size: 180px 35px;
}
…省略…
style>
head>
<body>
<h5>合同审批申请h5>
<table >
<tbody>
<tr>
<td class="titL"><span>所属事业部span>td>
<td colspan="2" class="contL cont"><span>$SSSYBspan>td>
<td class="titR"><span>合同编号span>td>
<td colspan="2" class="contR cont"><span>$HTBHspan>td>
tr>
<tr>
<td class="titL"><span>所属机构span>td>
<td colspan="2" class="contL cont"><span>$SSJGspan>td>
<td class="titR"><span>二级部门span>td>
<td colspan="2" class="contR cont"><span>$EJBMspan>td>
tr>
…此处省略…
#foreach($option in $OPTIONS)
<tr class="dataCont">
<td class="titL"><span>$option.flowNodeNamespan>td>
<td colspan="5" class="longCont cont">
<span>
#if (!$option.opnion)
#end
#if ($option.opnion)
$option.opnion
#end
span>
td>
tr>
#end
tbody>
table>
body>
html>
3、html转pdf方法
private void html2Pdf(String htmlPath, String pdfPath) throws Exception {
try{
String url = new File(htmlPath).toURI().toURL().toString();
OutputStream os = new FileOutputStream(pdfPath);
ITextRenderer renderer = new ITextRenderer();
renderer.setDocument(url);
// 解决中文支持问题
ITextFontResolver fontResolver = renderer.getFontResolver();
//宋体
fontResolver.addFont(ServletActionContext.getServletContext().getRealPath("/pdfjs-dist/web/vm/")+"/simsun.ttf",BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
//微软雅黑
fontResolver.addFont(ServletActionContext.getServletContext().getRealPath("/pdfjs-dist/web/vm/")+"/msyh.ttf",BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
renderer.layout();
renderer.createPDF(os);
os.close();
}catch(Exception ex){
ex.printStackTrace();
}
}
这种方法说白了也没有什么难点,但是有几个地方我捉摸了挺长时间才走通
PS
①:中文换行的问题,由于老外的字体都是以空格来分词的,所以之前的程序是遇到空格如果到边界就会换行,中文则不是,所以对这个地方进行了优化
②:中文字体,中文字体需要服务器上有这个字体多个字体需要多次添加
③:图片路径问题,之前按照百度以及Google的方法试验了很久,一直没走通,windows下毫无压力,Linux环境下的图片设置文件根目录会有问题,所以索性,所有的图片都搞成了绝对路径的方式回填到html中,大功告成!
转载请注明出处