有这样的需要,客户需要把表单信息导出,上级签字,这个涉及多行记录,需要导出word表格

找了很多方法,没有实现,现在将实现的方法分享出来

只有两个工具类,自带导出测试方法,根据自己需要修改图片和模板路径即可,亲测可用

WordUtils.java工具类

package com.fc.test.util;
import com.qiniu.util.Json;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge;import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;/*** 客户端工具类* @author zlxls* @date: 2020年04月21日 下午2:10:48*/
public class WordUtils {public void exportWordData(HttpServletResponse response){Map<String, Object> params = new HashMap<String, Object>();params.put("${position}", "java开发");params.put("${name}", "段然涛");params.put("${sex}", "男");params.put("${national}", "汉族");params.put("${birthday}", "生日");params.put("${address}", "许昌");params.put("${height}", "165cm");params.put("${biYeDate}", "1994-02-03");params.put("${landscape}", "团员");params.put("${zhuanYe}", "社会工作");params.put("${xueLi}", "本科");params.put("${school}", "江西科技师范大学");params.put("${phone}", "177");params.put("${eMail}", "157");try{Map<String,Object> header = new HashMap<String, Object>();header.put("width", 100);header.put("height", 150);header.put("type", "jpg");header.put("content", WordUtils.inputStream2ByteArray(new FileInputStream("C:\\Users\\Administrator\\Desktop\\01.jpg"), true));params.put("${header}",header);Map<String,Object> header2 = new HashMap<String, Object>();header2.put("width", 100);header2.put("height", 150);header2.put("type", "jpg");header2.put("content", WordUtils.inputStream2ByteArray(new FileInputStream("C:\\Users\\Administrator\\Desktop\\01.jpg"), true));params.put("${header2}",header2);List<String[]> testList = new ArrayList<String[]>();testList.add(new String[]{"1","1AA","1BB","1CC"});testList.add(new String[]{"2","2AA","2BB","2CC"});testList.add(new String[]{"3","3AA","3BB","3CC"});testList.add(new String[]{"4","4AA","4BB","4CC"});testList.add(new String[]{"5","4AA","4BB","4CC"});String path="F:\\JAVAProject\\dh161_appliance\\dh161_appliance\\target\\classes\\static\\tpl\\change_tpl.docx";  //模板文件位置String fileName= new String("测试文档.docx".getBytes("UTF-8"),"iso-8859-1");    //生成word文件的文件名}catch(Exception e){e.printStackTrace();}}/*** 导出word方法调用** @param response* @param list 数据集合* @param path 模板路径* @param fileName 导出名称* @param index 表格起始数据行数* @param index 是否合并单元格 无法适配,根据数字进行制定合并* @throws Exception*/public void exportWord(HttpServletResponse response,List<String[]> list,String path,String fileName,int index,int isMerge) throws Exception{Map<String, Object> params = new HashMap<String, Object>();exportWord(response,list,path,fileName,index,params,isMerge);}/*** 导出word方法调用** @param response* @param list 数据集合* @param path 模板路径* @param fileName 导出名称* @param index 表格起始数据行数* @throws Exception*/public void exportWord(HttpServletResponse response,List<String[]> list,String path,String fileName,int index) throws Exception{Map<String, Object> params = new HashMap<String, Object>();exportWord(response,list,path,fileName,index,params,0);}/*** 导出word方法调用** @param response* @param list 数据集合* @param path 模板路径* @param fileName 导出名称* @param index 表格起始数据行数* @param params 要替换的数据* @param isMerge 是否合并单元格 无法适配,根据数字进行制定合并* @throws Exception*/public void exportWord(HttpServletResponse response,List<String[]> list,String path,String fileName,int index,Map<String, Object> params,int isMerge) throws Exception{getWord(response,list,path,fileName,index,params,isMerge);}/*** 根据模板生成word** @param path 模板的路径* @param params 需要替换的参数* @param list 需要插入的参数* @param fileName 生成word文件的文件名* @param response* @param index 列表数据起始行数* @throws Exception*/public void getWord(HttpServletResponse response,List<String[]> list,String path,String fileName,int index,Map<String, Object> params,int isMerge) throws Exception {fileName= new String((fileName+".docx").getBytes("UTF-8"),"iso-8859-1");    //生成word文件的文件名File file = new File(path);InputStream is = new FileInputStream(file);CustomXWPFDocument doc = new CustomXWPFDocument(is);if(params.size()>0){this.replaceInPara(doc, params);    //替换文本里面的变量}this.replaceInTable(doc, params, list,index,isMerge); //替换表格里面的变量OutputStream os = response.getOutputStream();response.setHeader("Content-disposition", "attachment; filename=" + fileName);doc.write(os);this.close(os);this.close(is);}/*** 替换表格里面的变量** @param doc 要替换的文档* @param params 参数* @param tableList 数据列表* @param index 有效行数* @param isMerge 是否合并单元格 无法适配,根据数字进行制定合并*/private void replaceInTable(CustomXWPFDocument doc, Map<String, Object> params, List<String[]> tableList,int index,int isMerge) {Iterator<XWPFTable> iterator = doc.getTablesIterator();XWPFTable table;List<XWPFTableRow> rows;List<XWPFTableCell> cells;List<XWPFParagraph> paras;int indexRow = 0;while (iterator.hasNext()) {table = iterator.next();if (table.getRows().size() > 1) {//判断表格是需要替换还是需要插入,判断逻辑有$为替换,表格无$为插入if (this.matcher(table.getText()).find()) {rows = table.getRows();for (XWPFTableRow row : rows) {cells = row.getTableCells();for (XWPFTableCell cell : cells) {paras = cell.getParagraphs();for (XWPFParagraph para : paras) {this.replaceInPara(para, params, doc);}}}} else {insertTable(table, tableList,index,isMerge);  //插入数据}}}}/*** 为表格插入数据,行数不够添加新行** @param table 需要插入数据的表格* @param tableList 插入数据集合* @param index 插入数据集合* @param isMerge 是否合并单元格 无法适配,根据数字进行制定合并*/private static void insertTable(XWPFTable table, List<String[]> tableList,int index,int isMerge) {//创建行,根据需要插入的数据添加新行,不处理表头for (int i = 0; i < tableList.size(); i++) {XWPFTableRow row = table.createRow();}//遍历表格插入数据List<XWPFTableRow> rows = table.getRows();int lengthI = tableList.size();for (int i = 0; i < lengthI; i++) {List<XWPFTableCell> cells = table.getRow(i+index).getTableCells();int lengthJ = tableList.get(i).length;for (int j = 0; j < lengthJ; j++) {XWPFTableCell cell = cells.get(j);String s = tableList.get(i)[j];cell.setText(s);}}//以下是合并单元格if(isMerge==1){int fromCell =3;int toCell =5;for (int cellIndex = fromCell; cellIndex <= toCell; cellIndex++) {XWPFTableCell cell = table.getRow(0).getCell(cellIndex);if ( cellIndex == fromCell ) {// The first merged cell is set with RESTART merge valuecell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);} else {// Cells which join (merge) the first one, are set with CONTINUEcell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);}}fromCell =6;toCell =8;for (int cellIndex = fromCell; cellIndex <= toCell; cellIndex++) {XWPFTableCell cell = table.getRow(0).getCell(cellIndex);if ( cellIndex == fromCell ) {// The first merged cell is set with RESTART merge valuecell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);} else {// Cells which join (merge) the first one, are set with CONTINUEcell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);}}}}/*** 替换段落里面的变量** @param doc    要替换的文档* @param params 参数*/private void replaceInPara(CustomXWPFDocument doc, Map<String, Object> params) {Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();XWPFParagraph para;while (iterator.hasNext()) {para = iterator.next();this.replaceInPara(para, params, doc);}}/*** 替换段落里面的变量** @param para   要替换的段落* @param params 参数*/private void replaceInPara(XWPFParagraph para, Map<String, Object> params, CustomXWPFDocument doc) {List<XWPFRun> runs;Matcher matcher;if (this.matcher(para.getParagraphText()).find()) {runs = para.getRuns();int start = -1;int end = -1;String str = "";for (int i = 0; i < runs.size(); i++) {XWPFRun run = runs.get(i);String runText = run.toString();if ('$' == runText.charAt(0) && '{' == runText.charAt(1)) {start = i;}if ((start != -1)) {str += runText;}if ('}' == runText.charAt(runText.length() - 1)) {if (start != -1) {end = i;break;}}}for (int i = start; i <= end; i++) {para.removeRun(i);i--;end--;}for (Map.Entry<String, Object> entry : params.entrySet()) {String key = entry.getKey();if (str.indexOf(key) != -1) {Object value = entry.getValue();if (value instanceof String) {str = str.replace(key, value.toString());para.createRun().setText(str, 0);break;} else if (value instanceof Map) {str = str.replace(key, "");Map pic = (Map) value;int width = Integer.parseInt(pic.get("width").toString());int height = Integer.parseInt(pic.get("height").toString());int picType = getPictureType(pic.get("type").toString());byte[] byteArray = (byte[]) pic.get("content");ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteArray);try {//int ind = doc.addPicture(byteInputStream,picType);//doc.createPicture(ind, width , height,para);doc.addPictureData(byteInputStream, picType);doc.createPicture(doc.getAllPictures().size() - 1, width, height, para);para.createRun().setText(str, 0);break;} catch (Exception e) {e.printStackTrace();}}}}}}/*** 正则匹配字符串** @param str* @return*/private Matcher matcher(String str) {Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}", Pattern.CASE_INSENSITIVE);Matcher matcher = pattern.matcher(str);return matcher;}/*** 根据图片类型,取得对应的图片类型代码** @param picType* @return int*/private static int getPictureType(String picType) {int res = CustomXWPFDocument.PICTURE_TYPE_PICT;if (picType != null) {if (picType.equalsIgnoreCase("png")) {res = CustomXWPFDocument.PICTURE_TYPE_PNG;} else if (picType.equalsIgnoreCase("dib")) {res = CustomXWPFDocument.PICTURE_TYPE_DIB;} else if (picType.equalsIgnoreCase("emf")) {res = CustomXWPFDocument.PICTURE_TYPE_EMF;} else if (picType.equalsIgnoreCase("jpg") || picType.equalsIgnoreCase("jpeg")) {res = CustomXWPFDocument.PICTURE_TYPE_JPEG;} else if (picType.equalsIgnoreCase("wmf")) {res = CustomXWPFDocument.PICTURE_TYPE_WMF;}}return res;}/*** 将输入流中的数据写入字节数组** @param in* @return*/public static byte[] inputStream2ByteArray(InputStream in, boolean isClose) {byte[] byteArray = null;try {int total = in.available();byteArray = new byte[total];in.read(byteArray);} catch (IOException e) {e.printStackTrace();} finally {if (isClose) {try {in.close();} catch (Exception e2) {e2.getStackTrace();}}}return byteArray;}/*** 关闭输入流** @param is*/private void close(InputStream is) {if (is != null) {try {is.close();} catch (IOException e) {e.printStackTrace();}}}/*** 关闭输出流** @param os*/private void close(OutputStream os) {if (os != null) {try {os.close();} catch (IOException e) {e.printStackTrace();}}}
}

CustomXWPFDocument.java工具类

package com.fc.test.util;import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
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;
import java.io.IOException;
import java.io.InputStream;/*** 客户端工具类* @author zlxls* @date: 2020年04月21日 下午2:10:48*/
public class CustomXWPFDocument extends XWPFDocument {public CustomXWPFDocument(InputStream in) throws IOException {super(in);}public CustomXWPFDocument() {super();}public CustomXWPFDocument(OPCPackage pkg) throws IOException {super(pkg);}/*** @param id* @param width 宽* @param height 高* @param paragraph  段落*/public void createPicture(int id, int width, int height,XWPFParagraph paragraph) {final int EMU = 9525;width *= EMU;height *= EMU;String blipId = getAllPictures().get(id).getPackageRelationship().getId();CTInline inline = paragraph.createRun().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=\""+ blipId+"\" 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>";inline.addNewGraphic().addNewGraphicData();XmlToken xmlToken = null;try{xmlToken = XmlToken.Factory.parse(picXml);}catch(XmlException xe) {xe.printStackTrace();}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("图片"+ id);docPr.setDescr("测试");}
}

SpringBoot使用Word导出表格相关推荐

  1. java word导出表格_Java Word模板导出包含表格单元格合并

    java通过freemarker导出word循环合并表格单元格 本文主要讲解通过freemarker模板引擎来导出word,并且在word中包含表格的合并部分需要循环生成. 一.Java需要通过模板导 ...

  2. java 导出word 含表格_poi 导出word,导出表格(复杂表格合并行列)解决方法

    如下图:一个table表格,需要作为表格插入到word中: 1.首先对表格做拆分处理 代码如下:private String simplifyTable(String tableContent) { ...

  3. SpringBoot实现Word导出

    实现Word导出是根据 .ftl后缀的freemarker模板先生成相应的Word文档的xml文件,然后再根据xml文件转为doc后缀的Word文档. 我的 .ftl模板就是根据要生成的Word转为x ...

  4. 【word导出】JAVA使用POI实现word导出表格并简单设置样式

    参考资料 Java POI导出word文件及生成表格 POI官方文档网站 如何让表格中的文字居中 XWPFTableRow rowBt = table.createRow(); XWPFTableCe ...

  5. SpringBoot整合Freemarker导出word文档表格

    freemarker模板里面的template.process()方法里传入的第一个参数Object类型,如果是一个实体类对象在模板上怎么进行渲染,将实体类的值取出 freemarker会调用Obje ...

  6. 图片复制word java_java poi实现word导出(包括word模板的使用、复制表格、复制行、插入图片的使用)...

    java poi实现数据的word导出(包括word模板的使用.复制表格.复制行.插入图片的使用) 1.实现的效果 实现病人基本信息.多条病历数据.多项检查项图片的动态插入(网络图片) 2.模板 把w ...

  7. Springboot + vue 实现导出word

    Springboot + vue 实现导出word 后端代码 使用word先创建好已知的模板 使用word工具另存为.xml格式的文件 使用freemarker ftl模板 将修改后的xml文件复制到 ...

  8. java poi导出word 多表格 页眉 非xml

    poi可以操作excel表格和word文档,但是网上找的poi表格相关大多是操作excel表格,很少有word的复杂表格. 加上最近项目上也遇到了要使用java导出word多表格的问题. 开始网上找的 ...

  9. 《springboot中实现excel表格导出》

    <springboot中实现excel表格导出> 简介 在Spring Boot中,实现Excel表格导出的方式有很多种,以下是几种常见的方法: 使用Apache POI:Apache P ...

最新文章

  1. 阿里终面:为什么SSD不能当做内存用?
  2. 记录Android Studio项目提交到github上的出错处理
  3. reddit高赞资源:20h系统性深度学习强化学习课程,视频、PPT、代码全都有 | 免费...
  4. linux sed举例,sed 常用命令与参数,带举例:时时更新!
  5. 学习笔记(25):Python网络编程并发编程-Thread其他属性和守护线程
  6. centos 6.8 mysql 5.6_Mysql(5.6.35)在Linux(Centos 6.8)上安装
  7. 贪吃蛇 c语言 不死模式,c语言贪吃蛇游戏完整代码,c语言贪吃蛇教程
  8. SSM实现会议室预约管理系统
  9. 欢度国庆⭐️共享爬虫之美⭐️基于 Python 实现微信公众号爬虫(Python无所不能爬)
  10. 在Google上做搜索引擎优化 (SEO),最重要的是哪几点?
  11. python网络爬虫——自学笔记2.1用requests库和re库爬取图片
  12. 4007: [JLOI2015]战争调度
  13. matlab 菱形符号,matlab 图形符号
  14. html5+css3实现2D动画效果演示
  15. nvidia英伟达和七彩虹什么关系?为啥发布3080的是英伟达,七彩虹会给3080一个报价?
  16. Mac M1系统 miniconda安装、配置conda环境,及在conda环境中安装激活QIIME2
  17. win10如何使任务栏全透明
  18. 淘宝2011春季校园招聘笔试试题(答案+个人解析版)
  19. AV1官方的AOM code下载地址
  20. typora中实心圆和空心圆

热门文章

  1. android主流手机测试,硬件测试哪家强?安卓手机跑分软件横评
  2. 安卓原生系统开发与逆向工程
  3. 阿拉伯数字转换成大写的数字
  4. 设想一种防U盘病毒的方法,不知道是否管用
  5. 小程序游戏开发三个引擎用哪个好呢 Cocos,Egret,Laya?
  6. 讲座笔记 | 陆铭 城市、区域和国家发展:空间政治经济学的理论和实证研究
  7. Cadence OrCAD Capture 绘制总线的方法
  8. c++ 海战棋_GitHub - yifeitao/SimpleProgrammingProblems: 简单编程问题集中译版
  9. UG 信息窗口弹不出来 测量 长度 角度 信息 窗口 弹不出来
  10. 2022中山大学计算机考研专硕初试经验分享