Spring Boot統一異常處理以及引數校驗
一般情況我們前端向後端傳遞引數都是2種方式 JSON
或者 表單提交
因此本文分別講述 JSON提交
引數校驗和 表單提交
引數校驗在Spring Boot中是如何操作,以及校驗失敗如何統一轉交給異常處理類去處理的。
Api設計如下:
表單方式
: http://localhost:8080/get-args-valid?username=xxx&password=xxx
JSON方式
: http://localhost:8080/post-args-valid
{ "username":"123", "password":"123" } 複製程式碼
採用JSON方式提交,所以設定 content-type
如下:
Content-Type
: application/json
新建一個Spring Boot專案
Api如下設計:
/** * @author: hujiansong * @email: [email protected] * @since: 2019/1/29 16:53 */ @RestController public class ValidController { @GetMapping("/get-args-valid") public String getArgsValid(String username, String password) { return null; } @PostMapping("/post-args-valid") public String postArgsValid(@RequestBody User user) { return null; } @Data class User { String username; String password; } } 複製程式碼
先講 JSON
方式如何進行引數校驗
JSON方式
:
@RestController public class ValidController { @PostMapping("/post-args-valid") public String postArgsValid(@Valid<1> @RequestBody User user) { return null; } @Data static class User { @NotNull(message = "使用者名稱不能為空")<2> String username; @NotNull(message = "密碼不能為空") String password; } } 複製程式碼
注意: 這裡內部類 User
需要加上static,否則json傳過來無法解析
<1>: @Valid
表示這個實體引數交給Spring去校驗
<2>: @NotNull
校驗規則
如上2步操作就可以完成引數校驗:

可以看到如何 password
不傳遞,spring 已經幫我們做了引數校驗,再來看看 表單方式
表單方式
:
@RestController @Validated<1> public class ValidController { @GetMapping("/get-args-valid") public String getArgsValid(@NotNull(message = "使用者名稱不能空")<2> String username, @NotNull(message = "密碼不能為空") String password) { return null; } } 複製程式碼
同樣也是2步搞定
<1>: @Validated
,交給Spring去校驗
<2>: @NotNull
校驗規則
看看如果 password
不傳遞會返回什麼:

可見,Spring已經替我們做了引數校驗
Spring 還包含了很多校驗規則如下:
註解 | 解釋 |
---|---|
@Null | 被註釋的元素必須為 null |
@NotNull | 被註釋的元素必須不為 null |
@AssertTrue | 被註釋的元素必須為 true |
@AssertFalse | 被註釋的元素必須為 false |
@Min(value) | 被註釋的元素必須是一個數字,其值必須大於等於指定的最小值 |
@Max(value) | 被註釋的元素必須是一個數字,其值必須小於等於指定的最大值 |
@DecimalMin | 被註釋的元素必須是一個數字,其值必須大於等於指定的最小值 |
@DecimalMax | 被註釋的元素必須是一個數字,其值必須小於等於指定的最大值 |
@Size(max=, min=) | 被註釋的元素的大小必須在指定的範圍內 |
@Digits | 被註釋的元素必須是一個數字,其值必須在可接受的範圍內 |
@Past | 被註釋的元素必須是一個過去的日期 |
@Future | 被註釋的元素必須是一個將來的日期 |
@Pattern(regex=) | 被註釋的元素必須符合指定的正則表示式 |
異常統一處理
上面介紹瞭如何讓Spring校驗我們的引數,那麼可以看到 JSON
方式校驗返回的結果一大串,不是十分優雅。那麼利用統一異常處理則可優雅返回引數校驗結果。
JSON方式
:校驗失敗後,會丟擲一個 MethodArgumentNotValidException
表單方式
:校驗失敗,會丟擲一個 ConstraintViolationException
因此只需要在統一異常處理類裡面處理這2個異常即可。
ExceptionHanlder
表單方式
:
@RestControllerAdvice public class ExceptionHandler { @org.springframework.web.bind.annotation.ExceptionHandler(ConstraintViolationException.class) public Map<String, Object> methodArgNotValidException(ConstraintViolationException cve, HttpServletRequest httpServletRequest) { Set<ConstraintViolation<?>> cves = cve.getConstraintViolations(); StringBuffer errorMsg = new StringBuffer(); cves.forEach(ex -> errorMsg.append(ex.getMessage())); Map<String, Object> respMap = new HashMap<>(4); respMap.put("code", -1); respMap.put("msg", errorMsg); return respMap; } } 複製程式碼
重新呼叫:

JSON方式
:
@RestControllerAdvice public class ExceptionHandler { @org.springframework.web.bind.annotation.ExceptionHandler({MethodArgumentNotValidException.class}) public Map<String, Object> methodDtoNotValidException(Exception ex, HttpServletRequest request) { MethodArgumentNotValidException c = (MethodArgumentNotValidException) ex; List<ObjectError> errors = c.getBindingResult().getAllErrors(); StringBuffer errorMsg = new StringBuffer(); errors.stream().forEach(x -> { errorMsg.append(x.getDefaultMessage()).append(";"); }); Map<String, Object> respMap = new HashMap<>(4); respMap.put("code", -1); respMap.put("msg", errorMsg); return respMap; } } 複製程式碼
同樣呼叫,這次 username
為空試試看:

