导出Word几种方式:
- 使用第三方Java工具类库Hutool的Word工具类,参考网址为https://www.hutool.cn/docs/#/poi/Word生成-Word07Writer;
- 利用Apache POI和FreeMarker模板引擎;
- 第三方报表工具。
上面的几种方式虽然可以实现Word文档的导出,但有以下缺点:
- 第一种方式操作简单,但也只能生成简单的Word文档,无法生成有表格的Word文档;
- 第二种方式可以生成复杂的Word文档,但是还要进行Word转xml,xml转ftl的双重转换,不适合内容经常变更的Word文档;
- 第三种方式有时候不适合对格式要求严格的文档。
推荐使用的方法:
一种用Java语言实现的,通过XDocReport和FreeMarker模板引擎生成Word文档
准备环境
Java7及以上的版本。
开发工具
Eclipse/Idea。
模板语言
FreeMarker
Word编辑器
Microsoft 365或其他版本较高的Word编辑器
示例Word模板
制作模板
Word模板如上图,可以看到,结构比较简单,包括两个部分,第一部分是纯文字和数字,第二部分主要是表格。我们在实际的开发过程中生成的报表几乎都是动态生成的,所以模板中的数字和表格里的数据都要替换成我们后台的实际数据。
替换Word模板中的动态变量,我们需要掌握两个知识点:
Word文档中的Word域,word域是引导Word在文档中自动插入文字、图形、页码或其他信息的一组代码。在这里我们可以把 Word域理解成标识符,这个标识符表示Word文档中要被替换的内容;
FreeMarker模板下的变量表达式,比如用${city}替换Word示例模板中的北京市。
编辑Word模板
-
首先在Word模板中选中要替换的文本,在这儿拿标题中的"北京市"为例,然后键盘使用 Ctrl + F9 组合键将其设置为域,此时文本会被"{}"包围,接着鼠标右键选择【编辑域(E)...】:
[图片上传中...(image.png-7bacb8-1628991672444-0)]
在弹出的对话框中,类别选择“邮件合并”,域名选择 "MergeField",域属性中的域名填入模版表达式${city},点击【确定】按钮:-
编辑后的效果如下:
-
掌握替换文本的方法后,我们可以把Word模板第一部分需要替换的内容都替换成模板变量:
Word模板中表格数据的处理
表格数据的处理其实和上面对文本内容的处理是类似的,只不过要在Word模板中加上集合的变量,Java代码中也要有对集合进行特对的处理(这个在后面的代码展示部分会说)。
具体操作步骤如下:
-
选定表格中要替换的文本,然后键盘使用 Ctrl + F9 组合键将其设置为域,接着鼠标右键选择【编辑域(E)...】
在弹出的对话框中,类别选择“邮件合并”,域名选择 "MergeField",域属性中的域名填入模版表达式${goods.num},点击【确定】按钮;
-
重复步骤2,替换表格中的其他文本内容:
后台代码
添加依赖到pom.xml文件
org.apache.poi
poi
4.1.1
org.apache.poi
poi-ooxml
4.1.1
org.jxls
jxls
2.6.0
ch.qos.logback
logback-core
org.jxls
jxls-poi
1.2.0
fr.opensagres.xdocreport
fr.opensagres.xdocreport.core
2.0.2
fr.opensagres.xdocreport
fr.opensagres.xdocreport.document
2.0.2
fr.opensagres.xdocreport
fr.opensagres.xdocreport.template
2.0.2
fr.opensagres.xdocreport
fr.opensagres.xdocreport.document.docx
2.0.2
fr.opensagres.xdocreport
fr.opensagres.xdocreport.template.freemarker
2.0.2
org.freemarker
freemarker
2.3.23
commons-io
commons-io
2.5
编写Java代码
package com.tzsj.test;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import fr.opensagres.xdocreport.core.XDocReportException;
import fr.opensagres.xdocreport.document.IXDocReport;
import fr.opensagres.xdocreport.document.registry.XDocReportRegistry;
import fr.opensagres.xdocreport.template.IContext;
import fr.opensagres.xdocreport.template.TemplateEngineKind;
import fr.opensagres.xdocreport.template.formatter.FieldsMetadata;
import io.renren.entity.Goods;
@Controller
@RequestMapping("/word")
public class WordTest {
@Test
public void test() throws IOException, XDocReportException {
generateWord();
}
public void generateWord() throws IOException, XDocReportException {
//获取Word模板,模板存放路径在项目的resources目录下
InputStream ins = this.getClass().getResourceAsStream("/模板.docx");
//注册xdocreport实例并加载FreeMarker模板引擎
IXDocReport report = XDocReportRegistry.getRegistry().loadReport(ins,
TemplateEngineKind.Freemarker);
//创建xdocreport上下文对象
IContext context = report.createContext();
//创建要替换的文本变量
context.put("city", "北京市");
context.put("startDate", "2020-09-17");
context.put("endDate", "2020-10-16");
context.put("totCnt", 3638763);
context.put("totAmt", "6521");
context.put("onCnt", 2874036);
context.put("onAmt", "4768");
context.put("offCnt", 764727);
context.put("offAmt", "1753");
context.put("typeCnt", 36);
List goodsList = new ArrayList();
Goods goods1 = new Goods();
goods1.setNum(1);
goods1.setType("臭美毁肤");
goods1.setSv(675512);
goods1.setSa("589");
Goods goods2 = new Goods();
goods2.setNum(2);
goods2.setType("女装");
goods2.setSv(602145);
goods2.setSa("651");
Goods goods3 = new Goods();
goods3.setNum(3);
goods3.setType("手机");
goods3.setSv(587737);
goods3.setSa("866");
Goods goods4 = new Goods();
goods4.setNum(4);
goods4.setType("家具家装");
goods4.setSv(551193);
goods4.setSa("783");
Goods goods5 = new Goods();
goods5.setNum(5);
goods5.setType("食物饮品");
goods5.setSv(528604);
goods5.setSa("405");
goodsList.add(goods1);
goodsList.add(goods2);
goodsList.add(goods3);
goodsList.add(goods4);
goodsList.add(goods5);
context.put("goods", goodsList);
//创建字段元数据
FieldsMetadata fm = report.createFieldsMetadata();
//Word模板中的表格数据对应的集合类型
fm.load("goods", Goods.class, true);
//输出到本地目录
FileOutputStream out = new FileOutputStream(new File("D://商品销售报表.docx"));
report.process(context, out);
}
}
Word模板中生成序号
给表格数据添加序号是通过后台代码生成的,比如上面的"goods1.setNum(1)"这段代码,其实也可以在Word模板中设置对应的域变量来实现序号的填充。
语法如下:
@before-row[#list sequence as item]
item?index
@after-row[/#list]
在表格中添加上面的表达式,XDocReport就会自动解析并生成序号,表格中的其他字段也需要进行相应的改动:
提示:
- 序号的表达式要拆成三个域,如下图,要把这三部分分别设置成域;
设置完成的结果参考上面表格中的序号表达式,表达式中"item?index+1"是因为序号是从0开始的,所以要加1
- 表格中除序号的列需要改成item.xxx而不是之前的goods.xxx:
- 生成效果如下:
建议:序号最好在后台生成,用序号表达式生成的序号列会占用比较大的空间,对资源有所浪费。
补充
- JavaWeb项目中通常是通过浏览器下载的方式来下载Word文档,此时只需要把之前下载到本地的代码改成浏览器端下载的代码即可:
//输出到本地目录
//FileOutputStream out = new FileOutputStream(new File("D://商品销售报表.docx"));
//report.process(context, out);
//浏览器端下载
response.setCharacterEncoding("utf-8");
response.setContentType("application/msword");
String fileName = "商品销售报表.docx";
response.setHeader("Content-Disposition", "attachment;filename="
.concat(String.valueOf(URLEncoder.encode(fileName, "UTF-8"))));
report.process(context, response.getOutputStream());
- Word模板中的表格的长度最好充满Word文档的左右两边,否则如果表格下面还有其他文本内容,下面的文本内容会自动填充到表格的缝隙处,而且会对下面的文本内容进行覆盖。
Word模板中制作图片
图片的生成不使用编辑域,使用模板图片和Word的书签功能,而且需要在元数据中加入图片类型的代码
具体步骤:
-
在Word模版中需要插入图片的位置插入一张模版图片(说白了就一张背景图片),然后鼠标单击模板图片插入一个书签,设置书签名称,比如img1, 最后点击【添加】按钮:
如果需要插入多个图片,就在需要插入图片的位置插入多个模板图片并插入书签设置对应的书签名称即可,后台代码如下:
package com.tzsj.test;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import org.junit.Test;
import fr.opensagres.xdocreport.core.XDocReportException;
import fr.opensagres.xdocreport.document.IXDocReport;
import fr.opensagres.xdocreport.document.registry.XDocReportRegistry;
import fr.opensagres.xdocreport.template.IContext;
import fr.opensagres.xdocreport.template.TemplateEngineKind;
import fr.opensagres.xdocreport.template.formatter.FieldsMetadata;
public class ImgTest {
@Test
public void test() throws IOException, XDocReportException {
generateWordForImg();
}
public void generateWordForImg() throws IOException, XDocReportException {
//获取Word模板,模板存放路径在项目的resources目录下
InputStream ins = this.getClass().getResourceAsStream("/图片.docx");
//注册xdocreport实例并加载FreeMarker模板引擎
IXDocReport report = XDocReportRegistry.getRegistry().loadReport(ins,
TemplateEngineKind.Freemarker);
//创建xdocreport上下文对象
IContext context = report.createContext();
FieldsMetadata fm = report.createFieldsMetadata();
//元数据中加入图片
fm.addFieldAsImage("img1");
fm.addFieldAsImage("img2");
//获取图片
InputStream img1 = this.getClass().getResourceAsStream("/11.jpg");
InputStream img2 = this.getClass().getResourceAsStream("/33.jpg");
//把图片添加到上下文对象
context.put("img1", img1);
context.put("img2", img2);
//输出到本地目录
FileOutputStream out = new FileOutputStream(new File("D://图片报表.docx"));
report.process(context, out);
}
}
-
导出效果如下:
Word模板中制作图形
要在Word文档中生成柱状图、饼状图等图形,需要在项目中引入第三方绘图工具-------xchar
生成饼图
生成饼状图和生成图片的方法很类似,具体步骤如下:
-
在Word模版中需要插入图片的位置插入一张模版图片,然后鼠标单击模板图片插入一个书签,设置书签名称,比如chart,最后点击【添加】按钮:
编写pom文件:
org.knowm.xchart
xchart
3.5.4
2.2 后台代码:
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import org.junit.Test;
import org.knowm.xchart.BitmapEncoder;
import org.knowm.xchart.PieChart;
import org.knowm.xchart.PieChartBuilder;
import fr.opensagres.xdocreport.core.XDocReportException;
import fr.opensagres.xdocreport.document.IXDocReport;
import fr.opensagres.xdocreport.document.images.ByteArrayImageProvider;
import fr.opensagres.xdocreport.document.registry.XDocReportRegistry;
import fr.opensagres.xdocreport.template.IContext;
import fr.opensagres.xdocreport.template.TemplateEngineKind;
import fr.opensagres.xdocreport.template.formatter.FieldsMetadata;
public class ChartTest {
@Test
public void test() throws IOException, XDocReportException {
generateWordForChart();
}
public void generateWordForChart() throws IOException, XDocReportException {
//获取Word模板,模板存放路径在项目的resources目录下
InputStream ins = this.getClass().getResourceAsStream("/饼图.docx");
//注册xdocreport实例并加载FreeMarker模板引擎
IXDocReport report = XDocReportRegistry.getRegistry().loadReport(ins,
TemplateEngineKind.Freemarker);
//创建xdocreport上下文对象
IContext context = report.createContext();
FieldsMetadata fm = report.createFieldsMetadata();
//元数据中加入图片
fm.addFieldAsImage("chart");
PieChart chart = new PieChartBuilder().width(800).height(620)
.title("销售饼图").build();
//给饼图设置对应的值
chart.addSeries("臭美毁肤", 589);
chart.addSeries("女装", 651);
chart.addSeries("手机", 866);
chart.addSeries("家居家装", 783);
chart.addSeries("食物饮品", 405);
//生成饼图
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BitmapEncoder.saveBitmap(chart, baos, BitmapEncoder.BitmapFormat.JPG);
//把饼图添加到上下文对象
context.put("chart", new ByteArrayImageProvider(baos.toByteArray()));
//输出到本地目录
FileOutputStream out = new FileOutputStream(new File("D://饼图报表.docx"));
report.process(context, out);
}
}
-
导出效果如下:
生成柱状图
-
在Word模版中需要插入图片的位置插入一张模版图片,然后鼠标单击模板图片插入一个书签,设置书签名称categoryChart
后台代码:
@Test
void exportWordForCategoryChar() throws IOException, XDocReportException {
//获取Word模板,模板存放路径在项目的resources目录下
InputStream ins = this.getClass().getResourceAsStream("/柱状图.docx");
//注册xdocreport实例并加载FreeMarker模板引擎
IXDocReport report = XDocReportRegistry.getRegistry().loadReport(ins,
TemplateEngineKind.Freemarker);
//创建xdocreport上下文对象
IContext context = report.createContext();
FieldsMetadata fm = report.createFieldsMetadata();
//元数据中加入图片
fm.addFieldAsImage("categoryChart");
CategoryChart categoryChart = new CategoryChartBuilder().width(1000).height(500)
.title("销售柱状图").build();
List xData = new LinkedList<>();
List yData = new LinkedList<>();
for(int i=0;i<=5 ;i++){
xData.add(i+"月");
yData.add(1+i);
}
//这里要判断xData,yData是否为空,否则为空会报错
if(xData.isEmpty() || yData.isEmpty()){
yData.add(0);
xData.add("未知");
}
categoryChart.addSeries("上报总数",xData,yData);
//生成柱形图
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BitmapEncoder.saveBitmap(categoryChart, baos, BitmapEncoder.BitmapFormat.PNG);
//把柱状图添加到上下文对象
context.put("categoryChart",new ByteArrayImageProvider(baos.toByteArray()));
//输出到本地目录
FileOutputStream out = new FileOutputStream(new File("D://柱状图报表.docx"));
report.process(context, out);
}
-
生成效果如下
生成折线图
- 在Word模版中需要插入图片的位置插入一张模版图片,然后鼠标单击模板图片插入一个书签,设置书签名称xyChart
- 后台代码:
//获取Word模板,模板存放路径在项目的resources目录下
InputStream ins = this.getClass().getResourceAsStream("/word.docx");
//注册xdocreport实例并加载FreeMarker模板引擎
IXDocReport report = XDocReportRegistry.getRegistry().loadReport(ins,
TemplateEngineKind.Freemarker);
//创建xdocreport上下文对象
IContext context = report.createContext();
FieldsMetadata fm = report.createFieldsMetadata();
//元数据中加入图片
fm.addFieldAsImage("xyChart");
XYChart xyChart = new XYChartBuilder().width(1000).height(620).title("销售折线图").build();
List xData = new LinkedList<>();
List yyData = new LinkedList<>();
List yData = new LinkedList<>();
for(int i=0;i<3;i++){
xData.add(i+1);
}
yData.add(3);
yData.add(5);
yData.add(7);
yyData.add(4);
yyData.add(6);
yyData.add(1);
xyChart.addSeries("毛衣销售",xData,yData);
xyChart.addSeries("鞋子销售",xData,yyData);
//生成柱形图
ByteArrayOutputStream baos = new ByteArrayOutputStream();
BitmapEncoder.saveBitmap(xyChart, baos, BitmapEncoder.BitmapFormat.PNG);
//把柱状图添加到上下文对象
context.put("xyChart",new ByteArrayImageProvider(baos.toByteArray()));
//输出到本地目录
FileOutputStream out = new FileOutputStream(new File("D://折线图报表.docx"));
report.process(context, out);
-
生成效果如下
制作行列动态表格
因为小编使用 XdocReport 找不着什么方法可以动态生成行列的表格,但是可以通过画图工具,画出动态的行列表格,步骤如下:
- 按照生成图片的方式在word中插入书签:tableImg
2.创建工具类:
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.xwpf.usermodel.XWPFTableCell.XWPFVertAlign;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.math.BigInteger;
import java.util.InputMismatchException;
import java.util.List;
/**
* Created with IntelliJ IDEA.
* Description:
* User: ly
* Date: 2020-04-09
* Time: 11:07
* 导出word工具
*/
public class ExportWordUtil {
/**
* 动态导出word数据方法
* @param savePath 保存路径
* @param tab 标签头
* @param cname 中文字段名
* @param infos 内容数据
* @throws Exception
*/
public static void createSimpleTable(String savePath,String tab,List cname,List> infos) throws Exception {
XWPFDocument xdoc = new XWPFDocument();
XWPFParagraph xp = xdoc.createParagraph();
XWPFRun r1 = xp.createRun();
r1.setText(tab);
r1.addBreak(); // 换行
r1.setFontFamily("宋体");
r1.setFontSize(16);
r1.setTextPosition(10);
r1.setBold(true);
//左对齐
xp.setAlignment(ParagraphAlignment.LEFT);
// 表格最多的列数 根据得到的中文字段数量得到最多列
Integer col_total_count = cname.size();
// 需要创建的总条数 根据得到的内容得到最多行
Integer data_count = infos.size()+1;
XWPFTable xTable = xdoc.createTable(1, col_total_count);
CTTbl ttbl = xTable.getCTTbl();
CTTblPr tblPr = ttbl.getTblPr() == null ? ttbl.addNewTblPr() : ttbl
.getTblPr();
CTTblWidth tblWidth = tblPr.isSetTblW() ? tblPr.getTblW() : tblPr
.addNewTblW();
tblWidth.setW(new BigInteger("8600"));
tblWidth.setType(STTblWidth.DXA);
// 创建表头数据
int i = 0;
xTable.getRow(i).setHeight(500);
//循环表头信息
for (int i1 = 0; i1 < cname.size(); i1++) {
setCellText(xdoc, xTable.getRow(i).getCell(i1), cname.get(i1), "FFFFFF", getCellWidth(0));
}
// 创建表格内容
i++;
for (int i2 = i; i2 < data_count; i2++) {
XWPFTableRow row = xTable.insertNewTableRow(i2);
row.setHeight(450);
for (int j = 0, j2 = 0; j < col_total_count; j++, j2++) {
XWPFTableCell cell = row.createCell();
CTTc cttc = cell.getCTTc();
CTTcPr cellPr = cttc.addNewTcPr();
cellPr.addNewVAlign().setVal(STVerticalJc.CENTER);
cttc.getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);
cellPr.addNewTcW().setW(BigInteger.valueOf(getCellWidth(j2)));
cell.setText(infos.get(i2-1).get(j));
}
}
FileOutputStream fos = new FileOutputStream(savePath);
xdoc.write(fos);
fos.close();
}
/**
* 设置表头内容
*
* @param xDocument
* @param cell
* @param text
* @param bgcolor
* @param width
*/
private static void setCellText(XWPFDocument xDocument, XWPFTableCell cell,
String text, String bgcolor, int width) {
CTTc cttc = cell.getCTTc();
CTTcPr cellPr = cttc.addNewTcPr();
cellPr.addNewTcW().setW(BigInteger.valueOf(width));
cell.setColor(bgcolor);
cell.setVerticalAlignment(XWPFVertAlign.CENTER);
CTTcPr ctPr = cttc.addNewTcPr();
ctPr.addNewVAlign().setVal(STVerticalJc.CENTER);
cttc.getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);
cell.setText(text);
}
/**
* 设置列宽
*
* @param index
* @return
*/
private static int getCellWidth(int index) {
int cwidth = 1000;
if (index == 0) {
cwidth = 2100;
} else if (index == 1) {
cwidth = 2100;
} else if (index == 2) {
cwidth = 2100;
} else if (index == 3) {
cwidth = 2100;
}
return cwidth;
}
/**
* 生成图片
* @param cellsValue 以二维数组形式存放 表格里面的值
* @param path 文件保存路径
*/
public InputStream myGraphicsGeneration(String cellsValue[][], String path) {
// 字体大小
int fontTitileSize = 15;
// 横线的行数
int totalrow = cellsValue.length+1;
// 竖线的行数
int totalcol = 0;
if (cellsValue[0] != null) {
totalcol = cellsValue[0].length;
}
// 图片宽度
int imageWidth = 1024;
// 行高
int rowheight = 40;
// 图片高度
int imageHeight = totalrow*rowheight+50;
// 起始高度
int startHeight = 10;
// 起始宽度
int startWidth = 10;
// 单元格宽度
int colwidth = (int)((imageWidth-20)/totalcol);
BufferedImage image = new BufferedImage(imageWidth, imageHeight,BufferedImage.TYPE_INT_RGB);
Graphics graphics = image.getGraphics();
graphics.setColor(Color.WHITE);
graphics.fillRect(0,0, imageWidth, imageHeight);
graphics.setColor(new Color(220,240,240));
//画横线
for(int j=0;j 0 && l >0) {
font = new Font("微软雅黑",Font.PLAIN,fontTitileSize);
graphics.setFont(font);
graphics.setColor(Color.RED);
} else {
font = new Font("微软雅黑",Font.PLAIN,fontTitileSize);
graphics.setFont(font);
graphics.setColor(Color.BLACK);
}
graphics.drawString(cellsValue[n][l].toString(), startWidth+colwidth*l+5, startHeight+rowheight*(n+2)-10);
}
}
// 保存图片
// createImage(image, path);
ByteArrayOutputStream os = new ByteArrayOutputStream();
InputStream input = null;
try {
ImageIO.write(image, "png", os);
input = new ByteArrayInputStream(os.toByteArray());
} catch (IOException e) {
e.printStackTrace();
}
return input;
}
/**
* 将图片保存到指定位置
* @param image 缓冲文件类
* @param fileLocation 文件位置
*/
public void createImage(BufferedImage image, String fileLocation) {
try {
FileOutputStream fos = new FileOutputStream(fileLocation);
BufferedOutputStream bos = new BufferedOutputStream(fos);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(bos);
encoder.encode(image);
bos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 书写代码
@Test
void exportTest() throws Exception {
ExportWordUtil cg = new ExportWordUtil();
try {
//获取Word模板,模板存放路径在项目的resources目录下
InputStream ins = this.getClass().getResourceAsStream("/word.docx");
//注册xdocreport实例并加载FreeMarker模板引擎
IXDocReport report = XDocReportRegistry.getRegistry().loadReport(ins,
TemplateEngineKind.Freemarker);
//创建xdocreport上下文对象
IContext context = report.createContext();
FieldsMetadata fm = report.createFieldsMetadata();
//元数据中加入图片
fm.addFieldAsImage("tableImg");
String tableData1[][] = {{"8月31日","累计用户数","目标值","完成进度","时间进度", "进度差异"}, {"掌厅客户端(户)","469281","1500000","31.2%","33.6%", "-2.4%"}};
String[][] tableData2 = {{"8月31日(户)","新增用户数","日访问量","累计用户数","环比上月"},
{"合肥和巢湖","469281","1500000","31.2%","33.6%"},
{"芜湖","469281","1500000","31.2%","33.6%"},
{"蚌埠","469281","1500000","31.2%","33.6%"},
{"淮南","469281","1500000","31.2%","33.6%"},
{"马鞍山","469281","1500000","31.2%","33.6%"},
{"淮北","469281","1500000","31.2%","33.6%"}};
InputStream input = cg.myGraphicsGeneration(tableData2, "c:\\myPic.jpg");
//把图片添加到上下文对象
context.put("tableImg", input);
//输出到本地目录
FileOutputStream out = new FileOutputStream(new File("D://表格图片报表.docx"));
report.process(context, out);
} catch (Exception e) {
e.printStackTrace();
}
}
-
生成效果如下: