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);
}
}
}