该文章内容基于easypoi官方文档整理,对一些内容增加了更直白清晰的内容说明。
jdk版本:1.8+
easypoi依赖版本:3.0+
模板是处理复杂Excel的简单方法,复杂的Excel样式,可以用Excel直接编辑,完美的避开了代码编写样式的雷区,同时指令的支持,也提高了模板的高效性。只要你的模板制作的漂亮,那么在数据填充之后,生成的excel文件依然会很漂亮。
使用模板功能,顾名思义,你只需要创建好模板,并定义好模板中的数据类型,便可以将数据插入到模板中指定位置。
下面列举下EasyPoi支持的指令以及作用,最主要的就是各种fe的用法
整体风格和el表达式类似,大家应该也比较熟悉 采用的写法是{{属性}},然后根据表达式里面的数据取值
关于样式问题 easypoi不会改变excel原有的样式,如果是遍历,easypoi会根据模板的那一行样式进行复制
在cn.afterturn.easypoi.test.excel.template 这个目录下面 https://gitee.com/lemur/easypoi-test/tree/master/src/test/java/cn/afterturn/easypoi/test/excel/template
看一个常见的导出模板–专项支出用款申请书 (文件路径 WEB-INF/doc/专项支出用款申请书_map.xls)
图1
这里面有正常的标签以及 f e 遍 历 , fe遍历, fe遍历,fe遍历应该是使用最广的遍历,用来解决遍历后下面还有数据的处理方式 我们要生成的是这个需要一些list集合和一些单纯的数据
fe的写法 **fe标志 冒号 list数据 单个元素数据(默认t,可以不写) 第一个元素 ** 如: {{$fe: maplist t t.id }}
通过上图我们可以看到,一个指令是以 {{ 开始,以 }} 结尾,即使是多列中,如上图第一列中,{{ 与 }}不在同一列,被{{ 与 }}包裹的数据,全都是第一个变量的一个子数据。
以下为示例代码,主要是构造数据TemplateExportParams是主要的参数数据
@Test
public void fe_map() throws Exception {
TemplateExportParams params = new TemplateExportParams(
"WEB-INF/doc/专项支出用款申请书_map.xls");
Map<String, Object> map = new HashMap<String, Object>();
map.put("date", "2014-12-25");
map.put("money", 2000000.00);
map.put("upperMoney", "贰佰万");
map.put("company", "执笔潜行科技有限公司");
map.put("bureau", "财政局");
map.put("person", "JueYue");
map.put("phone", "1879740****");
List<Map<String, String>> listMap = new ArrayList<Map<String, String>>();
for (int i = 0; i < 4; i++) {
Map<String, String> lm = new HashMap<String, String>();
lm.put("id", i + 1 + "");
lm.put("zijin", i * 10000 + "");
lm.put("bianma", "A001");
lm.put("mingcheng", "设计");
lm.put("xiangmumingcheng", "EasyPoi " + i + "期");
lm.put("quancheng", "开源项目");
lm.put("sqje", i * 10000 + "");
lm.put("hdje", i * 10000 + "");
listMap.add(lm);
}
map.put("maplist", listMap);
Workbook workbook = ExcelExportUtil.exportExcel(params, map);
File savefile = new File("D:/excel/");
if (!savefile.exists()) {
savefile.mkdirs();
}
FileOutputStream fos = new FileOutputStream("D:/excel/专项支出用款申请书_map.xls");
workbook.write(fos);
fos.close();
}
第3行代码 TemplateExportParams params = new TemplateExportParams( “WEB-INF/doc/专项支出用款申请书_map.xls”);
这行代码中使用easypoi的导入模板参数类TemplateExportParams将WEB-INF/doc/专项支出用款申请书_map.xls模板xls进行导入。
第5行代码 Map
该行代码的意思是定义一个map对象,所有将会在模板中使用的数据都封装到该map对象中。
第6行代码 map.put(“date”, “2014-12-25”);
该行代码的意思是封装了一个数据名为date的数据,数据值为 2014-12-25 ,在模板中该值将会替代{{date}} 数据。
第13行代码 List
该行代码的意思是封装一条List
第29行代码 Workbook workbook = ExcelExportUtil.exportExcel(params, map);
该代码将模板数据params 与实际数据map进行整合。最后生成一个Workbook对象。
最后将workbook对象输出到一个文件中。完成了模板功能的使用。
备注说明
在实际开发过程中,也可以直接在controller中直接将数据返回给前端页面,主要点就是在上面的代码中的Workbookr对象的流直接输出到response的out对象中,然后在相应头中海需要注意的是设置UTF-8编码格式,同时响应头 content-type 要设置成 application/vnd.ms-excel ,响应头Content-Disposition要设置为attachment;filename="你的文件名“。示例代码如下
特别要注意的就是UTF-8编码,跟响应头一定不能少,如果缺少的话,前端页面可能无法正常解析数据,浏览器也无法实现自动下载excel文件。
当然在easypoi中已经帮我们实现了这一种方式,具体使用方式参考第三节。
easypoi view 项目是为了更简单的方便搭建在导出时候的操作,利用spring mvc 的view 封装,更加符合spring mvc的风格 view下面包括多个 view的实现
view的是使用方法大同小异,都有一个对应的bean,里面保护指定的参数常量 同意用modelmap.put(‘常量参数名’,‘值’)就可以,最后返回这个view名字
注解目录扫描的时候加上 cn.afterturn.easypoi.view 就可以使用了
EasypoiBigExcelExportView 是针对大数据量导出特定的View,在跳转到这个View的时候不需要查询数据,而且这个View自己去查询数据,用户只要实现IExcelExportServer接口就可以了 对应的常量类BigExcelConstants
public interface IExcelExportServer {
/**
* 查询数据接口
* @param obj 查询条件
* @param page 当前页数
* @return
*/
public List<Object> selectListForExcelExport(Object obj, int page);
}
EasypoiBigExcelExportView 判断是否还有下一页的条件是,如果selectListForExcelExport 返回null就认为是最后一页了,如果返回有数据这page+1继续查询 在我们自己的controller中
@RequestMapping("load")
public void downloadByPoiBaseView(ModelMap map, HttpServletRequest request,
HttpServletResponse response) {
ExportParams params = new ExportParams("2412312", "测试", ExcelType.XSSF);
params.setFreezeCol(2);
map.put(BigExcelConstants.CLASS, MsgClient.class);
map.put(BigExcelConstants.PARAMS, params);
//就是我们的查询参数,会带到接口中,供接口查询使用
map.put(BigExcelConstants.DATA_PARAMS, new HashMap<String,String>());
map.put(BigExcelConstants.DATA_INTER,excelExportServer);
PoiBaseView.render(map, request, response, BigExcelConstants.EASYPOI_BIG_EXCEL_VIEW);
}
我们需要把参数条件封装成map或者其他类型,上面的obj可以把参数自己转回来 参数名字 BigExcelConstants.DATA_PARAM 然后把实现查询的接口注入进来就可以了 map.put(BigExcelConstants.DATA_INTER,excelExportServer); 后面就和其他View一样了
注解导出的View是这个EasypoiSingleExcelView,其实View大家可以忽略不看,主要用到的还是他对应的bean对象 NormalExcelConstants 注解到处还比较简单,大家只要把datalist,class和params 这几个参数put下就可以了。 具体的案例
@RequestMapping()
public String download(ModelMap map) {
List<MsgClient> list = new ArrayList<MsgClient>();
for (int i = 0; i < 100; i++) {
MsgClient client = new MsgClient();
client.setBirthday(new Date());
client.setClientName("小明" + i);
client.setClientPhone("18797" + i);
client.setCreateBy("JueYue");
client.setId("1" + i);
client.setRemark("测试" + i);
MsgClientGroup group = new MsgClientGroup();
group.setGroupName("测试" + i);
client.setGroup(group);
list.add(client);
}
ExportParams params = new ExportParams("2412312", "测试", ExcelType.XSSF);
params.setFreezeCol(2);
map.put(NormalExcelConstants.DATA_LIST, list); // 数据集合
map.put(NormalExcelConstants.CLASS, MsgClient.class);//导出实体
map.put(NormalExcelConstants.PARAMS, params);//参数
map.put(NormalExcelConstants.FILE_NAME, params);//文件名称
return NormalExcelConstants.EASYPOI_EXCEL_VIEW;//View名称
}
和非View导出基本一致,只是把调用方法封装了而已,其他参数还都是一样的,具体可以看下测试项目的 EasypoiSingleExcelViewTest
作为动态注解存在的 List ,也提供的单独的View方便大家使用,EasypoiMapExcelView 使用方法都是一样,直接看下例子吧
@RequestMapping()
public String download(ModelMap modelMap) {
List<ExcelExportEntity> entity = new ArrayList<ExcelExportEntity>();
ExcelExportEntity excelentity = new ExcelExportEntity("姓名", "name");
excelentity.setNeedMerge(true);
entity.add(excelentity);
entity.add(new ExcelExportEntity("性别", "sex"));
excelentity = new ExcelExportEntity(null, "students");
List<ExcelExportEntity> temp = new ArrayList<ExcelExportEntity>();
temp.add(new ExcelExportEntity("姓名", "name"));
temp.add(new ExcelExportEntity("性别", "sex"));
excelentity.setList(temp);
entity.add(excelentity);
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
Map<String, Object> map;
for (int i = 0; i < 10; i++) {
map = new HashMap<String, Object>();
map.put("name", "1" + i);
map.put("sex", "2" + i);
List<Map<String, Object>> tempList = new ArrayList<Map<String, Object>>();
tempList.add(map);
tempList.add(map);
map.put("students", tempList);
list.add(map);
}
ExportParams params = new ExportParams("2412312", "测试", ExcelType.XSSF);
params.setFreezeCol(2);
modelMap.put(MapExcelConstants.MAP_LIST, list); //数据集合
modelMap.put(MapExcelConstants.ENTITY_LIST, entity); //注解集合
modelMap.put(MapExcelConstants.PARAMS, params);//参数
modelMap.put(MapExcelConstants.FILE_NAME, "EasypoiMapExcelViewTest");//文件名称
return MapExcelConstants.EASYPOI_MAP_EXCEL_VIEW;//View名称
}
具体案例参考EasypoiMapExcelViewTest
模板导出提供的EasypoiTemplateExcelView以及对应的bean TemplateExcelConstants 案例
@RequestMapping()
public String download(ModelMap modelMap) {
Map<String, Object> map = new HashMap<String, Object>();
TemplateExportParams params = new TemplateExportParams(
"doc/foreach.xlsx");
List<TemplateExcelExportEntity> list = new ArrayList<TemplateExcelExportEntity>();
for (int i = 0; i < 4; i++) {
TemplateExcelExportEntity entity = new TemplateExcelExportEntity();
entity.setIndex(i + 1 + "");
entity.setAccountType("开源项目");
entity.setProjectName("EasyPoi " + i + "期");
entity.setAmountApplied(i * 10000 + "");
entity.setApprovedAmount((i + 1) * 10000 - 100 + "");
list.add(entity);
}
map.put("entitylist", list);
map.put("manmark", "1");
map.put("letest", "12345678");
map.put("fntest", "12345678.2341234");
map.put("fdtest", null);
List<Map<String, Object>> mapList = new ArrayList<Map<String, Object>>();
for (int i = 0; i < 1; i++) {
Map<String, Object> testMap = new HashMap<String, Object>();
testMap.put("id", "xman");
testMap.put("name", "小明" + i);
testMap.put("sex", "1");
mapList.add(testMap);
}
map.put("maplist", mapList);
mapList = new ArrayList<Map<String, Object>>();
for (int i = 0; i < 6; i++) {
Map<String, Object> testMap = new HashMap<String, Object>();
testMap.put("si", "xman");
mapList.add(testMap);
}
map.put("sitest", mapList);
modelMap.put(TemplateExcelConstants.FILE_NAME, "用户信息"); //文件名
modelMap.put(TemplateExcelConstants.PARAMS, params);//参数
modelMap.put(TemplateExcelConstants.MAP_DATA, map);//数据
return TemplateExcelConstants.EASYPOI_TEMPLATE_EXCEL_VIEW;//view名称
}
具体案例EasypoiTemplateExcelViewTest
假如因为不可抗拒或者其他神奇的原因,view导出无法使用,作者遇到过好几次了,各种神奇原因都有,提供一个统一的封装,算是一个补救措施吧 上面的modelMap写法和设置参数还是一样,最后直接输出就可以了 PoiBaseView.render(modelMap, request, response,View名称);
看个简单demo
@RequestMapping("load")
public void downloadByPoiBaseView(ModelMap map, HttpServletRequest request,
HttpServletResponse response) {
List<MsgClient> list = new ArrayList<MsgClient>();
for (int i = 0; i < 100; i++) {
MsgClient client = new MsgClient();
client.setBirthday(new Date());
client.setClientName("小明" + i);
client.setClientPhone("18797" + i);
client.setCreateBy("JueYue");
client.setId("1" + i);
client.setRemark("测试" + i);
MsgClientGroup group = new MsgClientGroup();
group.setGroupName("测试" + i);
client.setGroup(group);
list.add(client);
}
ExportParams params = new ExportParams("2412312", "测试", ExcelType.XSSF);
params.setFreezeCol(2);
map.put(NormalExcelConstants.DATA_LIST, list);
map.put(NormalExcelConstants.CLASS, MsgClient.class);
map.put(NormalExcelConstants.PARAMS, params);
PoiBaseView.render(map, request, response, NormalExcelConstants.EASYPOI_EXCEL_VIEW);
}
java.io.FileNotFoundException: class path resource [excelTemplate/waterTemplate.xlsx] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/C:/code/…
在springboot项目中,如果是以jar方式运行项目可能会报以上错误
TemplateExportParams templateExportParams = new TemplateExportParams("doc/xxx.xls"); 加载不到模板
这是因为jar方式运行的代码,文件路径有所不同,所以直接使用相对路径会报错,找不到模板文件,最新版easypoi框架是使用以下方式处理了该问题的。
//判断是否是网络地址
if (url.startsWith("http")) {
URL urlObj = new URL(url);
URLConnection urlConnection = urlObj.openConnection();
urlConnection.setConnectTimeout(30 * 1000);
urlConnection.setReadTimeout(60 * 1000);
urlConnection.setDoInput(true);
fileis = urlConnection.getInputStream();
} else {
//先用绝对路径查询,再查询相对路径
try {
fileis = new FileInputStream(url);
} catch (FileNotFoundException e) {
//获取项目文件
fileis = FileLoaderImpl.class.getClassLoader().getResourceAsStream(url);
}
}
我们需要做的是将模板文件放在resources工程目录下,定义好模板文件夹,然后将模板文件放入该文件夹中
如:
对应的代码改为模板相对路径就可以了为:
TemplateExportParams templateExportParams = new TemplateExportParams("excelTemplate/xxx.xls");
//获取项目文件
fileis = FileLoaderImpl.class.getClassLoader().getResourceAsStream(url);
}
}
我们需要做的是将模板文件放在resources工程目录下,定义好模板文件夹,然后将模板文件放入该文件夹中
如:
对应的代码改为模板相对路径就可以了为:
TemplateExportParams templateExportParams = new TemplateExportParams("excelTemplate/xxx.xls");