使用easy excel导入excel数据到系统

1、自定义校验注解

/*** <p>Excel导入Decimal类型校验</p>*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelDecimalValid {String min();String max();String message() default "小数类型数字填写超出范围";
}
/**
* <p>Excel导入正则表达式校验</p>
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelPatternValid {String regexp() default "";String name() default "";String message() default "不符合规则";
}/*** <p>Excel导入Int类型校验</p>*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelIntValid {int min();int max();String message() default "整数数字填写超出范围";
}/*** <p>Excel导入字符串长度校验</p>*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelStrValid {int length() default 0;String message() default "文字填写超出长度要求";
}/*** <p>Excel导入必填校验注解</p>*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelValid {String message() default "导入有未填入的字段";/*** 表头字段*/String name() default "";
}

2、校验类

/*** <p>Excel导入字段校验</p*/
public class ExcelImportValid {/*** Excel导入字段校验** @param object 校验的JavaBean 其属性须有自定义注解*/@SneakyThrowspublic static void valid(Object object) throws ExcelValidException {Field[] fields = object.getClass().getDeclaredFields();for (Field field : fields) {//设置可访问field.setAccessible(true);//属性的值Object fieldValue = null;try {fieldValue = field.get(object);} catch (IllegalAccessException e) {throw new RuntimeException(e);}//是否包含必填校验注解boolean isExcelValid = field.isAnnotationPresent(ExcelValid.class);if (isExcelValid && Objects.isNull(fieldValue)) {String name = field.getAnnotation(ExcelValid.class).name();throw new ExcelValidException("【" + name + "】列有未填值项");}//是否包含字符串长度校验注解boolean isExcelStrValid = field.isAnnotationPresent(ExcelStrValid.class);if (isExcelStrValid) {String cellStr = fieldValue.toString();int length = field.getAnnotation(ExcelStrValid.class).length();if (StringUtils.isNotBlank(cellStr) && cellStr.length() > length) {throw new ExcelValidException(field.getAnnotation(ExcelStrValid.class).message());}}//是否包含int类型校验注解boolean isExcelIntValid = field.isAnnotationPresent(ExcelIntValid.class);if (isExcelIntValid) {if (fieldValue instanceof Integer) {int cellInt = Integer.parseInt(fieldValue.toString());int min = field.getAnnotation(ExcelIntValid.class).min();int max = field.getAnnotation(ExcelIntValid.class).max();if (cellInt < min || cellInt > max) {throw new ExcelValidException(field.getAnnotation(ExcelIntValid.class).message());}}}//是否包含decimal类型注解boolean isExcelDecimalValid = field.isAnnotationPresent(ExcelDecimalValid.class);if (isExcelDecimalValid) {if (isBigDecimal(fieldValue.toString())) {BigDecimal cellDecimal = new BigDecimal(fieldValue.toString());BigDecimal min = new BigDecimal(field.getAnnotation(ExcelDecimalValid.class).min());BigDecimal max = new BigDecimal(field.getAnnotation(ExcelDecimalValid.class).max());if (cellDecimal.compareTo(min) < 0 || cellDecimal.compareTo(max) > 0) {throw new ExcelValidException(field.getAnnotation(ExcelDecimalValid.class).message());}} else {throw new ExcelValidException("不是小数数字类型");}}// 是否包含正则校验boolean isExcelPatternValid = field.isAnnotationPresent(ExcelPatternValid.class);if (isExcelPatternValid) {String cellStr = fieldValue.toString();String pattern = field.getAnnotation(ExcelPatternValid.class).regexp();String name = field.getAnnotation(ExcelPatternValid.class).name();if (StringUtils.isBlank(name)) {throw new ExcelValidException("【" + name + "】列有未填值项");}if (StringUtils.isNotBlank(cellStr) && !Pattern.matches(pattern, cellStr)) {throw new ExcelValidException("【" + name + "】不符合规则");}}}}private static boolean isBigDecimal(String decimal) {try {BigDecimal bd = new BigDecimal(decimal);return true;} catch (NumberFormatException e) {return false;}}
}

3、自定义异常处理

/*** 导入excel自定义异常类*/
public class ExcelValidException extends RuntimeException {private static final long serialVersionUID = 1L;private int code;public ExcelValidException(String msg) {this(100, msg, null);}public ExcelValidException(int code, String msg) {this(code, msg, null);}public ExcelValidException(int code, String msg, Exception nestedEx) {super(msg, nestedEx);this.code = code;}
}

4、监听器

@Slf4j
public class ImportExcelDataListener<T> extends AnalysisEventListener<T> {//service的名称private final String serviceName;// 校验通过数据处理方法private final String accessMethodName;// 异常数据处理private final String errorMethodName;private final String version;private Map<String, Object> paramMap = new HashMap<>();public ImportExcelDataListener(String serviceName, Map<String, Object> param) {this.serviceName = serviceName;this.accessMethodName = "savaSuccessForExcel";this.errorMethodName = "saveErrorForExcel";version = UUID.randomUUID().toString();paramMap = param;}public ImportExcelDataListener(String serviceName) {this.serviceName = serviceName;this.accessMethodName = "savaSuccessForExcel";this.errorMethodName = "saveErrorForExcel";version = UUID.randomUUID().toString();paramMap = new HashMap<>();}// 校验通过数据private final List<T> successList = new LinkedList<>();//异常数据  (key:原因,value:data项)private final Map<String, List<T>> errorMap = new HashMap<>();/*** <p>所有数据解析完成后调用此方法</p>*/@SneakyThrows@Overridepublic void doAfterAllAnalysed(AnalysisContext context) throws ExcelValidException {//保存数据,确保最后的遗留数据也能保存到数据库或者进行其他操作this.execute();if (errorMap.size() > 0) {this.executeError();}}/*** <p>数据转换异常时的处理,比如required是Integer,provided是"sss"的字符串</p>*/@Overridepublic void onException(Exception exception, AnalysisContext context) throws Exception {exception.printStackTrace();if (exception instanceof ExcelDataConvertException) {Integer columnIndex = ((ExcelDataConvertException) exception).getColumnIndex() + 1;Integer rowIndex = ((ExcelDataConvertException) exception).getRowIndex() + 1;String message = String.format("第%s行,第%s列数据格式有误,请核实", rowIndex, columnIndex);throw new RuntimeException(message);} else {super.onException(exception, context);}}@Overridepublic void invoke(T data, AnalysisContext analysisContext) {//通用方法数据校验try {ExcelImportValid.valid(data);} catch (ExcelValidException e) {List<T> ts = errorMap.get(e.getMessage());if (CollectionUtils.isEmpty(ts)) {ts = new LinkedList<>();}ts.add(data);errorMap.put(e.getMessage(), ts);return;}//将解析完的数据加入到list中successList.add(data);// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOMif (successList.size() >= 600) {try {this.execute();} catch (Exception e) {e.printStackTrace();}// 存储完成清理 listsuccessList.clear();}}//执行数据保存的操作public void execute() throws Exception {try {Object beanService = SpringUtil.getBean(serviceName + "Impl");Class<?> beanClass = beanService.getClass();Method method = beanClass.getMethod(accessMethodName, List.class, String.class, Map.class);method.invoke(beanService, successList, version, paramMap);} catch (NoSuchMethodException | IllegalAccessException e) {log.warn("import error:", e);throw new RuntimeException("导入执行保存失败");} catch (InvocationTargetException e) {e.printStackTrace();throw new ExcelValidException("有异常数据");}}//执行错误数据处理的操作public void executeError() {try {Object beanService = SpringUtil.getBean(serviceName + "Impl");Class<?> beanClass = beanService.getClass();Method method = beanClass.getMethod(errorMethodName, Map.class, String.class);method.invoke(beanService, errorMap, version);} catch (NoSuchMethodException | IllegalAccessException e) {log.warn("execute error:", e);throw new RuntimeException("处理错误数据失败");} catch (InvocationTargetException e) {throw new ExcelValidException("有异常数据");}}
}

5、数据处理接口,使用范型

/*** 导入数据处理接口*/
public interface EasyExcelImportService<T> {/*** 异常数据处理方法 <errorMsg,data>* @param errorMap*/void saveErrorForExcel(Map<String, List<T>> errorMap,String version) throws ExcelValidException;/*** 正常数据处理* @param entityList* @param param 参数*/void savaSuccessForExcel(List<T> entityList,String version, Map<String,Object> param);
}

6、异常数据实体类(把校验失败的数据存入数据库,方便做导出,根据自己的具体业务自定义字段)

public class ImportErrorLog {@TableId(type = IdType.ASSIGN_UUID)private String id;/*** 服务名称*/private String service;/*** json数据*/private String data;/*** 唯一标识*/private String version;/*** 创建时间*/@TableField(fill = FieldFill.INSERT)@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private Date createTime;
}

7、日期类型需要自定义转换器

/*** 日期转换类*/
public class LocalDateConverter implements Converter<LocalDate> {@Overridepublic Class<LocalDate> supportJavaTypeKey() {return LocalDate.class;}@Overridepublic CellDataTypeEnum supportExcelTypeKey() {return CellDataTypeEnum.STRING;}@Overridepublic LocalDate convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {if (cellData.getType().equals(CellDataTypeEnum.NUMBER)) {LocalDate localDate = LocalDate.of(1900, 1, 1);//excel 有些奇怪的bug, 导致日期数差2localDate = localDate.plusDays(cellData.getNumberValue().longValue() - 2);return localDate;}else {return LocalDate.parse(cellData.getStringValue(), DateTimeFormatter.ofPattern("yyyy-MM-dd"));}}@Overridepublic WriteCellData<?> convertToExcelData(LocalDate value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {return new WriteCellData<>(value.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));}}

8、业务处理类实现EasyExcelImportService接口即可

public class DemoServiceImpl implements EasyExcelImportService<Demo> {/***     异常数据处理*/@Overridepublic void saveErrorForExcel(Map<String, List<Demo>> errorMap, String version) throws ExcelValidException {LinkedList<Demo> errorList = new LinkedList<>();/*** errorMap 的key是错误信息,value是excel的一行数据*/ImportErrorLog errorLog = importErrorLogMapper.selectOne(new QueryWrapper<ImportErrorLog>().eq("version", version).last("limit 1"));// 因为注解只能校验数据的合法性,并不能校验是否符合业务逻辑,所以这里加了版本号,同一批次的错误信息保存一条记录if (errorLog == null){errorLog = ImportErrorLog.builder().service("service").version(version).data(JSON.toJSONString(errorList)).build();// 入库importErrorLogMapper.insert(errorLog);}else {String data = errorLog.getData();List<Demo> importDemoList = JSONObject.parseArray(data, Demo.class);errorList.addAll(importDemoList);errorLog.setData(JSON.toJSONString(errorList));// 入库importErrorLogMapper.updateById(errorLog);}// 为了提醒前端有异常数据throw new ExcelValidException("have error data");}// 正常信息处理@Overridepublic void savaSuccessForExcel(List<Demo> entityList, String version, Map<String,Object> param) {if (CollectionUtils.isEmpty(entityList)) {return;}// 业务逻辑校验Map<String,List<Demo>> errorMap = new HashMap<>();Iterator<Demo> iterator = entityList.iterator();while (iterator.hasNext()){Demo next = iterator.next();if (projectTempByCodeMap.get(next.getProjectCode()) == null){iterator.remove();List<Demo> importDemoList = errorMap.get("项目编码错误");if (CollectionUtils.isEmpty(importDemoList)){importDemoList = new LinkedList<>();}importPmDailyList.add(next);errorMap.put("项目编码错误",importPmDailyList);}}if (CollectionUtils.isEmpty(entityList)){// 存储错误信息if (errorMap.size()>0){saveErrorForExcel(errorMap, version);}return;}// 业务逻辑处理。。。。。。
}

9、如果想导出某一批次的异常数据,直接查询数据库,做导出即可

easy-excel导入相关推荐

  1. 使用Easy Excel导入数据,性别为男女,数据库值为0、1

    Controller控制层 @ApiOperation(value = "用户 - 导出")@GetMapping(value = "/export")publ ...

  2. 【RuoYi-Vue-Plus】学习笔记 41 - Easy Excel(一)Excel 2003(*.xls)导入流程分析(源码)

    文章目录 前言 参考目录 框架集成 1.Maven 2.框架集成公共部分 2.1.Excel 操作工具类 `ExcelUtil` 2.2.导入监听接口 `ExcelListener` 2.3.默认监听 ...

  3. 【RuoYi-Vue-Plus】学习笔记 42 - Easy Excel(二)Excel 2007(*.xlsx)导入流程分析(源码)

    文章目录 前言 参考目录 框架集成 1.Maven 2.框架集成公共部分 2.1.Excel 操作工具类 `ExcelUtil` 2.2.导入监听接口 `ExcelListener` 2.3.默认监听 ...

  4. easyexcel 设置标题_EasyExcel,让 excel 导入导出更加简单

    做积极的人,而不是积极废人! 来源:jianshu.com/p/8f3defdc76d4EasyExcelGitHub上的官方说明快速开始maven仓库地址导入导出总结 EasyExcel 在做exc ...

  5. SpringBoot集成EasyPoi实现Excel导入导出

    作者介绍: 本人Java特工,代号:Cris Li : 中文名:克瑞斯理 简书地址: 消失的码农 - 简书 CSDN地址: https://blog.csdn.net/jianli95 个人纯洁版博客 ...

  6. 一小时教你轻松学会使用Java 整合 Easy Excel 操作 Excel 文件

    文章目录 一.Apache POI简介 二.POI操作Excel 构建maven项目导入依赖 使用POI实现基本写操作 使用POI实现大数据量写操作 使用POI实现基本读操作 使用POI读取不同类型的 ...

  7. 一款Excel导入导出解决方案组成的轻量级开源组件

    Excel-Boot GitHub地址:gitee.com/nw1992/easy- 码云地址:github.com/programmere- Excel-Boot是一款Excel导入导出解决方案组成 ...

  8. easyexcel 在 设置标题_EasyExcel,让excel导入导出更加简单

    EasyExcel 在做excel导入导出的时候,发现项目中封装的工具类及其难用,于是去gitHub上找了一些相关的框架,最终选定了EasyExcel.之前早有听闻该框架,但是一直没有去了解,这次借此 ...

  9. Easy Excel

    Easy Excel Easy Excel 1. 为什么有使用easyexcle 2. easvexcel拟解决的问题 3. 工作原理 4. ORM根据数据库表创建实体类的一个小技巧 5. 写exce ...

  10. Easy Excel 使用总结

    title: Easy Excel 使用总结 date: 2022-10-14 17:33:57 tags: Excel categories: 开发技术及框架 cover: https://cove ...

最新文章

  1. 设置3d rotationY 旋转之后元件大小改变解决方案
  2. [转] ubuntu 无线网络 配置 virtualbox
  3. struts-execl.xml
  4. RecyclerView详细了解
  5. 解决asterisk sip呼叫 488 no acceptable here
  6. java中String相等问题
  7. 二十九、PHP框架Laravel学习笔记——Debugbar 调试器
  8. MyBatis Plus 批量数据插入功能,yyds!
  9. Android 10 正式版本或将于 9 月 3 日推出
  10. 世界独创的螺旋数组低于n(o^2)的生成算法
  11. js 跨域访问 找了好长时间
  12. go程序设计语言学习 popCount
  13. 正则 纳税号_正则表达式号码靓号类型判断代码
  14. 细胞治疗质量控制解决方案
  15. dva是什么游戏_Dva爱你哟 她原来就是韩国少女宋哈娜原型
  16. Python每日一练——列表,元组和字典第五关:单星运算符和双星运算符
  17. iwlwifi(AC9260)移植总结
  18. 【技术分享】 ​IE浏览器漏洞利用技术的演变 ( 二 )
  19. 智慧工业之化工厂人员定位系统为什么要采用RFID技术来实现?苏州新导为您解答化工厂难点
  20. office2016专业增强版

热门文章

  1. three.js 制作地球标注的两种方法
  2. 电脑安装python3.74_python3.4学习笔记(十六) windows下面安装easy_install和pip教程
  3. Android应用市场上架管理
  4. 【ubuntu】运行.py文件
  5. 数学建模——matlab绘制 地图 散点图连线图 (运用plot、scatter、struct、xlsread等函数)【全文8000字】
  6. 2019知识付费走向何方?
  7. 你是“最佳实践”的受害者吗
  8. 四级准考证在电脑上什么格式
  9. 待办日程怎么设置稍后提醒
  10. 怎么给雷神笔记本安装系统?