Spring使用AOP完成统一结果封装实例demo
作者: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统一结果封装内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!