事情是这样的,前段时间做代码review的时候,发现项目中有一个方法代码量超鸡儿多,而且大部分都是写的参数校验的代码,各种if else,得,我们先抓着缕一缕需求先。

产品需求

找到产品要到了需求文档,需求是这样得:

  • excel数据模板下载

  • excel数据导入

  • 导入得时候根据模板得校验规则来进行筛选,导入成功得返回成功列表,数据有问题得返回失败列表,失败列表支持数据编辑修正

好吧。看到需求第一眼可能就是第三列有点难度,我们知道,传统得数据校验是在DTO上面加注解

如下:

//第一种 
public Result test(@RequestBody @Validated TestDTO dto) {...} 
//第二种 
public  Result  test(@RequestBody @Valid TestDTO dto{...} 
//第三种 
public Result  test(@RequestBody @Validated(value = {SaveGroup.class}) TestDTO dto) {...} 

TestDTO 里面呢会有一些类似 @NotNull 、 @NotBlank 、 @Size 等校验注解,这里就不列了。

然后再在全局异常拦截那里进行统一封装,使其放回得数据结构尽量保持统一,所以一般还得有一个 GlobalExceptionHandle

代码优化实战:我又优化了一百个 if else

代码优化实战:我又优化了一百个 if else_第1张图片

讲到常见得数据校验,那么我们画风一转,再回来看需求,可见以上需求是不满足得,首先,我们入参是一个文件,也就是用户传得那个excel,我们得先解析文件再进行数据判断,合法得放一个集合,不合法得放一个集合,再者,即使入参是一个数组,这种校验一旦不满足立马进异常处理了,无法返回给前端正确得数据结构,所以引入了我们今天解决这类需求得解决方案。

重构开始-开篇

我们以之前写文章里面得一个项目 easyexcel-demo 为模板进行代码得改造和编写

代码地址:https://github.com/pengziliu/GitHub-code-practice

代码优化实战:我又优化了一百个 if else_第2张图片

下载之前做的小demo,运行起来,创建一个工作簿导入数据

创建一份Excel数据

代码优化实战:我又优化了一百个 if else_第3张图片

PostMan模拟调用数据解析

代码优化实战:我又优化了一百个 if else_第4张图片

项目代码和控制台输出

代码优化实战:我又优化了一百个 if else_第5张图片

重构开始-实战

好吧,上面介绍了一下之前项目得基本读取excel功能,我们就基于以上功能来实现我们开篇所说得需求。

我们对手机号和姓名自定义一下规则:

  • 手机号满足基本手机号规则

  • 姓名非空且不能超过四个字符

返回成功失败两个集合,全部满足得返回到成功,只要有一条不满足得丢入失败列表。

定义返回得数据结构

新建返回对象 UserExcelVO.java

代码优化实战:我又优化了一百个 if else_第6张图片

好了,兄弟们,这里我要上同事写的伪代码了。坐好扶稳了!!!

@PostMapping("/importExcel") 
    public UserExcelVO importExcel(@RequestParam("file") MultipartFile file){ 
        List list = null; 
        List fail = new ArrayList<>(); 
        UserExcelVO userExcelVO = new UserExcelVO(); 
        String mobieReg = "^[1][3,4,5,7,8][0-9]{9}$$"; 
        try { 
            list = EasyExcel.read(file.getInputStream(),UserExcelModel.class,new ModelExcelListener()).sheet().doReadSync(); 

            list.forEach(data->{ 
                //处理姓名的校验 
                if(StringUtils.isEmpty(data.getName())||data.getName().length()> 4 ){ 
                    fail.add(data); 
                    return; 
                } 
                //处理手机号的校验 
                if (StringUtils.isEmpty(data.getMobile())|| !data.getMobile().matches(mobieReg)) { 
                    fail.add(data); 
                    return; 
                } 
                //以下根据字段多少可能有n个if 
            }); 
            userExcelVO.setFail(fail); 
            list.removeAll(fail); 
            userExcelVO.setSuccess(list); 
        } catch (IOException e) { 
            e.printStackTrace(); 
        } 
        return userExcelVO; 
    } 

测试数据:

用户名 年龄 手机号 性别 
宝典哥1 11 23847235 男 
宝典哥2 12 15813847236 男 
宝典哥3 13 15813847237 男 
宝典哥4 14 15813847238 男 
宝典哥5 15 15813847239 男 
宝典哥6 16 15813847240 男 
宝典哥7 17 152247241 男 
宝典哥8 18 15813847242 男 
宝典哥9 19 15813847243 男 
宝典哥10 20 15813847244 男 
宝典哥11 21 15813847245 男 
宝典哥12 22 15813847246 男 
宝典哥13 23 15813847247 男 
宝典哥14 24 15813847248 男 
宝典哥15 25 15813847249 男 

测试结果:

{ 
    "success": [ 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥2", 
            "age": 12, 
            "mobile": "15813847236", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥3", 
            "age": 13, 
            "mobile": "15813847237", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥4", 
            "age": 14, 
            "mobile": "15813847238", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥5", 
            "age": 15, 
            "mobile": "15813847239", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥6", 
            "age": 16, 
            "mobile": "15813847240", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥8", 
            "age": 18, 
            "mobile": "15813847242", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥9", 
            "age": 19, 
            "mobile": "15813847243", 
            "sex": "男" 
        } 
    ], 
    "fail": [ 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥1", 
            "age": 11, 
            "mobile": "23847235", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥7", 
            "age": 17, 
            "mobile": "152247241", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥10", 
            "age": 20, 
            "mobile": "15813847244", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥11", 
            "age": 21, 
            "mobile": "15813847245", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥12", 
            "age": 22, 
            "mobile": "15813847246", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥13", 
            "age": 23, 
            "mobile": "15813847247", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥14", 
            "age": 24, 
            "mobile": "15813847248", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥15", 
            "age": 25, 
            "mobile": "15813847249", 
            "sex": "男" 
        } 
    ] 
} 

根据测试结果应该是问题不大的,我这里也是模拟一下,但是实际的业务场景,一个excel里面假如是订单数据,最少是几十个字段起步的,难道要写几十个if else ,明显是不合理的,那我们能不能使用注解的方式帮我们解决问题呢,如果使用注解的话应该如何使用呢?

开造!

创建 ValidationUtils.java

public class ValidationUtils { 

    public static Validator getValidator(){ 
        return validator; 
    } 

    static Validator validator; 
    static{ 
        ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory(); 
        validator=validatorFactory.getValidator(); 
    } 
} 

对Model加注解

代码优化实战:我又优化了一百个 if else_第7张图片

对Controller进行改写

@PostMapping("/v2/importExcel") 
   public UserExcelVO importExcelV2(@RequestParam("file") MultipartFile file){ 
       List list = null; 
       List fail = new ArrayList<>(); 
       UserExcelVO userExcelVO = new UserExcelVO(); 
       try { 
           list = EasyExcel.read(file.getInputStream(),UserExcelModel.class,new ModelExcelListener()).sheet().doReadSync(); 
           list.forEach(data->{ 
            //此处3行代码解决了一百个if else 
               Set> violations  =  ValidationUtils.getValidator().validate(data); 
               if(violations.size()>0){ 
                   fail.add(data); 
               } 
           }); 
           userExcelVO.setFail(fail); 
           list.removeAll(fail); 
           userExcelVO.setSuccess(list); 
       } catch (IOException e) { 
           e.printStackTrace(); 
       } 
       return userExcelVO; 
   } 

对同一组数据进行测试

代码优化实战:我又优化了一百个 if else_第8张图片

测试结果如下,可以发现,两种实现数据输出结果一致

{ 
    "success": [ 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥2", 
            "age": 12, 
            "mobile": "15813847236", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥3", 
            "age": 13, 
            "mobile": "15813847237", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥4", 
            "age": 14, 
            "mobile": "15813847238", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥5", 
            "age": 15, 
            "mobile": "15813847239", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥6", 
            "age": 16, 
            "mobile": "15813847240", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥8", 
            "age": 18, 
            "mobile": "15813847242", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥9", 
            "age": 19, 
            "mobile": "15813847243", 
            "sex": "男" 
        } 
    ], 
    "fail": [ 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥1", 
            "age": 11, 
            "mobile": "23847235", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥7", 
            "age": 17, 
            "mobile": "152247241", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥10", 
            "age": 20, 
            "mobile": "15813847244", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥11", 
            "age": 21, 
            "mobile": "15813847245", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥12", 
            "age": 22, 
            "mobile": "15813847246", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥13", 
            "age": 23, 
            "mobile": "15813847247", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥14", 
            "age": 24, 
            "mobile": "15813847248", 
            "sex": "男" 
        }, 
        { 
            "cellStyleMap": {}, 
            "name": "宝典哥15", 
            "age": 25, 
            "mobile": "15813847249", 
            "sex": "男" 
        } 
    ] 
} 

代码仓库

https://github.com/pengziliu/GitHub-code-practice

最新代码已提交,欢迎star,里面包含很多的项目教程和实例

写代码的时候,除了做功能,应该要考虑代码的扩展性,不然产品说加个功能,我们又得吭哧吭哧写代码,那这样也台悲催了。

【编辑推荐】

  1. 20年招聘经验:我所看重的开发人员的品质
  2. 技术Leader远离代码,就是自废武功?
  3. 微软部分Edge插件疑是李鬼 大神分析称其有恶意代码
  4. 数据集轻松按需搜索,这个工具有近2000个图像数据集,可免费获取
  5. 几行代码即可高效创建数据集,谷歌开源 TFRecorder

【责任编辑:张燕妮 TEL:(010)68476606】