简介
asypoi功能如同名字easy,主打的功能就是让一个没见接触过poi的人员就可以方便的写出Excel导出,Excel模板导出,Excel导入,Word模板导出,通过简单的注解和模板语言(熟悉的表达式语法),完成以前复杂的写法。
一、场景描述
客户要求导出一张结算报表,报表的列头是选择结算的日期区间,也就是需要根据日期分组,然后计算这个日期下的结算金额和笔数,最后再计算合计。针对这个场景,我整理了下代码,如下:
二、使用步骤
1.引入Jar包
这是针对导出Excel的,如果是Word还需要自行拷贝其他包(示例):
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-base</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>4.2.0</version>
</dependency>
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-annotation</artifactId>
<version>4.2.0</version>
</dependency>
2.代码实现
代码如下(示例):
public void exportReport(Map<String, Object> params, HttpServletRequest request,
HttpServletResponse response) {
ModelMap modelMap = new ModelMap();
Map<String, Object> dataMap = Maps.newHashMap();
//模板存放路径,在你项目的Resource下随便建个文件夹,把模板放进去就好
TemplateExportParams tempParams = new TemplateExportParams("TemplateFiles/test.xlsx");
// 获取结算数据
List<TestEntity> list = baseDao.getAllSummaryList(params);
// 把数据转成excel数据
List<TestExcel> dataList = ConvertUtils.sourceToTarget(list, TestExcel.class);
//按照结算日期分组(获取动态列头)
Map<Object, List<TestExcel>> listTwo = new HashMap<>();
//根据商户分组(获取行)
Map<Object, List<TestExcel>> listOne = dataList.stream().collect(Collectors.groupingBy(TestExcel::getSubMerchantAccNo));
//创建列和行集合
List<Map<String, Object>> colList = new ArrayList<Map<String, Object>>();
List<Map<String, Object>> valList = new ArrayList<Map<String, Object>>();
Map<String, Object> value = new HashMap<String, Object>();
//序列号(报表要用)
int seq= 0;
for(Object subNO : listOne.keySet()){
seq+=1;
//获取这个商户下的交易明细
List<TestExcel> detailList=listOne.get(subNO);
for(int i = 0;i<detailList.size();i++){
//获取结算时间
String paymentTime = detailList.get(i).getSettlementtime();
for (Object time : listTwo.keySet()) {
Map<String, Object> map = new HashMap<String, Object>();
//先处理表头
if (paymentTime.equals(time)) {
if(colList.size()>0){
//这里是判断列集合里有没有重复的,去重
boolean flag = false;
for(int j =0 ; j < colList.size();j++){
if(colList.get(j).get("paymentTime").equals(paymentTime)){
flag = true;
break;
}
}
if(flag == false){
map.put("paymentTime", time);
map.put("bs", "笔数");
map.put("je", "金额");
// t.这是easypoi的语法,后面拼接时间是为了区分这个笔数和金额是属于哪个日期下的
map.put("transCount", "t.transCount"+time);
map.put("transAmount", "t.transAmount"+time);
colList.add(map);
}
}else{
map.put("paymentTime", time);
map.put("bs", "笔数");
map.put("je", "金额");
map.put("transCount", "t.transCount"+time);
map.put("transAmount", "t.transAmount"+time);
colList.add(map);
}
break;
}
}
}
//行添加
Map<String, Object> map1 = new HashMap<String, Object>();
//计算这个商户在某个日期区间内的金额和笔数的合计
int totalCnt = detailList.parallelStream().filter(e -> StringKit.notBlank(e.getTransCount()))
.mapToInt(TestExcel::getTransCount).sum();
double totalAmt = detailList.parallelStream().filter(e -> StringKit.notBlank(e.getTransAmount()))
.mapToDouble(e -> e.getTransAmount().doubleValue()).sum();
map1.put("subMerchantAccNo", detailList.get(0).getSubMerchantAccNo()); //subMerchantAccNo 商户号
map1.put("subMerchantName", detailList.get(0).getSubMerchantName()); //subMerchantName 商户名
map1.put("totalCnt", totalCnt); //合计笔数 2020
map1.put("totalAmt", totalAmt); //合计金额 2020
map1.put("seqNum", seq); //合计金额 2020
for(int a = 0;a<detailList.size();a++){
//笔数
int transCount = detailList.get(a).getTransCount();
//金额
BigDecimal transAmount = detailList.get(a).getTransAmount();
//结算时间
map1.put("transCount"+detailList.get(a).getTranstime(), transCount);
map1.put("transAmount"+detailList.get(a).getTranstime(), transAmount);
//这里的key对应上面列的value,根据这个找到某个笔数和金额的值,一个商户肯定对应多个日期,那有几个日期就要put几个
}
valList.add(map1);
}
//根据结算日期排序
colList.sort((t1, t2) -> t1.get("paymentTime").toString().compareTo(t2.get("paymentTime").toString()));
dataMap.put("valList", valList);
dataMap.put("colList", colList);
tempParams.setColForEach(true);//这个必须要加
// 日期类型
dataMap.put("dateTypeName", params.get("dateTypeName"));
// 数据类型
dataMap.put("dataTypeName", params.get("dataTypeName"));
// 结算周期
dataMap.put("settlementCycle", params.get("startDate") + "至" + params.get("endDate"));
// sheet页名称
tempParams.setSheetName(Convert.toStrArray("结算表"+ DateUtils.getMillisecond()));
//导出excel
modelMap.put(TemplateExcelConstants.FILE_NAME, "结算表" + DateUtils.getMillisecond());
modelMap.put(TemplateExcelConstants.PARAMS, tempParams);
modelMap.put(TemplateExcelConstants.MAP_DATA, dataMap);
PoiBaseView.render(modelMap, request, response, TemplateExcelConstants.EASYPOI_TEMPLATE_EXCEL_VIEW);
}
3.模板创建
模板里的字段都对应着代码里的字段,可自行调整。模板主要分为四部分,一是行循环【valList】,这里得到了序列号,商户号和商户名。二是列循环【colList】,这里得到的是日期列头。三是内部的子循环,得到的是一个商户对应的全部日期的集合,对应代码最后一个循环体部分,这里的语法也不一样,用的是【v_fe】。最后是合计部分,这里是单独一列,并且必须放在日期循环体的前面,也就是合计部分不能在最后一列,这是因为easypoi会覆盖掉循环体外的列,网上说的什么隔开一列,试过无法解决,所以只能放在前面。
4.结果展示
三、 总结
以上就是今天要讲的内容,本文主要是介绍一种easypoi的复杂Excel导出的方法,它还可以快速导出word等,有不清楚的欢迎留言,觉得写的不错的,可以点赞收藏鼓励哟!