新人博主,随笔记录。主要还是通过自己日常工作积累,系统整理一些技术。希望能够节省更多人的时间,走出自己的路。
看了自己发的文章,可以帮助一些小伙伴很开心!!
上一篇文章主要用我个人觉得,效果很好的方法做excel的导出。但是那只是符合正常,简单的excel导出。可能很多小伙伴,会遇到一些复杂的样式的excel的导出。这一篇同样是用EasyExcel,主要是做一些数据格式复杂的excel,当然这一篇文章不包含复杂表头的excel导出
这一篇的环境和上一篇我们共用一个。因为都是用EasyExcel这个包中的API,所以没必要换一个工程。还不明白的小伙伴可以去瞟一眼我的上一篇文章Java从零开始实现导出excel(一)
这里同样用的是上一篇的实体。不过有点改变,我将性别这一列放开了。
这里有个需要注意的地方,因为EasyExcel是通过实体中@ExcelProperty注解中的index去匹配excel中的列,所以当我们不使用模板时,index一定要是连续且有效的,否则我们生成的excel中会出现空白表头列的情况
例如:下面这图是我没有放开性别那个字段时导出的excel表头
导出方法:
/**
* 使用EasyExcel导出excel
* @param response
* @throws Exception
*/
@GetMapping(value = "/exportExcel")
public void exportExcel(HttpServletResponse response) throws Exception {
response.setContentType("multipart/form-data");
response.setCharacterEncoding("utf-8");
response.setContentType("application/octet-stream;charset=utf-8");
LocalDate time = LocalDate.now();
String fileName = URLDecoder.decode("easyExcel导出_" + time, "UTF-8");
response.setHeader("Content-Disposition", "attachment; filename=\"" + new String(fileName.getBytes("gb2312"), "ISO8859-1") + ".xls" + "\"");
OutputStream out = response.getOutputStream();
List<Student> data = getData();
Map<Integer,String[]> map = new HashMap<>();
map.put(2,new String[]{
"男","女"});//下拉导出
ExcelUtil.exportBySelect(out,data,map);
out.close();
}
//封装导出数据
private List<Student> getData() {
List<Student> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Student student = new Student();
student.setName("测试学生姓名-" + i);
student.setAge(i);
student.setSex(i % 2 == 1 ? "男" : "女");
student.setNum(111111L);
student.setAddress("追晨始梦CSDN博客");
list.add(student);
}
return list;
}
工具类:
ExcelUtil
/**
* 功能描述: 导出数据到Excel
*
* 使用阿里easyPoi 自定义导出excel携带下拉框
*
* @param out 输出
* @param list 需写入的数据
* @param mapDropDown 下拉框数据
*/
public static void exportBySelect(OutputStream out, List<? extends BaseRowModel> list, Map<Integer, String[]> mapDropDown) {
EasyExcelFactory.write(out, list.get(0).getClass()).registerWriteHandler(new EasyExcelSheetSelectUtils(mapDropDown)).sheet().doWrite(list);
}
这个公共方法中,我们需要去调用registerWriteHandler方法:将我们创建的自定义拦截器放入其中。
这个拦截器是我们这篇文章的重点——直接代码看
EasyExcelSheetSelectUtils
package com.example.demo;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationConstraint;
import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.XSSFDataValidation;
import java.util.Map;
/**
* 自定义设置excel样式
*/
public class EasyExcelSheetSelectUtils implements SheetWriteHandler {
//第0列开始 设置某列的下拉内容
private Map<Integer,String[]> mapDropDown;
public EasyExcelSheetSelectUtils(Map<Integer, String[]> mapDropDown) {
this.mapDropDown = mapDropDown;
}
@Override
public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
}
/**
* 自定义设置excel样式
* @param writeWorkbookHolder
* @param writeSheetHolder
*/
@Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
//获取sheet页
Sheet sheet = writeSheetHolder.getSheet();
///开始设置下拉框 //设置下拉框
DataValidationHelper helper = sheet.getDataValidationHelper();
for (Map.Entry<Integer, String[]> entry : mapDropDown.entrySet()) {
/***起始行、终止行、起始列、终止列**/
CellRangeAddressList addressList = new CellRangeAddressList(1, 1000, entry.getKey(), entry.getKey());
/***设置下拉框数据**/
DataValidationConstraint constraint = helper.createExplicitListConstraint(entry.getValue());
DataValidation dataValidation = helper.createValidation(constraint, addressList);
/***处理Excel兼容性问题**/
if (dataValidation instanceof XSSFDataValidation) {
dataValidation.setSuppressDropDownArrow(true);
dataValidation.setShowErrorBox(true);
} else {
dataValidation.setSuppressDropDownArrow(false);
}
sheet.addValidationData(dataValidation);
}
//合并单元格
sheet.addMergedRegion(new CellRangeAddress(1, 2, 0, 0));
}
}
这个里面我写了两个常见的案例:
当然了,可能小伙伴们在实际工作中可能有很多不一样的需求,看完我的两个案例的实现,相信你所需要的样式,都可以自己实现。
这个功能可能模板导出时候,会更加方便一点。这里我觉得主要是一个思想
首先我们看实现的过程
我们自定义的拦截器一定要继承SheetWriteHandler这个接口
这个接口中有两个虚函数:
我们这里一般会用到下面那个函数 :afterSheetCreate
我们在自定义的拦截器中定义了一个私有属性mapDropDown,用来装下拉框的参数。用一个有参构造将我们需要的数据传进来
key: 表示第几列需要加入下拉框
value: 表示加入下拉框的值
这里我是只做了个案例,将excel表格中的第一列的第一行和第二行进行合并
有了这个sheet页的对象,那其他自定义功能的效果,小伙伴们可以发挥自己的技术,根据自己的需求完成excel导出!
源码链接
官方文档地址