用于通过模板生成PDF,在项目中生成个人授权协议函、个人电子保单、流水报表,数据报表等,将HTML静态模板写出来后,将数据替换成动态数据即可。

<!-- html2pdf -->
<dependency><groupId>org.xhtmlrenderer</groupId><artifactId>flying-saucer-pdf</artifactId><version>9.1.16</version>
</dependency><dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.13</version>
</dependency><!-- freemarker -->
<dependency><groupId>org.freemarker</groupId><artifactId>freemarker</artifactId><version>2.3.31</version>
</dependency><!-- docx4j docx2pdf -->
<dependency><groupId>org.docx4j</groupId><artifactId>docx4j</artifactId><version>6.1.2</version>
</dependency>
<dependency><groupId>org.docx4j</groupId><artifactId>docx4j-export-fo</artifactId><version>6.0.0</version>
</dependency>

templates.ftl 放入resource/templates文件目录中

<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><title>Title</title><style>@page {size:  210mm 290mm; /* size: 210mm 297mm;  设置纸张大小:A4(210mm 297mm)、A3(297mm 420mm) 横向则反过来 *//*margin-bottom: 1cm;*//*padding: 1em;*//*页眉*//*@top-center {*//*    content: counter(page);*//*    font-family: SimSun;*//*    font-size: 15px;*//*    color:#000;*//*};*//*@top-right{*//*    background: url("https://dpxdata.oss-cn-beijing.aliyuncs.com/upload/kbt/null_1660715685801.png") top right no-repeat;*//*    width: 195px;height: 50px;*//*    content: "logo";*//*    font-family: SimSun;*//*    font-size: 15px;*//*    !*color:#000;*!*//*};*//*页脚*/@bottom-center{content: counter(page);font-family: SimSun;font-size: 15px;color:#000;};/*@bottom-right{*//*    content: "第" counter(page) "页 共" counter(pages) "页";*//*    font-family: SimSun;*//*    font-size: 15px;*//*    color:#000;*//*};*/}* {page-break-inside: always;}</style>
</head><body style="font-family: SimSun; font-size: 14px">
<div style="">${text!''}
</div></body>
</html>
simsun.ttc 为字体文件

1.HTML 生成 PDF

HttpHeaders 写法

@GetMapping("/pdf")public ResponseEntity<?> export(HttpServletResponse response) {try {HttpHeaders headers = new HttpHeaders();Map<String, Object> dataMap = new HashMap<>(16);dataMap.put("text", "张三");String htmlStr = FreeMarkUtils.freemarkerRender(dataMap, "templates.ftl");byte[] pdfBytes = FreeMarkUtils.createPDF(htmlStr, "simsun.ttc");if (pdfBytes != null && pdfBytes.length > 0) {String fileName = System.currentTimeMillis() + (int) (Math.random() * 90000 + 10000) + ".pdf";headers.setContentDispositionFormData("attachment", fileName);headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);return new ResponseEntity<byte[]>(pdfBytes, headers, HttpStatus.OK);}} catch (Exception e) {e.printStackTrace();}HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_JSON_UTF8);return new ResponseEntity<>("{ \"code\" : \"404\", \"message\" : \"not found\" }", headers, HttpStatus.NOT_FOUND);}

Response 写法

    @GetMapping("/pdf")public void export(HttpServletResponse response) {InputStream inputStream = null;try {// 设置参数Map<String, Object> dataMap = new HashMap<>(16);dataMap.put("text", "张三");String htmlStr = FreeMarkUtils.freemarkerRender(dataMap, "template.ftl");byte[] data = FreeMarkUtils.createHtml2Pdf(htmlStr, "simsun.ttc");// 设置文件名String fileName = System.currentTimeMillis() + (int) (Math.random() * 90000 + 10000) + ".pdf";// 浏览器直接下载文件generateFile(response, data, fileName);// 获取输入流inputStream = new ByteArrayInputStream(data);// 输入流保存阿里云final String url = OssBootUtil.upload(inputStream, "upload/agree/" + fileName);log.info(url);} catch (Exception e) {e.printStackTrace();} finally {try {if (inputStream != null) {inputStream.close();}} catch (IOException ex) {ex.printStackTrace();}}}@GetMapping("/doc")public void doc(HttpServletResponse response) {Map<String, Object> dataMap = new HashMap<>();dataMap.put("name", "zhangsan");String fileName = System.currentTimeMillis() + (int) (Math.random() * 90000 + 10000) + ".doc";generateFile(response, FreeMarkUtils.freemarkerRender(dataMap, "test.ftl").getBytes(StandardCharsets.UTF_8), fileName);}@GetMapping("/doc2pdf")public void doc2pdf(HttpServletResponse response) {Map<String, Object> dataMap = new HashMap<>();dataMap.put("name", "张三");final byte[] data = FreeMarkUtils.createDocx2Pdf(dataMap, "document.ftl", "templates/test3.docx");String fileName = System.currentTimeMillis() + (int) (Math.random() * 90000 + 10000) + ".pdf";generateFile(response, data, fileName);}/*** 下载文件* @param response 相应* @param data 数据* @param fileName 文件名*/private void generateFile(HttpServletResponse response, byte[] data, String fileName) {response.setHeader("content-Type", "application/octet-stream");response.setCharacterEncoding("utf-8");response.setHeader("Content-disposition", "attachment;filename=" + fileName);try {response.getOutputStream().write(data);} catch (IOException e) {e.printStackTrace();} finally {try {response.getOutputStream().close();} catch (IOException e) {e.printStackTrace();}}}

2. docx 文件生成PDF

新建word 2007 test3.docx

复制文件,重命名为test3.zip,解压后

复制word/document.xml文件到项目中 document.ftl,更改文件内容变量

导出PDF工具类

package com.dpxdata.backend.report;import cn.hutool.core.io.file.FileMode;
import com.itextpdf.text.*;
import com.itextpdf.text.Image;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.WordUtils;
import org.docx4j.Docx4J;
import org.docx4j.convert.out.FOSettings;
import org.docx4j.fonts.IdentityPlusMapper;
import org.docx4j.fonts.Mapper;
import org.docx4j.fonts.PhysicalFonts;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.stereotype.Component;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.ui.freemarker.SpringTemplateLoader;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Enumeration;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;/*** @Description: pdf 导出工具类* @Author: LiSaiHang* @Date: 2022/1/7 11:30 上午*/
@Component
@Slf4j
public class FreeMarkUtils {private FreeMarkUtils() {}private volatile static Configuration configuration;static {if (configuration == null) {synchronized (FreeMarkUtils.class) {if (configuration == null) {configuration = new Configuration(Configuration.VERSION_2_3_28);}}}}/*** freemarker 引擎渲染 html** @param dataMap  传入 html 模板的 Map 数据* @param fileName 模板文件名称*                 eg: "templates/template.ftl"* @return*/public static String freemarkerRender(Map<String, Object> dataMap, String fileName) {configuration.setDefaultEncoding("UTF-8");configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);try {// TODO Jar包运行时,是无法读取classpath下资源文件,可以通过 SpringTemplateLoader 读取资源文件目录final SpringTemplateLoader templateLoader = new SpringTemplateLoader(new DefaultResourceLoader(), "classpath:templates");configuration.setTemplateLoader(templateLoader);configuration.setLogTemplateExceptions(false);configuration.setWrapUncheckedExceptions(true);Template template = configuration.getTemplate(fileName);return FreeMarkerTemplateUtils.processTemplateIntoString(template, dataMap);} catch (IOException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}return null;}/*** 使用 iText 生成 PDF 文档** @param htmlTmpStr html 模板文件字符串* @param fontFile   所需字体文件(相对路径+文件名)*/public static byte[] createHtml2Pdf(String htmlTmpStr, String fontFile) {ByteArrayOutputStream outputStream = null;byte[] result = null;// 生成 字体临时文件// TODO jar包运行后,是无法直接读取 classpath 下的资源文件,需要通过文件流读取,生成临时文件final File tempFile = getTempFile(fontFile);// TODO jar包运行后,是无法直接读取 classpath 下的资源文件,需要通过文件流读取,生成临时文件try {outputStream = new ByteArrayOutputStream();ITextRenderer renderer = new ITextRenderer();renderer.setDocumentFromString(htmlTmpStr);ITextFontResolver fontResolver = renderer.getFontResolver();// 解决中文支持问题,需要所需字体(ttc)文件fontResolver.addFont(tempFile.getAbsolutePath(), BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);renderer.layout();renderer.createPDF(outputStream);// 对Html2Pdf 的文件插入水印图片final String fileName = System.currentTimeMillis() + (int) (Math.random() * 90000 + 10000) + ".pdf";addWaterMark(outputStream.toByteArray(), fileName);final ByteArrayOutputStream fileOutputStream = getFileOutputStream(new File(fileName));result = fileOutputStream.toByteArray();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (com.lowagie.text.DocumentException e) {e.printStackTrace();} finally {try {if (outputStream != null) {outputStream.flush();outputStream.close();}if (tempFile.exists()) {tempFile.delete();}} catch (IOException e) {e.printStackTrace();}}return result;}/*** freemark生成word----docx格式** @param dataMap      数据源* @param templateFile document.xml模板的文件名* @param docxFile     docx模板的文件名* @return 生成的文件路径*/public static byte[] createDocx2Pdf(Map<String, Object> dataMap, String templateFile, String docxFile) {//word输出流ZipOutputStream zipout = null;//docx格式的word文件路径//输出word文件路径和名称String fileName = "applyWord_" + System.currentTimeMillis() + ".docx";// 生成docx临时文件final File tempPath = new File(fileName);// 获取docx模板final File docxTempFile = getTempFile(docxFile);try {//freeMark根据模板生成内容xml// 获取 document.ftl 输入流final String str = freemarkerRender(dataMap, templateFile);ByteArrayInputStream documentInput = new ByteArrayInputStream(str.getBytes(StandardCharsets.UTF_8));final ZipFile zipFile = new ZipFile(docxTempFile);System.out.println(zipFile.getName());Enumeration<? extends ZipEntry> zipEntrys = zipFile.entries();// docx文件输出流zipout = new ZipOutputStream(new FileOutputStream(tempPath));//循环遍历主模板docx文件,替换掉主内容区,也就是上面获取的document.xml的内容//------------------覆盖文档------------------int len = -1;byte[] buffer = new byte[1024];while (zipEntrys.hasMoreElements()) {ZipEntry next = zipEntrys.nextElement();final InputStream is = zipFile.getInputStream(next);if (next.toString().indexOf("media") < 0) {zipout.putNextEntry(new ZipEntry(next.getName()));if ("word/document.xml".equals(next.getName())) {//写入填充数据后的主数据信息if (documentInput != null) {while ((len = documentInput.read(buffer)) != -1) {zipout.write(buffer, 0, len);}}} else {//不是主数据区的都用主模板的while ((len = is.read(buffer)) != -1) {zipout.write(buffer, 0, len);}is.close();}}}} catch (Exception e) {e.printStackTrace();} finally {try {if (zipout != null) {zipout.close();}if (docxTempFile.exists()) {docxTempFile.delete();}} catch (Exception ex) {ex.printStackTrace();}}// word转pdffinal String pdfFile = convertDocx2Pdf(fileName);return getFileOutputStream(new File(pdfFile)).toByteArray();}/*** word(docx)转pdf** @param wordPath docx文件路径* @return 生成的带水印的pdf路径*/public static String convertDocx2Pdf(String wordPath) {OutputStream os = null;InputStream is = null;//输出pdf文件路径和名称final String fileName = "pdfNoMark_" + System.currentTimeMillis() + ".pdf";try {is = new FileInputStream(wordPath);WordprocessingMLPackage mlPackage = WordprocessingMLPackage.load(is);Mapper fontMapper = new IdentityPlusMapper();fontMapper.put("隶书", PhysicalFonts.get("LiSu"));fontMapper.put("宋体", PhysicalFonts.get("SimSun"));fontMapper.put("微软雅黑", PhysicalFonts.get("Microsoft Yahei"));fontMapper.put("黑体", PhysicalFonts.get("SimHei"));fontMapper.put("楷体", PhysicalFonts.get("KaiTi"));fontMapper.put("新宋体", PhysicalFonts.get("NSimSun"));fontMapper.put("华文行楷", PhysicalFonts.get("STXingkai"));fontMapper.put("华文仿宋", PhysicalFonts.get("STFangsong"));fontMapper.put("宋体扩展", PhysicalFonts.get("simsun-extB"));fontMapper.put("仿宋", PhysicalFonts.get("FangSong"));fontMapper.put("仿宋_GB2312", PhysicalFonts.get("FangSong_GB2312"));fontMapper.put("幼圆", PhysicalFonts.get("YouYuan"));fontMapper.put("华文宋体", PhysicalFonts.get("STSong"));fontMapper.put("华文中宋", PhysicalFonts.get("STZhongsong"));//解决宋体(正文)和宋体(标题)的乱码问题PhysicalFonts.put("PMingLiU", PhysicalFonts.get("SimSun"));PhysicalFonts.put("新細明體", PhysicalFonts.get("SimSun"));PhysicalFonts.addPhysicalFonts("SimSun", WordUtils.class.getResource("/simsun1.ttc"));mlPackage.setFontMapper(fontMapper);os = new FileOutputStream(fileName);//docx4j  docx转pdfFOSettings foSettings = Docx4J.createFOSettings();foSettings.setWmlPackage(mlPackage);Docx4J.toFO(foSettings, os, Docx4J.FLAG_EXPORT_PREFER_XSL);is.close();//关闭输入流os.close();//关闭输出流} catch (Exception e) {e.printStackTrace();} finally {// 删除docx 临时文件File file = new File(wordPath);if (file != null && file.isFile() && file.exists()) {file.delete();}try {if (is != null) {is.close();}if (os != null) {os.close();}} catch (Exception ex) {ex.printStackTrace();}}return fileName;}/*** 文件转字节输出流** @param outFile 文件* @return*/public static ByteArrayOutputStream getFileOutputStream(File outFile) {// 获取生成临时文件的输出流InputStream input = null;ByteArrayOutputStream bytestream = null;try {input = new FileInputStream(outFile);bytestream = new ByteArrayOutputStream();int ch;while ((ch = input.read()) != -1) {bytestream.write(ch);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {bytestream.close();input.close();log.info("删除临时文件");if (outFile.exists()) {outFile.delete();}} catch (IOException e) {e.printStackTrace();}}return bytestream;}/*** 获取资源文件的临时文件* 资源文件打jar包后,不能直接获取,需要通过流获取生成临时文件** @param fileName 文件路径 temp/temp.ftl* @return*/public static File getTempFile(String fileName) {final File tempFile = new File(fileName);InputStream fontTempStream = null;try {fontTempStream = FreeMarkUtils.class.getClassLoader().getResourceAsStream(fileName);FileUtils.copyInputStreamToFile(fontTempStream, tempFile);} catch (Exception e) {e.printStackTrace();} finally {try {if (fontTempStream != null) {fontTempStream.close();}} catch (IOException e) {e.printStackTrace();}}return tempFile;}/*** 插入图片水印* @param srcByte 已生成PDF的字节数组(流转字节)* @param destFile 生成有水印的临时文件 temp.pdf* @return*/public static FileOutputStream addWaterMark(byte[] srcByte, String destFile) {// 待加水印的文件PdfReader reader = null;// 加完水印的文件PdfStamper stamper = null;FileOutputStream fileOutputStream = null;try {reader = new PdfReader(srcByte);fileOutputStream = new FileOutputStream(destFile);stamper = new PdfStamper(reader, fileOutputStream);int total = reader.getNumberOfPages() + 1;PdfContentByte content;// 设置字体//BaseFont font = BaseFont.createFont();// 循环对每页插入水印for (int i = 1; i < total; i++) {final PdfGState gs = new PdfGState();// 水印的起始content = stamper.getUnderContent(i);// 开始content.beginText();// 设置颜色 默认为蓝色//content.setColorFill(BaseColor.BLUE);// content.setColorFill(Color.GRAY);// 设置字体及字号//content.setFontAndSize(font, 38);// 设置起始位置// content.setTextMatrix(400, 880);//content.setTextMatrix(textWidth, textHeight);// 开始写入水印//content.showTextAligned(Element.ALIGN_LEFT, text, textWidth, textHeight, 45);// 设置水印透明度// 设置笔触字体不透明度为0.4fgs.setStrokeOpacity(0f);Image image = null;image = Image.getInstance("url");// 设置坐标 绝对位置 X Y 这个位置大约在 A4纸 右上角展示LOGOimage.setAbsolutePosition(472, 785);// 设置旋转弧度image.setRotation(0);// 旋转 弧度// 设置旋转角度image.setRotationDegrees(0);// 旋转 角度// 设置等比缩放 图片大小image.scalePercent(4);// 依照比例缩放// image.scaleAbsolute(200,100);//自定义大小// 设置透明度content.setGState(gs);// 添加水印图片content.addImage(image);// 设置透明度content.setGState(gs);//结束设置content.endText();content.stroke();}} catch (IOException e) {e.printStackTrace();} catch (DocumentException e) {e.printStackTrace();} finally {try {stamper.close();fileOutputStream.close();reader.close();} catch (DocumentException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}return fileOutputStream;}
}

Spring Boot Freemark HTML 生成 PDF、生成水印Logo、docx文件生成PDF,Jar包运行可读取模板文件、字体文件相关推荐

  1. springboot读取linux文件_spring\-boot以jar包方式时读取resource或是template文件 | Prayer's Laputa...

    现象 以jar包方式部署系统,想读取resource或是template下面的文件时,报 File Not Found 我遇到的情况是,整个项目达成了一个包,在开发环境(windows + idea) ...

  2. Spring Boot项目利用MyBatis Generator进行数据层代码自动生成

    概 述 MyBatis Generator (简称 MBG) 是一个用于 MyBatis和 iBATIS的代码生成器.它可以为 MyBatis的所有版本以及 2.2.0之后的 iBATIS版本自动生成 ...

  3. java图片加水印上传工具类_基于Spring Boot实现图片上传/加水印一把梭操作

    文章共537字,阅读大约需要 2分钟 ! 概述 很多网站的图片为了版权考虑都加有水印,尤其是那些图片类网站.自己正好最近和图片打交道比较多,因此就探索了一番基于 Spring Boot这把利器来实现从 ...

  4. java spring上传图片_基于Spring Boot实现图片上传/加水印一把梭操作

    文章共 537字,阅读大约需要 2分钟 ! 概述 很多网站的图片为了版权考虑都加有水印,尤其是那些图片类网站.自己正好最近和图片打交道比较多,因此就探索了一番基于 Spring Boot这把利器来实现 ...

  5. php pdf 文字水印图片,php如何给pdf加上文字水印和图片水印[未测试]

    php给pdf加上水印 环境 php5.5.12 fpdi-1.5.2 fpdf-1.7 原理 利用fpdi来加载已知pdf文件,用fpdf对pdf进行操作 注意事项 免费的fpdi只支持处理pdf1 ...

  6. IntelliJ IDEA生成jar包运行报Error:A JNI error has occurred,please check your installation and try again

    首先介绍一下IntelliJ IDEA生成jar包的方式: 1.打开项目,打开FIile->Project Structure...菜单.如下图: 选中Artifacts,点+号,选择JAR,再 ...

  7. Spring Boot Jar包运行指定配置文件

    springboot会按照下列优先级来加载application.property配置文件:优先级由高到低 1.jar包同级目录的config目录下 2.jar包同级目录的application.pr ...

  8. Spring Aop开发过程中可能出现的异常(通过这些异常可以知道需要什么Jar包)

    出现的问题解决:  问题1:Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/common ...

  9. Springboot —— 根据docx填充生成word文件,并导出pdf

    文章目录 前言 将docx模板填充数据生成doc文件 1.依赖引入 2.doc文件转换docx,并标注别名 3.编写java代码实现数据填充 docx文件填充数据导出pdf(web) 1.依赖引入 2 ...

最新文章

  1. oracle挂堎,Oracle 冷拷备实例挂到新ORACLE时应注意问题。
  2. H5打开预览PDF,PPT等文件
  3. 非线性规划-三种常见参数估计算法及联系
  4. 上周热点回顾(10.27-11.2)
  5. Mosaic获5.5亿美元住宅太阳能融资贷款
  6. 微软caffe-SSD的训练和预测(windows cpu)
  7. 面经——C/C++常见面试知识点总结附面试真题
  8. 人才第一!英伟达大幅扩大深度学习学院(DLI)规模
  9. 北通usb手柄_多平台适配,北通斯巴达2无线版手柄操控灵敏
  10. js实现textarea滚动条位置始终在最下方
  11. PMP试题 每日一练快速提分
  12. supervise用法_supervise过去式和用法例句
  13. 2019网易校招笔试题 瞌睡
  14. 模拟qq邮箱mysql数据库_后台管理系统3.0(SrpingBoot+MySQL)界面仿QQ邮箱源代码
  15. Specification 对象的常用方法
  16. dropping incoming packet
  17. img显示保存在服务器中的图片,img显示服务器图片不显示
  18. 二层交换、三层交换和路由的原理及区别
  19. 条码标签剥离机是什么
  20. 爱普生L301墨仓打印机评测

热门文章

  1. 2014哈商大ICPC/ACM校赛解题报告
  2. java实习生面试会问什么问题,大量教程
  3. 剑网三正剧动画预告的台词
  4. Hive On Tez自定义Job Name
  5. 5620亿参数,最大多模态模型控制机器人,谷歌把具身智能玩出新高度
  6. 深度学习工具audioFlux---一个系统的音频特征提取库
  7. 消防工程师 第二篇 建筑防火 4.2 平面布置
  8. “计算机系统概述”学习提纲
  9. linux 内核 input,初识linux中的input设备
  10. PL/SQL Profiling