01-EXCEL数据导入——数据校验及导入
1.目的
导入excel数据,对异常数据进行校验。
2.需求分析
- 1.excel数据导入前校验
- 数据格式校验
- 数据类型校验
- 数据是否符合业务进行校验
- 2.excel中导入数据替换
- 导入行业数据替换成数据库中code
- 导入城市数据替换成对应code
- 导入字典数据替换成对应的code
3.技术分析
-
1.excel数据的读,使用alibaba提供的easyExcel
-
2.数据格式校验,自定义注解
-
3.业务校验,增加校验接口,根据具体业务扩展
4.代码实现过程
1.引入依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.9</version>
</dependency>
2.定义校验注解类
@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RegexCheck {
RegexCheckEnum[] regexType() default {RegexCheckEnum.NULL} ;
String dictCode() default ""; //配置字典数据
}
3.定义注解校验类型枚举
@Getter
@AllArgsConstructor
public enum RegexCheckEnum {
NULL("", "可以为空"),//如果可以为空,必须使用这个类型,其他类型兼带非空的校验
NOTNULL("\\S","不为空"),
BIRTHDAY("[1-9]{4}([-./])\\d{1,2}\\1\\d{1,2}", "生日"),
EMAIL("\\w+@\\w+\\.[a-z]+(\\.[a-z]+)?", "邮件"),
IDCARD("[1-9]\\d{13,16}[a-zA-Z0-9]{1}", "身份证"),
DIGIT( "\\-?[1-9]\\d+","整数"),
DECIMAL( "[-+]?[0-9]*\\.?[0-9]+","浮点数"),
POSTCODE("[1-9]\\d{5}","邮编"),
CHINESE("[1-9]{4}([-./])\\d{1,2}\\1\\d{1,2}","中文"),
PHONE("^(13[0-9]|14[579]|15[0-3,5-9]|16[6]|17[0135678]|18[0-9]|19[89])\\d{8}$", "手机号码");
private String regex;
private String msg;
public static List<String> regexCheck(RegexCheckEnum[] enums,String name, Object val) {
List<String> msgs = new ArrayList<>();
//空和非空校验
if(StringUtils.isEmpty(val)){
final RegexCheckEnum tempEnum = Arrays.stream(enums).filter(e -> e.name().equals(NULL.name())).findAny().orElse(null);
if(StringUtils.isEmpty(tempEnum)){
msgs.add("【"+name+"】不符合不能为空的规则");
}else{
return null;
}
}
Arrays.stream(enums).forEach(e->{
if(!e.name().equals(NULL.name()) && !e.name().equals(NOTNULL.name())){//过滤空和非空校验
final boolean flag = Pattern.matches(e.getRegex(), String.valueOf(val));
if(!flag){
msgs.add("【"+name+"】不符合"+e.getMsg()+"的规则");
}
}
});
return msgs;
}
}
4.定义业务校验拓展接口和通用校验类
- 业务扩展接口
public interface ImportInterface<T> {
//每次校验后进行的操作
void afterPerCheck(List<String> errMsgs, T t);
//。。。。。其他业务接口在这里进行扩展
}
- 通用校验处理类
@Component
public class ImportService<T,M extends ImportInterface> {
//全局缓存数据
@Autowired
private TibesInitCache tibesInitCache;
@Autowired
private M m;
/**
* 导入数据校验操作
* @param datas
* @param t
* @return
* @throws JsonProcessingException
*/
public Map<String,Object> checkData(List<T> datas,Class<T> t) throws JsonProcessingException {
//校验字段
final Map<String, RegexCheck> fileds = getFieldCheck(t);
final Map<String,String> properties = getFieldProperty(t);
Map<String,List<String>> error = new HashMap<>();
int count = 0 ;
for(int i = 0 ; i < datas.size() ; i++) {
final JSONObject d = (JSONObject) JSONObject.toJSON(datas.get(i));
List<String> errMsgs = new ArrayList<>();
fileds.forEach((k,v)->{
String name=properties.get(k);
//校验错误信息
List<String> msgs = RegexCheckEnum.regexCheck(v.regexType(),name, d.get(k));
if(!StringUtils.isEmpty(msgs) && msgs.size() > 0){
errMsgs.addAll(msgs);
}
//统一替换字典数据,统一替换城市相关数据后续配置
});
//实体类校验后操作,其他个性化校验在这里增加
m.afterPerCheck(errMsgs,datas.get(i));
if(errMsgs.size() > 0){
++ count ;
error.put(String.valueOf(i + 1),errMsgs);
}
}
if(count > 0){
final Map<String, Object> params = new HashMap<>();
params.put("normalNums",datas.size() - count);
params.put("errorNums",count);
params.put("error",error);
return params ;
}
return null;
}
5.具体使用
- 实体类
@Data
public class Import {
@ExcelProperty("姓名")
@RegexCheck(regexType = {RegexCheckEnum.NOTNULL})
private String name;
@ExcelProperty("手机号码")
@RegexCheck(regexType = {RegexCheckEnum.PHONE})
private String phone;//手机号
}
- controller层
@PostMapping("/import")
public ResponsePacket importFile(MultipartFile file) throws Exception {
final List<Import> datas = EasyExcel.read(file.getInputStream(), Import.class, null).sheet().headRowNumber(2).doReadSync();
return service.importData(datas);
}
- service 层
public interface Service extends IService<CpCustomer>, ImportInterface<Import>{}
public class OperServiceImpl extends ServiceImpl<Mapper, Oper> implements Service{
@Override
public void afterPerCheck(List<String> errMsgs, Import import) {
//业务判断
boolean flag = 业务处理;
if(业务处理){
String msg = "【手机号】"+import.phone()+"已经存在";
errMsgs.add(msg);
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示