正文
Integer code;
private
String message;
private
T data;
public
static
Result
success
(T data)
{
return
new
Result<>(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMessage(), data);
}
public
static
Result
success
(String message, T data)
{
return
new
Result<>(ResultEnum.SUCCESS.getCode(), message, data);
}
public
static
Result> failed() {
return
new
Result<>(ResultEnum.COMMON_FAILED.getCode(), ResultEnum.COMMON_FAILED.getMessage(),
null
);
}
public
static
Result> failed(String message) {
return
new
Result<>(ResultEnum.COMMON_FAILED.getCode(), message,
null
);
}
public
static
Result> failed(IResult errorResult) {
return
new
Result<>(errorResult.getCode(), errorResult.getMessage(),
null
);
}
public
static
Result
instance
(Integer code, String message, T data)
{
Result
result =
new
Result<>();
result.setCode(code);
result.setMessage(message);
result.setData(data);
return
result;
}
}
统一返回结构后,在 Controller 中就可以使用了,但是每一个 Controller 都写这么一段最终封装的逻辑,这些都是很重复的工作,所以还要继续想办法进一步处理统一返回结构。
| 统一包装处理
Spring 中提供了一个类 ResponseBodyAdvice ,能帮助我们实现上述需求:
public interface ResponseBodyAdvice<T> {
boolean supports(MethodParameter returnType, Class extends HttpMessageConverter>> converterType);
@Nullable
T beforeBodyWrite(@Nullable T body, MethodParameter returnType, MediaType selectedContentType, Class extends HttpMessageConverter>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response);
}
ResponseBodyAdvice 是对 Controller 返回的内容在 HttpMessageConverter 进行类型转换之前拦截,进行相应的处理操作后,再将结果返回给客户端。
那这样就可以把统一包装的工作放到这个类里面:
// 如果引入了swagger或knife4j的文档生成组件,这里需要仅扫描自己项目的包,否则文档无法正常生成
@RestControllerAdvice(basePackages = "com.example.demo")
public class ResponseAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType, Class extends HttpMessageConverter>> converterType) {
// 如果不需要进行封装的,可以添加一些校验手段,比如添加标记排除的注解
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class extends HttpMessageConverter>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
// 提供一定的灵活度,如果body已经被包装了,就不进行包装
if (body instanceof Result) {
return body;
}
return Result.success(body);
}
}
经过这样改造,既能实现对 Controller 返回的数据进行统一包装,又不需要对原有代码进行大量的改动。
| 参数校验
Java API 的规范 JSR303 定义了校验的标准 validation-api ,其中一个比较出名的实现是 hibernate validation。
spring validation 是对其的二次封装,常用于 SpringMVC 的参数自动校验,参数校验的代码就不需要再与业务逻辑代码进行耦合了。
①@PathVariable 和 @RequestParam 参数校验
Get 请求的参数接收一般依赖这两个注解,但是处于 url 有长度限制和代码的可维护性,超过 5 个参数尽量用实体来传参。
对 @PathVariable 和 @RequestParam 参数进行校验需要在入参声明约束的注解。
如果校验失败,会抛出 MethodArgumentNotValidException 异常。
@RestController(value = "prettyTestController")
@RequestMapping("/pretty")
public class TestController {
private TestService testService;
@GetMapping(