本文参考文档:
SpringBoot整合EasyExcel实现
Java+EasyExcel实现文件导入导出,导入导出如此简单
导出导入一般使用阿里巴巴的easyexcel 阿帕奇的poi; 简单的一般建议使用easyexcel使用更方便,excel单元格合并等复杂操作推荐使用poi
这里
本篇文章使用easyexcel讲解导入导出
1. 引入pom依赖
<!--easyExcel-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
</dependency>
2.excel文件导出
导出时要设置导出文件名已经编码格式等,这些代码抽取出来封装为工具类
public class ExportUtil {
public static void setFilename(HttpServletResponse response, String prefix) throws IOException {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode(prefix + "_" + DateFormatUtils.format(new Date(), "yyyyMMddHHmmss"), "UTF-8");
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + fileName + ".xlsx");
}
}
导出时要考虑数据量的问题,建议使用分页查询,或者游标分页,循环写入流中;
示例中导出的不是实体类,而是Map
所以这里表头是在代码中封装,没有在实体类添加注解@ExcelProperty("商品编号")
这里用Map是因为要做动态的导出,代码中有些是我的特殊逻辑,不用关注,后面我会写段伪代码方便大家看
public void exportBK(HttpServletResponse response, OverviewSearch search) throws IOException, ParseException {
// bkObjId可以理解为是哪个表的唯一ID, 这里不用关注
String bkObjId = search.getBkObjId();
//每个List<String>是一个表头字段,用List<List<String>>表头有序
// 并且查询表格数据后,每条数据中的字段处理,与head的有序集合顺序一致
List<List<String>> head = new ArrayList<>();
List<String> propertyIds;
//我的表格是动态表头,每个人可以自定义选择表头,每个人的表头会保存到数据库
//这里是查询当前用户 当前表格的表头字段
List<ObjAttDes> objAttDes = objAttDesService.searchByBkObjId(bkObjId);
//封装表头数据类型 List<List<String>>
propertyIds = objAttDes.stream().map(ObjAttDes::getBkPropertyId).collect(Collectors.toList());
objAttDes.forEach(objAttDe -> {
List<String> list = new ArrayList<>();
list.add(objAttDe.getBkPropertyName());
head.add(list);
});
ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).head(head).build();
//新建一个空的Excel工作簿,填充值后将值写入流中
WriteSheet writeSheet = EasyExcel.writerSheet(bkObjId).build();
try {
int pageNum = 1;
int pageSize = 200;
while (true){
//设置分页
search.setPageNum(pageNum);
search.setPageSize(pageSize);
//分页查询
List<Map<String, Object>> info = overviewService.searchBKInst(search).getInfo();
//我的代码特殊逻辑,做了很多特殊处理,例如时间,数组,枚举,不用关注
objAttDesService.formatInst(search.getBkObjId(), info);
// 查询出来的数据,但是用户自定义的表头是部分字段
//按照用户保存表头字段顺序,重新组织数据 和表头照应, 这里List<Object>就是一条数据
List<List<Object>> dataList = new ArrayList<>();
info.forEach(map -> {
List<Object> list = new ArrayList<>();
for (String propertyId : propertyIds) {
Object value = map.get(propertyId);
list.add(value);
}
dataList.add(list);
});
//工作簿填充数据 填充值后将值写入流中
excelWriter.write(dataList, writeSheet);
//查询结果数据,不满pageSize 结束循环
if(info.size() < pageSize){
break;
}
//翻页
pageNum++;
}
} finally {
if (excelWriter != null) {
excelWriter.finish();
}
}
}
伪代码示例:
ExportUtil.setFilename(response, "导出文件名");
//每个List<String>是一个表头字段,用List<List<String>>表头有序
// 并且查询body数据后,每条数据中的字段处理,与head的有序集合顺序一致
List<List<String>> head = new ArrayList<>();
List<List<Object>> dataList = new ArrayList<>();
//这里设置单元格样式字体策略等
ExcelWriter excelWriter = EasyExcel.write(httpServletResponse.getOutputStream()).head(head).build();
//工作簿名称可以不设置
WriteSheet writeSheet = EasyExcel.writerSheet("工作簿名称").build();
try {
int start = 0;
int limit = 500;
while (true) {
//查询数据
List<Map<String, Object>> maps = findPage(start,limit);
if (maps.isEmpty()) {
break;
}
excelWriter.write(dataList, writeSheet);
start += limit;
}
} finally {
if (excelWriter != null) {
excelWriter.finish();
}
}
当然如果你导出的不是动态表头的表格,完全可以用实体类映射,下面我用实例类注解方式@ExcelProperty封装一个通用的导出组件,当然你也可以仿照@ExcelProperty 自定义一个注解;
这个组件没有做分页查询当数据量大时,会存在问题,大家可以自己改造写,这里我就不再搞了,如果有需要可以给我评论,后面我再加上
@Component
@Slf4j
@ServiceMethodLog(printParams = false)
public class ExportComponent {
@Autowired
ObjectMapper objectMapper;
public void export(HttpServletResponse response, Supplier supplier) throws Exception {
//获取数据 这里使用供给式函数接口 参数例如 ()-> xxxMapper.queryDetails()
List dbData = supplier.get();
if (CollectionUtils.isEmpty(dbData)) {
throw new ApplicationException(ExceptionEnum.SPOT_BUGS_METHOD_RETURN_NULL);
}
Field[] fields = dbData.get(0).getClass().getDeclaredFields();
List<String> headIds = new ArrayList<>(fields.length);
//表头
List<List<String>> head = new ArrayList<>(fields.length);
//数据
List<List<Object>> data = new ArrayList<>(dbData.size());
//封装表头
for (Field field : fields) {
field.setAccessible(true);
ExcelProperty annotation = field.getAnnotation(ExcelProperty.class);
if (annotation == null || StringUtils.isBlank(annotation.value()[0])) {
continue;
}
head.add(Collections.singletonList(annotation.value()[0]));
headIds.add(field.getName());
}
//封装数据
List<Map<String, Object>> maps = objectMapper.readValue(objectMapper.writeValueAsString(dbData), new TypeReference<List<Map<String, Object>>>() {
});
maps.forEach(map -> {
List<Object> list = new ArrayList<>(fields.length);
for (String headId : headIds) {
list.add(map.get(headId));
}
data.add(list);
});
ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).head(head).build();
WriteSheet writeSheet = EasyExcel.writerSheet().build();
try {
excelWriter.write(data, writeSheet);
} finally {
if (excelWriter != null) {
excelWriter.finish();
}
}
}
}
这种导出非常适合做游标查询,游标查询可参考文章完成www.cnblogs.com/jingzh/p/17…