52

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

 3 years ago
source link: https://mp.weixin.qq.com/s/X6ZySG9WWvK1utQpyZqSog
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

原创 码畜君 JAVA葵花宝典 1周前
docker|架构|Boot

事情是这样的,前段时间做代码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

640?wx_fmt=png

image-20200809162534227

640?wx_fmt=png

image-20200809162624232

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

重构开始-开篇

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

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

640?wx_fmt=png

image-20200809163432162

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

创建一份Excel数据

640?wx_fmt=png

image-20200809173342671

PostMan模拟调用数据解析

640?wx_fmt=png

image-20200809173308231

项目代码和控制台输出

640?wx_fmt=png

image-20200809173613381

重构开始-实战

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

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

  • 手机号满足基本手机号规则
  • 姓名非空且不能超过四个字符

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

定义返回得数据结构

新建返回对象UserExcelVO.java

640?wx_fmt=png

image-20200809174433991

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

@PostMapping("/importExcel")
    public UserExcelVO importExcel(@RequestParam("file") MultipartFile file){
        List<UserExcelModel> list = null;
        List<UserExcelModel> 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加注解

640?wx_fmt=png

image-20200809181934329

对Controller进行改写

 @PostMapping("/v2/importExcel")
    public UserExcelVO importExcelV2(@RequestParam("file") MultipartFile file){
        List<UserExcelModel> list = null;
        List<UserExcelModel> 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<ConstraintViolation<UserExcelModel>> 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;
    }

对同一组数据进行测试

640?wx_fmt=png

image-20200809182924261

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

{
    "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,里面包含很多的项目教程和实例

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK