由于本人技术有限本篇导出也是根据网上大家的做出的demo混合而成。有不足的地方请大家指出。好改正,使以后看到的freemarker导出pdf的朋友们能通俗易懂上手。
本程序是在maven中实现的所以如果有的朋友是用jar包实现的请注意版本号。
- <!-- itext 组件 -->
- <dependency>
- <groupId>com.itextpdf.tool</groupId>
- <artifactId>xmlworker</artifactId>
- <version>5.5.10</version>
- </dependency>
- <dependency>
- <groupId>com.lowagie</groupId>
- <artifactId>itext</artifactId>
- <version>2.0.8</version>
- </dependency>
- <!-- freemarker -->
- <dependency>
- <groupId>org.freemarker</groupId>
- <artifactId>freemarker</artifactId>
- <version>2.3.20</version>
- </dependency>
- <dependency>
- <groupId>org.xhtmlrenderer</groupId>
- <artifactId>flying-saucer-pdf</artifactId>
- <version>9.0.9</version>
- </dependency>
- <dependency>
- <groupId>org.xhtmlrenderer</groupId>
- <artifactId>core-renderer</artifactId>
- <version>R8</version>
- </dependency>
这里需要注意下。itext要用2.0.8的版本要不然会在下面的itext使用的时候报字节错误。
程序也是个在web中实现的所以代码实现的时候也是访问的。
- @RequestMapping(value="/pdfdown",method={RequestMethod.GET,RequestMethod.POST})
- public void PDFchange(HttpServletRequest request, HttpServletResponse response) throws Exception{
- //从数据库中查询需要的条件
- Map<String,Object> variables = new HashMap<String,Object>();
- List<UserTestBean> userList = new ArrayList<UserTestBean>();
- UserTestBean tom = new UserTestBean("Tom",19,1);
- UserTestBean amy = new UserTestBean("Amy",28,0);
- UserTestBean leo = new UserTestBean("Leo",23,1);
- userList.add(tom);
- userList.add(amy);
- userList.add(leo);
- variables.put("title", "你看");
- variables.put("userList", userList);
- /*variables.put("title","gerenjianli");
- variables.put("userName","xueyucheng");
- variables.put("userSex","man");
- variables.put("userAge","17");
- variables.put("height","161");sss
- variables.put("address","handan");
- variables.put("University","ligong");sssss
- variables.put("skill","jineng");
- variables.put("content","asdasasd");*/
- String ftlName="ceshi.ftl";
- //然后组装好之后调用该方法 FTLIMAGEPATH是用的配置模板中的内容实现的
- try {
- ByteArrayOutputStream bos= PDFUtil.createPDF(request, ftlName, variables,FTLIMAGEPATH);/**字节*/
- PDFUtil.renderPdf(response, bos.toByteArray(), "123");
- } catch (Exception e) {
- logger.error("pdf导出出错。。。",e);
- }
- }
bean可以自己随便写个只要按照模式就行。下面也是调用的pdf工具类。让其实现的是客户端下载保存。没有在服务器端保存
- import java.io.ByteArrayInputStream;
- import java.io.ByteArrayOutputStream;
- import java.io.File;
- import java.io.IOException;
- import java.io.StringWriter;
- import java.io.UnsupportedEncodingException;
- import java.io.Writer;
- import java.util.Locale;
- import java.util.Map;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import javax.xml.parsers.DocumentBuilder;
- import javax.xml.parsers.DocumentBuilderFactory;
- import org.xhtmlrenderer.pdf.ITextFontResolver;
- import org.xhtmlrenderer.pdf.ITextRenderer;
- import com.lowagie.text.pdf.BaseFont;
- import freemarker.template.Configuration;
- import freemarker.template.Template;
- /**
- * pdf转换类
- * @author test fengruiqi
- * 创建 时间2017年2月4日 上午9:36:42
- *
- */
- public class PDFUtil {
- /**
- * 创建pdf
- * @author fengruiqi
- * 创建时间 2017年2月4日 下午6:47:18
- * @param request
- * @param ftlName
- * @param root
- * @return
- * @throws Exception
- */
- public static ByteArrayOutputStream createPDF(HttpServletRequest request, String ftlName,Map root,String imageName) throws Exception {
- String basePath =request.getSession().getServletContext().getRealPath("/");//绝对路径
- String basePath2=basePath.replaceAll("\\\\", "/");
- Configuration cfg = new Configuration();
- try {
- cfg.setLocale(Locale.CHINA);
- cfg.setEncoding(Locale.CHINA, "UTF-8");
- //设置编码
- cfg.setDefaultEncoding("UTF-8");
- //设置模板路径
- cfg.setDirectoryForTemplateLoading(new File(basePath + "/WEB-INF/views/ftl/"));
- //解决图片路径问题 设置好图片所选择的路径
- if(imageName!=null && !"".equals(imageName)){
- root.put("imagePath",imageName);
- }
- //获取模板
- Template template = cfg.getTemplate(ftlName);
- template.setEncoding("UTF-8");
- Writer writer = new StringWriter();
- //数据填充模板
- template.process(root, writer);
- String str = writer.toString();
- //pdf生成
- DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
- ITextRenderer iTextRenderer = new ITextRenderer();
- iTextRenderer.setDocumentFromString(str);
- //设置字体 其他字体需要添加字体库
- ITextFontResolver fontResolver = iTextRenderer.getFontResolver();
- fontResolver.addFont(basePath + "/WEB-INF/views/font/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
- iTextRenderer.setDocument(builder.parse(new ByteArrayInputStream(str.getBytes())),null);
- iTextRenderer.layout();
- //生成PDF
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- iTextRenderer.createPDF(baos);
- baos.close();
- return baos;
- } catch(Exception e) {
- throw new Exception(e);
- }
- }
- /**
- * 客户端下载pdf
- * @author fengruiqi
- * 创建时间 2017年2月4日 下午7:05:01
- * @param response
- * @param bytes
- * @param filename
- */
- public static void renderPdf(HttpServletResponse response, final byte[] bytes, final String filename) {
- /* initResponseHeader(response, PDF_TYPE); */
- setFileDownloadHeader(response, filename, ".pdf");
- if (null != bytes) {
- try {
- response.getOutputStream().write(bytes);
- response.getOutputStream().flush();
- } catch (IOException e) {
- throw new IllegalArgumentException(e);
- }
- }
- }
- /**
- * 分析并设置contentType与headers.
- */
- /*
- private HttpServletResponse initResponseHeader(HttpServletResponse response, final String contentType, final String... headers) {
- // 分析headers参数
- String encoding = DEFAULT_ENCODING;
- boolean noCache = DEFAULT_NOCACHE;
- for (String header : headers) {
- String headerName = StringUtils.substringBefore(header, ":");
- String headerValue = StringUtils.substringAfter(header, ":");
- if (StringUtils.equalsIgnoreCase(headerName, HEADER_ENCODING)) {
- encoding = headerValue;
- } else if (StringUtils.equalsIgnoreCase(headerName, HEADER_NOCACHE)) {
- noCache = Boolean.parseBoolean(headerValue);
- } else {
- throw new IllegalArgumentException(headerName + "不是一个合法的header类型");
- }
- }
- // 设置headers参数
- String fullContentType = contentType + ";charset=" + encoding;
- response.setContentType(fullContentType);
- if (noCache) {
- // Http 1.0 header
- response.setDateHeader("Expires", 0);
- response.addHeader("Pragma", "no-cache");
- // Http 1.1 header
- response.setHeader("Cache-Control", "no-cache");
- }
- return response;
- } */
- /**
- * 设置让浏览器弹出下载对话框的Header
- * @author fengruiqi
- * 创建时间 2017年2月4日 下午6:58:44
- * @param response
- * @param fileName
- * @param fileType
- */
- public static void setFileDownloadHeader(HttpServletResponse response, String fileName, String fileType) {
- try {
- // 中文文件名支持
- String encodedfileName = new String(fileName.getBytes("GBK"), "ISO8859-1");
- response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedfileName + fileType + "\"");
- } catch (UnsupportedEncodingException e) {
- }
- }
- }
。
我在解决图片路径的问题时候没有用网上的使用绝对路径的方法,而是在模板中设置了存储路径的字段,
在程序中直接做成村路路径访问。不知道是因为包的原因还是其他什么,使用绝对路径我这里发现不了图片导出一直有错。
- <html>
- <head>
- <title>${title}</title>
- <style>
- table {
- width:100%;border:green dotted ;border-width:2 0 0 2
- }
- td {
- border:green dotted;border-width:0 2 2 0
- }
- @page {
- size: 8.5in 11in;
- @bottom-center {
- content: "page " counter(page) " of " counter(pages);
- }
- }
- <#--使用字体一定要定义好-->
- body {
- font-family: SimSun;
- font-size:14px;
- font-style:italic;
- font-weight:500;
- }
- .heiti
- {
- font-family: simsun-bold;
- }
- </style>
- </head>
- <body>
- <h1>Just a blank page.</h1>
- <div style="page-break-before:always;">
- <div align="center">
- <h1>${title}</h1>
- </div>
- <div>
- <#-- freemarker的注释 imagePath是用来存储路径的 -->
- 图片支持 <img src="${imagePath}add.png " />
- </div>
- <table>
- <tr>
- <td><b>Name</b></td>
- <td><b>Age</b></td>
- <td><b>Sex</b></td>
- </tr>
- <#list userList as user>
- <tr>
- <td>${user.name}</td>
- <td>${user.age}</td>
- <td>
- <#if user.sex = 1>
- male
- <#else>
- female
- </#if>
- </td>
- </tr>
- </#list>
- </table>
- </div>
- </body>
- </html>