poi导出word内嵌表格

  • 设计分析部分
  • 后端代码部分
    • xml文件配置
    • 实体类
    • controller层
    • 使用到的工具类
    • service层
  • 前端代码部分
    • 测试页面

设计分析部分

首先要对导出word的需求进行分析,以下展示,本项目中,导出的word格式
出于某些保密原因,某些图片已被隐藏,可能给大家看到的效果没有现实导出的效果好,请各位自行脑补,多多包涵。
为什么要使用poi?其实,设计的时候,也思考过,使用模板的形式,直接向模板中添加数据,后来发现,如果使用模板非常容易产生错版,而使用poi会更好的自定义生成某一栏,自定义某一栏的行高等,所以尝试使用poi完成该项目的需求;
废话不多说,上代码:

后端代码部分

xml文件配置

引入项目相关的依赖,注意,此处的版本号常见使用3.11版本,那么,如果使用3.11版本,在本套代码中,插入图片部分的操作,需要作出部分改动

     <dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.17</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.17</version></dependency>

实体类

实体类部分,我选择的是表头的几个栏目配置为一个实体类

@Data
public class MaterialEntity {private String id;private Integer sort;//序号private String specifications;//规格private String unit;//单位private String num;//数量private Double netWeight;//净量private Double total;//总量private String remark;//备注private String materialNo;//物码
}

controller层

controller层上,提供一个接口,供导出时,页面调用

    @RequestMapping(value = "/exportDesignWord",method = RequestMethod.POST)public void exportDesignWord(@RequestParam(value = "basicId")String basicId ,HttpServletResponse response){try {materialService.exportDesign(basicId,response);}catch (Exception e){e.printStackTrace();}}

使用到的工具类

package com.exportword.utils;import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.*;
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 org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;import javax.imageio.stream.FileImageInputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigInteger;
import java.util.List;public class ExportWord extends XWPFDocument {public static PathMatchingResourcePatternResolver pathMatchingResourcePatternResolver = new PathMatchingResourcePatternResolver();private XWPFDocument doc;public ExportWord() {super();}public ExportWord(InputStream in) throws IOException {super(in);}public ExportWord(HttpServletResponse response, String fileName) {try {response.setContentType("application/vnd.ms-excel;charset=utf-8");response.setHeader("Content-Disposition","attachment;filename=" + new String((fileName).getBytes(), "iso-8859-1"));} catch (UnsupportedEncodingException e) {e.printStackTrace();}}public ExportWord(OPCPackage pkg) throws IOException {super(pkg);}public  XWPFDocument getDoc(){return this.doc;}public  void mergeCellsHorizontal(XWPFTable table, int row, int fromCell, int toCell) {for (int cellIndex = fromCell; cellIndex <= toCell; cellIndex++) {XWPFTableCell cell = table.getRow(row).getCell(cellIndex);if ( cellIndex == fromCell ) {cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);} else {cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);}}}/*** @描述: 跨行并单元格*/public void mergeCellsVertically(XWPFTable table, int col, int fromRow, int toRow) {for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {XWPFTableCell cell = table.getRow(rowIndex).getCell(col);if ( rowIndex == fromRow ) {// The first merged cell is set with RESTART merge valuecell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);} else {// Cells which join (merge) the first one, are set with CONTINUEcell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);}}}/***  合并单元格,从第几行第几列合并到第几行到第几列*/public void mergeCellsComplex(XWPFTable table, int fromRow, int fromCol, int toRow,int toCol) {int rows = toRow - fromRow;int cols = toCol - fromCol;for (int i = 0; i < rows; i++) {for (int j = 0; j < cols; j++) {mergeCellsVertically(table,fromCol+j,fromRow,toRow);}}for (int i = 0; i < cols; i++) {for (int j = 0; j < rows; j++) {mergeCellsHorizontal(table,fromRow+j,fromCol,toCol);}}}/*** @描述: 设置标题*/public void setTitle(XWPFParagraph titleParagraph, String title) {titleParagraph.setAlignment(ParagraphAlignment.CENTER);XWPFRun titleParagraphRun = titleParagraph.createRun();titleParagraphRun.setText(title);titleParagraphRun.setColor("000000");titleParagraphRun.setFontSize(22);titleParagraphRun.setUnderline(UnderlinePatterns.DOUBLE);setFontFamily(titleParagraphRun,"黑体");}/*** @描述: 设置字体*/public void setFontFamily(XWPFRun run,String fontFamily) {CTRPr rpr = run.getCTR().getRPr();CTFonts fonts = rpr.addNewRFonts();fonts.setAscii(fontFamily);fonts.setEastAsia(fontFamily);fonts.setHAnsi(fontFamily);}/*** @描述: 换行*/public void getWrap(ExportWord document) {XWPFParagraph paragraph = document.createParagraph();XWPFRun paragraphRun = paragraph.createRun();
//      paragraphRun.addBreak();}/*** createTable*/public XWPFTable createTable(ExportWord document, int rows, int cols) {XWPFTable infoTable = document.createTable(rows, cols);CTTbl ttbl = infoTable.getCTTbl();CTTblPr tblPr = ttbl.getTblPr() == null ? ttbl.addNewTblPr() : ttbl.getTblPr();CTTblWidth tblWidth = tblPr.isSetTblW() ? tblPr.getTblW() : tblPr.addNewTblW();CTJc cTJc = tblPr.addNewJc();cTJc.setVal(STJc.Enum.forString("center"));tblWidth.setW(new BigInteger("8300"));tblWidth.setType(STTblWidth.DXA);return infoTable;}/*** @描述: 设置列宽*/public void setColWidth(XWPFTable table) {List<XWPFTableRow> rows = table.getRows();XWPFTableRow row;List<XWPFTableCell> cells;XWPFTableCell cell;int rowSize = rows.size();int cellSize;for (int i = 0; i < rowSize; i++) {row = rows.get(i);cells = row.getTableCells(); // 获得单元格cellSize = cells.size();// 分列设置单元格宽度或者说列宽row.setHeight(400); // 设置行高for (int j = 0; j < cellSize; j++) {cell = cells.get(j);CTTcPr cellPr = cell.getCTTc().addNewTcPr();CTTblWidth cellw = cellPr.addNewTcW();cellw.setType(STTblWidth.DXA);cellPr.addNewTcW().setW(BigInteger.valueOf(500));}}}/*** @描述: 获取表格的列(不包括合并单元格的)*/public int getCellOfRow(XWPFTable table){List<XWPFTableRow> rows = table.getRows();if(rows.size()>0){return rows.get(0).getTableCells().size();}else{return 0;}}/*** @描述: 给表格赋值*/public void setTableTextLeft(XWPFTable table,int row,int col,String msg) {setTableText(table,row,col,msg,ParagraphAlignment.LEFT);}public void setTableTextRight(XWPFTable table,int row,int col,String msg) {setTableText(table,row,col,msg,ParagraphAlignment.RIGHT);}public void setTableTextCenter(XWPFTable table,int row,int col,String msg) {setTableText(table,row,col,msg,ParagraphAlignment.CENTER);}public void setTableTextBoth(XWPFTable table,int row,int col,String msg) {setTableText(table,row,col,msg,ParagraphAlignment.BOTH);}public void setTableText(XWPFTable table,int row,int col,String msg,ParagraphAlignment alignment) {List<XWPFTableCell> tableCells = table.getRow(row).getTableCells();XWPFTableCell cell= tableCells.get(col);cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);XWPFParagraph table_p = cell.getParagraphs().get(0);table_p.setAlignment(alignment);if (msg.indexOf("\n")>0){String[] split = msg.split("\n");for (int i = 0; i < split.length; i++) {XWPFRun table_run= table_p.createRun();table_run.setText(split[i]);table_run.setColor("000000");table_run.setFontSize(10);if (i<split.length-1){table_run.addBreak();//换行}setFontFamily(table_run,"宋体");}}else {XWPFRun table_run= table_p.createRun();table_run.setText(msg);table_run.setColor("000000");table_run.setFontSize(10);setFontFamily(table_run,"宋体");}}public void setTableTextAndImg(XWPFTable table,int row,int col,String picName,int imgWidth,int imgHeight,String msg) {List<XWPFTableCell> tableCells = table.getRow(row).getTableCells();XWPFTableCell cell= tableCells.get(col);cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);XWPFParagraph table_p = cell.getParagraphs().get(0);table_p.setAlignment(ParagraphAlignment.LEFT);try {InputStream inputStream = pathMatchingResourcePatternResolver.getResource("static/images/" + picName).getInputStream();table_p.createRun().addPicture(inputStream, XWPFDocument.PICTURE_TYPE_PNG, picName, Units.toEMU(imgWidth), Units.toEMU(imgHeight));} catch (InvalidFormatException | IOException e) {e.printStackTrace();}XWPFRun table_run = table_p.createRun();if (msg.indexOf("\n")>0){String[] split = msg.split("\n");for (int i = 0; i < split.length; i++) {table_run.setText(split[i]);table_run.setColor("000000");table_run.setFontSize(10);if (i<split.length-1){table_run.addBreak();//换行}setFontFamily(table_run,"宋体");}}else {table_run.setText(msg);table_run.setColor("000000");table_run.setFontSize(10);setFontFamily(table_run,"宋体");}}/*** setTableText* @描述: 给表格赋值并且设置样式*/public void setTableText(XWPFTable table,int row,int col,String msg, String style) {List<XWPFTableCell> tableCells = table.getRow(row).getTableCells();XWPFTableCell cell= tableCells.get(col);cell.setVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);XWPFParagraph table_p = cell.getParagraphs().get(0);table_p.setAlignment(ParagraphAlignment.CENTER);XWPFRun table_run= table_p.createRun();table_run.setText(msg);table_run.setColor("000000");table_run.setFontSize(10);setFontFamily(table_run,"宋体");if("bold".equals(style)){table_run.setBold(true);}if("boldBig".equals(style)){table_run.setFontSize(14);table_run.setBold(true);}}/**** image2byte* @描述: 将图片转换成字节保存到byte数组*/public byte[] image2byte(String path) {byte[] data = null;FileImageInputStream input = null;try {input = new FileImageInputStream(new File(path));ByteArrayOutputStream output = new ByteArrayOutputStream();byte[] buf = new byte[1024];int numBytesRead = 0;while ((numBytesRead = input.read(buf)) != -1) {output.write(buf, 0, numBytesRead);}data = output.toByteArray();output.close();input.close();} catch (FileNotFoundException ex1) {ex1.printStackTrace();} catch (IOException ex1) {ex1.printStackTrace();}return data;}}

service层

service层其实是一个绘制表格的过程,以及遍历数据list,用数据填充表格的过程

@Service
public class MaterialService {public void exportDesign(String name, HttpServletResponse response) {//此处是查询出的实体类型list,用来遍历填充表单内容List<MaterialEntity> listQuery = findListQuery(19);//使用填充的数据为假数据,到正式使用时,请自行写接口获取到一个listexportWord(response,listQuery);}//此处为造假数据的方法private List<MaterialEntity> findListQuery(int dataTolRows) {List<MaterialEntity> resultList = new ArrayList<MaterialEntity>();for (int i = 0; i < dataTolRows; i++) {MaterialEntity materialEntity = new MaterialEntity();materialEntity.setId(UUID.randomUUID().toString());materialEntity.setSort(i+1);materialEntity.setSpecifications("无缝钢管 Sch160 PE Φ21.3×4.78  GB/T 6479-20"+i);materialEntity.setUnit("t");materialEntity.setNetWeight((double) (((int)(Math.random()*10000))/100));materialEntity.setTotal((double) (((int)(Math.random()*10000))/100));materialEntity.setRemark("ABCD"+"-"+i);resultList.add(materialEntity);}return resultList;}//正式开始导出数据private void exportWord(HttpServletResponse response, List<MaterialEntity> listQuery) {System.out.println(listQuery);OutputStream out = null;try {// 获取输出流out = response.getOutputStream();//start创建表格部分开始// Word名字 后缀必须输docxExportWord document = new ExportWord(response,"文件名.docx");//根据页面设计的格式,填入数据时只填入的19行数据//除19行数据外,2行为表最底端空余的两行,并插入的说明内容//7行为表头及上方合并的单元格大块,所以,共创建19+9=28行表格;int rows = listQuery.size() + 9;//7+2   19+9=28 建立28行12列的表//12列,可以参照表格最下方的一行表格,上方表格多少都有单元格合并,无法直观看出12行单元格XWPFTable table_base= document.createTable(document, rows,12);
//end创建表格部分结束//start此处开始,进行单元格合并,合并成导出文件时,所需的表格样式//设置表头信息document.mergeCellsComplex(table_base,0,0,6,2);document.mergeCellsComplex(table_base,0,3,2,7);document.mergeCellsComplex(table_base,2,3,6,7);document.mergeCellsHorizontal(table_base,0,8,11);document.mergeCellsHorizontal(table_base,1,8,11);document.mergeCellsHorizontal(table_base,2,8,11);document.mergeCellsHorizontal(table_base,3,8,11);document.mergeCellsHorizontal(table_base,4,8,11);document.mergeCellsHorizontal(table_base,5,8,10);//设置实体数据信息document.mergeCellsHorizontal(table_base,6,1,5);document.mergeCellsHorizontal(table_base,6,10,11);
//end单元格合并结束,此时的表格基本与导出表格的外形相同//start此处开始,进行单元格部分数据填充//首先填充上方合并的大单元格部分//shiyou1.png为本地存放的一张图片,用于插入表中,作为页面上方的logo显示(已打马部分)document.setTableTextAndImg(table_base,0,0,"shiyou1.png",130,40," \n工程设计证书:A13\n" +"              924\n工程:150004-key\n      专业   HG   ");document.setTableTextCenter(table_base,0,3,"材料表");document.setTableTextCenter(table_base,2,3,"AAA\n改(成本部分)\n");document.setTableTextLeft(table_base,0,8,"项目号:");document.setTableTextLeft(table_base,1,8,"文件号:");document.setTableTextLeft(table_base,2,8,"CADD号:");document.setTableTextLeft(table_base,3,8,"设计阶段:施工图");document.setTableTextLeft(table_base,4,8,"日期:2020.");document.setTableTextCenter(table_base,5,8,"第 1 页 共 3 页");document.setTableTextCenter(table_base,5,11,"0 版");//填充实体表头document.setTableTextCenter(table_base,6,0,"序号");document.setTableTextCenter(table_base,6,1,"名称、规格及标准号");document.setTableTextCenter(table_base,6,6,"单位");document.setTableTextCenter(table_base,6,7,"数量");document.setTableTextCenter(table_base,6,8,"净量");document.setTableTextCenter(table_base,6,9,"总量");document.setTableTextCenter(table_base,6,10,"备注");//遍历实体数据填充for (int i = 0; i < listQuery.size(); i++) {//设置实体数据信息document.mergeCellsHorizontal(table_base,7+i,1,5);document.mergeCellsHorizontal(table_base,7+i,10,11);MaterialEntity entity = listQuery.get(i);Integer sort = entity.getSort();document.setTableTextCenter(table_base,7+i,0,StringUtils.isEmpty(sort)?"":sort.toString());String specifications = entity.getSpecifications();document.setTableTextCenter(table_base,7+i,1,StringUtils.isEmpty(specifications)?"":specifications);String unit = entity.getUnit();document.setTableTextCenter(table_base,7+i,6,StringUtils.isEmpty(unit)?"":unit);String num = entity.getNum();document.setTableTextCenter(table_base,7+i,7,StringUtils.isEmpty(num)?"":num);Double netWeight = entity.getNetWeight();document.setTableTextCenter(table_base,7+i,8,StringUtils.isEmpty(netWeight)?"":netWeight.toString());Double total = entity.getTotal();document.setTableTextCenter(table_base,7+i,9,StringUtils.isEmpty(total)?"":total.toString());String remark = entity.getRemark();document.setTableTextCenter(table_base,7+i,10,StringUtils.isEmpty(remark)?"":remark);}
//end数据填充部分结束document.setColWidth(table_base);//200
//            document.createTable()document.write(out);} catch (Exception e) {e.printStackTrace();}finally{try {out.flush();out.close();} catch (IOException e) {e.printStackTrace();}}}
}

前端代码部分

测试页面

写了一个测试页面,供调用接口,进行测试

<!DOCTYPE html>
<html lang="en">
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><title>首页</title><link rel="stylesheet" type="text/css" href="/thirdparty/jquery-easyui-1.5.5.4/themes/default/easyui.css"><link rel="stylesheet" type="text/css" href="/thirdparty/jquery-easyui-1.5.5.4/themes/icon.css"><link rel="stylesheet" type="text/css" href="/thirdparty/jquery-easyui-1.5.5.4/themes/color.css"><script type="text/javascript" src="/thirdparty/jquery-easyui-1.5.5.4/jquery.min.js"></script><script type="text/javascript" src="/thirdparty/jquery-easyui-1.5.5.4/jquery.easyui.min.js"></script><script type="text/javascript" src="/thirdparty/jquery-easyui-1.5.5.4/locale/easyui-lang-zh_CN.js"></script><script type="text/javascript" src="/thirdparty/jquery-easyui-1.5.5.4/easyui-msg.js"></script><script type="text/javascript" src="thirdparty/jquery-easyui-1.5.5.4/md5.js" type="text/javascript"></script>
</head>
<body>
<form id="download_word" method="post" action="/word/exportDesignWord"><input  name="name" id="download_word_name"><button onclick="exportMaterial">下载</button>
</form>
<script>function exportMaterial() {$("#download_word").submit();}
</script>
</body>
</html>

项目中导出了两张不同类型表格,导出第二张及以上表格时,需要类似于第一张表格的操作,在第一张下面,继续创建表格,然后遍历填充即可,deomo中仅提供了导出一张表格的方法,后续将对代码进行整理后,更新导出多套表格的代码;

以上部分不为项目中正式使用的代码,仅为demo测试,但基本用法已全部展示,根据自己项目的实际需要,可进行相应的调节。

如果觉得笔者写的不错,欢迎点赞,转载,转载时请注明出处,谢谢。

poi导出word时内嵌表格场景,即开即用相关推荐

  1. poi导出word时替换的段落内容会多出一个}和逗号_办公族必备11个Word文字处理技巧,太实用了!...

    Hello,各位叨友们好呀!我是叨叨君~ 在使用Word的过程中,大家经常会被一些小问题折磨到不行,这里叨叨君为大家整理了11个常见问题,专治Word疑难杂症! 01 打字时后面的字消失了 先来个简单 ...

  2. Java POI导出word文件及生成表格

    HWPF是处理 Microsoft Word 97(-2007) .doc文件格式,它还为较旧的Word 6和Word 95文件格式提供了有限的只读支持.包含在poi-scratchpad-XXX.j ...

  3. POI导出word中cell单元格内换行问题

    利用POI导出word时,换行符"\r\n"无法被正常识别,利用以下方式进行了word中cell单元格内的换行问题. 首先在需要换行字符串的对应位置处插入相应标记符,然后在设置wo ...

  4. EasyPoi模板导出word(简单文本、内嵌表格、循环图片)

    EasyPoi模板导出word(简单文本.内嵌表格.循环图片) 先上效果图 模板在此 依赖导入 *坑:注意依赖版本 4.3.0+才支持多图片循环导出 <!-- word导出 方式:easypoi ...

  5. POI导出word表格 office打开没问题 wps打开列有问题

    POI导出word表格 office打开没问题 wps打开列有问题 模板样式 导出文档office打开 wps打开文件 1.给表格设置宽,指定宽度 2.将布局固定 3.动态设置单元格的宽度 4.重点设 ...

  6. POI 导出 Word 表格

    项目需求,需要将页面上的报表导出Word文档. 一.报表如下: 二.主要实现代码 1.导出Util类 package com.yhksxt.util;import java.io.IOExceptio ...

  7. poi导出word文件(带表格)

    poi导出word文件(带表格) 一.背景介绍 现有业务需求根据前端页面上所选的时间和列,来生成word表格,方便打印. 二.POM <dependency><groupId> ...

  8. POI导出word文件中表格合并方法(行合并,列合并)

    项目中遇到记录一下 POI导出word文件中表格合并方法(行合并,列合并) . // word表格跨列合并单元格//row 指定行.fromCell 开始列数.toCell 结束列数.public v ...

  9. poi导出word:包括**普通的段落以及表格**。常用的**api**已经以注释的方式写了进去。

    poi导出word:包括普通的段落以及表格.常用的api已经以注释的方式写了进去. 代码如下: /* * @(#)WordExport.java * Copyright (c) * All right ...

最新文章

  1. tensorflow中的梯度弥散与梯度爆炸
  2. 来伊份与第四范式宣布战略合作 携手打造智慧零售新范本
  3. MySQL高级 - SQL优化 - limit优化
  4. springboot data.redis.RedisConnectionFactory 集成问题
  5. 自己的php工具,用PHP自己编写的站长工具箱
  6. python里turtle.circle什么意思_Python turtle.circle方法代碼示例
  7. 关于el-form中的rules未生效问题的解决方法
  8. HDU 1568 Fibonacci ★(取科学计数法)
  9. HDU 1242 特殊化带结构体BFS
  10. CTF逆向总结(二)
  11. Ubuntu虚拟机镜像下载及创建
  12. 51/STC12单片机SCON,PCON,TMOD寄存器定义及功能
  13. Serialize Your Deck with Positron [XML Serialization, XSD, C#]
  14. 判断一个整数是否是7的倍数
  15. windows ubuntu 双系统 蓝屏Technical information: ***stop:0x0000007B(0x80786B58,0xC0000034,0x00000000,0x00
  16. 3dsmax2020安装报1603错误的解决方法
  17. 推荐Layui镜像网站
  18. Android反模拟器的总结
  19. Ubuntu调用USB摄像头
  20. HTML+CSS网页制作——99银号

热门文章

  1. aws api gateway 网关的身份和访问管理
  2. linux服务篇-HTTP服务
  3. 鞋子,靴子,拖鞋傻傻分不清楚 pytorch实现分类 入门小案例
  4. 小钢炮 I7-8850H,UHD 630黑苹果10.14.4成功
  5. 五子棋透明棋盘界面设计(C语言)
  6. 带宽、码率、帧率、分辨率的基本概念
  7. vue 跳转到本地的html文件预览pdf
  8. 匿名用户可以通过ftp服务上传,下载
  9. color demura原理_一种针对OLED屏的DeMURA调整算法的制作方法
  10. 罗技 (Logitech) USB 网络摄像头 - 示意图素材