PDF的生成与下载

来源:互联网 发布:万网 解析 端口 编辑:程序博客网 时间:2024/05/16 17:16

近期做一个生成PDF的直接下载功能,当然一般有两种方法,一种是代码实现其内容,代码实现样式可参考 http://rensanning.iteye.com/blog/1538689,另一种通过制作模板向其添加数据生成PDF下载,模板制作方式参考: http://wenku.baidu.com/linkurl=3dKL69zhDcMywL4hNmvmLHP2MvG2oT6ahfqijlIVpcvz7W_xi6fYEoWQQBMzi8b2360KOvJFB9CCgKbvAN01Zr2k0LKnyOqPaxcm5vYdsCO;

由于本业务要求输出的PDF较为复杂,所以选择通过模板实现其样式进行PDF的输出,首先准备相应的jar包,

<pre name="code" class="java">核心包:<dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.4.3</version></dependency>中文支持包:<dependency>    <groupId>com.itextpdf</groupId>    <artifactId>itext-asian</artifactId>    <version>5.2.0</version></dependency>
中文支持的话其他版本有问题,上述两个版本同时使用通过测试的;

因为项目用的是SpringMVC,所以控制层代码:

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"></span><pre name="code" class="java">@RequestMapping("/download")    public String pdfDownload(Model model) {//添加数据model.addAttribute("data", "大哥"));        return "contract";    }
配置文件:
<pre name="code" class="java"><!-- 按照BeanName解析视图 --><bean class="org.springframework.web.servlet.view.BeanNameViewResolver"/><!-- 定义Pdf模版视图 -->        <bean id="contract" class="com.netease.cpp.view.PdfStamperView">  <property name="url" value=""  />        </bean>

Spring框架给我们集成了读取模板生成PDF的类AbstractPdfStamperView;但是其只集成的是itext2.7.0以前的版本,现在已变成itextpdf5.4以上,itext有些方法被itextpdf重写,导致我们不能直接使用AbstractPdfStamperView,解决方式是我们写个类去继承AbstractUrlBasedView,复制AbstractPdfStamperView的方法,重新引入相关方法,

/** * PDF模板视图 ;重新定义AbstractPdfStamperView类重写其中相关方法 */public abstract class AbstractPdf4StamperView extends AbstractUrlBasedView { public AbstractPdf4StamperView(){setContentType("application/pdf");}@Overrideprotected boolean generatesDownloadContent() {return true;}/** * 通过model判断读取模板 ,关闭相关流 */@Overrideprotected final void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response)  {     // IE workaround: write into byte array first.    <span style="white-space:pre"></span>ByteArrayOutputStream baos = createTemporaryOutputStream();String path = request.getSession().getServletContext().getRealPath("/");  String TemplatePDF = path + "WEB-INF/pdftemple/"+temp+".pdf"; PdfReader reader = null;PdfStamper stamper = null;try {reader = new PdfReader(TemplatePDF);stamper = new PdfStamper(reader, baos);mergePdfDocument(model, stamper, request, response);} catch (IOException ex) {LoggerUtil.error("读取模板异常", ex);} catch (PDFException e) {LoggerUtil.error("生成pdf异常", e);} catch (DocumentException dx){LoggerUtil.error("生成pdf异常", dx);} finally{if (stamper != null) {try {stamper.close();} catch (IOException e) {LoggerUtil.error("关闭IO异常", e);} catch (DocumentException dx){LoggerUtil.error("生成失败", dx);}}if(reader != null ){reader.close();}}// Flush to HTTP response.response.setContentType(getContentType());response.setContentLength(baos.size());// Flush byte array to servlet output stream.ServletOutputStream out = null;try {out = response.getOutputStream();baos.writeTo(out);out.flush();} catch (IOException e) {LoggerUtil.error("writeToResponse is Exception", e);} finally {if (out != null) {try {out.close();} catch (IOException e) {LoggerUtil.error("关闭IO异常", e);}}if (baos != null){try {baos.close();} catch (IOException e) {LoggerUtil.error("关闭IO异常", e);}}}}protected PdfReader readPdfResource() throws IOException {return new PdfReader(getApplicationContext().getResource(getUrl()).getInputStream());} protected abstract void mergePdfDocument(Map<String, Object> model, PdfStamper stamper,HttpServletRequest request, HttpServletResponse response) throws PDFException;}
原本renderMergedOutputModel方法只有下面几行:
@Overrideprotected final void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {// IE workaround: write into byte array first.ByteArrayOutputStream baos = createTemporaryOutputStream();PdfReader reader = readPdfResource();PdfStamper stamper = new PdfStamper(reader, baos);mergePdfDocument(model, stamper, request, response);stamper.close();// Flush to HTTP response.writeToResponse(response, baos);}
在测试过程中发现已加载的模板无法删除,才发现框架提供的方法没有关闭相关的流,所以也在该类下手动关闭了相关流,注意的是模板放在maven构建的resource下无法被加载,也能是模板被编译的故,具体原因待解,所以把模板放在了WEB-INF下,这也是原先框架放置的地方,因为在配置pdf模板视图是有个URL参数就是添的web-inf;只不过我要选择不同的模板所以重写了读取模板的方法。

接下来是写一个类去继承AbstractPdf4StamperView然后重写mergePdfDocument方法进行数据的添加:

package com.netease.cpp.view;import java.io.IOException;import java.io.UnsupportedEncodingException;import java.net.URLEncoder;import java.util.Calendar;import java.util.Map;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.itextpdf.text.DocumentException;import com.itextpdf.text.pdf.AcroFields;import com.itextpdf.text.pdf.PdfStamper;import com.netease.cpp.exception.PDFException;import com.netease.cpp.util.LoggerUtil;/** * 生成PDF */public class PdfStamperView extends AbstractPdf4StamperView {    @SuppressWarnings("unchecked")    @Override    protected void mergePdfDocument(Map<String, Object> model, PdfStamper stamper, HttpServletRequest request,HttpServletResponse response) throws PDFException {        // 设置response方式,使执行此controller时候自动出现下载页面,而非直接使用pdf打开          response.setContentType("APPLICATION/OCTET-STREAM"); try {response.setHeader("Content-Disposition", "attachment; filename="+ URLEncoder.encode(filename, "UTF-8"));} catch (UnsupportedEncodingException e) {LoggerUtil.error("文件名编码失败", e);throw new PDFException(e);}        AcroFields fields = stamper.getAcroFields();try {fillData(fields,model);} catch (IOException ex) {LoggerUtil.error("向pdf添加数据失败", ex);throw new PDFException(ex);} catch (DocumentException dx){LoggerUtil.error("向pdf添加数据失败", dx);}    stamper.setFormFlattening(true);//必须有,否则输出的pdf是一个表单}    //给模板添加数据    @SuppressWarnings("unchecked")    private void fillData(AcroFields fields,Map<String, Object> model)throws IOException, DocumentException {    Map<String, String> data=( Map<String, String>) model.get("data");    for (String key : data.keySet()) {        String value = data.get(key);        fields.setField(key, value);    }    }  }

代码中写出了一些注意事项,这样就能实现PDF的下载了






0 0