通过freemarker+iText生成pdf和doc文件

来源:互联网 发布:unity3d打字游戏 编辑:程序博客网 时间:2024/05/05 02:10

0、通过上一篇已经能够跑起来将ftl展示成html,这里进一步将ftl模版文件生成pdf和doc

1、公共类,初始化freemarker,从request里面获取参数,组装参数等

import freemarker.template.Configuration;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import javax.servlet.http.HttpServletRequest;import java.util.Enumeration;import java.util.HashMap;import java.util.Map;/** * Created by Administrator on 2016/11/2. */public class FreemarkerBase {    protected final Log logger = LogFactory.getLog(getClass());    private Configuration freemarker_cfg = null;    /**     * 获取freemarker的配置. freemarker本身支持classpath,目录和从ServletContext获取.     */    protected Configuration getFreeMarkerCFG(){        if (null == freemarker_cfg){            freemarker_cfg = new Configuration();            freemarker_cfg.setDefaultEncoding("utf-8");            //ftl是放在classpath下的一个目录            freemarker_cfg.setClassForTemplateLoading(this.getClass(), "/freemarker/");        }        return freemarker_cfg;    }    //取出req中的参数,这里最好用guawa等做一下参数验证,否则会报错,展示不合理    protected Map getRequestParams(HttpServletRequest req, String type){        String imgPath = req.getSession().getServletContext().getRealPath("");        Map<String, Object> map = new HashMap<>();        Enumeration<String> paramNames = req.getParameterNames();        // 通过循环将表单参数放入键值对映射中        while(paramNames.hasMoreElements()) {            String key = paramNames.nextElement();            String value = req.getParameter(key);            //word:如果ftl绑定的图片,需要根目录的路径            if("doc".equals(type)                    && (value.toLowerCase().contains(".jpg")                    || value.toLowerCase().contains(".png"))){                value = req.getSession().getServletContext().getRealPath("/upload") + "/" + value;            }            //pdf:这里我写的是访问连接的根目录,因为不知道为什么我写全路径就不行,怪异了。            else if("pdf".equals(type)                    && (value.toLowerCase().contains(".jpg")                    || value.toLowerCase().contains(".png"))){                value = "http://localhost:8080/upload/" + value;            }            // System.out.println(value);            map.put(key, value);        }        return map;    }}

2、公共方法

/* *下面两个是doc和pdf的公共方法 *///生成临时文件方法//templateFileName  模版名,即ftl文件名,见上面的show.ftl//params   ftl文件内的参数绑定//htmlFilePath  文件生成目录//suffix 后缀,eg:.doc .pdf 等等private String createTemplateDownFile(String templateFileName, Map params,                                      String htmlFilePath, String suffix){    String htmlFileName = "temp" + (int) (Math.random() * 100000) + suffix;    try{        Template t = getFreeMarkerCFG().getTemplate(templateFileName);        File mkPath = new File(htmlFilePath);        if (!mkPath.exists()){            mkPath.mkdirs();        }        File file = new File(htmlFilePath + "/" + htmlFileName);        Writer out = new OutputStreamWriter(new FileOutputStream(file), "utf-8");        t.process(params, out);    }catch (TemplateException e){        logger.error("freemarker模版参数绑定错误 " + templateFileName,e);        e.printStackTrace();    }catch (IOException e){        logger.error("html生成失败 " + htmlFileName,e);        e.printStackTrace();    }    return htmlFileName;}//下载方法private void downLoad(HttpServletResponse resp, String allPath, String suffix){    resp.setCharacterEncoding("utf-8");    //这里是一个生成名字的方法,我是用了一个我们自己的公共类,按照日期生成名字    String name = DateUtil.dateToStr(new Date(), 5  );    //根据后缀判断resp的题头文件    if("html".equals(suffix)){        resp.setContentType("text/html");    } else if("doc".equals(suffix)){        resp.setContentType("application/msword");    } else if("pdf".equals(suffix)){        resp.setContentType("application/PDF");    }    resp.addHeader("Content-Disposition", "attachment;filename=" + name + suffix);    //开始下载    File file = new File(allPath);    try {        InputStream fin = new FileInputStream(file);        ServletOutputStream out = resp.getOutputStream();        byte[] buffer = new byte[512];  // 缓冲区        int bytesToRead = -1;        // 通过循环将读入的文件的内容输出到浏览器中        while((bytesToRead = fin.read(buffer)) != -1) {            out.write(buffer, 0, bytesToRead);        }    } catch (IOException e) {        e.printStackTrace();    }}

3、生成doc文件很简单,不用额外导入什么jar

//主方法@RequestMapping("downDoc")public void downDoc(HttpServletRequest request, HttpServletResponse resp){    String rootPath =  request.getSession().getServletContext().getRealPath("/doc");    String fileName = createTemplateDownFile("show.ftl" , getRequestParams(request, "doc"), rootPath, ".doc");    String allPath = rootPath + "/" + fileName;    //下载公共方法    downLoad(resp, allPath, ".doc");}

4、生成pdf文件,pdf我是通过ftl生成html文件,再通过这个静态的html文件生成pdf,这样不知道是不是冗余,当时是测试html的下载,所以直接拿来用了。

引入jar:

<dependency>    <groupId>com.lowagie</groupId>    <artifactId>itext</artifactId>    <version>2.1.7</version></dependency><dependency>    <groupId>org.xhtmlrenderer</groupId>    <artifactId>flying-saucer-pdf</artifactId>    <version>9.0.9</version></dependency>

有歧义的jar,不引入

<!-- 2.*直接跳到了5.*,结构不大一样,网上demo多是2.*的,所以暂时先用了 --><dependency>    <groupId>com.itextpdf</groupId>    <artifactId>itextpdf</artifactId>    <version>5.4.3</version></dependency><!-- 我用bootstarp的css文件这里一直报错,后来用了上面的,是基于java,2.1css渲染的 --><dependency>    <groupId>org.xhtmlrenderer</groupId>    <artifactId>core-renderer</artifactId>    <version>R8</version></dependency><!-- 用了自己的文字,如果用itext的需要这个jar展示中文,不过我一直也搞不好报错,所以就用自己的了 --><dependency>    <groupId>com.itextpdf</groupId>    <artifactId>itext-asian</artifactId>    <version>5.2.0</version></dependency>

代码:

/** * 下载pdf文件 * @param request * @param resp */@RequestMapping("downPdf")public void downPdf(HttpServletRequest request, HttpServletResponse resp){    //eg:c:/workspace/项目/doc/    String rootPath =  request.getSession().getServletContext().getRealPath("");    String fileName = createTemplateDownFile("show.ftl" , getRequestParams(request, "pdf"), rootPath + "/html", ".html");    //根目录+下设文件夹名+文件名    String allPath = rootPath + "/html/" + fileName;    try {        //输入html的路径        String url = new File(allPath).toURI().toURL().toString();        //输出pdf路径,这里偷懒替换了html的名字改为pdf名字        String newFileName = fileName.substring(0, fileName.lastIndexOf(".")) + ".pdf";        String outputFile = rootPath + "/pdf/" + newFileName;        OutputStream os = new FileOutputStream(outputFile);        ITextRenderer renderer = new ITextRenderer();        renderer.setDocument(url);        // 解决中文支持问题,我是 copy了系统的宋体放到了项目里面,itext是直接扫描到classpath下面的,所以是相对路径,绝对也是可以的。还有,千万要注意,这里用simsun字体,也就是宋体,所以在ftl中的body标签要加样式<body style="font-family: SimSun">,而且ftl非常严格,meta标签最后一般没有“/>”,会报错提醒这里格式不对。        ITextFontResolver fontResolver = renderer.getFontResolver();        fontResolver.addFont("/font/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);        // 解决图片的相对路径问题,因为从request中提取参数的时候已经加上了域名全路径,这里就不写文件全路径了        // renderer.getSharedContext().setBaseURL("file:/C:xxxx");        renderer.layout();        renderer.createPDF(os);        os.close();        //下载公共方法        downLoad(resp, outputFile, ".pdf");    } catch (MalformedURLException e) {        e.printStackTrace();    } catch (FileNotFoundException e) {        e.printStackTrace();    } catch (IOException e) {        e.printStackTrace();    } catch (DocumentException e) {        e.printStackTrace();    }}

5、最后

  • 浏览器访问:localhost:8080/downPdf.do?host=qrcode.jpg或者localhost:8080/downDoc.do?host=qrcode.jpg就自动下载word和pdf文档了。
  • 不知道能不能直接ftl生成pdf,网上相关资料也不多,正好这个html下载下来判断样式,就先这样吧。
  • 还有一个问题是生成的pdf、html、doc因为要下载,所以都没有写删除的方法,暂时也不知道怎么清理。想到可以存入数据库,存入路径和名字需要的时候下载,还可以有删除的方法……再说。
  • 这里是记录为主,图片的路径和jar的选择,样式的判断费了很大的劲,所以记录一下以防以后使用。
  • 配合上一篇文章食用才可,springmvc的总体配置就不写了。


最后再重申一下,千万要注意,这里用simsun字体,也就是宋体,所以在ftl中的body标签要加样式style=”font-family: SimSun”,而且ftl非常严格,meta标签最后一般没有“/>”,会报错提醒这里格式不对。

1 0
原创粉丝点击