导入jar包
<dependency>
<groupId>com.deepoove</groupId>
<artifactId>poi-tl</artifactId>
<version>1.10.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.7</version>
</dependency>
准备模板
流程:制作模板->提供数据->渲染模板->下载word
注意:需要填充的数据需要使用{{}}来表示。
模板保存为docx格式,存放在resource目录下
提供数据
我这用的是我自己程序中的数据,map的key键必须与word模板中{{}}里的字段匹配
private Map<String, Object> assertMap(String rq, QualityWorkableFeedback qualityWorkableFeedback) {
Map<String, Object> params = new HashMap<>();
QualityProjectPlan projectPlan = new QualityProjectPlan();
Map<String, List<QualityProjectPlan>> map = projectPlanService.selectQualityProjectPlanList(projectPlan);
if (StringUtils.isNotNull(map)) {
List<QualityProjectPlan> qualityProjectPlans1 = map.get("one");
params.put("yf1", "1月");
params.put("zcxm1_1", qualityProjectPlans1.get(0).getAPXM());
params.put("zcxm1_2", qualityProjectPlans1.get(1).getAPXM());
params.put("zcxm1_3", qualityProjectPlans1.get(2).getAPXM());
params.put("zcxm1_4", qualityProjectPlans1.get(3).getAPXM())
}
return params;
}
工具方法
以下是在接口中用到的工具类
/**
* 将项目中的模板文件拷贝到根目录下
*
* @return
*/
private String copyTempFile(String templeFilePath) {
InputStream inputStream = getClass().getClassLoader().getResourceAsStream(templeFilePath);
String tempFileName = System.getProperty("user.home") + "/" + "科室质量目标管理落实反馈表模板.docx";
File tempFile = new File(tempFileName);
try {
FileUtils.copyInputStreamToFile(inputStream, tempFile);
} catch (IOException e) {
throw new RuntimeException(e);
}
return tempFile.getPath();
}
private void down(HttpServletResponse response, String filePath, String realFileName) {
String percentEncodedFileName = null;
try {
percentEncodedFileName = percentEncode(realFileName);
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
StringBuilder contentDispositionValue = new StringBuilder();
contentDispositionValue.append("attachment; filename=").append(percentEncodedFileName).append(";").append("filename*=").append("utf-8''").append(percentEncodedFileName);
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename");
response.setHeader("Content-disposition", contentDispositionValue.toString());
response.setHeader("download-filename", percentEncodedFileName);
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));
// 输出流
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());) {
byte[] buff = new byte[1024];
int len = 0;
while ((len = bis.read(buff)) > 0) {
bos.write(buff, 0, len);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 百分号编码工具方法
*
* @param s 需要百分号编码的字符串
* @return 百分号编码后的字符串
*/
public static String percentEncode(String s) throws UnsupportedEncodingException {
String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());
return encode.replaceAll("\\+", "%20");
}
编写接口
/**
* 导出word
* QualityWorkableFeedback 自定义的实体类
*/
@RequestMapping("/export")
public String export(HttpServletResponse response, QualityWorkableFeedback qualityWorkableFeedback) throws IOException {
//1.组装数据
Map<String, Object> params = assertMap(qualityWorkableFeedback.getFKSJ(), qualityWorkableFeedback);
//2.获取根目录,创建模板文件
String path = copyTempFile("word/科室质量目标管理落实反馈表模板.docx");
String fileName = System.currentTimeMillis() + ".docx";
String tmpPath = EmergencyConfig.getProfile()+ "/" + fileName;
try {
//3.将模板文件写入到根目录
//4.编译模板,渲染数据
XWPFTemplate template = XWPFTemplate.compile(path).render(params);
//5.写入到指定目录位置
FileOutputStream fos = new FileOutputStream(tmpPath);
template.write(fos);
fos.flush();
fos.close();
template.close();
//6.提供前端下载
down(response, tmpPath, fileName);
} catch (Exception e) {
e.printStackTrace();
} finally {
//7.删除临时文件
File file = new File(tmpPath);
file.delete();
File copyFile = new File(path);
copyFile.delete();
}
return tmpPath;
}
对于图片的格式,POI-TI也有几种方法可用
//指定图片路径
put("image", "img.png");
//svg
put("svg", "http://xxxx.svg");
//设置图片宽高
put("image", Pictures.ofLocal("img.png").size(100, 100).create());
//图片流
put("streamImg", Pictures.ofStream(new FileInputStream("img.jpeg"), PictureType.JPEG).size(100, 100).create);
//网路图片
put("urlImg", Pictures.ofUrl("http://xxxx.png").size(100, 100).create);
//Java图片
put("image", Pictures.ofBufferedImage(bufferImage, PictureType.PNG).size(100, 100).create);
前端接口
我这前端直接用的框架中自带的下载功能
getFkExpert() {
let obj = {
FKSJ: this.year
}
this.$confirm('是否确认导出数据项?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
.then(() => {
this.download('/workable/feedback/export', {
...obj
}, this.year.substring(0, 4) + `科室质量目标管理落实反馈表.docx`)
})
.catch(() => {
})
},
以下为补充内容,网上搜索的资料
导出表格内容不固定的word文档
表格动态内容填充,POI-TL提供了3种方式。
- 表格行循环
- 表格列循环
- 动态表格。
LoopRowTableRenderPolicy 是一个特定场景的插件,根据集合数据循环表格行。
注意:
模板中有两个list,这两个list需要置于循环行的上一行。
循环行设置要循环的标签和内容,注意此时的标签应该使用[ ]
本次使用的是表格行循环
接口
@RequestMapping("dynamicTable")
public void dynamicTable(HttpServletResponse response) {
//1.组装数据
StudentTable table = assertMap();
//2.获取根目录,创建模板文件
String path = copyTempFile("word/2.docx");
//3.获取临时文件
String fileName = System.currentTimeMillis() + ".docx";
String tmpPath = EmergencyConfig.getProfile()+ "/" + fileName;
try {
//4.编译模板,渲染数据
LoopRowTableRenderPolicy hackLoopTableRenderPolicy = new LoopRowTableRenderPolicy();
Configure config =
Configure.builder().bind("dataList", hackLoopTableRenderPolicy.build();
XWPFTemplate template = XWPFTemplate.compile(path, config).render(table);
//5.写入到指定目录位置
FileOutputStream fos = new FileOutputStream(tmpPath);
template.write(fos);
fos.flush();
fos.close();
template.close();
//6.提供下载
down(response, tmpPath, fileName);
} catch (Exception e) {
e.printStackTrace();
} finally {
//7.删除临时文件
File file = new File(tmpPath);
file.delete();
File copyFile = new File(path);
copyFile.delete();
}
}