图片模板
实现PDF生成,打印:①直接完全由java代码控制;②使用模板套打的方式(推荐使用,这里使用)
技术介绍:java实现对PDF的编辑,使用了Itext技术,需要jar包支持;
通过iText不仅可以生成PDF或rtf的文档,而且可以将XML、Html文件转化为PDF文件
参考:https://www.cnblogs.com/liaojie970/p/7132475.html
//配置文件如下:
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.10</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian<artifactId>
<version>5.2.0</version>
</dependency>
//配置完成后,首先是前端html或者jsp页面的下载按钮,去执行function函数里的请求。
//①直接完全由java代码控制
说明:
1.@RequestParam(value = “templateName”, required = false) :将参数中的templateName绑定到String templateName,这里required = false最好设置为false,除非你确定这个参数一定会传递给controller,否则会抛出参数绑定异常。
@RequestMapping(value = "/print")
@ResponseBody
public void pdfPrint(@RequsetParam(required = false,value = "templateName") String templateName,
HttpServletRequest request,HttpServletResponse response,AgentPayDetailInfo agentForm) throws Exception{
//首先说明agentPayInfo这个对象可以根据具体的需求自己的java对像,Text1-Text13是pdf模板上空白处的表单的key值,通过 该值可以用程序编辑pdf
//组装模板所需要的数据
HashMap<String,String> map = new HashMap<String,String>();
map.put("Text1",DataUtil.getDateFormatYH(agentPayInfo.getFinishDate()));//日期
map.put("Text2",Constants.PAY_ONESELF_NAME);//付款方全名
map.put("Text3",NumberToCN.number2CNMontrayUnit(agentPayInfo.getAmount());//人名币金额大写
map.put("Text4",agentPayInfo.getCardholder());//银行名称
map.put("Text5",agentPayInfo.getBankcardNo());/银行卡号
map.put("Text6",agentPayInfo.getBankName());//开户行
map.put("Text7",agentPayInfo.getAmount().toSting());//人名币金额小写
map.put("Text8",Constants.RMB);//账户类型
map.put("Text9",Constants.PAY_CERTIFIACTE_TYPE);//交易类型
map.put("Text10","");//用途
map.put("Text11",Constants.PAY_CERTIFIACTE_REMARK);//备注
String receiptNumber = DateUtil.getFDate(agentPayInfo.getFinishDate()) + agentPayInfo.getOutOrderId() + agentPayInfo.getSerialNumber();
map.put("Text12","电子回单编号:" + receiptNumber);
map.put("Text13",DateUtil.getFormatDate(agentPayInfo.getFinishDate()));//章子时间
//生成PDF
pdfStream = this.print(templateName,map,request);
/**
//①PrintWriter与ServletOutputStream文件下载的区别:
1. PrintWriter是以字符为单位,对所有的信息进行处理,而ServletOutputStream仅对二进制的资料进行处理。
2. PrintWriter在输出字符文本时内部需要将字符串转换成某种字符集编码的字节数组,使用他的好处就是不需要自己来完成从字符串到字节数组的转换。 转换的字符集编码是通过设置setContentTpye或setCharacterEncoding或setLocale等方法实现的;使用ServletOutputStream对象直接从一个字节输入流中读取出来,然后再原封不动的输出到客服端。
3. 这两个方法相互排斥,只能调用其一,如果要用,则要在换方法之前调用flush(),将缓冲区数据冲掉。
4. PrintWriter自动清空缓冲区的功能被使能时(构造函数中autoFlush置为true),仅当println()方法被调用时才自动清缓冲区,而不是像PrintStream一样遇到一个换行符就清缓冲。
*/
//写文件的最佳组合:PrintWriter out = new PrintWriter(new BufferWriter(new FileWriter(filename)));
ServletOutputStream sos = response.getOutputStream();
response.setContentType("application/pdf");
response.setHeader("Context-Disposition","inline;filename = \""
+ new String(receptionNumber.getBytes("gb18030"),"IOS8859-1" + ".pdf"+"\""));
int length = 0;
byte[] bytes = new byte[1024];
while(pdfStream != null && length = pdfStream.read(bytes) != -1){
sos.write(bytes,0,length);
}
sos.close();
//out.flush(),out是PrintWriter的实例 ;response.flushBuffer(),response是HttpServletResponse的实例
response.flushBuffer();//立即发送缓冲区中的输出
}
/**
*打印,以PDF为模板
*@param templateName String 模板名字
*@param map 模板数据HashMap
*@return InputStream
*@throws IOException
*/
private InputStream print(String templateName, HashMap map, HttpServletRequest request) throws IOException {
InputStream is = null;//抽象类是所有基于字节的输入流的超类
//服务器PDF模板文件名,得到的就是你tomcat下webapps下的的绝对路径
String realPath = request.getSession().getServletContext().getRealPath("/");
/java中如果不知道bean的类型或者不知道bean中的方法或属性时,无法给其赋值。
//但是java中有一个类可以在不知道bean的情况下也可以给其bean进行赋值和取值。那就是PropertyUtils类。
//该类可以对bean的属性(bean中要有属性的get和set方法)进行设值和取值。
//设值通过:PropertyUtils.setProperty(Object bean,String shuxing,String value)
//取值通过:PropertyUtils.getProperty(Object bean,String shuxing)
String web_info_URL = PropertyUtils.getValue("WEB_INFO_URL");
String agentPayPath = PropertyUtils.getValue("PDF_PATH");
String url = realPath + web_info_URL + agentPayPath;
String templatePath = url + "/model/";//模板路径
String serverPath = url + "/template/";//临时文件路径
PdfFormater pdf = new PdfFormater(templatePath, serverPath, templateName, map);
String PdfFilePath = pdf.DoTransform();
is = new FileInputStream(PdfFilePath);
return is;
}
//输出给页面是用ServletOutputStream ,设置了response的contextType(“application/pdf”);是由客户端自己的电脑完成//打印。小写换大写的工具类网上有很多。
//PdfFormater类
public class PdfFormer{
//路径设置
private String templateDir;
private String basePath;
private String templateFileFo;
//需要填充的数据
private Map dataMap;
private String templateFileName;
private String barcodeString;
private String resultFileName;
private List dynData;
/**
*@templateDir 模板文件所在目录
*@basePath 模板文件工作副本以及结果pdf文件所在工作目录
*@templateFileFo 模板文件名,推荐格式为“template.FO”,其文件由word模板文档在设计时转换而成
*@dataMap 对应模板的数据结HashMap,由调用该打印引擎的里的模板格式和约定进行准备
*/
public PdfFormater(String templateDir,String basePath,String templateFileFo,Map dataMap){
this.templateDir = templateDir;
this.basePath = basePath;
this.templateFileFo = templateFileFo;
this.dataMap = dataMap;
}
private BaseFont getBaseFont(Object obj){
//需要根据不同的模板返回字体
BaseFont bf = null;
try{
bf = BaseFont.createFont("STSong-light","UniGB-UCS2-H",BaseFont.NOT_EMBEDDED);
}catch(DocumentException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}
return bf;
}
public String DoTransform(){
long name = System.currentTimeMillis();//返回当前的计算机时间,date()方法就是继承它
tempFileName = "temp"+name+".pdf";
resultFileName = "best"+name+".pdf";
try{
PdfReader reader = new PdfReader("tempFileName");//模版文件目录
//设置文本域表单字体
PdfStamper stamper = new PdfStamper(reader,new FileOutputStream(basePath+"/"+tempFileName));
//设置文本域表单
AcroFields form = stamper.getAcroFields();
//设置文本域表单字体
form.addSubstitutionFont(getBaseFont(""));
transformRegular(form);
stamper.setFormFlattening(true);//设置为true
stamper.close();
postProcess();//同步方法
}catch(Excption e){
e.printStackTrace();
}
return base+"/"+resultFileName;
}
/**
*填充表单
*@param form
*/
private void transformRegular(AcroFields form){
if (dataMap == null || dataMap.size() == 0)
return;//只能用于void,强制结束
String key = "";
Iterator ekey = dataMap.keySet().iterator();
Object obj = null;
while (ekey.hasNext()){
try{
obj = dataMap.get(key);
if (obj instanceof List){
//map中放的list,为动态字段
dynData = (List)obj;
transformDynTable(form);
}else{
//非空放入
if (dataMap.get(key) != null)
form.setField(key,dataMap.get(key).toString());
}
}catch(IOException e){
e.printStackTrace();
}catch(DOCumentException e){
e.printStackTrace();
}
}
}
/**
*动态table填充
*@param form
*/
private void transformDynTable(AcroFields form){
if (dynData == null || dynData.size())
return;
Object obj = null;
ReflactUtils rutil = new ReflactUtils();
String name = "";
String value = "";
//getDeclareFields(),返回class中所有字段
//getFields(),只返回公共字段,即有public修饰的字段
//Fields、Fieldvalues和Fieldbyname的区别:
//Fields[]是将字段以数组列出;FieldValues[]是将字段数组中的值以名称方式直接取出
//FieldByName()虽然比较烦,但是在字段比较多,而且又有可能出现空值的情况下使用是最好的,在使用时这个方法时,必须指定所返回的值为何类型
Fields[] fld = obj.getClass().getDeclareFields();
for (int x = 0;x < dynData.size();x++){
obj = fld[i].getName();
value = (String)rutil.getFieldValue(obj,name);
try{
form.setFields(name+x,value);
}catch(IOException e){
e.printStackTrace();
}catch(DOCumentException e){
e.printStackTrace();
}
}
}
/**
*对生成的pdf文件进行后处理
*@throws RptException
*/
//synchronized关键字的用法,参见java关键字,“同步方法”
private synchronized void postProcess() throws Exception{
FileOutputStream fosRslt = null;
PdfStamper stamper = null;
try {
PdfReader reader = new PdfReader(basePath+"/"+tempFileName);
fosRslt = new FileOutputStream(basePath+"/"+resultFileName);
stamper = new PdfStamper(reader,fosRslt);
//比如:在特定位置插入图片,签名,需要计算pdf的宽度,高度,
//获取尺寸的两个方法:
//Rectangle pageSize = reader.getPageSize(1);
// Document document = new Document(pdfreader.getPageSize(1));
//例如: float height = pageSize.getHeight();float widths = document.getPageSize().getWidth();
Rectangle pageSize = reader.getPageSize(1);
float width = pageSize.getWidth();
bf = BaseFont.createFont("STSong-light","UniGB-UCS2-H",BaseFont.NOT_EMBEDDED);
//com.lowagie.text.pdf.PdfContentByte.setTextMatrix()
PdfContentType over;
int total = reader.getNumberOfPages()+1;//,迭代,每次只返回1
for (int i = 1;i < total;i++){
//这里可以加水印,此处没加
over = stamper.getOverContent(i);
if (total <= 2) break;
over.begintText();//用来设置文字的位置和字体---开始
over.setFontAndSize(bf,10);
over.setTextMatrix(width-92f,32);
over.showText("第"+i+"页");
over.endText(); //用来设置文字的位置和字体---结束
} catch (Exception ie) {
ie.printStackTrace();
} finally {
if (stamper != null) {
try {
stamper.close();
} catch (DocumentException e) {
//是XML等文件格式问题,报错
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fosRslt != null) {
try {
fosRslt.close();
} catch (IOException e) {
e.printStackTrace();
}
}
File pdfFile = new File(basePath, "/" + tempFileName);
//java file类delete()方法删除文件 ,删除之前需要关闭所有相关的流
pdfFile.delete();
}
}