Springboot —— 根据docx填充生成word文件,并导出pdf
文章目录
- 前言
- 将docx模板填充数据生成doc文件
- 1、依赖引入
- 2、doc文件转换docx,并标注别名
- 3、编写java代码实现数据填充
- docx文件填充数据导出pdf(web)
- 1、依赖引入
- 2、字体文件
- 3、编写工具类
- 4、编写测试接口
- 请求测试
- 参考资料
前言
在项目中碰见一个需求,需要将.doc
的合同,转换为pdf
实现打印与预览功能。
将docx模板填充数据生成doc文件
1、依赖引入
填充docx模板,只需要引入一个pom依赖即可实现。
<dependency><groupId>com.deepoove</groupId><artifactId>poi-tl</artifactId><version>1.5.0</version>
</dependency>
2、doc文件转换docx,并标注别名
用office或者wps,创建一个001.doc
文件,绘制表格,保存。
更改后缀为.docx
,确定后,在指定的位置,表示数据接受变量名称。
如下图所示:
3、编写java代码实现数据填充
import com.deepoove.poi.XWPFTemplate;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;/*** word 填充测试*/
public class TestWord {public static void main(String[] args) throws IOException {Map<String, Object> params = new HashMap<>();params.put("username","xiangjiao1");params.put("password","******");params.put("age",22);params.put("email","专注写bug测试中文");Resource resource = new ClassPathResource("templates_report/001.docx");File file = resource.getFile();// 数据填充XWPFTemplate template = XWPFTemplate.compile(file).render(params);String docOutPath = System.getProperty("user.dir")+File.separator+"springboot-poi"+File.separator+"pdf"+File.separator+ "1.doc";OutputStream outputStream = new FileOutputStream(docOutPath);template.write(outputStream);}
}
运行程序,查看结果。
测试项目结构如下:
docx文件填充数据导出pdf(web)
1、依赖引入
向docx
模板中填充数据,并导出pdf
类型的文件,除了上面的pom依赖之外,还需要引入其他的依赖信息,完整依赖如下所示:
<!-- docx 数据填充生成 doc文件 这个是主要 -->
<dependency><groupId>com.deepoove</groupId><artifactId>poi-tl</artifactId><version>1.5.0</version>
</dependency>
<!-- doc 转 pdf -->
<dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.13</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>
2、字体文件
在src\main\resources
下创建一个font
文件夹,其中放入simsun.ttc
字体文件。
3、编写工具类
思想很简单
1、先使用上面的docx模板填充数据生成
临时doc
文件,
2、再将doc文件转换为pdf文件
3、删除临时文件
【注意:】
为了避免出现多人同时操作,导致文件误删的问题,
需要尽可能地保证临时文件名称的唯一性。
import com.deepoove.poi.XWPFTemplate;
import com.itextpdf.text.*;
import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.text.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.stereotype.Component;
import java.io.*;
import java.util.Map;
import java.util.UUID;
import java.util.zip.ZipOutputStream;/*** pdf 导出工具类*/
@Component
@Slf4j
public final class FreeMarkUtils {/*** 根据docx模板填充数据 并生成pdf文件** @param dataMap 数据源* @param docxFile docx模板的文件名* @return 生成的文件路径*/public static byte[] createDocx2Pdf(Map<String, Object> dataMap, String docxFile) {//输出word文件路径和名称 (临时文件名,本次为测试,最好使用雪花算法生成,或者用uuid)String fileName = UUID.randomUUID().toString() + ".docx";// word 数据填充// 生成docx临时文件final File tempPath = new File(fileName);final File docxTempFile = getTempFile(docxFile);XWPFTemplate template = XWPFTemplate.compile(docxTempFile).render(dataMap);try {template.write(new FileOutputStream(tempPath));} catch (IOException e) {e.printStackTrace();}// word转pdffinal String pdfFile = convertDocx2Pdf(fileName);return getFileOutputStream(new File(pdfFile)).toByteArray();}/*** word(doc)转pdf** @param wordPath doc 生成的临时文件路径* @return 生成的带水印的pdf路径*/public static String convertDocx2Pdf(String wordPath) {OutputStream os = null;InputStream is = null;//输出pdf文件路径和名称 (临时文件 尽可能保证文件名称的唯一性)final String fileName = UUID.randomUUID().toString() + ".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("/font/simsun.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 文件路径 templates/xxx.docx* @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;}
}
4、编写测试接口
import cn.xj.util.FreeMarkUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;@RestController
@RequestMapping("/report")
public class ReportController {@GetMapping("/doc2pdf")public void doc2pdf(HttpServletResponse response) {Map<String, Object> params = new HashMap<>();params.put("username","xiangjiao1");params.put("password","******");params.put("age",22);params.put("email","专注写bug测试中文");final byte[] data = FreeMarkUtils.createDocx2Pdf(params, "templates_report/001.docx");String fileName = UUID.randomUUID().toString() + "_001_test.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();}}}
}
请求测试
http://localhost/report/doc2pdf
参考资料
Spring Boot Freemark HTML 生成 PDF、生成水印Logo、docx文件生成PDF,Jar包运行可读取模板文件、字体文件
Springboot —— 根据docx填充生成word文件,并导出pdf相关推荐
- PageOffice动态生成Word文件并转换为PDF
说明:PageOffice是客户端插件,做不到纯后台调用把word转为pdf.但是pageoffice的FileMaker对象可以实现不在客户端打开文件直接转换文件为pdf并保存到服务器端,看起来跟服 ...
- java xsl生成word文件_导出生成xsl文件
public String expData() throws Exception{ List list = subAreaService.findAll(); HSSFWorkbook hssf = ...
- 若依 springboot 使用freemarker生成word文件,并导出下载
目录 freemarker生成word文件并导出 一.环境准备 二.编写代码 1.实体类 2.mapper.xml文件 3.mapper.java文件 4.Service.java 5.Service ...
- Java技术:SpringBoot集成FreeMarker生成word文件
今天给大家分享SpringBoot集成FreeMarker模板引擎生成word文件的用法,感兴趣的可以学一下,完整源码地址在文章末尾处,欢迎互相沟通交流! 一.什么是F ...
- SpringBoot集成Freemarker,并使用API生成word文件
Spring Boot 集成 Freemarker spring boot 集成 freemarker 的简单使用 使用freemarker生成word文件 目录 Spring Boot 集成 Fre ...
- springboot项目使用beetl模板引擎生成word文件
一.详情可查看官网 1.官方网址:beetl官网 一.简单测试beetl生成word文件 1.在springboot项目中添加beetl的依赖 <dependency><groupI ...
- Python 自动化教程(5) : 自动生成Word文件
系列教程: Python 自动化教程(1) 概述,第一篇 Excel自动化 Python 自动化教程(2) : Excel自动化:使用pandas库 Python 自动化教程(3) : 自动生成PPT ...
- java 根据word模板生成word文件
Java可以使用Apache POI库来生成Word文件,并且也可以使用freemarker等模板引擎来实现根据Word模板生成Word文件的功能. 下面是一个简单的示例代码,可以帮助您快速入门. 模 ...
- java批量导出word_java 批量生成word 文件
最近在工作中遇到一个需求,我有一个拥有3000行数据的excel文件和一个word模板. 我需要将excel文件中的每一行数据填充到word模板文件中生成一个Word文件. 考虑到数据量较大且需求有可 ...
最新文章
- css美化单选款、复选框
- DL之self-attention:self-attention自注意力机制的简介、应用之详细攻略
- centos6上虚拟主机的实现
- 股市孙子兵法(收藏)
- mysql更新数据 update格式和alter对比
- Quick Cocos2dx 场景转换问题
- SQl常用语句总结(持续更新……)
- 1.7 编程基础之字符串 14 大小写字母互换 python
- remote: 认证失败,请确认您输入了正确的账号密码。 fatal: Authentication failed
- 彻底征服 Entity Framework Core 优化!
- java 查找引用_java – Eclipse查找方法的引用
- java script应用领域_JavaScript的应用
- 前端jquery学习
- 敏捷开发案例:用白板解决项目管理和团队沟通
- Interesting Housing Problem HDU - 2426 (KM)
- Mac 输入法原文件的安装位置
- Excel中的相对引用和绝对引用详解
- 【git commit --amend 修改提交记录】
- Python计算最大回撤、回撤天数
- Elasticsearch:从零开始到搜索 - 使用 Elasticsearch 摄取管道玩转你的数据
热门文章
- python入门之字符串
- Activity 的介绍和使用(一)
- 凌波微步-set的运用(去重)
- 知乎 鸿蒙目前只是安卓移植,[转载]转载:华为鸿蒙,一个本属于2025年的产品...
- H5在微信中获取openid
- CentOS使用(一)-----各种环境搭建
- “网络小偷”闯进无人超市 购物尝鲜要捂紧“钱包” 无人运营模式潜藏安全风险 或导致个人信息被窃取...
- 备胎的自我修养 |(3) 由零开始(下)
- nba里面啥是买断合同
- 简单的爬虫 从营养健康网爬取食物热量和营养成分等信息