代碼優化實戰:我又優化了一百個 if else
事情是這樣的,前段時間做代碼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?
?
講到常見得數據校驗,那么我們畫風一轉,再回來看需求,可見以上需求是不滿足得,首先,我們入參是一個文件,也就是用戶傳得那個excel,我們得先解析文件再進行數據判斷,合法得放一個集合,不合法得放一個集合,再者,即使入參是一個數組,這種校驗一旦不滿足立馬進異常處理了,無法返回給前端正確得數據結構,所以引入了我們今天解決這類需求得解決方案。
重構開始-開篇
我們以之前寫文章里面得一個項目 ??easyexcel-demo?
? 為模板進行代碼得改造和編寫
代碼地址:https://github.com/pengziliu/GitHub-code-practice
下載之前做的小demo,運行起來,創建一個工作簿導入數據
創建一份Excel數據
PostMan模擬調用數據解析
項目代碼和控制臺輸出
重構開始-實戰
好吧,上面介紹了一下之前項目得基本讀取excel功能,我們就基于以上功能來實現我們開篇所說得需求。
我們對手機號和姓名自定義一下規則:
- 手機號滿足基本手機號規則
- 姓名非空且不能超過四個字符
返回成功失敗兩個集合,全部滿足得返回到成功,只要有一條不滿足得丟入失敗列表。
定義返回得數據結構
新建返回對象 ??UserExcelVO.java?
?
好了,兄弟們,這里我要上同事寫的偽代碼了。坐好扶穩了!!!
@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加注解
對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;
}
對同一組數據進行測試
測試結果如下,可以發現,兩種實現數據輸出結果一致
{
"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,里面包含很多的項目教程和實例
寫代碼的時候,除了做功能,應該要考慮代碼的擴展性,不然產品說加個功能,我們又得吭哧吭哧寫代碼,那這樣也臺悲催了。