所需依賴包
<!--web依賴包,web應用必備-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
參數校驗 Validator + BindResult進行校驗
Validator可以非常方便的制定校驗規則,並自動幫你完成校驗。首先在入參里需要校驗的字段加上注解,每個注解對應不同的校驗規則,並可制定校驗失敗后的信息:
實體類 參數加上校驗注解
@Data
public class User {
@NotNull(message = "用戶id不能為空")
private Long id;
@NotNull(message = "用戶賬號不能為空")
@Size(min = 6, max = 11, message = "賬號長度必須是6-11個字符")
private String account;
@NotNull(message = "用戶密碼不能為空")
@Size(min = 6, max = 11, message = "密碼長度必須是6-16個字符")
private String password;
@NotNull(message = "用戶郵箱不能為空")
@Email(message = "郵箱格式不正確")
private String email;
}
校驗規則和錯誤提示信息配置完畢后,接下來只需要在接口需要校驗的參數上加上@Valid注解,並添加BindResult參數即可方便完成驗證:
@RestController
@RequestMapping("user")
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/addUser")
public String addUser(@RequestBody @Valid User user, BindingResult bindingResult) {
// 如果有參數校驗失敗,會將錯誤信息封裝成對象組裝在BindingResult里
for (ObjectError error : bindingResult.getAllErrors()) {
return error.getDefaultMessage();
}
return userService.addUser(user);
}
}
這樣當請求數據傳遞到接口的時候Validator就自動完成校驗了,校驗的結果就會封裝到BindingResult中去,如果有錯誤信息我們就直接返回給前端,業務邏輯代碼也根本沒有執行下去。
現在可以看一下參數校驗效果。我們故意給這個接口傳遞一個不符合校驗規則的參數,先傳遞一個錯誤數據給接口,故意將password這個字段不滿足校驗條件:
錯誤參數:
正確參數:
這樣是不是方便很多?不難看出使用Validator校驗有如下幾個好處:
- 簡化代碼: 之前業務層那么一大段校驗代碼都被省略掉了。
- 使用方便: 那么多校驗規則可以輕而易舉的實現,比如郵箱格式驗證,之前自己手寫正則表達式要寫那么一長串,還容易出錯,用Validator直接一個注解搞定。
- 更多注解 釋義:
- 減少耦合度: 使用Validator能夠讓業務層只關注業務邏輯,從基本的參數校驗邏輯中脫離出來。使用Validator+ BindingResult已經是非常方便實用的參數校驗方式了,在實際開發中也有很多項目就是這么做的,不過這樣還是不太方便,因為每寫一個接口都要添加一個BindingResult參數,然后再提取錯誤信息返回給前端。這樣有點麻煩,並且重復代碼很多,可以 直接將 BindingResult參數 去掉,也可以編寫全局異常處理 !
去掉BindingResult參數:
@PostMapping("/addUser")
public String addUser(@RequestBody @Valid User user) {
return userService.addUser(user);
}
去掉之后會試驗一下,還是按照之前一樣故意傳遞一個不符合校驗規則的參數給接口。此時觀察控制台可以發現接口已經引發MethodArgumentNotValidException異常了:
自動返回了非明文的錯誤信息,其實這樣就已經達到我們想要的效果了,參數校驗不通過自然就不執行接下來的業務邏輯。不過事情還沒有完,異常是引發了,可並沒有編寫返回錯誤信息的代碼呀,那參數校驗失敗了會響應什么數據給前端呢?
全局異常處理
參數校驗失敗會自動引發異常,我們當然不可能再去手動捕捉異常進行處理,不然還不如用之前BindingResult方式呢。又不想手動捕捉這個異常,又要對這個異常進行處理,那正好使用SpringBoot全局異常處理來達到一勞永逸的效果!
處理參數校驗異常>>>:
首先,我們需要新建一個類,在這個類上加上
@ControllerAdvice或@RestControllerAdvice注解這個類就配置成全局處理類了。
(這個根據你的Controller層用的是@Controller還是@RestController來決定)然后在類中新建方法,在方法上加上@ExceptionHandler注解並指定你想處理的異常類型,接着在方法內編寫對該異常的操作邏輯,就完成了對該異常的全局處理!我們現在就來演示一下對參數校驗失敗拋出的MethodArgumentNotValidException全局處理:
/**
* 錯誤請求控制器
*/
@RestControllerAdvice
@CrossOrigin
public class exceptionController {
public static Logger log = LoggerFactory.getLogger(exceptionController.class);
/** 自定義 處理 MethodArgumentNotValidException 參數校驗錯誤
* @param e
* @return 根據自定義返回結果 返回對應內容
* 如果 使用的是 org.hibernate.validator jar 的話 使用:
* MethodArgumentNotValidException.class 捕捉參數校驗異常
* 如果是 SpringBoot默認的校驗 使用:
* org.springframework.validation.BindException.class 捕捉參數校驗異常
* 我這里使用的是 SpringBoot默認的
*/
@ExceptionHandler(value = BindException.class)
public String BindException(BindException e) {
StringBuilder sb = new StringBuilder();
for (ObjectError error: e.getBindingResult().getAllErrors()) {
sb.append(error.getDefaultMessage());
sb.append("、");
}
String errorMsg = sb.substring(0,sb.length() - 1).toString();
return errorMsg;
}
}
404異常處理
因為 是后端接口都是API 返回的是JSON內容,並不是 使用模板引擎html頁面,但是SpringBoot 在發生404的時候會自動去映射,會去找對應模版, 需要將SpringBoot的錯誤自動映射給關閉:
1、關閉 SpringBoot錯誤自動映射,打開application.properties
# 關閉SpringBoot 錯誤自動映射 ,如 404錯誤 會自動映射尋找對應模板,系統使用全局異常處理了返回結果
spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false
2、在全局異常類中 處理 NoHandlerFoundException 404 異常
/**
* 錯誤請求控制器
*/
@RestControllerAdvice
@CrossOrigin
public class exceptionController {
public static Logger log = LoggerFactory.getLogger(exceptionController.class);
/** 自定義異常 處理 NoHandlerFoundException 404 異常
* @param e
* @return 根據自定義返回結果 返回對應內容
*/
@ExceptionHandler(value = NoHandlerFoundException.class)
public String NoHandlerFoundException(NoHandlerFoundExceptione) {
String msg = "請求錯誤,接口路徑錯誤!不存在";
// org.springframework.web.servlet.NoHandlerFoundException 為 404錯誤
return msg;
}
// 或者 在全局 異常中判斷處理
@ExceptionHandler(value = Exception.class)
public StringexceptionHandler(Exception e){
String msg = null;
// org.springframework.web.servlet.NoHandlerFoundException 為 404錯誤
if( e instanceof NoHandlerFoundException){
msg = "請求錯誤,接口路徑錯誤!不存在";
}else{
msg = "請求錯誤[{"+e.getMessage()+"}]";
}
return msg ;
}
}
自定義異常
全局處理當然不會只能處理一種異常,用途也不僅僅是對一個參數校驗方式進行優化。在實際開發中,如何對異常處理其實是一個很麻煩的事情。
1、 定義一個 運行異常實體類:
/**
* 自定義異常
*/
public class itException extends RuntimeException {
private String errorMsg;
public String getErrorMsg() {
return errorMsg;
}
// 創建 構造方法,傳入錯誤內容
public itException (String message) {
super(message);
this.errorMsg = message;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
}
2、在全局異常類中 處理 自定義的異常類
/**
* 錯誤請求控制器
*/
@RestControllerAdvice
@CrossOrigin
public class exceptionController {
public static Logger log = LoggerFactory.getLogger(exceptionController.class);
/** 自定義異常類 itException
* @param e
* @return 根據自定義返回結果 返回對應內容
*/
@ExceptionHandler(value = itException .class)
public String MethodArgumentNotValidException(itException e) {
String msg = e.getErrorMsg()
return msg;
}
}
3、使用:
public static void main(String[] args) {
// 測試自定義異常
throw new foundException("自定義異常");
}
異常結果:忽略我的 這個異常類和上面的 itException不一樣,因為 我臨時用的一個異常類 隨便娶的名字
到這里 SpringBoot寫出簡單的后端接口 就結束咯