1.工具类(下载到本地)
public class FreemarkerReportWriter { /** * 字体文件名称 */ private final static String DEFAULT_FONT = "yahei.ttf"; /** * templateContent ftl模版内容 * data ftl模版数据 * file 下载本地PDF文件 * classPath 文件路径 */ public static void createPdf(String templateContent, Map<String, Object> data, File file, String classPath) { FileOutputStream outputStream = null; ITextRenderer renderer = new ITextRenderer(); try { Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); StringTemplateLoader stringLoader = new StringTemplateLoader(); stringLoader.putTemplate("myTemplate", templateContent); cfg.setTemplateLoader(stringLoader); Template template = cfg.getTemplate("myTemplate", "utf-8"); String htmlData = FreeMarkerTemplateUtils.processTemplateIntoString(template, data); outputStream = new FileOutputStream(file); ITextFontResolver fontResolver = renderer.getFontResolver(); // 解决中文乱码问题,fontPath为中文字体地址 fontResolver.addFont(classPath + DEFAULT_FONT, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); renderer.setDocumentFromString(htmlData); renderer.layout(); renderer.createPDF(outputStream); } catch (Exception e) { log.error("生成失败", e); } finally { renderer.finishPDF(); IOUtils.closeQuietly(outputStream); } } public static void exportPdf(String templateContent, Map<String, Object> data, HttpServletResponse response) { File file = null; try { String classPath = PdfExportUtil.class.getProtectionDomain().getCodeSource().getLocation().getPath(); log.info("classPath路径:{}", classPath); String fileName = System.currentTimeMillis() + ".pdf"; createPdf(templateContent, data, new File(classPath + fileName), classPath); log.info("pdf长度:{}", new File(classPath + fileName).length()); file = new File(classPath + fileName); ServletOutputStream outputStream = response.getOutputStream(); FileInputStream fileInputStream = new FileInputStream(file); byte[] buffer = new byte[1024]; int len; while ((len = fileInputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, len); } fileInputStream.close(); outputStream.flush(); outputStream.close(); } catch (Exception e) { log.error("生成PDF失败", e); } finally { // 清理文件 file.delete(); } } public static void exportZip(String templateContent, List<Map<String, Object>> mapList, HttpServletResponse response) { try { String classPath = PdfExportUtil.class.getProtectionDomain().getCodeSource().getLocation().getPath(); log.info("classPath路径:{}", classPath); ZipOutputStream zips = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream())); zips.setMethod(ZipOutputStream.DEFLATED); DataOutputStream os = null; for (Map<String, Object> map : mapList) { File file = null; try { String fileName = System.currentTimeMillis() + ".pdf"; createPdf(templateContent, map, new File(classPath + fileName), classPath); log.info("pdf长度:{}", new File(classPath + fileName).length()); file = new File(classPath + fileName); zips.putNextEntry(new ZipEntry(fileName)); os = new DataOutputStream(zips); InputStream is = new FileInputStream(file); byte[] b = new byte[1024]; int length; while ((length = is.read(b)) != -1) { os.write(b, 0, length); } is.close(); zips.closeEntry(); } catch (Exception e) { log.error("生成PDF失败", e); } finally { // 清理文件 file.delete(); } } os.flush(); os.close(); zips.close(); } catch (Exception e) { log.error("生成ZIP失败", e); } } }
2.工具类(浏览器预览)
public class FreemarkerReportWriter { /** * 字体文件名称 */ private final static String DEFAULT_FONT_PATH = "fonts/simsun.ttf"; private final static String DEFAULT_FONT = "SimSun"; private final static String DEFAULT_PDF = ".pdf"; private final static String TEMPLATE_NAME = "myTemplate"; /** * fileName 文件名称 * templateContent ftl模版内容 * data ftl模版数据 * attachment 是否以下载附件的方式查看报表,否则以在线方式查看报表 * response HttpServletResponse */ public static void exportPdf(String fileName, String templateContent, Map<String, Object> data, boolean attachment, HttpServletResponse response) { Assert.hasLength(fileName, "The parameter `fileName` can not be empty."); Assert.hasLength(templateContent, "The parameter `templateContent` can not be empty."); if (!fileName.toLowerCase().endsWith(DEFAULT_PDF)) { fileName += ".pdf"; } ServletOutputStream outputStream = null; // 设置响应头 response.setContentType("application/pdf"); MimeDispositionType mimeDispositionType = attachment ? MimeDispositionType.attachment : MimeDispositionType.inline; response.setHeader("Content-Disposition", FileUtil.getContentDisposition(fileName, mimeDispositionType)); try { byte[] bytes = createPdf(templateContent, data); log.debug("pdf file length:{}", bytes.length); outputStream = response.getOutputStream(); outputStream.write(bytes); } catch (Exception e) { log.error("create pdf file failed:", e); } finally { IoUtil.close(outputStream); } } /** * templateContent ftl模版内容 * mapList ftl模版数据 * response HttpServletResponse */ public static void exportZip(String templateContent, List<Map<String, Object>> mapList, HttpServletResponse response) { Assert.hasLength(templateContent, "The parameter `templateContent` can not be empty."); try { ZipOutputStream zips = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream())); zips.setMethod(ZipOutputStream.DEFLATED); DataOutputStream os = null; for (Map<String, Object> map : mapList) { String fileName = ObjectUtil.isEmpty(map.get("fileName")) ? System.currentTimeMillis() + ".pdf" : String.valueOf(map.get("fileName")); try { byte[] bytes = createPdf(templateContent, map); log.debug("pdf file length:{}", bytes.length); zips.putNextEntry(new ZipEntry(fileName)); os = new DataOutputStream(zips); os.write(bytes); } catch (Exception e) { log.error("create pdf failed:", e); } finally { zips.closeEntry(); } } IoUtil.close(os); IoUtil.close(zips); } catch (Exception e) { log.error("create zip failed:", e); } } public static byte[] createPdf(String templateContent, Map<String, Object> data) { try { long startTime = System.currentTimeMillis(); Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); StringTemplateLoader stringLoader = new StringTemplateLoader(); stringLoader.putTemplate(TEMPLATE_NAME, templateContent); cfg.setTemplateLoader(stringLoader); Template template = cfg.getTemplate(TEMPLATE_NAME, StandardCharsets.UTF_8.name()); String htmlString = FreeMarkerTemplateUtils.processTemplateIntoString(template, data); log.info("htmlString Execution time :{}", System.currentTimeMillis() - startTime); ByteArrayOutputStream os = new ByteArrayOutputStream(); PdfRendererBuilder builder = new PdfRendererBuilder(); builder.useFont(() -> { try { return FreemarkerReportWriter.class.getClassLoader().getResourceAsStream(DEFAULT_FONT_PATH); } catch (Exception e) { log.error("createPdf error, load {} file failed.", DEFAULT_FONT_PATH); throw new RuntimeException(e); } }, DEFAULT_FONT, 400, BaseRendererBuilder.FontStyle.NORMAL, true); builder.withHtmlContent(htmlString, ""); builder.toStream(os); builder.run(); log.info("createPdf Execution time :{}", System.currentTimeMillis() - startTime); return os.toByteArray(); } catch (Exception e) { log.error("create pdf file failed:", e); return new byte[1024]; } } }
3.controller接口
@GetMapping("/exportPdf") @ApiOperation("导出PDF") public UnifyResponse<Void> exportPdf(@RequestParam("principalId") String principalId, HttpServletResponse response) { PrincipalInstrumentVO instrumentVO = principalInstrumentService.detail(principalId); if (BeanUtil.isNotEmpty(instrumentVO)) { // 设置响应头 response.setContentType("application/pdf"); response.setCharacterEncoding("utf-8"); response.setHeader("Content-Disposition", "inline; filename=\"pdf.pdf\""); PdfExportUtil.exportPdf(instrumentVO.getHtmlContent(), new HashMap<>(8), response); } return null; } @GetMapping("/exportZip") @ApiOperation("导出ZIP") public UnifyResponse<Void> exportZip(@RequestParam("principalId") String principalId, HttpServletResponse response) { List<Map<String, Object>> mapList = new ArrayList<>(); Map<String, Object> map1 = new HashMap<>(16); map1.put("invoice", "发票1"); map1.put("serialNumber", "123"); map1.put("orderNumber", "123"); mapList.add(map1); Map<String, Object> map2 = new HashMap<>(16); map2.put("invoice", "发票2"); map2.put("serialNumber", "456"); map2.put("orderNumber", "456"); mapList.add(map2); PrincipalInstrumentVO instrumentVO = principalInstrumentService.detail(principalId); // 设置响应头 response.setContentType("multipart/form-data"); response.setCharacterEncoding("utf-8"); response.setHeader("Content-Disposition", "attachment; filename=\"zip.zip\""); PdfExportUtil.exportZip(instrumentVO.getHtmlContent(), mapList, response); return null; }
4.说明
templateContent为FreeMarker模板的HTML内容