作用:controller入参使用了@RequestBody注解获取json数据,RequestBodyAdvice才能生效。很明显,原理是aop,在读取请求body数据前后进行额外的操作。
看看RequestBodyAdvice接口源码:
public interface RequestBodyAdvice {
boolean supports(MethodParameter methodParameter, Type targetType,
Class extends HttpMessageConverter>> converterType);
HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType, Class extends HttpMessageConverter>> converterType) throws IOException;
Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType, Class extends HttpMessageConverter>> converterType);
@Nullable
Object handleEmptyBody(@Nullable Object body, HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType, Class extends HttpMessageConverter>> converterType);
}
Spring默认提供了接口的抽象实现类RequestBodyAdviceAdapter , 我们可以继承这个类按需实现 , 让代码更简洁一点:
public abstract class RequestBodyAdviceAdapter implements RequestBodyAdvice {
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType, Class extends HttpMessageConverter>> converterType)
throws IOException {
return inputMessage;
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType, Class extends HttpMessageConverter>> converterType) {
return body;
}
@Override
@Nullable
public Object handleEmptyBody(@Nullable Object body, HttpInputMessage inputMessage,
MethodParameter parameter, Type targetType,
Class extends HttpMessageConverter>> converterType) {
return body;
}
}
例子:
@RestControllerAdvice(annotations = {RestController.class, Controller.class})
public class baseRequestValidationAdvice extends RequestBodyAdviceAdapter {
@Resource
private SysUseronlineMapper sysUserOnlineMapper;
@Resource
private TokenService tokenService;
@Override
public boolean supports(MethodParameter methodParameter, Type targetType,
Class extends HttpMessageConverter>> converterType) {
return true;
}
@Override
public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
Class extends HttpMessageConverter>> converterType) {
// 基础请求入参对象,可以对token等基础参数进行校验
baseRequest request = (baseRequest) body;
if (body instanceof baseRequest && !(body instanceof Login/confirm/iDto) && !(body instanceof LoginIdentifyDto)) {
if (StringUtils.isEmpty(request.getUserCode())) {
throw new ServiceException(CommonConstant.ERROR, CommonConstant.ERROR_USERCODE_EMPTY);
}
if (StringUtils.isEmpty(request.getToken())) {
throw new ServiceException(CommonConstant.ERROR, CommonConstant.ERROR_TOKEN_EMPTY);
}
SysUseronline sysUseronline = sysUserOnlineMapper.selectByPrimaryKey(request.getUserCode());
if (null == sysUseronline || !request.getToken().equals(sysUserOnline.getToken())) {
throw new ServiceException(CommonConstant.ERROR_TOKEN_INVALID,CommonConstant.ERROR_LOGOUT_ONLINE);
}
if (!(body instanceof LogOutDto) && StringUtils.isEmpty(request.getWarehouseCode())) {
throw new ServiceException(CommonConstant.ERROR, CommonConstant.ERROR_WAREHOUSECODE_EMPTY);
}
}
// 幂等性校验
checkIdempotent(inputMessage, parameter);
return body;
}
private void checkIdempotent(HttpInputMessage inputMessage, MethodParameter parameter){
// 幂等性校验, 校验通过则放行, 校验失败则抛出异常, 并通过统一异常处理返回友好提示
ApiIdempotent apiIdempotent = parameter.getMethod().getAnnotation(ApiIdempotent.class);
if (apiIdempotent != null) {
// 请求头中获得幂等性Id
if(inputMessage.getHeaders().containsKey(CommonConstant.TRACTIONID)){
// 校验等幂性,存到redis进行检验也行
String tractionId = inputMessage.getHeaders().get(CommonConstant.TRACTIONID).get(0);
tokenService.checkToken(tractionId);
}else{
throw new ServiceException(ResponseCode.ILLEGAL_ARGUMENT.getMsg());
}
}
}
}
ResponseBodyAdvice
作用:controller出参返回json数据,ResponseBodyAdvice才能生效。很明显,原理都是aop,在请求返回body数据前进行额外的操作。
看看ResponseBodyAdvice接口源码:
public interface ResponseBodyAdvice{ 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); }
例子:
@RestControllerAdvice(annotations = {RestController.class, Controller.class})
public class WebControllerAdvice implements ResponseBodyAdvice {
private Logger logger = LoggerFactory.getLogger(getClass());
@Resource
private TokenService tokenService;
@ResponseBody
@ExceptionHandler(Exception.class)
public Result exceptionHandler(Exception e) {
return Result.DefaultFailure(e.getMessage());
}
@Override
public boolean supports(MethodParameter methodParameter, Class extends HttpMessageConverter>> aClass) {
// controller方法上有幂等性注解ApiIdempotent才触发
Method method = methodParameter.getMethod();
return method.isAnnotationPresent(ApiIdempotent.class);
}
@Override
public Result beforeBodyWrite(Result restResult, MethodParameter methodParameter, MediaType mediaType, Class extends HttpMessageConverter>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
String token = "";
if(serverHttpRequest.getHeaders().containsKey(CommonConstant.TRACTIONID)) {
token = serverHttpRequest.getHeaders().get(CommonConstant.TRACTIONID).get(0);
}
if(CommonConstant.SUCCESS.equals(restResult.getCode()) || CommonConstant.PAR_SUCCESS.equals(restResult.getCode()) ){
// 刷新token
int result = tokenService.updateToken(token);
logger.info("request success update token, result:{}", result);
} else if(CommonConstant.PICKCODE01.equals(restResult.getCode())){
int result = tokenService.updateTokenAndMsg(token, restResult.getMessage());
logger.info("request success update token, result:{}", result);
} else {
int result = tokenService.deleteToken(token);
logger.info("request error delete token, result:{}", result);
}
return restResult;
}
}



