以前兩篇文章 Spring-boot自定義參數校驗註解和如何在spring-boot中進行參數校驗,咱們介紹了,參數校驗以及如何自定義參數校驗註解,可是當傳遞參數出錯時,只是把錯誤信息打印到了控制檯,合理的作法是應該把校驗的錯誤信息返回給前端,告知用戶那裏有問題,下面就這一步內容進行說明。html
上篇文章 Spring-boot自定義參數校驗註解的最後,在控制檯打印了校驗出錯的信息前端
出錯的異常類是MethodArgumentNotValidException
,那若是想要自定義異常的返回,就須要在全局的異常處理器中針對這種異常進行處理。java
在這篇文章 spring-boot自定義異常返回中,咱們說了如何進行自定義異常的返回,參數校驗的錯誤信息返回依然按照此方式進行處理,在全局異常處理類中定義異常處理方法:spring
@ExceptionHandler(value = MethodArgumentNotValidException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseBody public UnifyResponse handlerBeanValidationException(HttpServletRequest request, MethodArgumentNotValidException ex) { String requestUri = request.getRequestURI(); String method = request.getMethod(); List<ObjectError> errors = ex.getBindingResult().getAllErrors(); return UnifyResponse.builder() .code(5000) .message(formatError(errors)) .requestUri(method + " " + requestUri) .build(); } private String formatError(List<ObjectError> errors) { StringBuilder builder = new StringBuilder(); errors.forEach(error -> builder.append(error.getDefaultMessage()).append(";")); return builder.toString(); }
咱們來對上面的代碼進行一下解釋:app
@ExceptionHandler(value = MethodArgumentNotValidException.class)
這裏指定List<ObjectError> errors = ex.getBindingResult().getAllErrors()
進行參數校驗的時候,可能多個參數都有問題,咱們但願可以有問題的參數的錯誤信息所有都返回回去,因此這裏要獲取全部的錯誤。回顧一下參數的定義,對這裏有疑惑的同窗能夠看一下這篇文章Spring-boot自定義參數校驗註解函數
@Builder @Getter @Setter @PasswordEqual(min = 5, message = "密碼和確認密碼不同") public class UserDto { private int userId; @Length(min = 2, max = 10, message = "用戶名長度必須在2-10的範圍內") private String username; private String password; private String confirmPassword; }
接下來咱們定再定義一個簡單的接口,當傳參出錯時看異常處理方法可否按照定義的那樣返回錯誤信息spring-boot
@RequestMapping("/v2/user/create") public UserDto createUser(@RequestBody @Validated UserDto userDto){ return userDto; }
咱們先來構造一個密碼和確認密碼不一致的狀況測試
能夠看到定義的錯誤信息被返回,並且狀態碼和自定義的code都是符合設計的,接下來咱們再看一下多個參數錯誤的場景:ui
上面的場景中,用戶名是不符合要求的,密碼和確認密碼也不同,因此會產生兩條錯誤信息,將其拼接到一塊兒,返回給前端。設計
以前討論的都是body裏提交的參數,接下來咱們看下路徑參數或者查詢參數校驗出錯時的處理
咱們先定義兩個接口一個是路徑參數查詢信息,一個是經過查詢參數查詢信息
@GetMapping("/v2/user/info") public UserDto getUserInfo(@RequestParam @Length(min = 2, max = 5, message = "用戶名長度必須在2-5的範圍") String username){ return UserDto.builder() .userId(1000) .username(username) .build(); } @GetMapping("/v2/user/{username}") public UserDto getUserInfoV2(@PathVariable @Length(min = 2, max = 5, message = "用戶名長度必須在2-5的範圍") String username){ return UserDto.builder() .userId(2000) .username(username) .build(); }
而後咱們訪問這兩接口,當發生錯誤時,看看他們會不會進入上文定義的異常處理方法中:
很明顯,並無進入上文定義的異常處理方法中,而是進入了handleException這個異常方法當中,這個算是個兜底的異常處理方法。
看一下控制檯的輸出:
這裏拋出了ConstraintViolationException異常,這個異常咱們並無定製對應的異常處理函數,下面咱們就來寫一下:
@ExceptionHandler(ConstraintViolationException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseBody public UnifyResponse handlerConstraintViolationException(HttpServletRequest request, ConstraintViolationException ex){ String requestUri = request.getRequestURI(); String method = request.getMethod(); Set<ConstraintViolation<?>> errors = ex.getConstraintViolations(); return UnifyResponse.builder() .code(6000) .message(formatConstraintException(errors)) .requestUri(method + " " + requestUri) .build(); } private String formatConstraintException(Set<ConstraintViolation<?>> constraintViolations){ StringBuilder builder = new StringBuilder(); constraintViolations.forEach(constraintViolation -> builder.append(constraintViolation.getMessage())); return builder.toString(); }
總體來講異常處理和上文幾乎是同樣的,只是獲取錯誤message的方式不同而已,咱們再請求一下:
至此參數校驗的錯誤message自定義返回,都完成了。
本文連接:https://www.immortalp.com/articles/2020/05/16/1589623786527.html
歡迎你們去 個人博客 瞅瞅,裏面有更多關於測試實戰的內容哦!!