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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM