spring boot AOP 1-- 封装统一的返回值

spring boot AOP 1-- 封装统一的返回值

日常工作中,经常遇到需要restful接口实现统一的返回值。即返回值要求返回统一的格式,即如下这种格式:

@Builder
@Data
public class ResponseData {
    /**
     * 错误信息
     */
    private String message;

    /**
     * 返回的code
     */
    private String code;

    /**
     * 返回的数据
     */
    private Object data;
}

要实现接口都实现这样效果,我们可以想到springAOP功能,在返回值的切面上对数据进行处理。

实现一 @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;

    }
}

代码说明:

  1. @Aspect表名这是一个切面类,spring boot会指定切面上执行方法。
  2. @Pointcut("execution(public * com.admin.spring.controller..*(..))")表明这是指定的切面方法,其中com.admin.spring.controller下面的所有类执行完后,就会进行AOP处理。
  3. 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);
    }
}

代码说明

  1. ResponseBodyWrapFactoryBean是个普通的bean,但是它有一个成员变量RequestMappingHandlerAdapter。在它的初始化的方法中afterPropertiesSet,获取得到RequestResponseBodyMethodProcessor返回值的处理器。
  2. decorateHandler中对RequestResponseBodyMethodProcessor的处理器进行包装。
  3. ResponseBodyWrapHandler包装处理器实现HandlerMethodReturnValueHandler的方法。
  4. handleReturnValue中先判断classreturnValue上是否有@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;
    }

}

代码说明

  1. @ControllerAdvice是为那些声明了(@ExceptionHandler@InitBinder@ModelAttribute注解修饰的)方法的类而提供的专业化的@Component , 以供多个 Controller类所共享。
  2. handlerException处理controller层返回的异常。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Spring Boot是一个用于构建独立的、生产级别的Spring应用程序的框架,它提供了丰富的功能和特性,方便开发人员快速搭建和开发项目。 在Spring Boot中使用AOP(面向切面编程)可以实现将一些公共的功能逻辑代码从业务逻辑代码中解耦出来,提高代码的复用性和可维护性。通过AOP可以在方法的前后注入一些通用的逻辑,例如日志记录、异常处理、权限校验等。 其中,使用AOP进行结果的统一封装是很常见的需求。通过AOP可以在方法执行后对返回的结果进行封装统一处理返回结果的格式,并可以对结果进行一些统一的处理操作,例如添加统一返回码、返回信息、返回时间等。 在Spring Boot中使用AOP进行结果的统一封装可以按照以下步骤进行: 1. 创建一个切面(Aspect),通过在切面类上加上@Aspect注解标识该类是一个切面类。 2. 在切面类中定义一个切点(Pointcut),通过定义一个方法并添加@Pointcut注解来指定切入点。 3. 在切面类中定义一个通知(Advice),通过@Before、@After、@Around等注解来指定通知类型,并在通知方法中编写需要执行的逻辑。 4. 在通知方法中获取方法的返回结果,并进行相应的封装和处理。 5. 在Spring Boot的配置类中添加@EnableAspectJAutoProxy注解来启用AOP。 使用以上步骤可以实现对方法返回结果的统一封装,使得返回结果具有统一的格式和处理逻辑。这样可以提高代码的重用性和可维护性,并且可以在一处对结果进行集中处理,减少了代码的重复性,提高了开发效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值