freemarket+itext+springboot将html静态页面渲染后导出为pdf文件
1、maven依赖 <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.4.2</version> </dependency> <dependency> <groupId>org.xhtmlrenderer</groupId> <artifactId>core-renderer</artifactId> <version>R8</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-io</artifactId> <version>1.3.2</version>
</dependency>
2、controller @RequestMapping(value = "projectExport", method = RequestMethod.GET) public void projectExport(HttpServletRequest request, HttpServletResponse response) { try { Map map=new HashMap<String,Object>(); map.put("test","测试"); ByteArrayOutputStream baos = PDFUtil.createPDF("templates/project.html", map); //设置response文件头 PDFUtil.renderPdf(response, baos.toByteArray(), "pdf文件"); baos.close(); } catch (Exception e) { logger.info("导出报错",e); } } 3、PDFUtil import com.itextpdf.text.pdf.BaseFont; import freemarker.template.Configuration; import freemarker.template.Template; import org.apache.commons.io.output.ByteArrayOutputStream; import org.apache.commons.lang.StringUtils; import org.xhtmlrenderer.pdf.ITextFontResolver; import org.xhtmlrenderer.pdf.ITextRenderer; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.util.Locale; /** * PDF工具类 * @author LQX * */ public class PDFUtil { private static String DEFAULT_ENCODING="utf-8"; private static String PDF_TYPE="application/pdf"; private static boolean DEFAULT_NOCACHE=true; private static String HEADER_ENCODING="utf-8"; private static String HEADER_NOCACHE="no-cache"; /** * 生成PDF文件流 * @param ftlName 文件名称 * @param root 数据 * @return ByteArrayOutputStream * @throws Exception */ public static ByteArrayOutputStream createPDF(String ftlName, Object root) throws Exception { //相对路径 File file = new File(PDFUtil.class.getResource("/").getPath()); Configuration cfg = new Configuration(); try { cfg.setLocale(Locale.CHINA); cfg.setEncoding(Locale.CHINA, "UTF-8"); //设置编码 cfg.setDefaultEncoding("UTF-8"); //设置模板路径 cfg.setDirectoryForTemplateLoading(file); //获取模板 Template template = cfg.getTemplate(ftlName); template.setEncoding("UTF-8"); ITextRenderer iTextRenderer = new ITextRenderer(); //设置字体 ITextFontResolver fontResolver = iTextRenderer.getFontResolver(); fontResolver.addFont(file.getPath() + "/public/font/simsun.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); Writer writer = new StringWriter(); //数据填充模板 template.process(root, writer); //设置输出文件内容及路径 String str = writer.toString(); iTextRenderer.setDocumentFromString(str); /*iTextRenderer.getSharedContext().setBaseURL("");//共享路径*/ iTextRenderer.layout(); //生成PDF ByteArrayOutputStream baos = new ByteArrayOutputStream(); iTextRenderer.createPDF(baos); baos.close(); return baos; } catch(Exception e) { throw new Exception(e); } } 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 static 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. * @param */ 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) { } } }
3、project.html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>PDF下载</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <style mce_bogus="1" type="text/css"> body {font-family: SimSun; } @page {size: 800mm 400mm} </style> </head> <body> <table width="100%" height="60" border="0" align="center" cellpadding="0" cellspacing="0"> <tr> <td>12345</td> <td>${test}</td> <td>abc</td> </tr> </table> </body> </html>
需要注意的点:
(1)、中文字体
html中要将body标签的字体设置为SimSun,然后项目中要放这个字体文件,因为服务器中通常没有这个文件,simsun.ttf字体百度上都可以下载。只有设置了字体后html中的中文才能识别出来。
(2)、css文件
如果你想导的pdf文件的样式是css渲染后的页面样式,一定要注意link中css引用的路径,通常用服务器的绝对路径,你也可以自己换一换路径试试。导出时会因为一些外部的文件的路径写的不对而出现空指针异常,可以先把这些都注释掉再调试。
(3)、html标签
这个工具导出的时候对html标签的要求比较的严格,比如一些闭合标签一定要写完整,href链接中直接请求接口带参数的时候有&连接的时候要在&后面加上amp;
(4)、pdf文件的大小
给这个html文件加上css样式@page {size:800mm 400mm}这个样式可以调整pdf的文件,因为我导出的时候宽度达不到我想要的宽度,但是我还是不会动态的去设置这个大小,欢迎知道的小伙伴指教。
————————————————
原文链接:https://blog.csdn.net/haha_66666/article/details/83025919