java导出word套打

 这篇文档手把手教你完成导出word套打,有这个demo,其他word套打导出都通用。

 1、主要依赖

        <!--hutool--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.3.0</version></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-core</artifactId><version>5.3.0</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.1.2</version></dependency><dependency><groupId>repository.org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.22</version></dependency><dependency><groupId>repository.org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.9</version></dependency>

 2、模板excel见附件。

3、以下为导出代码逻辑:

package com.example.demo.excel;import cn.hutool.poi.word.PicType;
import lombok.Data;/*** 图片对象* @author xiajun*/
@Data
public class WordImage {/*** 图片宽度*/private int width = 100;/*** 图片高度*/private int height = 100;/*** 图片地址* resource资源相对路径*/private String path;/*** 字节流*/private byte[] source;/*** 图片类型* 默认PNG**/private PicType imageType = PicType.PNG;}
package com.example.demo.excel;import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.poi.word.Word07Writer;
import cn.hutool.poi.word.WordUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;/*** word导出* @author xiajun*/
@Slf4j
@RestController
@RequestMapping("mvc/word")
public class WordExport {@GetMapping(path = "/export")public void export(HttpServletResponse response) throws IOException {//1、============================模拟数据===============================Map<String, Object> params = new HashMap<>();params.put("${name}", "张三");params.put("${sex}", "男");params.put("${birth}", "1999.11");params.put("${age}", "25");params.put("${nation}", "汉族");params.put("${npn}", "四川成都");params.put("${bpn}", "四川成都");params.put("${pt}", "2017.02");params.put("${workTime}", "2016.03");params.put("${hn}", "健康");params.put("${beFawts}", "打篮球");params.put("${proTec}", "高级工程师");params.put("${degree}", "大学本科");params.put("${education}", "文学学士");params.put("${school}", "北京大学文院");params.put("${major}", "语言学");params.put("${dutyDegree}", "研究生毕业");params.put("${dutyEducation}", "其他");params.put("${dutySchool}", "四川大学土木学院");params.put("${dutyMajor}", "工程造价");params.put("${jobName}", "党委书记,组织部长,宣传部部长");//图片设置WordImage wordImage = new WordImage();wordImage.setHeight(150);wordImage.setWidth(100);byte[] imageBytes = FileUtil.readBytes("templates/fm.png");wordImage.setSource(imageBytes);params.put("@{photo}", wordImage);//一段长文本拆分,按照分行进行展示,例如简历这种String resume = "2017.08--2018.08  北京大学光华管理学院工商管理就读研究生\r2023.05--2023.09  简历测试职务\r2023.05--2023.09  外部人员挂职职务\r2023.09--         图书档案资料人员";params.put("${resume}", resume);//2、============================获取word模板===============================Word07Writer writer = WordUtil.getWriter(FileUtil.file("templates/mb.docx"));XWPFDocument document = writer.getDoc();//获取模板文档//3、============================获取模板文本的段落===============================Iterator<XWPFParagraph> paragraphStrings = document.getParagraphsIterator();while (paragraphStrings.hasNext()) {XWPFParagraph paragraph = paragraphStrings.next();log.info("文本段落文字:{}", paragraph.getText());}//4、============================获取模板表格的段落===============================Iterator<XWPFTable> tableIterator = document.getTablesIterator();while (tableIterator.hasNext()) {XWPFTable table = tableIterator.next();Iterator<XWPFTableRow> rows = table.getRows().listIterator();while (rows.hasNext()) {XWPFTableRow row = rows.next();Iterator<XWPFTableCell> cells = row.getTableCells().listIterator();while (cells.hasNext()) {XWPFTableCell cell = cells.next();List<XWPFParagraph> paragraphCells = cell.getParagraphs();//只去表格中的一个段落XWPFParagraph paragraph = CollectionUtil.isNotEmpty(paragraphCells) ? paragraphCells.get(0) : null;if(paragraph != null){String paragraphString = paragraph.getText();//段落中的文字//占位符替换TemplateProcessor.matchTemplate(paragraphString, params, paragraph);}}}}//5、======================输出文件====================================// 设置content—typeresponse.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset:utf-8");response.setHeader("Content-Disposition", "attachment;filename=data.docx");// 设置标题//Content-disposition是MIME协议的扩展,MIME协议指示MIME用户代理如何显示附加的文件。ServletOutputStream outputStream = response.getOutputStream();//将Writer刷新到OutPutwriter.flush(outputStream, true);outputStream.close();}
}
package com.example.demo.excel;import cn.hutool.poi.word.PicType;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.poi.xwpf.usermodel.XWPFTableCell;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlToken;
import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline;/*** word模板处理* @author xiajun*/
@Slf4j
public class TemplateProcessor {final static Pattern patternString = Pattern.compile("\\$\\{[^{}]+}");//匹配文字final static Pattern patternTable = Pattern.compile("#\\{[^{}]+}");//匹配表格final static Pattern patternImg = Pattern.compile("@\\{[^{}]+}");//匹配照片/*** 模板占位符匹配** @param template* @param variables* @return*/public static void matchTemplate(String template, Map<String, Object> variables, XWPFParagraph paragraph) {//文字占位符替换Matcher matcher = patternString.matcher(template);while (matcher.find()) {String variable = matcher.group();//占位符dealXWPFRun(paragraph,variables,variable);//文档中占位符去除并设置套打文字}//图片占位符替换Matcher matcherImg = patternImg.matcher(template);while (matcherImg.find()) {String variable = matcherImg.group();//占位符dealXWPFRun(paragraph,variables,variable);//文档中占位符去除并设置套打图片}}/*** 获取文档占位符run,并且进行替换* @param paragraph* @param variables* @param variable*/public static void dealXWPFRun(XWPFParagraph paragraph, Map<String, Object> variables, String variable){Object object = variables.get(variable);//需要替换的对象if (paragraph != null) {//获取占位符第一个String beginTag = variable.substring(0, 1);Iterator<XWPFRun> runs = paragraph.getRuns().listIterator();boolean flag = false;//是否开始拼接StringBuffer placeholder = new StringBuffer();List<List<XWPFRun>> allRuns = new ArrayList<>();//所有占位符涉及到的runList<XWPFRun> currentRuns = new ArrayList<>();//当前占位符涉及到的runwhile (runs.hasNext()) {XWPFRun run = runs.next();//开始符号处理if (run.text().contains(beginTag)) {flag = true;}if (flag) {String runString = run.text();placeholder.append(runString);currentRuns.add(run);}if (variable.equals(placeholder.toString())) {allRuns.add(currentRuns);currentRuns = new ArrayList<>();//重置listflag = false;}}//将占位符涉及到的每个run list的第一个元素进行赋值,其他设置为空Iterator<List<XWPFRun>> iterator = allRuns.listIterator();while (iterator.hasNext()) {List<XWPFRun> runList = iterator.next();for (int i = 0; i < runList.size(); i++) {if (i == 0) {//文字处理if(object instanceof String){setRunText(runList.get(i),(String)object);}//图片处理if(object instanceof WordImage){setRunImg(runList.get(i),(WordImage)object);}} else {runList.get(i).setText("", 0);}}}}}/*** 设置Run中的图片* @param run* @param wordImage*/private static void setRunImg(XWPFRun run, WordImage wordImage){PicType picType = wordImage.getImageType();try {run.setText("", 0);//往文档加入图片String picId = run.getDocument().addPictureData(wordImage.getSource(), picType.getValue());//将图片放在指定run中insertImageInRun(run, picId, run.getDocument().getNextPicNameNumber(picType.getValue()),wordImage.getWidth(), wordImage.getHeight());} catch (InvalidFormatException e) {e.printStackTrace();}}/*** 设置Run中的文本** @param run* @param text*/private static void setRunText(XWPFRun run, String text) {if (text.contains("\r")) {String[] split = text.split("\r");List<String> contents = Arrays.asList(split);run.setText(contents.get(0), 0);XWPFParagraph paragraph =(XWPFParagraph)run.getParent();XWPFTableCell cell = (XWPFTableCell)paragraph.getBody();for (int i = 1; i < contents.size(); i++) {//替换的肯定有段落获取第一个段落XWPFParagraph newParagraph = cell.addParagraph();newParagraph.getCTP().setPPr(paragraph.getCTP().getPPr());XWPFRun newRun = newParagraph.createRun();newRun.getCTR().setRPr(run.getCTR().getRPr());String content = contents.get(i);newRun.setText(content);}} else {run.setText(text,0);}}/*** run中插入图片** @param run* @param picId* @param id* @param width* @param height*/private static void insertImageInRun(XWPFRun run, String picId, int id, int width, int height) {final int EMU = 9525;width *= EMU;height *= EMU;CTInline inline = run.getCTR().addNewDrawing().addNewInline();String picXml = "" +"<a:graphic xmlns:a=\"http://schemas.openxmlformats.org/drawingml/2006/main\">" +"   <a:graphicData uri=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" +"      <pic:pic xmlns:pic=\"http://schemas.openxmlformats.org/drawingml/2006/picture\">" +"         <pic:nvPicPr>" +"            <pic:cNvPr id=\"" + id + "\" name=\"Generated\"/>" +"            <pic:cNvPicPr/>" +"         </pic:nvPicPr>" +"         <pic:blipFill>" +"            <a:blip r:embed=\"" + picId + "\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\"/>" +"            <a:stretch>" +"               <a:fillRect/>" +"            </a:stretch>" +"         </pic:blipFill>" +"         <pic:spPr>" +"            <a:xfrm>" +"               <a:off x=\"0\" y=\"0\"/>" +"               <a:ext cx=\"" + width + "\" cy=\"" + height + "\"/>" +"            </a:xfrm>" +"            <a:prstGeom prst=\"rect\">" +"               <a:avLst/>" +"            </a:prstGeom>" +"         </pic:spPr>" +"      </pic:pic>" +"   </a:graphicData>" +"</a:graphic>";XmlToken xmlToken = null;try {xmlToken = XmlToken.Factory.parse(picXml);} catch (XmlException xe) {
//            xe.printStackTrace();throw new RuntimeException("图片XML解析失败");}inline.set(xmlToken);inline.setDistT(0);inline.setDistB(0);inline.setDistL(0);inline.setDistR(0);CTPositiveSize2D extent = inline.addNewExtent();extent.setCx(width);extent.setCy(height);CTNonVisualDrawingProps docPr = inline.addNewDocPr();docPr.setId(id);docPr.setName("Picture " + id);docPr.setDescr("Generated");}
}

4、导出效果:

注意事项:如果你调整了代码设置数据,但是没生效,把target目录下的class文件删除重启哈就生效了。

============================好用记得点个赞哟!!!==========================

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/606070.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

IPv6路由协议---IPv6动态路由(RIPng)

IPv6动态路由协议 动态路由协议有自己的路由算法,能够自动适应网络拓扑的变化,适用于具有一定数量三层设备的网络。缺点是配置对用户要求比较高,对系统的要求高于静态路由,并将占用一定的网络资源和系统资源。 路由表和FIB表 路由器转发数据包的关键是路由表和FIB表,每…

CreateDIBSection失败的问题记录

错误记录 [ERROR] (:0, ): QPixmap::fromWinHICON(), failed to GetIconInfo() (操作成功完成。) [ERROR] (:0, ): QPixmap::fromWinHICON(), failed to GetIconInfo() (参数错误。) [ERROR] (:0, ): QPixmap::fromWinHICON(), failed to GetIconInfo() (参数错误。) [ERROR] …

升级 Vite 5 出现警告 The CJS build of Vite‘s Node API is deprecated.

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…

数仓建设学习路线(一)

前言 数仓建设实践路线是语兴发布在B站的系列课程&#xff0c;搜索语兴呀即可学习完整的数仓建设理论。 大数据相关岗位 大数据常见的岗位主要包括实时开发、数据治理、数据安全、数据资产等。 其中&#xff1a; 实时开发组的主要任务是实时可视化制作(大屏/彩蛋/战报&…

前端结合MQTT实现连接 订阅发送信息等操作 VUE3

MQTT客户端下载 使用测试 在我之前文章中 MQTT下载基础使用 下面记录一下前端使用的话的操作 1.安装 npm i mqtt引入 import * as mqtt from "mqtt/dist/mqtt.min"; //VUE3 import mqtt from mqtt //VUE2 一、MQTT协议中的方法 Connect。等待与服务器建立连接…

[VUE]2-vue的基本使用

目录 vue基本使用方式 1、vue 组件 2、文本插值 3、属性绑定 4、事件绑定 5、双向绑定 6、条件渲染 7、axios 8、⭐跨域问题 &#x1f343;作者介绍&#xff1a;双非本科大三网络工程专业在读&#xff0c;阿里云专家博主&#xff0c;专注于Java领域学习&#xff0c;擅…

气膜建筑:舒适、智能、可持续

气膜建筑之所以能够拥有广阔的发展空间&#xff0c;源于其融合了诸多优势特点&#xff0c;使其成为未来建筑领域的前沿趋势。 气膜建筑注重环境可持续性和能源效率。在材料和设计上&#xff0c;它采用可回收材料、提高热保温效果&#xff0c;并积极利用太阳能等可再生能源&…

【洛谷学习自留】p9226 糖果

解题思路&#xff1a; 简单的计算题&#xff0c;用n对k取余&#xff0c;如果余数为0&#xff0c;则输出k的值&#xff0c;否则输出&#xff08;k-余数&#xff09;的值。 代码实现&#xff1a; import java.util.Scanner;public class p9226 {public static void main(Strin…

【2023 CCF 大数据与计算智能大赛】基于TPU平台实现超分辨率重建模型部署 基于QuickRNet的TPU超分模型部署

2023 CCF 大数据与计算智能大赛 《赛题名称》 基于QuickRNet的TPU超分模型部署 巴黎欧莱雅 林松 智能应用业务部算法工程师 中信科移动 中国-北京 gpu163.com 团队简介 巴黎欧莱雅团队包含一个队长和零个队员。 队长林松&#xff0c;研究生学历&#xff0c;2019-202…

【一份老网工珍藏多年的网络配置笔记,很重要!】

01、交换机、路由器的几种配置模式及模式转换 1. 用户模式 登录到交换机&#xff08;路由器&#xff09;时会自动进入用户模式&#xff0c;提示符为 switchname>。在该模式下只能够查看相关信息&#xff0c; 对 IOS的运行不产生任何影响。 2. 特权模式 用户模式下&#xff…

精进单元测试技能 —— Pytest断言的艺术!

本篇文章主要是阐述Pytest在断言方面的应用。让大家能够了解和掌握Pytest针对断言设计了多种功能以适应在不同测试场景上使用。 了解断言的基础 在Pytest中&#xff0c;断言是通过 assert 语句来实现的。简单的断言通常用于验证预期值和实际值是否相等&#xff0c;例如&#…

蒙牛×每日互动合作获评中国信通院2023“数据+”行业应用优秀案例

当前在数字营销领域&#xff0c;品牌广告主越来越追求品效协同。针对品牌主更注重营销转化的切实需求&#xff0c;数据智能上市企业每日互动&#xff08;股票代码&#xff1a;300766&#xff09;发挥自身数据和技术能力优势&#xff0c;为垂直行业的品牌客户提供专业的数字化营…

实时云渲染的技术原理是什么?一篇文章讲透云渲染

实时云渲染依赖互联网的连接和高性能服务集群&#xff0c;为客户实时提供渲染画面&#xff0c;它有以下几个关键技术&#xff1a; 1、GPU上云 利用云服务器强大的GPU替代本地GPU进行图形处理&#xff0c;提高性能、可替换性和扩展性。2、视频流化技术 这项技术能在远程执行用户…

【ArcGIS微课1000例】0087:经纬度格式转换(度分秒转度、度转度分秒)

ArcGIS软件可以很方便的直接实现度分秒转度、度转度分秒。 文章目录 一、转换预览二、工具介绍三、案例解析一、转换预览 借助ArcGIS快速实现度分秒与度及其他格式的坐标转换。例如:度分秒→度 度分秒: 度: 二、工具介绍 转换坐标记法:将一个或两个字段包含的坐标记法从一…

XREAL推出其新款AR眼镜:XREAL Air 2 Ultra,体量轻内置音效

这款眼镜堪称科技的杰作&#xff0c;它以钛合金为框架&#xff0c;尽显轻盈与精致。配备的双3D环境传感器&#xff0c;宛如双眼般敏锐&#xff0c;能精准捕捉头部运动&#xff0c;让你在虚拟与现实间自由穿梭。120Hz的超高刷新率与500尼特的亮度&#xff0c;让你在4米之外感受1…

搭建React开发环境-webpack实现

周末在家学会React前端知识&#xff0c;记录下来&#xff0c;方便备查。 webpack版本&#xff1a;webpack5 编译器&#xff1a;vscode 第一步、新建项目及初始化 1&#xff09;新建项目文件夹 可命名为 my_webpack 2&#xff09;初始化项目 使用命令 npm init -y&#xff0c;…

Centos7 MongoDB安装

基础配置&#xff08;Centos7.5镜像&#xff0c;2核2GB内存&#xff0c;50GB硬盘&#xff09; 主机名IPmongodb192.168.100.124 &#xff08;在MongoDB官网有linux安装MongoDB的步骤&#xff09; &#xff08;1&#xff09;配置yum源 [rootmongodb ~]# cat /etc/yum.repos.d…

DDIA 第十一章:流处理

本文是《数据密集型应用系统设计》&#xff08;DDIA&#xff09;的读书笔记&#xff0c;一共十二章&#xff0c;我已经全部阅读并且整理完毕。 采用一问一答的形式&#xff0c;并且用列表形式整理了原文。 笔记的内容大概是原文的 1/5 ~ 1/3&#xff0c;所以你如果没有很多时间…

如何修复 SQL Server 数据库中的恢复挂起状态?

当我们想与关系数据库交互时&#xff0c;SQL 就会出现并帮助用户与数据库进行交互。SQL 从高级语言中获取用户的输入&#xff0c;然后访问将代码转换为机器可理解的形式。SQL 确实会恢复数据库文件&#xff0c;但有时 SQL 服务器恢复暂挂阶段会进入帐户&#xff0c;这会停止恢复…

系统编程--VIM特辑

这里写目录标题 vim三种工作模式进入文本模式的快捷键在命令模式下进行文本编辑删除快捷键复制粘贴查找替换查找替换 vim其他操作 vim打造简易IDE vim 三种工作模式 具体可见第二章对vim的详细介绍 需要注意的是&#xff0c;在末行模式下执行完一次命令&#xff0c;就可以直接…