马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
形貌
利用Java代码封装的一个Excel批量导入框架,利用EasyExcel完成excel文件方面的交互,重在整合功能,仅需少量代码就可以在本身的项目中快速引入该功能。可以流式分批读取Excel中的数据,克制OOM,利用多线程进步处置惩罚速率,异步线程处置惩罚便于前端查察导入进度与处置惩罚效果。
框架代码采取了操持模式中的战略模式,只必要实现此中的战略类(针对本身的业务来处置惩罚每行数据),就可以快速利用导入功能,而且给出了前端的配套代码示例(vue)。
demo项目所在:https://github.com/destinyol/excel-multi-import-progress
(demo项目不包罗数据库交互部门,以是无法运行,只是演示代码怎样利用)
框架项目文件结构:
ps:修改ExcelImportMainTool 中的 BATCH_COUNT 可自界说每次从excel中读取多少行数据,默认1000行
效果展示
可调参数
ExcelImportMainTool类中有一些可以根据现实情况自行调解的参数- public static final int BATCH_COUNT = 1000; // 批量处理,每批从excel中读取并处理的数据行数,可根据情况自行修改
- public int BATCH_INSERT_COUNT = 200; // 使用批量插入时的每批次处理数量(传入handleMultiDataAndSave函数的数组大小),可根据情况自行修改,可动态设置
- public static final boolean PROCESS_SAVE_RESULT_LIST = true; // redis保存进度条时是否保存报错结果数组ExcelResDto,true保存,false不保存
复制代码 利用方法
1、继续EasyExcelReadDataAbstract抽象类并实现此中EasyExcelReadData接口的方法,该子类是对应EasyExcel导入的实体类,用来存储单行数据,必要实现此中的方法- public interface EasyExcelReadData {
- /**
- * 去掉每个字段首尾空格(若不需要则方法体为空即可)
- * (处理过程中每行会调用一次)
- */
- public void trimAllFields();
- /**
- * 为了排除表格空行(建议实现该方法,空行比较容易出现)
- * 检查该行中的每个属性是否都为null或空字符串,如果是,则返回true;否则返回false
- * (处理过程中每行会调用一次)
- */
- public boolean dataIsAllEmpty();
- }
复制代码 比方:- @Data
- public class CustomerImportDto extends EasyExcelReadDataAbstract {
- @ExcelProperty(value = "客户名称")
- private String name;
- @ExcelProperty(value = "手机号")
- private String phone;
- // ***********************
- // 省略各种字段
-
-
- @Override
- public boolean dataIsAllEmpty(){
- return (name == null || name.isEmpty()) &&
- (phone == null || phone.isEmpty());
- }
- @Override
- public void trimAllFields() {
- if (name != null) name = name.trim();
- if (phone != null) phone = phone.trim();
- }
- }
复制代码 2、实现DataDealHandler接口及对应方法,该实现类是用于自界说的数据处置惩罚与生存,便于衔接差别的业务场景
(要用批量插入就实现handleMultiDataAndSave方法,要用逐条插入就实现handleOneDataAndSave)- public interface DataDealHandler {
- /**
- * 返回模板表头行数(根据对应模板配置实现该方法,例如表头三行:return 3;)
- * @return
- */
- public Integer getHeadRows();
- /**
- * 处理单条数据(比如去重,特殊判断,或者其他自定义业务)
- * 并自行保存该条数据到数据库
- * @param importData EasyExcelReadDataAbstract的子类
- * @return 返回结果内容(显示给前端,表格行号+错误内容)。若返回类为null,则该条数据导入成功,不用显示;若不为null,则将其放入错误结果集中
- */
- @Transactional(rollbackFor = Exception.class)
- default public ExcelResDto handleOneDataAndSave(EasyExcelReadData importData){
- throw new RuntimeException("未实现逐条插入数据处理函数handleOneDataAndSave");
- }
- /**
- * 批量处理数据(比如去重,特殊判断,或者其他自定义业务)
- * 并自行保存数据到数据库,若抛出错误则这一批全部回滚
- * @param importDataList EasyExcelReadDataAbstract的子类list
- * @return 返回结果内容数组(显示给前端,表格行号+错误内容)。若数组长度为0,则全部成功;如果长度大于0,则将其放入错误结果集中
- */
- @Transactional(rollbackFor = Exception.class)
- default public List<ExcelResDto> handleMultiDataAndSave(List<EasyExcelReadData> importDataList){
- throw new RuntimeException("未实现批量插入数据处理函数handleMultiDataAndSave");
- }
- }
复制代码 3、直接调用- // --------------------------------------导入任务启动的地方---------------------------------
- // 构造DataDealHandler的实现类的实例对象
- DataDealHandlerImpl handler = new DataDealHandlerImpl(xxxxx,xxxxx自定义构造);
- // 启动导入主函数并异步执行,返回redis中保存的该进度的processKey,可以直接返回给前端用于查询进度
- // (逐条插入,需实现对应方法)
- String processKey = ExcelImportMainTool.buildImport(
- EasyExcelReadDataAbstract的子类.class,
- handler,
- redisTemplate // 进度保存在redis中,所以需要自行注入redisTemplate
- ).runAsyncSingle(multipartFile);
- // (批量插入,需实现对应方法)
- String processKey = ExcelImportMainTool.buildImport(
- EasyExcelReadDataAbstract的子类.class,
- handler,
- redisTemplate // 进度保存在redis中,所以需要自行注入redisTemplate
- ).setBatchInsertCount(250) // 设置批量插入每批传入`DataDealHandler`中的数据量,不设置则默认200行
- .runAsyncMulti(multipartFile);
复制代码- // ---------------------------------------轮询或其他手段,获取任务进度-----------------------
- // 获取进度(静态方法,需传入redisTemplate)
- ImportProgress progress = ExcelImportMainTool.getProgress(redisTemplate, processKey);
复制代码 至此整个功能就跑起来了
利用示例
数据实体类实现类- /**
- * 示例:easyExcel导入的数据实体类
- * ( EasyExcelReadDataAbstract的子类 )
- */
- @Data
- public class CustomerImportDto extends EasyExcelReadDataAbstract {
- @ExcelProperty(value = "销售")
- private String saleUserName;
- @ExcelProperty(value = "客户名称")
- private String name;
- @ExcelProperty(value = "联系人")
- private String contacts;
- @ExcelProperty(value = "联系电话")
- private String phone;
- @ExcelProperty(value = "统一社会信用代码")
- private String sucCode;
- @ExcelProperty(value = "法人")
- private String legalPerson;
- @ExcelProperty(value = "注册资本(单位万元)")
- private String registerMoney;
- @ExcelProperty(value = "客户地址")
- private String address;
- /**
- * 检查类中的每个属性是否为null或空字符串,如果是,则返回true;否则返回false
- * @return
- */
- @Override
- public boolean dataIsAllEmpty(){
- return (saleUserName == null || saleUserName.isEmpty()) &&
- (name == null || name.isEmpty()) &&
- (contacts == null || contacts.isEmpty()) &&
- (phone == null || phone.isEmpty()) &&
- (sucCode == null || sucCode.isEmpty()) &&
- (legalPerson == null || legalPerson.isEmpty()) &&
- (registerMoney == null || registerMoney.isEmpty()) &&
- (address == null || address.isEmpty());
- }
- @Override
- public void trimAllFields() {
- if (saleUserName != null){
- saleUserName = saleUserName.replaceAll("\\s+", "");
- }
- if (name != null) name = name.trim();
- if (contacts != null) contacts = contacts.trim();
- if (phone != null) phone = phone.trim();
- if (sucCode != null) sucCode = sucCode.trim();
- if (legalPerson != null) legalPerson = legalPerson.trim();
- if (registerMoney != null) registerMoney = registerMoney.trim();
- if (address != null) address = address.trim();
- }
- }
复制代码 战略类实现类接口示例- /**
- * excel 导入客户
- * @return
- */
- @PostMapping("/importExcel")
- public Response importExcel(MultipartFile file){
- Response response = new Response();
- response.ret(0,"成功了");
- try {
- CustomerImportDataHandler handler = new CustomerImportDataHandler(userMapper,tdCustomerMapper);
- // 逐条插入
- String processKey = ExcelImportMainTool.buildImport(CustomerImportDto.class, handler, redisTemplate).runAsyncSingle(file);
- // 批量插入
- // String processKey = ExcelImportMainTool.buildImport(CustomerImportDto.class, handler, redisTemplate).runAsyncMulti(file);
- response.setData(processKey);
- } catch (Exception e) {
- e.printStackTrace();
- response.ret(111000,"出错了");
- }
- return response;
- }
- /**
- * 获取进度
- * @return
- */
- @GetMapping("/getProgress")
- public Response getProgress(String key){
- Response response = new Response();
- response.ret(0,"成功了");
- try {
- ImportProgress progress = ExcelImportMainTool.getProgress(redisTemplate, key);
- response.setData(progress);
- } catch (Exception e) {
- e.printStackTrace();
- response.ret(111001,"出错了");
- }
- return response;
- }
复制代码 |