javascript
SpringBoot2 参数管理实践,入参出参与校验
一、參數管理
在編程系統中,為了能寫出良好的代碼,會根據是各種設計模式、原則、約束等去規范代碼,從而提高代碼的可讀性、復用性、可修改,實際上個人覺得,如果寫出的代碼很好,即別人修改也無法破壞原作者的思路和封裝,這應該是非常高水準。
但是在日常開發中,礙于很多客觀因素,很少有時間去不斷思考和優化代碼,所以只能從實際情況的角度去思考如何構建系統代碼,保證以后自己還能讀懂自己的代碼,在自己的幾年編程中,實際會考慮如下幾個方面:代碼層級管理,命名和注釋統一,合理的設計業務數據庫,明確參數風格。
這里就來聊一下參數管理,圍繞:入參、校驗、返參三個方面內容。
如何理解代碼規范這個概念:即大多數開發認同,愿意遵守的約束,例如Spring框架和Mvc模式對于工程的管理,《Java開發手冊》中對于業務開發的規定,其根本目的都是想避免隨著業務發展,代碼演變到無法維護的境界。
二、接收參數
接收參數方式有很多種,List,Map,Object等等,但是為了明確參數的語義,通常都需要設計參數對象的結構并且遵守一定的規范,例如明確禁止Map接收參數:
Rest風格接收單個ID參數:
@GetMapping("/param/single/{id}") public String paramSingle (@PathVariable Integer id){return "Resp:"+id ; }接收多個指定的參數:
@GetMapping("/param/multi") public String paramMulti (@RequestParam("key") String key, @RequestParam("var") String var){return "Resp:"+key+var ; }基于Java包裝對象入參:
@PostMapping("/param/wrap") public ParamIn paramWrap (@RequestBody ParamIn paramIn){return paramIn ; }-- 參數對象實體 public class ParamIn {private Integer id ;private String key ;private String var ;private String name ; }以上是在開發中常用的幾種接參方式,這里通常會遵守下面幾個習慣:
- 參數語義:明確接收參數的作用;
- 個數限制:參數超過三個使用包裝對象;
- 避免多個接口使用單個包裝對象入參;
- 避免包裝對象主體過于復雜;
參數接收并沒有很復雜的約束,整體上也比較容易遵守,通常的問題在于處理較大主體對象時,容易產生一個包裝對象被多處復用,進而導致對象字段屬性很多,這種情況在復雜業務中尤其容易出現,這種對象并不利于web層接口使用,或者很多時候都會在業務層和接口層混用對象;
在業務層封裝復雜的BO對象來降低業務管理的復雜度,這是合理常見的操作,可以在web接口層面根據接口功能各自管理入參主體,在業務實現的過程中,再傳入BO對象中。
避免復雜的業務包裝對象在各個層亂飄,如果多個接口入參都是同一個復雜的對象,很容易讓開發人員迷茫。
三、響應參數
與參數接收相對應的就是參數響應,參數響應通常具有明確的約束規范:響應主體數據,響應碼,描述信息。通常來說就是這樣三個核心要素。
響應參數主體:
這里泛型的使用通常用來做主體數據的接收。
public class Resp<T> {private int code ;private String msg ;private T data ;public static <T> Resp<T> ok (T data) {Resp<T> result = new Resp<>(HttpStatus.OK);result.setData(data);return result ;}public Resp (HttpStatus httpStatus) {this.code = httpStatus.value();this.msg = httpStatus.getReasonPhrase();}public Resp(int code, String msg, T data) {this.code = code;this.msg = msg;this.data = data;} }Code狀態碼
即接口狀態,建議參照并遵守HttpStatus中狀態碼的描述,這是開發普遍遵守的規范,如果不滿足業務需求,在適當自定義部分編碼,可以完全自定義一套響應碼,但是沒太多必要。
Msg描述
描述接口的響應的Msg可能就是:成功或失敗,更多的時候是需要處理業務異常的提示信息,例如單號不存在,賬號凍結等等,通常需要從業務異常中捕獲提示信息,并響應頁面,或者入參校驗不通過的描述。
Data數據
接口響應的主體數據,不同的業務響應的對象肯定不同,所以這里基于泛型機制接收即可,再以JSON格式響應頁面。
參考案例
接口返參:
@PostMapping("/resp/wrap") public Resp<KeyValue> respWrap (@RequestBody KeyValue keyValue){return Resp.ok(keyValue) ; }響應格式:
{"code": 200,"msg": "OK","data": {"key": "hello","value": "world"} }四、參數校驗
參數接收和響應相對都不是復雜的,比較難處理的就是參數校驗:入參約束校驗,業務合法性校驗,響應參數非空非null校驗,等各種場景。
在系統運行過程中,任何參數都不是絕對可靠的,所以參數校驗隨處可見,不同場景下的參數校驗,都有其必要性,但其根本目的都是為了給到請求端提示信息,快速打斷流程,快速響應。
1、借鑒參考
很多封裝思想,設計模式,或者這里說的參數校驗,都可以參考現有Java源碼或者優秀的框架,這是一個應該具備的基礎意識。
Java原生方法之java.lang.Thread線程:
public void interrupt() {if (this != Thread.currentThread())checkAccess();synchronized (blockerLock) {Interruptible b = blocker;if (b != null) {interrupt0(); b.interrupt(this);return;}}interrupt0(); }在Java源碼中,大部分都是采用原生的if判斷方式,對參數執行校驗
Spring框架之org.springframework.util.ClassUtils工具類部分代碼:
public static Class<?> forName(String name, @Nullable ClassLoader classLoader)throws ClassNotFoundException, LinkageError {Assert.notNull(name, "Name must not be null");Class<?> clazz = resolvePrimitiveClassName(name);if (clazz == null) {clazz = commonClassCache.get(name);}if (clazz != null) {return clazz;} }在Spring框架中除了基礎的if判斷之外,還封裝一個org.springframework.util.Assert斷言工具類。
2、常用校驗方式
If判斷
@GetMapping("/check/base") public String baseCheck (@RequestParam("var") String var){if (var == null) {return var+" is null" ;}if ("".equals(var)){return var+" is empty" ;}if ("hello".equals(var)){return var+" sensitive word " ;}return var + " through " ; }這種判斷在代碼中很常見,只是一旦遇到校驗的主體對象很大,并且在分布式的環境中,需要重復寫if判斷的話,容易出錯是一個方面,對開發人員的耐心考驗是另一個方面。
Valid組件
在早幾年的時候,比較流行的常用校驗組件Hibernate-Validator,后來興起的Validation-Api,據說是參考前者實現,不過這并不重要,二者都簡化了對JavaBean的校驗機制。
基于注解的方式,標記Java對象的字段屬性,并設定如果校驗失敗的提示信息。
public class JavaValid {@NotNull(message="ID不能為空")private Integer id ;@Email(message="郵箱格式異常")private String email ;@NotEmpty(message = "字段不能為空")@Size(min = 2,max = 10,message = "字段長度不合理")private String data ; }校驗結果打印:
public class JavaValidTest {private static Validator validator ;@BeforeClasspublic static void beforeBuild (){validator = Validation.buildDefaultValidatorFactory().getValidator();}@Testpublic void checkValid (){JavaValid valid = new JavaValid(null,"email","data") ;Set<ConstraintViolation<JavaValid>> validateInfo = validator.validate(valid) ;// 打印校驗結果validateInfo.stream().forEach(validObj -> {System.out.println("validateInfo:"+validObj.getMessage());});} }接口使用:
@PostMapping("/java/valid") public JavaValid javaValid (@RequestBody @Valid JavaValid javaValid,BindingResult errorMsg){if (errorMsg.hasErrors()){List<ObjectError> objectErrors = errorMsg.getAllErrors() ;objectErrors.stream().forEach(objectError -> {logger.info("CheckRes:{}",objectError.getDefaultMessage());});}return javaValid ; }這種校驗機制基于注解方式,可以大幅度簡化普通的入參校驗,但是對業務參數的合法校驗并不適應,例如常見的ID不存在,狀態攔截等。
Assert斷言
關于Assert斷言方式,起初是在單元測試中常見,后來在各種優秀的框架中開始常見,例如Spring、Mybatis等,然后就開始出現在業務代碼中:
public class AssertTest {private String varObject ;@Beforepublic void before (){varObject = RandomUtil.randomString(6) ;}@Testpublic void testEquals (){Assert.assertEquals(varObject+"不匹配",varObject,RandomUtil.randomString(6));}@Testpublic void testEmpty (){Assert.assertTrue(StrUtil.isNotEmpty(varObject));Assert.assertFalse(varObject+" not empty",StrUtil.isNotEmpty(varObject));}@Testpublic void testArray (){/*數組元素不相等: arrays first differed at element [1];Expected :u08Actual :mwm*/String var = RandomUtil.randomString(5) ;String[] arrOne = new String[]{var,RandomUtil.randomString(3)} ;String[] arrTwo = new String[]{var,RandomUtil.randomString(3)} ;Assert.assertArrayEquals("數組元素不相等",arrOne,arrTwo);} }Assert斷言,可以替換傳統的if判斷,大量減少參數校驗的代碼行數,提高程序的可讀性,這種風格是目前比較流行的方式。
五、源代碼地址
GitHub·地址 https://github.com/cicadasmile/middle-ware-parent GitEE·地址 https://gitee.com/cicadasmile/middle-ware-parent閱讀標簽
【Java基礎】【設計模式】【結構與算法】【Linux系統】【數據庫】
【分布式架構】【微服務】【大數據組件】【SpringBoot進階】【Spring&Boot基礎】
【數據分析】【技術導圖】【 職場】
總結
以上是生活随笔為你收集整理的SpringBoot2 参数管理实践,入参出参与校验的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: runat=server 所代表及隐含的
- 下一篇: ”System.Configuratio