这个是跟上一篇写的freemarker导出word是一块的。但是关联性不是很大。由于本人技术有限本篇导出也是根据网上大家的做出的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 > <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>
将其需要的内容填充到模板里面使其补充就好,暂时还没发现问题。如果后续有问题再更改。大家发现问题或者有疑问的可以联系我qq963633167