注:有更好解决方法,参考:https://blog.csdn.net/m0_49605579/article/details/122583318
1.导入依赖
maven版:
<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>
gradle版:
compile "fr.opensagres.xdocreport:fr.opensagres.xdocreport.core:2.0.2"
compile "fr.opensagres.xdocreport:fr.opensagres.xdocreport.document:2.0.2"
compile "fr.opensagres.xdocreport:fr.opensagres.xdocreport.document.docx:2.0.2"
compile "fr.opensagres.xdocreport:fr.opensagres.xdocreport.template:2.0.2"
compile "fr.opensagres.xdocreport:fr.opensagres.xdocreport.template.freemarker:2.0.2"
compile "org.freemarker:freemarker:2.3.23"
compile "commons-io:commons-io:2.5"
compile "org.apache.poi:poi:3.14"
compile "org.apache.poi:poi-ooxml:3.14"
2.创建导出模板
纯文字使用${}占位,图片使用建立初始化图片并添加书签的方式占位,
书签名就是datamap的键名,多张图片添加多个书签
3.编写代码(这里使用浏览器下载方式导出)
(1)导出工具方法
/**
* 导出工具方法
* // *
* // * @param response 相应头
* // * @param map 集合外数据
* // * @param list 遍历数据
* // * @param fileName 文件名称(带后缀)
* // * @return 是否导出成功
* // * @throws IOException
* // * @throws XDocReportException
*/
public static void exportFile (
HttpServletResponse response,
Map<String, File> fileDataMap,
String fileName,
Map<String, Object> map,
List<Object> list) throws IOException, XDocReportException {
// 获取Word模板,模板存放路径在项目的resources目录下
// 这里的Kit为当前工具方法的类名,如果不是静态方法可以直接用this
InputStreamins= Kit.class.getResourceAsStream(fileName);
// 注册xdocreport实例并加载FreeMarker模板引擎
IXDocReportreport=XDocReportRegistry.getRegistry().loadReport(ins, TemplateEngineKind.Freemarker);
// 创建xdocreport上下文对象
IContext context = report.createContext();
//添加文本数据
if (map != null) {
for (String s : map.keySet()) {
context.put(s, map.get(s));
}
}
//添加循环表格数据(需要自行添加,模板对应加上关键字)
if (list != null) {
context.put("resultList", list);
// 创建字段元数据
FieldsMetadata fm = report.createFieldsMetadata();
// Word模板中的表格数据对应的集合类型
fm.load("resultList", Object.class, true);
}
FieldsMetadata metadata = report.createFieldsMetadata();
// 替换word模板中的动态图片
if (fileMap != null) {
for (String s : fileMap.keySet()) {
IImageProvider zp = new FileImageProvider((fileMap.get(s)), true);
zp.setSize(130F, 130F);
metadata.addFieldAsImage(s);
report.setFieldsMetadata(metadata);
context.put(s, zp);
}
}
// 浏览器端下载
response.setCharacterEncoding("utf-8");
response.setContentType("application/msword");
response.setHeader(
"Content-Disposition",
"attachment;filename=".concat(String.valueOf(URLEncoder.encode(fileName, "UTF-8"))));
report.process(context, response.getOutputStream());
}
(2)业务逻辑代码
try{
Map<String, File> fileMap = null;
Map<String, Object> exportMap = new hashMap();
exportMap.put("???","data");
int num = 1;
//由于poitl和导入功能用的poi版本冲突,无法用,这里使用IXDocReport对象做导出
//可以循环添加,键名可以拼接为img1,img2,img3。。。,模板书签名对应
//需要导出的文件集合,对接实际业务service
List<File> list = new arrayList();
if(list != null) {
fileMap = new hashMap();
for (File f : list) {
fileMap.put("img" + num , f);
num ++;
}
}
Kit.exportFile(response, fileMap, "模板名称.docx", exportMap, null);
} catch (Exception e) {
e.printStackTrace();
}
(3)因为我们业务文件接口返回的是byte数组,所以这里提供一个byte数组转File对象的方法(网上c的)
/**
* byte数组转file对象工具方法(中方法)
*
* @param inputStream
* @param name
* @param ext
* @param tmpDirFile
* @return
* @throws IOException
*/
public static File createTmpFile(
InputStream inputStream, String name, String ext, File tmpDirFile) throws IOException {
File resultFile = File.createTempFile(name, '.' + ext, tmpDirFile);
resultFile.deleteOnExit();
FileUtils.copyToFile(inputStream, resultFile);
return resultFile;
}
/**
* byte数组转file对象工具方法
*
* @param bytes 文件byte数组
* @param fileType 输出文件类型
* @return file对象
* @throws IOException io异常
*/
public static File bytesToFile(byte[] bytes, String fileType) throws IOException {
return createTmpFile(
new ByteArrayInputStream(bytes),
UUID.randomUUID().toString(),
fileType,
Files.createTempDirectory("tempFile").toFile());
}
4.那么问题来了,图片数量不定怎么确定初始化图片再添加书签呢,困扰了很久,最后直接用20张纯白图片(这里采用微信截图,截了很小一张,100张也没有几k,全都添加对应书签,不够20张也看不出来,缺点是不满20张会空一行出来),弄好后调用方法点击导出ok
注:方法思路由该贴而来
https://blog.csdn.net/plxddyxnmd/article/details/109129838