人力资源网站怎么建设,网站营销推广计划书,网站建设内容介绍,wordpress怎么添加子目录1 问题背景 需求要做一个导出excel的功能 2 前言 本篇着重阐述后端怎么实现#xff0c;前端实现的部分只会粗略阐述。该实现方案是经过生产环境考验的#xff0c;不是那些拿来练手的小demo。本文阐述的方案可以借鉴用来做毕设或者加到自己玩的项目中去。再次声明#xff0c;…
1 问题背景 需求要做一个导出excel的功能 2 前言 本篇着重阐述后端怎么实现前端实现的部分只会粗略阐述。该实现方案是经过生产环境考验的不是那些拿来练手的小demo。本文阐述的方案可以借鉴用来做毕设或者加到自己玩的项目中去。再次声明本文是百万级数据量的企业级解决方案不是学校里面的毕设或者自己搭环境玩玩的小demo。客户不会去一页一页地点击导出本文阐述的是一键导出几千行甚至上万行的数据。如果本文与你了解到的方案有出入可以在评论区交流像那种导出几行或十来行的方案就不要说了。有读者在评论里提问“请教百万行能撑住吗”笔者没有去验证有兴趣或者有疑问的读者可以去验证下本文的解决方案是导出几千或上万行数据。本文也只是想介绍电商生产环境中真实的需求以及真实的解决方案如果要导出百万行那就只能采用异步方式去进行导出了文末有提供思路。 3 实现思路
后端查询要导出的数据此处简称data使用阿里的EasyExcel组件将data写到HttpServletResponse里面返回指定的响应头、响应内容的类型、字符编码。响应出去的数据是二进制数据此处简称bytes数据前端使用前端框架提供的方法将 bytes数据转成blob然后生成下载地址然后进行下载
4 后端实现 要引入阿里的EasyExcel依赖此处不赘述 dependencygroupIdcom.alibaba/groupIdartifactIdeasyexcel/artifactIdversion2.1.7/version/dependency下面是excel文件要保存的信息需要指定列头 Data
public class UserInfoVO {ExcelProperty(value 用户ID,index 0)private Long id;ExcelProperty(value 用户姓名,index 1)private String username;ExcelProperty(value 性别,index 2)private String sex;
}导出的伪代码如下 PostMapping(/xx/xxx/xxx)public void export(HttpServletResponse reponse) {// 设置响应头等response.setHeader(Content-Disposition, attachment;filename 文件名(随便定义).xlsx);response.setContentType(application/vnd.ms-excel);response.setCharacterEncoding(UTF-8);// 查数据假如要导出UserInfo的列表信息ListUserInfoVO data selectData();// 导出数据 EasyExcel.write(response.getOutputStream()).head(UserInfoVO.class).sheet().doWrite(data);}5 设置Excel自适应列宽 思路实现easyexcel提供的类并重写方法写数据到HttpServletReponse的时候注册一个自适应列宽的bean 实现AbstractColumnWidthStyleStrategy类如下所示 public class CustomCellWriteWeightConfig extends AbstractColumnWidthStyleStrategy {private MapInteger, MapInteger, Integer CACHE new HashMap();Overrideprotected void setColumnWidth(WriteSheetHolder writeSheetHolder, ListCellData cellDataList, Cell cell, Head head, Integer integer, Boolean isHead) {boolean needSetWidth isHead || !CollectionUtils.isEmpty(cellDataList);if (needSetWidth) {MapInteger, Integer maxColumnWidthMap CACHE.get(writeSheetHolder.getSheetNo());if (maxColumnWidthMap null) {maxColumnWidthMap new HashMap();CACHE.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap);}Integer columnWidth this.dataLength(cellDataList, cell, isHead);if (columnWidth 0) {if (columnWidth 254) {columnWidth 254;}Integer maxColumnWidth maxColumnWidthMap.get(cell.getColumnIndex());if (maxColumnWidth null || columnWidth maxColumnWidth) {maxColumnWidthMap.put(cell.getColumnIndex(), columnWidth);Sheet sheet writeSheetHolder.getSheet();sheet.setColumnWidth(cell.getColumnIndex(), columnWidth * 256);}}}}/*** 计算长度* param cellDataList* param cell* param isHead* return*/private Integer dataLength(ListCellData cellDataList, Cell cell, Boolean isHead) {if (isHead) {return cell.getStringCellValue().getBytes().length;} else {CellData cellData cellDataList.get(0);CellDataTypeEnum type cellData.getType();if (type null) {return -1;} else {switch (type) {case STRING:// 换行符数据需要提前解析好int index cellData.getStringValue().indexOf(\n);return index ! -1 ?cellData.getStringValue().substring(0, index).getBytes().length 1 : cellData.getStringValue().getBytes().length 1;case BOOLEAN:return cellData.getBooleanValue().toString().getBytes().length;case NUMBER:return cellData.getNumberValue().toString().getBytes().length;default:return -1;}}}}
}注册自适应列宽的组件 EasyExcel.write(response.getOutputStream()).head(SubscriptionOrderExportResp.class)// 注册自适应列宽组件.registerWriteHandler(new CustomCellWriteWeightConfig()).sheet().doWrite(data);6 方案优缺点
优点实现简单轻量级。能快速迭代上线 。
缺点使用了同步方式返回数据如果excel文件的数据量很多那么将耗费很多时间甚至http连接已经断开了还未响应出去。
改进本文解决方案是采用了同步方式导出实时返回excel文件。可以做一个异步方式后端创建一个任务异步生成excel文件然后文件上传到对象存储服务器。前端轮询任务是否完成后端返回文件地址给前端下载。