多种类型的数据导出
一、前言
我们在使用EasyExcel导出的时候,通常都是通过EasyExcel.write(OutputStream outputStream, Class head)
,这里的Class就是我们需要导出的实体类,一般情况下我们传入一个实体,就能导出数据。
但有时候一个页面中有几个tab页的情况,如果我想分别导出每个tab页的信息,这个时候我们会根据tab页类型去导出各个tab页的数据。如果只有一两个tab页的话,我们可以使用if-else
来判断,但是如果有四五个tab页的话,用if-else
的话,代码就会显得很臃肿。
为解决这个问题,我们就用到了策略模式
和函数式编程
来实现多种类型的数据导出功能。
二、准备工作
2.1 准备一个导出的类DemoDTO.java
,该DTO为数据库查询出来的数据
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class DemoDTO implements Serializable {
// 其他属性
// ....
private Demo1DTO demo1DTO;
private Demo2DTO demo2DTO;
}
2.1. 准备一个导出的基类ExportBaseDTO.java
,定义公共的属性,如:index:序号;createTime:创建时间…其他导出的类继承这个基类
@Data
public class ExportBaseDTO extends BaseRowModel {
@ExcelProperty(index = 0, value = "序号")
private String index;
@ExcelProperty(value = "创建时间")
private String createTime;
}
2.2. 准备2个导出的类Demo1ExportDTO.java
、Demo2ExportDTO.java
,定义自己的属性,并继承基类ExportBaseDTO.java
注:这里创建2个类做实例,具体根据自己业务需要创建导出的类
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Demo1ExportDTO extends ExportBaseDTO {
@ExcelProperty(value = "编号")
private String appNo;
@ExcelProperty(index = 1, value = "买方")
private String buyerName;
@ExcelProperty(index = 2, value = "卖方")
private String sellerName;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Demo2ExportDTO extends ExportBaseDTO {
@ExcelProperty(value = "编号")
private String appNo;
@ExcelProperty(value = "项目名称")
private String projectName;
}
三、具体实现
3.1 定义2个map和1个List,classHeadMap
、copyStrategies
和excludeCols
private Map<TypeEnum, Class<? extends ExportBaseDTO>> classHeadMap = new HashMap<>();
private Map<TypeEnum, CopyPropertiesStrategy> copyStrategies = new HashMap<>();
private List<String> excludeCols = new ArrayList<>();
classHeadMap:key为导出的类型,value为对应的导出实体;
copyStrategies:key为导出的类型,value为策略的接口;
excludeCols:导出的时候某些属性不导出
3.2 定义一个接口
interface CopyPropertiesStrategy {
void copyProperties(String index, DemoDTO demoDTO, List<ExportBaseDTO> data);
}
3.3 在Bean
初始化的时候给map
和list
赋值
@PostConstruct
private void init() {
if (classHeadMap.isEmpty()) {
classHeadMap.put(TypeEnum.DEMO1, Demo1ExportDTO.class);
classHeadMap.put(TypeEnum.DEMO2, Demo2ExportDTO.class);
}
if (copyStrategies.isEmpty()) {
copyStrategies.put(TypeEnum.DEMO1, ((index, demoDTO, data) -> {
Demo1ExportDTO demo1ExportDTO = new Demo1ExportDTO();
Demo1DTO demo1DTO = demoDTO.getDemo1ExportDTO();
BeanUtils.copyProperties(demo1DTO, demo1ExportDTO);
// 设置值
demo1ExportDTO.setIndex(index);
data.add(demo1ExportDTO);
}));
copyStrategies.put(TypeEnum.DEMO2, (index, demoDTO, data) -> {
Demo2DTO demo2DTO = demoDTO.getDemo2ExportDTO();
BeanUtils.copyProperties(demo2DTO, demo2ExportDTO);
// 设置值
demo2ExportDTO.setIndex(index);
data.add(demo2ExportDTO);
});
}
if (excludeCols.isEmpty()) {
// 忽略字段
excludeCols.add("appNo");
}
}
3.4 导出方法
@Override
public void export(HttpServletResponse response, TypeEnum type, RoleEnum roleEnum, List<DemoDTO> DemoList) throws IOException {
setExportHeader(response, type);
List<ExportBaseDTO> data = new ArrayList<>();
if (CollectionUtils.isNotEmpty(DemoList)) {
int index = 0;
for (DemoDTO demoDTO : DemoList) {
copyStrategies.get(type).copyProperties(String.valueOf(++index), demoDTO, data);
}
}
if (factorRoleEnum.equals(RoleEnum.TEST_ROLE)) {
EasyExcel.write(response.getOutputStream(), classHeadMap.get(type)).excludeColumnFiledNames(excludeCols).sheet(type.getDisplayName()).registerWriteHandler(new CustomCellWriteWeightConfig()).doWrite(data);
} else {
EasyExcel.write(response.getOutputStream(), classHeadMap.get(type)).sheet(type.getDisplayName()).registerWriteHandler(new CustomCellWriteWeightConfig()).doWrite(data);
}
}
private static void setExportHeader(HttpServletResponse response, TypeEnum type) throws UnsupportedEncodingException {
String newFileName = new String((type.getDisplayName() +
"_" +
(new SimpleDateFormat("yyyyMMdd")).format(new Date())).getBytes(), "UTF-8") +
".xlsx";
response.setHeader("Content-Disposition", "attachment;filename=\"" + URLEncoder.encode(newFileName, "UTF-8") + "\"");
response.setContentType("application/octet-stream");
}
四、总结
以上便是使用策略模式
和函数式编程
的方式实现多种tab页的导出功能,通过策略模式来消除if-else
,使得代码尽量不那么臃肿。另外通过函数式编程,让数据在调用的时候填充到指定的DTO中。