在編程系統中,爲了能寫出良好的代碼,會根據是各類設計模式、原則、約束等去規範代碼,從而提升代碼的可讀性、複用性、可修改,實際上我的以爲,若是寫出的代碼很好,即別人修改也沒法破壞原做者的思路和封裝,這應該是很是高水準。java
可是在平常開發中,礙於不少客觀因素,不多有時間去不斷思考和優化代碼,因此只能從實際狀況的角度去思考如何構建系統代碼,保證之後本身還能讀懂本身的代碼,在本身的幾年編程中,實際會考慮以下幾個方面:代碼層級管理,命名和註釋統一,合理的設計業務數據庫,明確參數風格。git
這裏就來聊一下參數管理,圍繞:入參、校驗、返參三個方面內容。github
如何理解代碼規範這個概念:即大多數開發認同,願意遵照的約束,例如Spring框架和Mvc模式對於工程的管理,《Java開發手冊》中對於業務開發的規定,其根本目的都是想避免隨着業務發展,代碼演變到沒法維護的境界。web
接收參數方式有不少種,List,Map,Object等等,可是爲了明確參數的語義,一般都須要設計參數對象的結構而且遵照必定的規範,例如明確禁止Map接收參數:算法
Rest風格接收單個ID參數:spring
@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 ; }
以上是在開發中經常使用的幾種接參方式,這裏一般會遵照下面幾個習慣:json
參數接收並無很複雜的約束,總體上也比較容易遵照,一般的問題在於處理較大主體對象時,容易產生一個包裝對象被多處複用,進而致使對象字段屬性不少,這種狀況在複雜業務中尤爲容易出現,這種對象並不利於web層接口使用,或者不少時候都會在業務層和接口層混用對象;segmentfault
在業務層封裝複雜的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校驗,等各類場景。
在系統運行過程當中,任何參數都不是絕對可靠的,因此參數校驗隨處可見,不一樣場景下的參數校驗,都有其必要性,但其根本目的都是爲了給到請求端提示信息,快速打斷流程,快速響應。
不少封裝思想,設計模式,或者這裏說的參數校驗,均可以參考現有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
斷言工具類。
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 ; @BeforeClass public static void beforeBuild (){ validator = Validation.buildDefaultValidatorFactory().getValidator(); } @Test public 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 ; @Before public void before (){ varObject = RandomUtil.randomString(6) ; } @Test public void testEquals (){ Assert.assertEquals(varObject+"不匹配",varObject,RandomUtil.randomString(6)); } @Test public void testEmpty (){ Assert.assertTrue(StrUtil.isNotEmpty(varObject)); Assert.assertFalse(varObject+" not empty",StrUtil.isNotEmpty(varObject)); } @Test public void testArray (){ /* 數組元素不相等: arrays first differed at element [1]; Expected :u08 Actual :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基礎】