Spring使用AOP完成统一结果封装实例demo

 更新时间:2023年02月06日 11:39:29   作者:ss无所事事  
这篇文章主要介绍了Spring使用AOP完成统一结果封装,本文通过实现demo给大家详细讲解,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

Spring使用AOP完成统一结果封装

起因:自己写项目的时候忍受不了每个方法都要写一个retrun Result.success();retrun Result.error();,同时想到项目运行时异常的统一捕捉处理,于是我就在想有没有一种方法能够快捷有效的实现统一返回结果格式的方法。同时也能够比较方便的设置各种参数方便使用,于是我就想到AOP。

Demo实现

引入依赖

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

自定义注解(NoResult.java 使用此注解的method,将不会封装返回结果)

/**
 * @interface自定义注解
 * @Target: 注解的作用目标  PARAMETER:方法参数   METHOD:方法 TYPE:类、接口
 *
 * @Retention:注解的保留位置  RUNTIME  种类型的Annotations将被JVM保留,
 *
 * 能在运行时被JVM或其他使用反射机制的代码所读取和使用
 */
@Documented
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface NoResult {
}

ResultCode.class 用于定义Reponses返回码

public enum ResultCode {
    SUCCESS(0, "操作成功", ""),
    ERROR(1, "操作失败", "");

    private final int code;

    /**
     * 状态码信息
     */
    private final String message;

    /**
     * 状态码描述(详情)
     */
    private final String description;

    ResultCode(int code, String message, String description) {
        this.code = code;
        this.message = message;
        this.description = description;
    }

    public int getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }

    public String getDescription() {
        return description;
    }
}

BaseResponse.java 用于定义统一返回结果结构

/**
 * 通用返回类
 *
 * @param <T>
 * @author Chengming.Zhang
 */
@Data
public class BaseResponse<T> implements Serializable {

    private int code;

    private T data;

    private String message;

    private String description;

    public BaseResponse(int code, T data, String message, String description) {
        this.code = code;
        this.data = data;
        this.message = message;
        this.description = description;
    }

    public BaseResponse(int code, T data, String message) {
        this(code, data, message, "");
    }

    public BaseResponse(int code, T data) {
        this(code, data, "", "");
    }

    public BaseResponse(ResultCode resultCode) {
        this(resultCode.getCode(), null, resultCode.getMessage(), resultCode.getDescription());
    }
    public BaseResponse(ResultCode resultCode, T data) {
        this(resultCode.getCode(), data, resultCode.getMessage(), resultCode.getDescription());
    }
}

切面实现

import com.study.project.annotation.NoResult;
import com.study.project.common.BaseResponse;
import com.study.project.common.ResultCode;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.*;

import java.lang.reflect.Method;

/**
 * @author Chengming.Zhang
 * @date 2023/2/5
 */
@Slf4j
@Aspect
@Component
public class ResulyAspect {
    @Pointcut("execution(* com.study.project.controller.*..*(..))")
    public void pointAspect() {
    }

    /**
     * 环绕通知
     *
     * @param joinPoint
     */
    @Around("pointAspect()")
    public Object doAfter(ProceedingJoinPoint joinPoint) throws Throwable {
        // 转换为method
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        // 包装结果
        return packageResult(joinPoint, method);
    }

    public Object packageResult(ProceedingJoinPoint joinPoint, Method method) throws Throwable {
        Class<?> returnType = method.getReturnType();
        Object result = joinPoint.proceed();
        // void不需要包装
        if (returnType.equals(void.class) || returnType.equals(Void.class)) {
            return result;
        }
        // 设置了不需要包装的接口
        NoResult noResult = method.getAnnotation(NoResult.class);
        if (noResult == null) {
            noResult = method.getDeclaringClass().getAnnotation(NoResult.class);
        }
        if (noResult != null) {
            return result;
        }
        // 非restful风格接口不需要包装
        RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
        GetMapping getMapping = method.getAnnotation(GetMapping.class);
        PostMapping postMapping = method.getAnnotation(PostMapping.class);
        DeleteMapping deleteMapping = method.getAnnotation(DeleteMapping.class);
        PutMapping putMapping = method.getAnnotation(PutMapping.class);
        PatchMapping patchMapping = method.getAnnotation(PatchMapping.class);
        if (requestMapping != null || getMapping != null || postMapping != null || deleteMapping != null || putMapping != null || patchMapping != null) {
            if (result == null) {
                return new BaseResponse(ResultCode.ERROR);
            } else {
                if (result instanceof BaseResponse) {
                    BaseResponse baseResponse = (BaseResponse) result;
                    return baseResponse;
                } else {
                    return new BaseResponse(ResultCode.SUCCESS, result);
                }
            }
        } else {
            return result;
        }
    }
}

代码分析

@Pointcut 注解用于定义一个切面,上述代码中的切面表示com.study.project.controller包及其子包下的所有类和方法
@Around(“pointAspect()”) 表示此方法应用于 pointAspect切面,@Around 表示在切点的前后都执行此方法
这中间其实还有一个小插曲,我本来想用JoinPoint类,并使用@After后置通知的方法,结果我发现我在后置通知的JoinPoint里面无法获取方法的接口result,所以后面就换了ProceedingJoinPoint类,这个类有一个特殊的方法proceed()可以直接获取方法的返回值。

Controller实现

import com.study.project.annotation.NoResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author Chengming.Zhang
 * @date 2023/2/4
 */
@RestController
public class TestController {

    @RequestMapping("/test1")
    public Object test1(){
        return "test1";
    }

    @NoResult
    @RequestMapping("/test2")
    public Object test2(){
        return "test2";
    }

    @RequestMapping("/test3")
    public Object test3(){
        return null;
    }
}

结果

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


到此为止,我们就实现了统一的结果封装。

到此这篇关于Spring使用AOP完成统一结果封装的文章就介绍到这了,更多相关Spring使用AOP统一结果封装内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java中 equals 重写时为什么一定也要重写 hashCode

    Java中 equals 重写时为什么一定也要重写 hashCode

    这篇文章主要介绍了Java中 equals 重写时为什么一定也要重写 hashCode,equals 方法和 hashCode 方法是 Object 类中的两个基础方法,它们共同协作来判断两个对象是否相等,所以之间到底有什么联系呢,接下来和小编一起进入文章学习该内容吧
    2022-05-05
  • AndroidStudio无法新建Java工程的简单解决办法

    AndroidStudio无法新建Java工程的简单解决办法

    AS创建java工程是非常麻烦的,AS没有提供直接创建java工程的方法且常常无法新建,这篇文章主要给大家介绍了关于AndroidStudio无法新建Java工程的简单解决办法,需要的朋友可以参考下
    2024-06-06
  • MyBatisPlus中@TableField注解的基本使用

    MyBatisPlus中@TableField注解的基本使用

    这篇文章主要介绍了MyBatisPlus中@TableField注解的基本使用,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • java音频播放示例分享(java如何播放音频)

    java音频播放示例分享(java如何播放音频)

    java如何播放音频?下面的代码就介绍了java音频播放示例,需要的朋友可以参考下
    2014-04-04
  • java.net.MalformedURLException异常的解决方法

    java.net.MalformedURLException异常的解决方法

    下面小编就为大家带来一篇java.net.MalformedURLException异常的解决方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • Spring中Properties的配置方式

    Spring中Properties的配置方式

    这篇文章主要介绍了Spring中Properties的配置方式,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-02-02
  • RedisKey的失效监听器KeyExpirationEventMessageListener问题

    RedisKey的失效监听器KeyExpirationEventMessageListener问题

    这篇文章主要介绍了RedisKey的失效监听器KeyExpirationEventMessageListener问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • java之super关键字用法实例解析

    java之super关键字用法实例解析

    这篇文章主要介绍了java之super关键字用法实例解析,较为详细的分析了super关键字的用法及内存分布,需要的朋友可以参考下
    2014-09-09
  • 解决在for循环中remove list报错越界的问题

    解决在for循环中remove list报错越界的问题

    这篇文章主要介绍了解决在for循环中remove list报错越界的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • log4j使用详细解析

    log4j使用详细解析

    Log4j 除了可以记录程序运行日志信息外还有一重要的功能就是用来显示调试信息。下面通过本文给大家介绍log4j使用详细解析,感兴趣的朋友一起看看吧
    2017-10-10

最新评论