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统一结果封装内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot中配置AOP详解

    SpringBoot中配置AOP详解

    这篇文章主要介绍了SpringBoot中配置AOP详解,Spring Boot 在Spring 的基础上对AOP的配置提供了自动化配置解决方案spring-boot-starter-aop,使开发者能够更加便捷地在Spring Boot项目中使用AOP,需要的朋友可以参考下
    2024-01-01
  • Spring boot security权限管理集成cas单点登录功能的实现

    Spring boot security权限管理集成cas单点登录功能的实现

    这篇文章主要介绍了Spring boot security权限管理集成cas单点登录,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-03-03
  • Java用 Rhino/Nashorn 代替第三方 JSON 转换库

    Java用 Rhino/Nashorn 代替第三方 JSON 转换库

    本篇文章主要介绍了Java用 Rhino/Nashorn 代替第三方 JSON 转换库,非常具有实用价值,需要的朋友可以参考下
    2017-05-05
  • Java wait和notifyAll实现简单的阻塞队列

    Java wait和notifyAll实现简单的阻塞队列

    这篇文章主要介绍了Java wait和notifyAll实现简单的阻塞队列,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-10-10
  • Spring配置文件无法读取properties属性的解决

    Spring配置文件无法读取properties属性的解决

    这篇文章主要介绍了Spring配置文件无法读取properties属性的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • mybatis 字段名自动转小写的实现

    mybatis 字段名自动转小写的实现

    这篇文章主要介绍了mybatis 字段名自动转小写的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • Java简单实现定时器

    Java简单实现定时器

    这篇文章主要为大家详细介绍了Java简单实现定时器,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-04-04
  • SpringBoot配置logback.xml 多环境的操作步骤

    SpringBoot配置logback.xml 多环境的操作步骤

    最近在研究springboot的日志,所以记录一下,做一下总结,今天重点给大家介绍SpringBoot配置logback.xml 多环境的操作步骤,要实现多环境的配置,主要是依赖于springboot的application.yml文件去实现,感兴趣的朋友跟随小编一起看看吧
    2021-05-05
  • 关于gradle多模块项目依赖管理方式

    关于gradle多模块项目依赖管理方式

    这篇文章主要介绍了关于gradle多模块项目依赖管理方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • Java转换解析中间带有 “T“和“Z“ 的时间格式

    Java转换解析中间带有 “T“和“Z“ 的时间格式

    这篇文章主要给大家介绍了关于Java转换解析中间带有 “T“和“Z“ 的时间格式,相信很多小伙伴在时间格式转换的时候非常头疼,文中通过代码示例介绍的非常详细,需要的朋友可以参考下
    2024-01-01

最新评论