優雅的實現前後端交互Validator+@RestControllerAdvice

前後端交互經常遇到參數多,不同開發人員返回數據結構不統一的問題,今天分享一種跟更優雅的方式,讓研發人員跳出格式限制,把更多的經歷放在邏輯處理上。
1、參數校驗:Validator + BindResult進行校驗
1.1 構建User實體類,通過註解形式校驗參數。

@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;
}


1.2 controller增加@Valid註解,即可啓用校驗。校驗失敗,會拋出MethodArgumentNotValidException異常。

@RestController
@RequestMapping("user2")
public class UserController2 {
    @PostMapping("/addUser")
    public User addUser(@RequestBody @Valid User user) {

        return user;
    }
}

2、統一返回數據結構
2.1 全局異常處理
    定義ExceptionControllerAdvice,使用全局註解@RestControllerAdvice(basePackages = "com.example.demo.controller"),接受異常註解@ExceptionHandler(MethodArgumentNotValidException.class),即可統一處理異常。

@RestControllerAdvice(basePackages = "com.example.demo.controller")
public class ExceptionControllerAdvice {
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResultVO<String> MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        // 從異常對象中拿到ObjectError對象
        ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
        // 然後提取錯誤提示信息進行返回
        return new ResultVO<>(ResultCode.VALIDATE_FAILED, objectError.getDefaultMessage());
    }
}


2.2 全局數據結構處理
    定義ResponseControllerAdvice,使用全局註解@RestControllerAdvice(basePackageClasses = {UserController2.class,UserController.class}),實現ResponseBodyAdvice<Object>,即可處理全局返回結果。

@RestControllerAdvice(basePackageClasses = {UserController2.class,UserController.class})
public class ResponseControllerAdvice implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        // 如果接口返回的類型本身就是ResultVO那就沒有必要進行額外的操作,返回false
        System.out.println(methodParameter.getGenericParameterType().equals(ResultVO.class));
        return !methodParameter.getGenericParameterType().equals(ResultVO.class);
    }

    @Override
    public Object beforeBodyWrite(Object data, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        // String類型不能直接包裝,所以要進行些特別的處理
        if (methodParameter.getGenericParameterType().equals(String.class)) {
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                // 將數據包裝在ResultVO裏後,再轉換爲json字符串響應給前端
                return objectMapper.writeValueAsString(new ResultVO<>(data));
            } catch (JsonProcessingException e) {
                throw new APIException("返回String類型錯誤");
            }
        }
        // 將原本的數據包裝在ResultVO裏
        return new ResultVO<>(data);
    }
}

3、結果測試
3.1 異常測試


3.2 正常結果測試

簡單易學,搞定!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章