当前位置:主页 > java教程 > Spring使用AOP统一结果封装

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

发布:2023-04-14 10:20:01 59


给寻找编程代码教程的朋友们精选了相关的编程文章,网友红白山根据主题投稿了本篇教程内容,涉及到Spring使用AOP统一结果封装、Spring统一结果封装、Spring AOP封装、Spring使用AOP统一结果封装相关内容,已被390网友关注,相关难点技巧可以阅读下方的电子资料。

Spring使用AOP统一结果封装

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


参考资料

相关文章

网友讨论