EasyExcel 导出动态表格
一般推荐使用方法二,但方法一也一定要看,会有很多收获。
需求
:前端选择对应列,导出对应列的数据,比如前端选择了 姓名、名称、学号列
那么就需要导出如下表格:
ok,需求明确。
方法一 (推荐待选字段过多不用写VO的情况)
① 通过反射拿到实体对应的字段、属性等信息,返给前端供前端选择。
这里利用了@TableField 、@ApiModelProperty
注解拿到对应的
注释(name)、字段名(filedName)、数据库字段名(key)
public List<Map<String, String>> getFields() {Field[] declaredFields = HbProjectInfo.class.getDeclaredFields();List<Map<String, String>> resultList = new ArrayList<>();for (Field field : declaredFields) {if (field.isAnnotationPresent(TableField.class) && field.getAnnotation(TableField.class).exist()) {Map<String, String> map = new HashMap<>();String key = field.getAnnotation(TableField.class).value();String name = null;if (field.isAnnotationPresent(ApiModelProperty.class)) {name = field.getAnnotation(ApiModelProperty.class).value();}map.put("key", key);map.put("name", name);map.put("filedName", field.getName());resultList.add(map);}}return resultList;}
结果JSON
[{"filedName": "name","name": "名字","key": "NAME"},{"filedName": "age","name": "年龄","key": "AGE"},{"filedName": "studentId","name": "学号","key": "STUDENT_ID"}
]
② 前端选择后,传给后端
后端传入的 JSON ,比如他选了 年龄、年龄两个字段
[{"filedName": "name","name": "名字","key": "NAME"},{"filedName": "age","name": "年龄","key": "AGE"}
]
③ 后端接口:
studentService 是自己的实现类,自己 @AutoWired 出来即可
@PostMapping("/export")@ApiOperation(value = "学员信息导出", notes = "")public AjaxResult export(HttpServletResponse response, @RequestBody List<Map<String,String>> headList) throws Exception {studentService.export(response,headList);return AjaxResult.success("导出成功!");}
④ 实现我们的 export 方法 下面是正文,请好好看
public void export(HttpServletResponse response,List<Map<String,String>> headList) throws Exception {if(CollectionUtils.isEmpty(headList)){headList = hbProjectInfoService.getFields();}List<String> names = headList.stream().map(m -> m.get("name")).collect(Collectors.toList());List<String> keys = headList.stream().map(m -> m.get("key")).collect(Collectors.toList());List<String> filedNames = headList.stream().map(m -> m.get("filedName")).collect(Collectors.toList());//表头List<List<String>> heads = new ArrayList<>();String title = "数据导出";for (String name : names) {List<String> head0 = new ArrayList<>();head0.add(title);head0.add(name);heads.add(head0);}//填充数据List<List<Object>> dataList = new LinkedList<>();String join = String.join(",", keys);List<Student> list = studentService.getColumnsData(join);for (Student student: list) {List<Object> objectList = new LinkedList<>();Class<? extends Student> ac = Student.getClass();for (String name : filedNames) {Field field = ac.getDeclaredField(name);field.setAccessible(true);Object o = field.get(hbProjectInfo);objectList.add(o);}dataList.add(objectList);}// 头的策略WriteCellStyle headWriteCellStyle = new WriteCellStyle();// 背景设置为白色headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());WriteFont headWriteFont = new WriteFont();headWriteFont.setFontHeightInPoints((short)16);headWriteCellStyle.setWriteFont(headWriteFont);// 内容的策略WriteCellStyle contentWriteCellStyle = new WriteCellStyle();// 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);//设置边框contentWriteCellStyle.setBorderTop(BorderStyle.THIN);contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);contentWriteCellStyle.setBorderRight(BorderStyle.THIN);contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);//居中contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);// 背景白色contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());WriteFont contentWriteFont = new WriteFont();// 字体大小contentWriteFont.setFontHeightInPoints((short)12);contentWriteCellStyle.setWriteFont(contentWriteFont);// 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);// 设置响应头// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postmanresponse.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf-8");// 这里URLEncoder.encode可以防止中文乱码 当然和 easyexcel 没有关系String fileName = URLEncoder.encode("学员信息表", "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");// 先仅仅写入头,再以不写入头的方式写入数据EasyExcel.write(response.getOutputStream()).head(heads).registerWriteHandler(horizontalCellStyleStrategy)//列宽自适应.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())//设置头部和内容的行高.registerWriteHandler(new SimpleRowHeightStyleStrategy((short)50,(short)30)).sheet("学员信息表").doWrite(dataList);}
结果就是:
你也可以了解各种策略,来实现你的目的,但是我是真的没再官网知道 EasyExcel 的所有 策略,网上也找不到适合我的,就只能从官网上拼拼凑凑这么个东西。
方法二 (一般情况下推荐)
使用 includeColumnFieldNames
includeSet
为动态表头的 code
是个 Set<String>
,dataList
为数据,这里需要一个 List <Student >
让实体的字段名称与 includeSet 的 code 对应上即可。
@Data
public class Student {@ExcelProperty(value = {"学员基本信息","姓名"},order = 0)private String name;@ExcelProperty(value = {"学员基本信息","年龄"},order = 1)private String age;@ExcelProperty(value = {"学员基本信息","学号"},order = 2)private String studentID;
}
具体实现代码:
public void getStudent(HttpServletResponse response) throws Exception {//这里我是写死的,你可以让前端传Set<String> headList = new HashSet<>();headList.add("name");headList.add("age");//数据List<Student> dataList = new LinkedList<>();Student student = new Student();student.setName("张三");student.setAge("12");student.setStudentID("12123213");dataList.add(student);Student student1 = new Student();student1.setName("李四");student1.setAge("13");student1.setStudentID("32432432");dataList.add(student1);response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf-8");// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系String fileName = URLEncoder.encode("学员基本信息", "UTF-8").replaceAll("\\+", "%20");// 设置Content-Disposition属性值response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");EasyExcel.write(response.getOutputStream(), Student.class).includeColumnFieldNames(headList).registerWriteHandler(new ExcelWidthStyleStrategy()).registerWriteHandler(new ExcelHeightStyleStrategy()).registerWriteHandler(new HbTableStyle()).sheet("学员基本信息").doWrite(dataList);}
HbTableStyle
类:方法一的头部策略、内容策略一致,直接使用改类即可,他们都共同继承了 AbstractVerticalCellStyleStrategy
public class HbTableStyle extends AbstractVerticalCellStyleStrategy {public HbTableStyle() {}@Overrideprotected WriteCellStyle headCellStyle(Head head) {// 头的策略WriteCellStyle headWriteCellStyle = new WriteCellStyle();// 背景设置为白色headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());WriteFont headWriteFont = new WriteFont();headWriteFont.setFontHeightInPoints((short)16);headWriteCellStyle.setWriteFont(headWriteFont);return headWriteCellStyle;}@Overrideprotected WriteCellStyle contentCellStyle(Head head) {// 内容的策略WriteCellStyle contentWriteCellStyle = new WriteCellStyle();// 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);//设置边框this.setBorderStyle(contentWriteCellStyle);//居中contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);// 背景白色contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());WriteFont contentWriteFont = new WriteFont();// 字体大小contentWriteFont.setFontHeightInPoints((short)12);contentWriteCellStyle.setWriteFont(contentWriteFont);return contentWriteCellStyle;}private static void setBorderStyle(WriteCellStyle contentWriteCellStyle){//设置边框样式contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);contentWriteCellStyle.setBorderTop(BorderStyle.THIN);contentWriteCellStyle.setBorderRight(BorderStyle.THIN);contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);}
}
总结:
区别:方法一灵活,想怎么玩怎么玩,不用定义实体,有点复杂
方法二,简单方便,实用于大部分业务,比起方法一可能没那么灵活,但也够用了。
更多的API使用请查询官网:EasyExcel官网
我就是没仔细看官网API下面有很多的参数配置,只看了基础文档,才写出的方法一。希望大家以后看文档,仔细认真。