一、场景
根据模板样式进行word导出。
二、模板制作
通过xdocreport、FreeMarker来实现该场景。
首先,当然是要有一个word模板,接下来简单讲解如何制作word模板。
2.1、文本替换
1.选中要替换的文本。
2.键盘使用 Ctrl + F9 组合键将其设置为域,此时文本会被{}包围。
3.鼠标右键选择“编辑域”。
4.域名选择“邮件合并”,域代码填写 ${XXX!},${}是标识符,XXX表示变量名,!表示该变量允许为空(不加!则反之)。
2.2、表格循环
1.在第一个单元格设置域 @before-row[#list XXX as item],XXX为数组对象。
2.紧接着在 @before-row域后面继续设置域 @after-row[/#list]。
3.在 @before-row域与 @after-row域之间设置内容域 ${item.index!}。
4.后续单元格不用设置 @before-row域和@after-row域,直接设置内容域 ${item.detail!}就行。
2.3、普通循环
1.设置域 [#list XXX as item],XXX为数组对象。
2.设置域 [/#list]。
3.将内容域 ${item.index!}放到中间即可。
2.4、图片替换
1.正常在word插入图片。
2.选中图片,工具栏选择插入,选择书签,新增书签。
三、代码实现
先引入依赖:
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.1</version>
</dependency>
<dependency>
<groupId>org.jxls</groupId>
<artifactId>jxls</artifactId>
<version>2.6.0</version>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jxls</groupId>
<artifactId>jxls-poi</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.xdocreport.core</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.xdocreport.document</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.xdocreport.template</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.xdocreport.document.docx</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>fr.opensagres.xdocreport.template.freemarker</artifactId>
<version>2.0.2</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.23</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
</dependency>
接下来进行接口代码编写:
3.1、文本替换
public void createReport() throws IOException, XDocReportException {
// 获取Word模板,模板存放路径在项目的resources目录下
Resource resource = new ClassPathResource("templates/模板.docx");
@Cleanup InputStream inputStream = resource.getInputStream();
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
// 设置响应类型
response.setContentType("application/msword");
// 设置字符编码
response.setCharacterEncoding("utf-8");
// 设置响应头信息
response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("报告.docx", "utf-8"));
ServletOutputStream outputStream = response.getOutputStream();
try {
// 注册xdocreport实例并加载FreeMarker模板引擎
IXDocReport report = XDocReportRegistry.getRegistry().loadReport(inputStream, TemplateEngineKind.Freemarker);
// 创建xdocreport上下文对象
IContext context = report.createContext();
// 创建xdocreport元数据
FieldsMetadata fm = report.createFieldsMetadata();
// 创建要替换的文本变量,key要与word模板设置的key对应
context.put("createTime", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
context.put("organization", "码农保护协会");
// 输出
report.setFieldsMetadata(fm);
report.process(context, outputStream);
} catch (IOException e) {
e.printStackTrace();
} finally {
outputStream.flush();
outputStream.close();
}
}
3.2、图片替换
// 获取图片给 new ByteArrayImageProvider()构造函数使用
URL url = new URL("https://e12b7d3.png");
URLConnection conn = url.openConnection();
InputStream inputStream = conn.getInputStream();
// 与word模板中图片的书签名一致
fm.addFieldAsImage("wayline_img");
// 也可将图片转为byte[],再使用 new ByteArrayImageProvider()构造函数
context.put("wayline_img", new ByteArrayImageProvider(inputStream, true)); // true:使用原图宽高,false:使用word模板插入的图片宽高
3.3、循环替换文本及图片
// 加载集合元数据
fm.load("XXX", ReportVO.class, true); // XXX为模板中设置的循环域数组对象名,ReportVO为循环类
// 集合图片字段与模板图片书签映射
fm.addFieldAsImage("detail_img", "item.imageByte", NullImageBehaviour.RemoveImageTemplate); // detail_img为模板循环图片的书签名,imageByte为ReportVO的图片字段
context.put("XXX", value); // XXX为模板中设置的循环域数组对象名,value为List<ReportVO>对象,ReportVO的字段要与模板中循环域内容的key对应