一、 关键词

POI:Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能

POI-TL:基于Apache POI的Word模板引擎,通过插件机制使其具有高度扩展性

word格式:

1. doc:POI组件HWPF组件支持对doc文件的操作

2. docx:POI组件XWPF组件支持对docx文件的操作

3. POI-TL使用的是XWPF组件,所以更好的支持docx文件的操作。

二、 简单用法示例

1. 依赖

org.apache.poi

poi

4.1.0

org.apache.poi

poi-ooxml

4.1.0

com.deepoove

poi-tl

1.5.0

2. word模板

3. 初始化数据

public Map initWordData() throws Exception {

Map renderData = new HashMap<>();

// 文本标题

TextRenderData title = new TextRenderData("这是一个标题");

renderData.put("title", title);

// 文本副标题

TextRenderData subTitle = new TextRenderData("这是一个副标题");

renderData.put("sub_title", subTitle);

// 文本内容

StringBuilder contentValue = new StringBuilder()

.append("内容一")

.append(System.lineSeparator())

.append("内容二")

.append(System.lineSeparator())

.append("内容三")

.append(System.lineSeparator())

.append("内容四")

.append(System.lineSeparator())

.append("......");

TextRenderData content = new TextRenderData("00C1FF" ,contentValue.toString());

renderData.put("content", content);

// 作者信息

Map author = new HashMap<>();

author.put("name", "作者");

author.put("email", new HyperLinkTextRenderData("xxx@xxx.xxx","https://www.baidu.com"));

PictureRenderData avatar = new PictureRenderData(100, 100, ".jpg", BytePictureUtils.getUrlBufferedImage("https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1566878817&di=ecc0bc000703c669f5d660ca9bb70f17&src=http://img11.photophoto.cn/20090505/0035035789118626_s.jpg"));

author.put("avatar", avatar);

renderData.put("author", author);

// 表格1 (使用表格模板)

RowRenderData header = RowRenderData.build("单元格1", "单元格2");

RowRenderData row1 = RowRenderData.build("测试11", "测试12");

RowRenderData row2 = RowRenderData.build("测试21", "测试22");

List table1RenderData = new ArrayList<>();

table1RenderData.add(row1);

table1RenderData.add(row2);

MiniTableRenderData miniTableRenderData = new MiniTableRenderData(header, table1RenderData, MiniTableRenderData.WIDTH_A4_MEDIUM_FULL);

renderData.put("table1", miniTableRenderData);

// 表格2 (需要添加填充表信息策略)

List table2RenderData = new ArrayList<>();

table2RenderData.add(RowRenderData.build("张三","地址xxx"));

table2RenderData.add(RowRenderData.build("李四","地址xxx"));

renderData.put("table2", table2RenderData);

return renderData;

}

4. 定义现有表格填充数据策略

// 自定义表格填充策略

public class DetailTablePolicy extends DynamicTableRenderPolicy {

// 填充的起始行,

// 注意:行号从0开始

private int row = 1;// 默认从第一行开始

public int getRow() {

return row;

}

public void setRow(int row) {

this.row = row;

}

public DetailTablePolicy() {

}

public DetailTablePolicy(int row) {

this.row = row;

}

@Override

public void render(XWPFTable table, Object data) {

if (null == data) return;

// 对应渲染的表格数据

List table2RenderData = (List) data;

// 删除当前起始行

table.removeRow(row);

// 插入每一行

for (int i = 0,len = table2RenderData.size(); i < len; i++) {

XWPFTableRow insertNewTableRow = table.insertNewTableRow(row+i);

RowRenderData rowRenderData = table2RenderData.get(i);

for (int j = 0,len2 = rowRenderData.size(); j < len2; j++) insertNewTableRow.createCell();

// 渲染每一行数据

MiniTableRenderPolicy.Helper.renderRow(table, row + i, rowRenderData);

}

}

}

5. 导出word

public void exportWord() {

OutputStream os = null;

XWPFTemplate template = null;

try {

Map renderData = initWordData();

Configure.ConfigureBuilder builder = Configure.newBuilder();

// 使用自定义表格填充策略

builder.customPolicy("table2", new DetailTablePolicy(1));

Configure configure = builder.build();

// 模板文件

String templatePath = "D:\\Desktop\\SimpleTemplate.docx";

InputStream is = new FileInputStream(new File(templatePath));

// 输出位置

String outPath = "D:\\Desktop\\test.docx";

os = new FileOutputStream(new File(outPath));

// 编译,导入策略插件,并渲染数据

template = XWPFTemplate.compile(is, configure).render(renderData);

// 输出

template.write(os);

os.flush();

} catch (Exception e) {

e.printStackTrace();

} finally {

try {

if (os != null) {

os.close();

}

if (template != null) {

template.close();

}

} catch (IOException e) {

e.printStackTrace();

}

}

}

6. 运行结果

7. 注意:

当word中有表格需要渲染时(无论是{{#table}}或者是自定义的表格),都需要加入poi-ooxml依赖,否则会报错

如图:(模板中存在table1和table2)

注释poi-ooxml

运行时会报错:

三、 自定义策略

1. 导出表格(带图片)

1.1. 依赖

同简单示例

1.2. 模板

1.3. 初始化数据

1.3.1. 注意:

● RowRenderData中存放的数据是String或TextRenderData,因此需要将PictureRenderData转为String类型

● 然后渲染数据时,再将String转为PictureRenderData类型

● PictureRenderData没有无参构造函数,无法使用com.fasterxml.jackson.databind.ObjectMapper进行相互转换。因此需要自定义一个类来实现PictureRenderData与String之间的转换

● 具体实现如下:

○ 将PictureRenderData转换为PicRenderDataConvert对象,然后将PicRenderDataConvert对象转为String类型写入RowRenderData中

PictureRenderData avatar = new PictureRenderData(100, 100, ".jpg", BytePictureUtils.getUrlBufferedImage("https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1566878817&di=ecc0bc000703c669f5d660ca9bb70f17&src=http://img11.photophoto.cn/20090505/0035035789118626_s.jpg"));

PicRenderDataConvert picRenderDataConvert = new PicRenderDataConvert(avatar);

List picRenderData = new ArrayList<>();

RowRenderData picRow = RowRenderData.build("张三", mapper.writeValueAsString(picRenderDataConvert));

○ 在渲染数据时,再获取PictureRenderData对象

PicRenderDataConvert picRenderDataConvert = mapper.readValue(text, PicRenderDataConvert.class);

// 转换图片

PictureRenderData pictureRenderData = picRenderDataConvert.convert();

if (pictureRenderData != null) {

com.deepoove.poi.policy.PictureRenderPolicy.Helper.renderPicture(par.createRun(), pictureRenderData);

}

1.3.2. 自定义PictureRenderData转换类

public class PicRenderDataConvert {

// 字段与PictureRenderData相同

private int width;

private int height;

private String path;

private transient byte[] data;

private String altMeta;

// 无参构造

public PicRenderDataConvert() {

}

public PicRenderDataConvert(PictureRenderData pictureRenderData) {

this.width = pictureRenderData.getWidth();

this.height = pictureRenderData.getHeight();

this.path = pictureRenderData.getPath();

this.altMeta = pictureRenderData.getAltMeta();

this.data = pictureRenderData.getData();

}

// 转换方法,获取PictureRenderData对象

public PictureRenderData convert() {

if (data == null && StringUtils.isEmpty(path)) {

return null;

}

PictureRenderData pictureRenderData = new PictureRenderData(width, height, path, data);

return pictureRenderData;

}

}

1.3.3. 初始化数据

public Map initWordData() throws Exception {

Map renderData = new HashMap<>();

PictureRenderData avatar = new PictureRenderData(100, 100, ".jpg", BytePictureUtils.getUrlBufferedImage("https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1566878817&di=ecc0bc000703c669f5d660ca9bb70f17&src=http://img11.photophoto.cn/20090505/0035035789118626_s.jpg"));

// 渲染表格(包含图片)

List picRenderData = new ArrayList<>();

PicRenderDataConvert picRenderDataConvert = new PicRenderDataConvert(avatar);

RowRenderData picRow = RowRenderData.build("张三", mapper.writeValueAsString(picRenderDataConvert));

picRenderData.addAll(Arrays.asList(picRow, picRow));

renderData.put("pic_table", picRenderData);

return renderData;

}

1.4. 定义图片表格策略

public class DetailPicTablePolicy extends DynamicTableRenderPolicy {

// 填充数据其实行

// 注意:行号从0开始

private int row = 1;

ObjectMapper mapper = new ObjectMapper();

public DetailPicTablePolicy() {

}

public DetailPicTablePolicy(int row) {

this.row = row;

}

public int getRow() {

return row;

}

public void setRow(int row) {

this.row = row;

}

@Override

public void render(XWPFTable xwpfTable, Object data) {

if (null == data) return;

List renderData = (List) data;

if (null != renderData) {

xwpfTable.removeRow(row);

// 循环插入行

for (int i = 0, len = renderData.size(); i < len; i++) {

XWPFTableRow insertNewTableRow = xwpfTable.insertNewTableRow(row + i);

RowRenderData rowRenderData = renderData.get(i);

// 插入每一个单元格

for (int j = 0, len2 = rowRenderData.getCellDatas().size(); j < len2; j++)

insertNewTableRow.createCell();

// 自定义渲染表格(包括图片)

renderCellPic(xwpfTable, row + i, rowRenderData);

}

}

}

private void renderCellPic(XWPFTable table, int row, RowRenderData rowData) {

if (null != rowData && rowData.size() > 0) {

XWPFTableRow tableRow = table.getRow(row);

ObjectUtils.requireNonNull(tableRow, "Row " + row + " do not exist in the table");

TableStyle rowStyle = rowData.getRowStyle();

List cellList = rowData.getCellDatas();

XWPFTableCell cell = null;

for (int i = 0; i < cellList.size(); ++i) {

cell = tableRow.getCell(i);

if (null == cell) {

RenderPolicy.logger.warn("Extra cell data at row {}, but no extra cell: col {}", row, cell);

break;

}

renderCell(cell, (CellRenderData) cellList.get(i), rowStyle);

}

}

}

public void renderCell(XWPFTableCell cell, CellRenderData cellData, TableStyle rowStyle) {

TableStyle cellStyle = null == cellData.getCellStyle() ? rowStyle : cellData.getCellStyle();

if (null != cellStyle && null != cellStyle.getBackgroundColor()) {

cell.setColor(cellStyle.getBackgroundColor());

}

TextRenderData renderData = cellData.getRenderData();

String cellText = renderData.getText();

if (!StringUtils.isBlank(cellText)) {

CTTc ctTc = cell.getCTTc();

CTP ctP = ctTc.sizeOfPArray() == 0 ? ctTc.addNewP() : ctTc.getPArray(0);

XWPFParagraph par = new XWPFParagraph(ctP, cell);

StyleUtils.styleTableParagraph(par, cellStyle);

String text = renderData.getText();

String[] fragment = text.split("\\n", -1);

if (fragment.length <= 1) {

try {

PicRenderDataConvert picRenderDataConvert = mapper.readValue(text, PicRenderDataConvert.class);

// 渲染图片

PictureRenderData pictureRenderData = picRenderDataConvert.convert();

if (pictureRenderData != null) {

com.deepoove.poi.policy.PictureRenderPolicy.Helper.renderPicture(par.createRun(), pictureRenderData);

}

} catch (Exception e) {

// 渲染文本

com.deepoove.poi.policy.TextRenderPolicy.Helper.renderTextRun(par.createRun(), renderData);

}

} else {

for (int j = 0; j < fragment.length; ++j) {

if (0 != j) {

par = cell.addParagraph();

StyleUtils.styleTableParagraph(par, cellStyle);

}

XWPFRun run = par.createRun();

StyleUtils.styleRun(run, renderData.getStyle());

run.setText(fragment[j]);

}

}

}

}

}

1.5. 浏览器导出word

public void exportWord(HttpServletRequest request,

HttpServletResponse response) throws Exception {

Map renderData = initWordData();

Configure.ConfigureBuilder builder = Configure.newBuilder();

// 表格(含图片)渲染策略

builder.customPolicy("pic_table", new DetailPicTablePolicy(1));

Configure configure = builder.build();

String fileName = "测试文档";

String templatePath = "D:\\Desktop\\PicTableTemplate.docx";

renderWord(request, response, fileName, templatePath, renderData, configure);

}

public void renderWord(HttpServletRequest request,

HttpServletResponse response,

String fileName,

String templatePath,

Map renderData,

Configure configure) {

String codedFileName = "临时文档.docx";

ServletOutputStream out = null;

XWPFTemplate template = null;

try {

if (!StringUtils.isEmpty(fileName)) {

codedFileName = fileName + ".docx";

}

if (request.getHeader("USER-AGENT").toLowerCase().indexOf("msie") > 0 || request.getHeader("USER-AGENT").toLowerCase().indexOf("rv:11.0") > 0 || request.getHeader("USER-AGENT").toLowerCase().indexOf("edge") > 0) {

codedFileName = URLEncoder.encode(codedFileName, "UTF8");

} else {

codedFileName = new String(codedFileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);

}

response.setHeader("content-disposition", "attachment;filename=" + codedFileName);

InputStream is = new FileInputStream(new File(templatePath));

if (configure == null) {

template = XWPFTemplate.compile(is).render(renderData);

} else {

template = XWPFTemplate.compile(is, configure).render(renderData);

}

out = response.getOutputStream();

template.write(out);

out.flush();

} catch (Exception e) {

e.printStackTrace();

} finally {

try {

if (out != null) {

out.close();

}

if (template != null) {

template.close();

}

} catch (IOException e) {

e.printStackTrace();

}

}

}

1.6. 运行结果

四、 总结

1. 依赖完整

必须存在

依赖,否则无法进行word中的表格渲染

2. 插件机制实现可扩展的word导出

3. POI-TL支持

文件操作

4. 参考文档

java word导出表格_Java实现word导出(表格带图片)相关推荐

  1. java调用word模板文件_Java使用模板导出word文档

    Java使用模板导出word文档 需要导入freemark的jar包 使用word模板,在需要填值的地方使用字符串代替,是因为word转换为xml文件时查找不到要填入内容的位置.尽量不要在写字符串的时 ...

  2. java word表格_java操作word的表格

    java操作word的表格 最近项目中需要把提交的页面表单的数据动态写在word模板中,简单的写了个工具类.里面有怎眼操作word 中表格的内容,可以在word中已有的表格后面添加行并且可以增加内容. ...

  3. java怎么导出有模板的表格_java用模板导出数据表格-Go语言中文社区

    1.创建表格: 2.编写导出的controller; @PostMapping("/cust/report/customer/export") public void export ...

  4. java循环导出word文档_Java使用freemarker导出word文档

    通过freemarker,以及JAVA,导出word文档. 共分为三步: 第一步:创建模板文件 第二步:通过JAVA创建返回值. 第三步:执行 分别介绍如下: 第一步: 首先创建word文档,按照想要 ...

  5. java word文本框_Java 读取Word文本框中的文本、图片、表格

    Word可插入文本框,文本框中可嵌入文本.图片.表格等内容.对文档中的已有文本框,也可以读取其中的内容.本文以Java程序代码来展示如何读取文本框,包括读取文本框中的文本.图片以及表格等. [程序环境 ...

  6. java word创建表格_Java 在Word中创建表格

    import com.spire.doc.*;import com.spire.doc.documents.*;importcom.spire.doc.fields.TextRange;import ...

  7. java io导出excel表格_Java IO 导入导出Excel表格

    1.将excel导入到内存 1. 调用工作簿Workbook的静态方法getWorkbook(),获得工作簿Workbook对象 InputStream in = new FileInputStrea ...

  8. java word转成表格_java将Word/Excel/PDF文件转换成HTML整理

    项目开发过程中,需求涉及到了各种文档转换为HTML或者网页易显示格式,现在将实现方式整理如下: 一.使用Jacob转换Word,Excel为HTML "JACOB一个Java-COM中间件. ...

  9. java导出复杂excel表格_java使用freemarker导出复杂的excel表格

    正常导出excel表格使用的poi,但是导出复杂的excel有点困难,但是可以使用freemaker模板来导出复杂的excel. 都是先生成一个Excel表格的模板,最好是增加一行数据.具体看图里面的 ...

  10. java word表格_Java 添加Word表格行或列

    import com.spire.doc.*; import com.spire.doc.documents.BorderStyle; import java.awt.*; public class ...

最新文章

  1. 2012年度IT博客大赛50强报道:高俊峰
  2. mybatis mysql rownum_MyBatis怎样实现MySQL动态分页?
  3. ubuntu-11.10-server-i386学习笔记-SVN版本服务器安装
  4. Java中的引用类型(强引用、弱引用)和垃圾回收
  5. 程序员如何坚持写作? 1
  6. 【纸牌识别】基于matlab形态学扑克牌识别【含Matlab源码 1352期】
  7. angular.injector()
  8. 读书笔记:普林斯顿微积分读本
  9. The Elements of Style 4ed ---英文写作指南(一)
  10. emmagee测试汇总
  11. python 去除文本空行
  12. 整合阿里云域名 + 腾讯云 CDN + 又拍云存储的使用流程
  13. FastDFS作者余庆谈真正的开源精神
  14. jmeter压力测试并发
  15. RTSP实时音视频传输介绍
  16. 计算机的发展史英语作文,选择一种计算机英语作文:求一篇关于计算机发展史的英语作文...
  17. 尝试用bert做文本聚类
  18. CPLD/FPGA四位七段数码管动态扫描
  19. asp php微信支付,Asp微信支付接口代码 微信中生成订单后可以直接调出微信钱包直接付款_随便下源码网...
  20. Qt 解决程序全屏运行弹窗引发任务栏显示

热门文章

  1. java创建一个自己的类库_建立并使用自己的类库
  2. mPaaS 月度小报|魔方卡片(Cube)公测,十个卡片模板任意使用
  3. 5G无线关键技术 — 大规模天线技术
  4. ILSVRC竞赛详细介绍(ImageNet Large Scale Visual Recognition Challenge)
  5. 最好用的七大顶级 API 接口测试工具
  6. 计算机PS个人规划目标,这里有一份PS个人陈述写作规划
  7. python写接口程序_利用Python开发PCAN程序接口
  8. MD5介绍以及如何破解MD5算法
  9. JAVA代码实现MD5加密算法
  10. 求助:安装windows server 2003的时候报错:用 Windows NT 4.0 创建基本卷