spring boot
AOP 1-- 封装统一的返回值
日常工作中,经常遇到需要restful
接口实现统一的返回值。即返回值要求返回统一的格式,即如下这种格式:
@Builder
@Data
public class ResponseData {
/**
* 错误信息
*/
private String message;
/**
* 返回的code
*/
private String code;
/**
* 返回的数据
*/
private Object data;
}
要实现接口都实现这样效果,我们可以想到spring
的AOP
功能,在返回值的切面上对数据进行处理。
实现一 @Aspect
@Slf4j
@Aspect
@Component
public class ResponseAspect {
/**
* 切面方法
* 封装函数返回值
*/
@Pointcut("execution(public * com.admin.spring.controller..*(..))")
public void wrapResponse() {
log.info("Wrap HttpResponse");
}
/**
* 环切方法
*
* @param proceedingJoinPoint
* @return
*/
@Around(value = "wrapResponse()")
public ResponseData doAround(ProceedingJoinPoint proceedingJoinPoint) {
ResponseData re = new ResponseData();
try {
//获取方法的执行结果
Object obj = proceedingJoinPoint.proceed();
//判断返回类型是否是ResponseData
if(obj instanceof ResponseData) {
return (ResponseData)obj;
}
//构建返回对象
re = ResponseData.builder().code("200")
.data(obj).build();
} catch (Throwable th) {
//构建异常的放回对象
re = ResponseData.builder().code("500")
.message(th.getMessage()).build();
}
return re;
}
}
代码说明:
- @Aspect表名这是一个切面类,
spring boot
会指定切面上执行方法。 @Pointcut("execution(public * com.admin.spring.controller..*(..))")
表明这是指定的切面方法,其中com.admin.spring.controller
下面的所有类执行完后,就会进行AOP处理。proceedingJoinPoint.proceed();
获取返回值。然后判断函数的返回值是否ResponseData
类型,是就直接返回,否就进行封装。
实现二 HandlerMethodReturnValueHandler
@Component
public class ResponseBodyWrapFactoryBean implements InitializingBean {
private final RequestMappingHandlerAdapter adapter;
@Autowired
public ResponseBodyWrapFactoryBean(RequestMappingHandlerAdapter adapter) {
this.adapter = adapter;
}
@Override
public void afterPropertiesSet() throws Exception {
//获取所有返回值的处理器
List<HandlerMethodReturnValueHandler> returnValueHandlers = adapter.getReturnValueHandlers();
if(returnValueHandlers.size() > 0) {
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(returnValueHandlers);
decorateHandler(handlers);
adapter.setReturnValueHandlers(handlers);
}
}
/**
* 包装返回值处理器
* @param handlers
*/
private void decorateHandler(List<HandlerMethodReturnValueHandler> handlers) {
for(HandlerMethodReturnValueHandler handler : handlers) {
//获取得到返回值处理器
if(handler instanceof RequestResponseBodyMethodProcessor) {
ResponseBodyWrapHandler decorator = new ResponseBodyWrapHandler(handler);
int index = handlers.indexOf(handler);
handlers.set(index, decorator);
break;
}
}
}
}
public class ResponseBodyWrapHandler implements HandlerMethodReturnValueHandler {
private final HandlerMethodReturnValueHandler delegate;
@Autowired
public ResponseBodyWrapHandler(HandlerMethodReturnValueHandler delegate) {
this.delegate = delegate;
}
@Override
public boolean supportsReturnType(MethodParameter returnType) {
//支持的类型
return delegate.supportsReturnType(returnType);
}
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
//获取类上的注解
//如果注解了@IgnoreResponseWrapper 就不对返回值进行包装
IgnoreResponseWrapper wraper = returnType.getDeclaringClass().getAnnotation(IgnoreResponseWrapper.class);
if(wraper != null) {
delegate.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
return;
}
//获取返回类型上的注解
//如果注解了@IgnoreResponseWrapper 就不对返回值进行包装
wraper = returnType.getMethodAnnotation(IgnoreResponseWrapper.class);
if(wraper != null) {
delegate.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
return;
}
ResponseData res = new ResponseData();
res.setCode("200");
res.setData(returnValue);
delegate.handleReturnValue(res, returnType, mavContainer, webRequest);
}
}
代码说明
ResponseBodyWrapFactoryBean
是个普通的bean
,但是它有一个成员变量RequestMappingHandlerAdapter
。在它的初始化的方法中afterPropertiesSet
,获取得到RequestResponseBodyMethodProcessor
返回值的处理器。- 在
decorateHandler
中对RequestResponseBodyMethodProcessor
的处理器进行包装。 ResponseBodyWrapHandler
包装处理器实现HandlerMethodReturnValueHandler
的方法。- 在
handleReturnValue
中先判断class
,returnValue
上是否有@IgnoreResponseWrapper
来决定是否对返回值进行包装。
上面的方法存在一个问题就是,没有实现对异常的封装,只能对返回值封装,因此我们还需要使用@ControllerAdvice
来对返回值进行处理:
@ControllerAdvice
public class ResponseAdvice {
/**
*
* @param
* @return
*/
@ResponseBody
@ExceptionHandler(value = Exception.class)
public ResponseData handlerException(Exception e) {
ResponseData r = new ResponseData();
r.setData(null);
r.setCode("500");
r.setMessage(e.getMessage());
return r;
}
}
代码说明
@ControllerAdvice
是为那些声明了(@ExceptionHandler
、@InitBinder
或@ModelAttribute
注解修饰的)方法的类而提供的专业化的@Component
, 以供多个Controller
类所共享。handlerException
处理controller
层返回的异常。