本文探討spring boot 2.7.14版本中GET和POST請求參數校驗的差異,以及如何統一校驗結果格式。 許多開發者在使用@RequestBody @Valid校驗POST請求體時能夠成功捕獲MethodArgumentNotValidException,但GET請求使用@RequestParam @NotNull或@Validated注解卻常常拋出MissingServletRequestParameterException,而非預期的校驗失敗信息。
這是因為@RequestParam本身不支持JSR-303校驗注解(如@NotNull),它只負責將請求參數映射到方法參數。@Validated注解作用于方法參數對象,而單個long feedId并非對象。
為了解決這個問題并統一校驗結果格式,我們采用以下方法:
首先,將GET請求參數封裝到DTO對象中:
@GetMapping("/api") public String apiGet(@Valid ApiGetRequest request) { // ... } public class ApiGetRequest { @NotNull private Long feedId; // getters and setters }
創建ApiGetRequest類,將feedId作為屬性并添加@NotNull注解,利用Spring的校驗機制進行非空校驗。
其次,自定義全局異常處理器,統一處理校驗異常:
@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler({MethodArgumentNotValidException.class, MissingServletRequestParameterException.class}) @ResponseBody public ResponseEntity<String> handleValidationExceptions(Exception ex) { String errorMessage; if (ex instanceof MethodArgumentNotValidException) { MethodArgumentNotValidException e = (MethodArgumentNotValidException) ex; errorMessage = e.getBindingResult().getFieldError().getDefaultMessage(); } else if (ex instanceof MissingServletRequestParameterException) { MissingServletRequestParameterException e = (MissingServletRequestParameterException) ex; errorMessage = "校驗失敗:" + e.getParameterName() + ":不能為null"; } else { errorMessage = "未知錯誤"; } return ResponseEntity.badRequest().body(errorMessage); } }
此全局異常處理器捕獲MethodArgumentNotValidException和MissingServletRequestParameterException,并構建統一格式的錯誤信息。 使用ResponseEntity返回更規范的http響應,包含狀態碼。
通過此方案,無論POST請求的MethodArgumentNotValidException還是GET請求的MissingServletRequestParameterException,都能被統一處理,返回一致的錯誤信息格式,從而滿足了開發者對校驗結果格式的要求。 這提升了代碼的可維護性和可讀性。