前后端交互经常遇到参数多,不同开发人员返回数据结构不统一的问题,今天分享一种跟更优雅的方式,让研发人员跳出格式限制,把更多的经历放在逻辑处理上。
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 正常结果测试
简单易学,搞定!