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: 1358199510@qq.com
* @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
為空試試看: