<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在基於spring框架的專案開發中,必然會遇到controller層,它可以很方便的對外提供資料介面服務,也是非常關鍵的出口,所以非常有必要進行規範統一,使其既簡潔又優雅。
controller層的職責為負責接收和響應請求,一般不負責具體的邏輯業務的實現。controller主要工作如下:
目前controller層程式碼會存在的問題:
優雅寫法一:統一返回結構
統一返回值型別,無論專案前後端是否分離都是非常必要的,方便對接介面的前端開發人員更加清晰地知道這個介面的呼叫是否成功,不能僅僅簡單地看返回值是否為 null 就判斷成功與否,因為有些介面的設計就是如此。
統一返回結構,通過狀態碼就能清楚的知道介面的呼叫情況:
@Data public class ResponseData<T> { private Boolean status = true; private int code = 200; private String message; private T data; public static ResponseData ok(Object data) { return new ResponseData(data); } public static ResponseData ok(Object data,String message) { return new ResponseData(data,message); } public static ResponseData fail(String message,int code) { ResponseData responseData= new ResponseData(); responseData.setCode(code); responseData.setMessage(message); responseData.setStatus(false); responseData.setData(null); return responseData; } public ResponseData() { super(); } public ResponseData(T data) { super(); this.data = data; } public ResponseData(T data,String message) { super(); this.data = data; this.message=message; } }
@AllArgsConstructor @Data public enum ResponseCode { SYS_FAIL(1, "操作失敗"), SYS_SUCESS(200, "操作成功"), SYSTEM_ERROR_CODE_403(403, "許可權不足"), SYSTEM_ERROR_CODE_404(404, "未找到請求資源"), ; private int code; private String msg; }
統一返回結構後,就可以在controller中使用了,但是每個controller都這麼寫,都是很重複的工作,所以還可以繼續想辦法處理統一返回結構。
優雅寫法二:統一包裝處理
Spring 中提供了一個類 ResponseBodyAdvice ,能幫助我們實現上述需求:
ResponseBodyAdvice 是對 Controller 返回的內容在 HttpMessageConverter 進行型別轉換之前攔截,進行相應的處理操作後,再將結果返回給使用者端。這樣就可以把統一包裝處理的工作放到這個類裡面,其中supports判斷是否要交給beforeBodyWrite 方法執行,true為需要,false為不需要,beforeBodyWrite 是對response的具體處理。
@RestControllerAdvice(basePackages = "com.example.demo") public class ResponseAdvice implements ResponseBodyAdvice<Object> { @Override public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { // 如果不需要進行封裝的,可以新增一些校驗手段,比如新增標記排除的註解 return true; } @Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) { // 提供一定的靈活度,如果body已經被包裝了,就不進行包裝 if (body instanceof Result) { return body; } return Result.success(body); } }
這樣即能實現對controller返回的資料進行統一,又不需要對原有程式碼進行大量的改動了。
優雅寫法三:引數校驗
Java API 的規範 JSR303 定義了校驗的標準 validation-api ,其中一個比較出名的實現是 hibernate validation。
@PathVariable 和 @RequestParam 引數校驗:get請求的引數接收一般依賴這兩個註解,但是處於 url 有長度限制和程式碼的可維護性,超過 5 個引數儘量用實體來傳參;
對 @PathVariable 和 @RequestParam 引數進行校驗需要在入參處宣告約束的註解,如果校驗失敗,會丟擲 MethodArgumentNotValidException 異常。
@RestController @RequestMapping("/test") public class TestController { private TestService testService; @Autowired public void setTestService(TestService prettyTestService) { this.testService = prettyTestService; } @GetMapping("/{num}") public Integer num(@PathVariable("num") @Min(1) @Max(20) Integer num) { return num * num; } @GetMapping("/email") public String email(@RequestParam @NotBlank @Email String email) { return email; } }
@RequestBody 引數校驗:post和put 請求的引數推薦使用 @RequestBody 請求體引數;
對 @RequestBody 引數進行校驗需要在 DTO 物件中加入校驗條件後,再搭配 @Validated 即可完成自動校驗。如果校驗失敗,會丟擲 ConstraintViolationException 異常。
@Data public class TestDTO { @NotBlank private String userName; @NotBlank @Length(min = 6, max = 20) private String password; @NotNull @Email private String email; } @RestController @RequestMapping("/test") public class TestController { private TestService testService; @Autowired public void setTestService(TestService testService) { this.testService = testService; } @PostMapping("/testValidation") public void testValidation(@RequestBody @Validated TestDTO testDTO) { this.testService.save(testDTO); } }
自定義校驗規則:有些時候 JSR303 標準中提供的校驗規則不滿足複雜的業務需求,也可以自定義校驗規則;
優雅寫法四:自定義異常與統一攔截異常
原來丟擲的異常會有如下問題:
自定義異常是為了後面統一攔截異常時,對業務中的異常有更加細顆粒度的區分,攔截時針對不同的異常作出不同的響應。
統一攔截異常的是為了可以與前面定義下來的統一包裝返回結構能對應上,還有就是希望無論系統發生什麼異常,Http 的狀態碼都要是 200 ,儘可能由業務來區分系統的異常。
//自定義異常 public class ForbiddenException extends RuntimeException { public ForbiddenException(String message) { super(message); } } //自定義異常 public class BusinessException extends RuntimeException { public BusinessException(String message) { super(message); } } //統一攔截異常 @RestControllerAdvice(basePackages = "com.example.demo") public class ExceptionAdvice { /** * 捕獲 {@code BusinessException} 異常 */ @ExceptionHandler({BusinessException.class}) public Result<?> handleBusinessException(BusinessException ex) { return Result.failed(ex.getMessage()); } /** * 捕獲 {@code ForbiddenException} 異常 */ @ExceptionHandler({ForbiddenException.class}) public Result<?> handleForbiddenException(ForbiddenException ex) { return Result.failed(ResultEnum.FORBIDDEN); } /** * {@code @RequestBody} 引數校驗不通過時丟擲的例外處理 */ @ExceptionHandler({MethodArgumentNotValidException.class}) public Result<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) { BindingResult bindingResult = ex.getBindingResult(); StringBuilder sb = new StringBuilder("校驗失敗:"); for (FieldError fieldError : bindingResult.getFieldErrors()) { sb.append(fieldError.getField()).append(":").append(fieldError.getDefaultMessage()).append(", "); } String msg = sb.toString(); if (StringUtils.hasText(msg)) { return Result.failed(ResultEnum.VALIDATE_FAILED.getCode(), msg); } return Result.failed(ResultEnum.VALIDATE_FAILED); } /** * {@code @PathVariable} 和 {@code @RequestParam} 引數校驗不通過時丟擲的例外處理 */ @ExceptionHandler({ConstraintViolationException.class}) public Result<?> handleConstraintViolationException(ConstraintViolationException ex) { if (StringUtils.hasText(ex.getMessage())) { return Result.failed(ResultEnum.VALIDATE_FAILED.getCode(), ex.getMessage()); } return Result.failed(ResultEnum.VALIDATE_FAILED); } /** * 頂級異常捕獲並統一處理,當其他異常無法處理時候選擇使用 */ @ExceptionHandler({Exception.class}) public Result<?> handle(Exception ex) { return Result.failed(ex.getMessage()); } }
通過上述寫法,可以發現 Controller 的程式碼變得非常簡潔優雅,可以清楚知道每個引數、每個DTO的校驗規則,可以明確返回的結構,包括異常情況。
到此這篇關於SpringBoot中controller深層詳細講解的文章就介紹到這了,更多相關SpringBoot controller內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45