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,将不会封装返回结果)
@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 用于定义统一返回结果结构
@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;
@Slf4j
@Aspect
@Component
public class ResulyAspect {
@Pointcut("execution(* com.study.project.controller.*..*(..))")
public void pointAspect() {
}
@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;
@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统一结果封装内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!