easypoi根据模板导出word
在工作中,模板导出必不或缺,实现模板导出的第三方工具包也有很多。例如:poi、freemaker、hutool的word工具类以及第三方报表工具。这里我简单介绍一下easypoi
poi和easypoi区别
poi和easypoi都是Apache提供的,那么他们之间有什么区别呢?
从他俩的名字不难看出,easypoi更容易上手,使用更加简便,Excel导出,Excel导入,通过简单的注解,完成以前复杂的写法
环境搭建
所需依赖
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-spring-boot-starter</artifactId>
<version>4.1.0</version>
</dependency>
poi和easypoi冲突问题解决
4.10之前的版本会有冲突,使用4.10或更高版本
简单上手
1.模板准备
本文只适用于.docx文档
注意:整体风格和el表达式类似,采用的写法是{{}}代表表达式,然后根据表达式里面的数据取值。
2.将模板存放在数据库或项目中
3.上代码
service层 代码片
。
//获取模板文档
File rootFile =new File(ResourceUtils.getURL("classpath:").getPath());
File templateFile= new File(rootFile,"/word/项目资金拨付申请表.docx");
//随机生成单据编号
String djbh = UUID.randomUUID().toString();
//1.查出对应数据
Map<String,Object> map = jiApplyZJMapper.exportZFSQ(jjZJVo);
map.put("DJBH", djbh);
//2.映射为模板
XWPFDocument word = WordExportUtil.exportWord07(templateFile.getPath(),map);
String filename = "支付申请.docx";
//导出
response.setHeader("content-disposition","attachment;filename="+new String(filename.getBytes(),"ISO8859-1"));
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
word.write(response.getOutputStream());
4.效果展示
5.部分NULL数据导出之后显示问题
我的处理方法是在sql中或在代码中去判断再替换成" "(这种方法不供参考~)
可能有更好的方法,比如在模板准备过程中的el表达式可以规避NULL数据。
实现原理深入浅出
//service层核心代码
XWPFDocument word = WordExportUtil.exportWord07(templateFile.getPath(),map);
1.step into
//WordExportUtil中exportWord07方法代码
public static XWPFDocument exportWord07(String url, Map<String, Object> map) throws Exception {
return (new ParseWord07()).parseWord(url, map);
}
2.step into
//ParseWord07中parseWord方法代码
public XWPFDocument parseWord(String url, Map<String, Object> map) throws Exception {
MyXWPFDocument doc = WordCache.getXWPFDocumen(url);
this.parseWordSetValue(doc, map);
return doc;
}
这里解释一下:
WordCache.getXWPFDocumen(url);这个方法是通过拿到该文件的输入流将其封装成一个文档对象
3.step into getXWPFDocumen(url)
//WordCache中getXWPFDocumen方法代码
public static MyXWPFDocument getXWPFDocumen(String url) {
InputStream is = null;
try {
is = POICacheManager.getFile(url);
MyXWPFDocument doc = new MyXWPFDocument(is);
MyXWPFDocument var3 = doc;
return var3;
} catch (Exception var13) {
LOGGER.error(var13.getMessage(), var13);
} finally {
try {
is.close();
} catch (Exception var12) {
LOGGER.error(var12.getMessage(), var12);
}
}
return null;
}
4.step into parseWordSetValue(doc,map)
//ParseWord07中parseWordSetValue方法代码
private void parseWordSetValue(MyXWPFDocument doc, Map<String, Object> map) throws Exception {
/**
doc.getParagraphs()是针对于文档(非表格)每一行;
之后判断是否存在“{{”,存在的话将map中的键与“{{xxx}}”去匹配,并替换值
*/
this.parseAllParagraphic(doc.getParagraphs(), map);
/**
parseHeaderAndFoot是针对于文档头尾;
之后判断是否存在“{{”,存在的话将map中的键与“{{xxx}}”去匹配,并替换值
*/
this.parseHeaderAndFoot(doc, map);
/**
getTablesIterator获取文档中的表格;
*/
Iterator itTable = doc.getTablesIterator();
/**
遍历文档中的表格;判断是否存在“{{”,存在的话将map中的键与“{{xxx}}”去匹配,并替换值;
*/
while(itTable.hasNext()) {
XWPFTable table = (XWPFTable)itTable.next();
if (table.getText().indexOf("{{") != -1) {
this.parseThisTable(table, map);
}
}
}
总结
1.easypoi导出word简单来说,先给模板用el表达式定义好字段名,再从数据库查出数据,最后用其封装的方法匹配替换即可
2.easypoi其实是封装了比较复杂的poi从而实现上手简易
3.本文测试用例比较简单,是针对于单条数据的表格,还有更复杂的有待探讨,比如循环导出、大数据量的效率问题等