提示:以下是本篇文章正文内容,下面案例可供参考
代码如下:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.6</version>
<exclusions>
<exclusion>
<artifactId>poi</artifactId>
<groupId>org.apache.poi</groupId>
</exclusion>
<exclusion>
<artifactId>poi-ooxml</artifactId>
<groupId>org.apache.poi</groupId>
</exclusion>
<exclusion>
<artifactId>poi-ooxml-schemas</artifactId>
<groupId>org.apache.poi</groupId>
</exclusion>
</exclusions>
</dependency>
@Data
@ApiModel(value = "测试导出DTO")
@HeadStyle(horizontalAlignment = HorizontalAlignment.CENTER)
@HeadFontStyle(bold = true ,color = -1)
public class ExcelMultipurposeDTO {
@ColumnWidth(value = 20)
@ExcelProperty(value = {"项目","项目"} ,index = 0)
private String project;
@ExcelIgnore
private String site;
@ColumnWidth(value = 25)
@ExcelProperty(value = {"网点","网点"} ,index = 1)
private String stationName;
@ColumnWidth(value = 15)
@ExcelProperty(value = {"本期发生数","业务笔数"} ,index = 2)
private Integer currentTransCount;
@ColumnWidth(value = 15)
@ExcelProperty(value = {"本期发生数","发生额"} ,index = 3)
private BigDecimal currentTransAmount;
@ColumnWidth(value = 15)
@ExcelProperty(value = {"本期发生数","结算服务费"} ,index = 4)
private BigDecimal currentServiceFee;
@ColumnWidth(value = 15)
@ExcelProperty(value = {"本年发生数","业务笔数"} ,index = 5)
private Integer yearTransCount;
@ColumnWidth(value = 15)
@ExcelProperty(value = {"本年发生数","发生额"} ,index = 6)
private BigDecimal yearTransAmount;
@ColumnWidth(value = 15)
@ExcelProperty(value = {"本年发生数","结算服务费"} ,index = 7)
private BigDecimal yearServiceFee;
}
其中,@HeadStyle 和 @HeadFontStyle是设置表头居中,字体加粗和颜色。@ColumnWidth 是设置列宽,@ExcelProperty 里面有value 和index属性,value 是列名,index 是列的顺序。
List<ExcelMultipurposeDTO> resultList = xxxDao.getList(); //获取需要导出的数据
try {
// 设置第几列合并
int[] mergeColumnIndex = {0}; //这边我需要指定合并第一列,所以赋值0,如果需要合并多列,直接逗号分隔:int[] mergeColumnIndex = {0,1,2}
// 需要从第几行开始合并
int mergeRowIndex = 1;
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 设置文件名称
String fileName = URLEncoder.encode("测试导出", "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
// sheet名称
EasyExcel.write(response.getOutputStream(), ExcelMultipurposeDTO.class)
// excel版本
.excelType(ExcelTypeEnum.XLSX)
// 是否自动关流
.autoCloseStream(Boolean.TRUE)
.registerWriteHandler(new ExcelFillCellMergeStrategy(mergeRowIndex,mergeColumnIndex)).
sheet("测试导出").doWrite(resultList);
} catch (Exception e) {
e.printStackTrace();
}
package com.umasoft.modules.webapps.reportmanage.service.impl;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import java.util.List;
/**
* @author
* @date
*/
public class ExcelFillCellMergeStrategy implements CellWriteHandler {
private int[] mergeColumnIndex;
private int mergeRowIndex;
public ExcelFillCellMergeStrategy() {
}
public ExcelFillCellMergeStrategy(int mergeRowIndex, int[] mergeColumnIndex) {
this.mergeRowIndex = mergeRowIndex;
this.mergeColumnIndex = mergeColumnIndex;
}
@Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) {
}
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {
//当前行
int curRowIndex = cell.getRowIndex();
//当前列
int curColIndex = cell.getColumnIndex();
if (curRowIndex > mergeRowIndex) {
for (int i = 0; i < mergeColumnIndex.length; i++) {
if (curColIndex == mergeColumnIndex[i]) {
mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);
break;
}
}
}
}
private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {
//获取当前行的当前列的数据和上一行的当前列列数据,通过上一行数据是否相同进行合并
Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();
Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);
Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();
// 比较当前行的第一列的单元格与上一行是否相同,相同合并当前单元格与上一行
if (curData.equals(preData)) {
Sheet sheet = writeSheetHolder.getSheet();
List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();
boolean isMerged = false;
for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {
CellRangeAddress cellRangeAddr = mergeRegions.get(i);
// 若上一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元
if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {
sheet.removeMergedRegion(i);
cellRangeAddr.setLastRow(curRowIndex);
sheet.addMergedRegion(cellRangeAddr);
isMerged = true;
}
}
// 若上一个单元格未被合并,则新增合并单元
if (!isMerged) {
CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex);
sheet.addMergedRegion(cellRangeAddress);
}
}
}
}
代码逻辑大概是:如果第一列的内容一样,那就把这些列合并形成一对多的展现形式。
代码中指定合并第一列,所以是excel将“项目”列进行了合并,当然了,源数据的格式需要自己组装,下面附上源数据格式,仅供参考:
[
{
"site":"代理业务",
"project":"代理业务"
},
{
"site":"地铁3号线林场",
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"超市代理网点",
"currentTransAmount":0,
"stationName":"地铁3号线林场",
"yearServiceFee":0,
"currentTransCount":0
},
{
"site":"鸡鸣寺",
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"超市代理网点",
"currentTransAmount":0,
"stationName":"鸡鸣寺",
"yearServiceFee":0,
"currentTransCount":0
},
{
"site":"智汇APP微信充值结算",
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"超市代理网点",
"currentTransAmount":0,
"yearServiceFee":0,
"currentTransCount":0
},
{
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"超市代理网点",
"currentTransAmount":0,
"stationName":"小计",
"yearServiceFee":0,
"currentTransCount":0
},
{
"site":"仙林中心",
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"主卡代理充值",
"currentTransAmount":0,
"stationName":"仙林中心",
"yearServiceFee":0,
"currentTransCount":0
},
{
"site":"S8宁天线卸甲甸",
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"主卡代理充值",
"currentTransAmount":0,
"stationName":"S8宁天线卸甲甸",
"yearServiceFee":0,
"currentTransCount":0
},
{
"site":"江苏东方航空国际旅业公司燕归楼商务酒店",
"yearTransAmount":3,
"yearTransCount":1,
"currentServiceFee":0,
"project":"主卡代理充值",
"currentTransAmount":0,
"stationName":"东航燕归楼商务酒店",
"yearServiceFee":0,
"currentTransCount":0
},
{
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"主卡代理充值",
"currentTransAmount":3,
"stationName":"小计",
"yearServiceFee":0,
"currentTransCount":1
},
{
"site":"智汇APP支付宝充值结算",
"yearTransAmount":40689.86,
"yearTransCount":779,
"currentServiceFee":0,
"project":"其他代理网点",
"currentTransAmount":66849.86,
"stationName":"金尧标超 ",
"yearServiceFee":0,
"currentTransCount":878
},
{
"site":"智汇APP支付宝充值结算",
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"其他代理网点",
"currentTransAmount":66849.86,
"stationName":"金尧标超 ",
"yearServiceFee":0,
"currentTransCount":878
},
{
"site":"智汇APP支付宝充值结算",
"yearTransAmount":26160,
"yearTransCount":99,
"currentServiceFee":0,
"project":"其他代理网点",
"currentTransAmount":66849.86,
"stationName":"金尧生活超市",
"yearServiceFee":0,
"currentTransCount":878
},
{
"site":"智汇APP支付宝充值结算",
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"其他代理网点",
"currentTransAmount":66849.86,
"stationName":"金尧生活超市",
"yearServiceFee":0,
"currentTransCount":878
},
{
"site":"智汇APP支付宝充值结算",
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"其他代理网点",
"currentTransAmount":66849.86,
"stationName":"金尧生活超市",
"yearServiceFee":0,
"currentTransCount":878
},
{
"site":"智汇APP支付宝充值结算",
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"其他代理网点",
"currentTransAmount":66849.86,
"stationName":"金尧标超 ",
"yearServiceFee":0,
"currentTransCount":878
},
{
"site":"智汇APP支付宝充值结算",
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"其他代理网点",
"currentTransAmount":66849.86,
"stationName":"金尧标超 ",
"yearServiceFee":0,
"currentTransCount":878
},
{
"site":"智汇APP支付宝充值结算",
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"其他代理网点",
"currentTransAmount":66849.86,
"stationName":"金尧生活超市",
"yearServiceFee":0,
"currentTransCount":878
},
{
"site":"智汇APP支付宝充值结算",
"yearTransAmount":26160,
"yearTransCount":99,
"currentServiceFee":0,
"project":"其他代理网点",
"currentTransAmount":66849.86,
"stationName":"金尧标超 ",
"yearServiceFee":0,
"currentTransCount":878
},
{
"site":"智汇APP支付宝充值结算",
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"其他代理网点",
"currentTransAmount":66849.86,
"stationName":"金尧生活超市",
"yearServiceFee":0,
"currentTransCount":878
},
{
"site":"智汇APP支付宝充值结算",
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"其他代理网点",
"currentTransAmount":66849.86,
"stationName":"金尧标超 ",
"yearServiceFee":0,
"currentTransCount":878
},
{
"site":"智汇APP支付宝充值结算",
"yearTransAmount":40689.86,
"yearTransCount":779,
"currentServiceFee":0,
"project":"其他代理网点",
"currentTransAmount":66849.86,
"stationName":"金尧生活超市",
"yearServiceFee":0,
"currentTransCount":878
},
{
"site":"智汇APP支付宝充值结算",
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"其他代理网点",
"currentTransAmount":66849.86,
"stationName":"金尧标超 ",
"yearServiceFee":0,
"currentTransCount":878
},
{
"site":"智汇APP支付宝充值结算",
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"其他代理网点",
"currentTransAmount":66849.86,
"stationName":"金尧生活超市",
"yearServiceFee":0,
"currentTransCount":878
},
{
"site":"1号线南京站北广场",
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"其他代理网点",
"currentTransAmount":0,
"stationName":"1号线南京站北广场",
"yearServiceFee":0,
"currentTransCount":0
},
{
"site":"地铁3号线星火路",
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"其他代理网点",
"currentTransAmount":0,
"stationName":"地铁3号线星火路",
"yearServiceFee":0,
"currentTransCount":0
},
{
"yearTransAmount":133699.72,
"yearTransCount":1756,
"currentServiceFee":0,
"project":"其他代理网点",
"currentTransAmount":133699.72,
"stationName":"小计",
"yearServiceFee":0,
"currentTransCount":1756
},
{
"site":"自助业务",
"project":"自助业务"
},
{
"site":"扬子六合",
"yearTransAmount":5.5,
"yearTransCount":2,
"currentServiceFee":0,
"project":"银行渠道",
"currentTransAmount":0,
"yearServiceFee":0,
"currentTransCount":0
},
{
"site":"地铁4号线云南路",
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"银行渠道",
"currentTransAmount":0,
"stationName":"地铁4号线云南路",
"yearServiceFee":0,
"currentTransCount":0
},
{
"currentServiceFee":0,
"project":"银行渠道",
"currentTransAmount":5.5,
"stationName":"小计",
"currentTransCount":2
},
{
"site":"代收代付",
"project":"代收代付"
},
{
"site":"自有人工业务",
"project":"自有人工业务"
},
{
"site":"地铁1号线软件大道",
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"紫金卡充值",
"currentTransAmount":0,
"stationName":"地铁1号线软件大道",
"yearServiceFee":0,
"currentTransCount":0
},
{
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"紫金卡充值",
"currentTransAmount":0,
"stationName":"小计",
"yearServiceFee":0,
"currentTransCount":0
},
{
"site":"邻仕家江东南路店",
"yearTransAmount":22.8,
"yearTransCount":1,
"currentServiceFee":0,
"project":"吉利卡充值",
"currentTransAmount":0,
"yearServiceFee":0,
"currentTransCount":0
},
{
"site":"S8宁天线龙池",
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"吉利卡充值",
"currentTransAmount":0,
"stationName":"S8宁天线龙池",
"yearServiceFee":0,
"currentTransCount":0
},
{
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"吉利卡充值",
"currentTransAmount":22.8,
"stationName":"小计",
"yearServiceFee":0,
"currentTransCount":1
},
{
"site":"线上业务",
"project":"线上业务"
},
{
"site":"扬子六合",
"yearTransAmount":5.5,
"yearTransCount":2,
"currentServiceFee":0,
"project":"银行渠道",
"currentTransAmount":0,
"yearServiceFee":0,
"currentTransCount":0
},
{
"site":"地铁4号线云南路",
"yearTransAmount":0,
"yearTransCount":0,
"currentServiceFee":0,
"project":"银行渠道",
"currentTransAmount":0,
"stationName":"地铁4号线云南路",
"yearServiceFee":0,
"currentTransCount":0
},
{
"currentServiceFee":0,
"project":"银行渠道",
"currentTransAmount":5.5,
"stationName":"小计",
"currentTransCount":2
},
{
"site":"退值业务",
"project":"退值业务"
}
]
相对于easypoi而言,这样的方式实现复杂表头和动态合并列就简单多了,只需要将源数据的格式处理好,直接调用封装好的方法就可以。希望对大家有帮助,感谢阅读!