Spring使用AOP完成统一结果封装实例demo
作者:ss无所事事 时间:2021-12-16 18:49:06
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;
}
}
结果
到此为止,我们就实现了统一的结果封装。
来源:https://blog.csdn.net/qq_43649799/article/details/128887636
标签:Spring,AOP,统一结果封装
0
投稿
猜你喜欢
Java设计模式之观察者模式(Observer模式)介绍
2022-10-16 04:40:42
JavaWeb开发之【Tomcat 环境配置】MyEclipse+IDEA配置教程
2022-05-04 12:50:18
使用Spring事件机制实现异步的方法
2023-06-23 06:47:08
Java利用Selenium操作浏览器的示例详解
2022-06-17 17:34:20
MyBatis学习教程(四)-如何快速解决字段名与实体类属性名不相同的冲突问题
2023-11-25 05:43:49
Java线程间的通信方式详解
2022-05-20 10:33:47
C语言多种获取字符串长度的方法
2021-07-01 16:30:29
Android自定义View仿IOS圆盘时间选择器
2023-10-12 20:40:32
理解Java多线程之并发编程
2021-11-25 11:14:56
java JVM原理与常识知识点
2022-06-24 16:26:50
android Launcher3设置默认桌面应用
2022-07-20 20:18:42
Spring实战之注入集合值操作示例
2023-03-04 04:02:53
C#中decimal保留2位有效小数的实现方法
2023-01-30 07:35:13
Idea jdk版本问题解决方案
2022-04-14 11:57:41
Java实现石头剪刀布小游戏
2023-02-25 22:41:29
ADO.NET实体数据模型详细介绍
2023-10-16 12:15:41
Kotlin编程循环控制示例详解
2022-06-02 11:53:54
android POST数据遇到的UTF-8编码(乱码)问题解决办法
2022-09-12 22:31:46
C#表达式目录树示例详解
2021-10-01 01:52:46
详解Guava中EventBus的使用
2021-09-13 07:36:34