Spring使用AOP完成统一结果封装实例demo
作者:ss无所事事 发布时间:2021-12-16 18:49:06
标签: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;
}
}
结果
到此为止,我们就实现了统一的结果封装。
来源:https://blog.csdn.net/qq_43649799/article/details/128887636


猜你喜欢
- 目录1、创建 Android 库2、上传aar包至Maven * 3、其他项目使用4、QA1、创建 Android 库按以下步骤在项目中创建新
- MybatisPlus分页排序查询字段带有下划线如果使用MybatisPlus的自动转驼峰命名法,分页排序查询的字段带有下划线时,会出问题。
- 一直以来做对外的接口文档都比较原始,基本上都是手写的文档传来传去,最近发现了一个新玩具,可以在接口上省去不少麻烦。swagger是一款方便展
- 本文实例为大家分享了Android仿京东分类效果展示的具体代码,供大家参考,具体内容如下1.写一个fragmentimport androi
- 本文以实例形式展示了基于C#实现Windows服务状态启动和停止服务的方法。非常实用。分享给大家供大家参考之用。具体方法如下:首先先引用:S
- 本文实例为大家分享了RxJava Retrofit实现购物车展示的具体代码,供大家参考,具体内容如下先给大家展示一下效果图框架结构: 1.项
- 引入线程是为了减少程序在并发执行时所付出的时空开销。属性:轻型实体。它不拥有系统资源,只是有一点必不可少的、能保证独立运行的资源。独立调度和
- 目录1、如果一个方法或变量是"private"访问级别,那么它的访问范围是:2、代码将打印?3、下面关于hibernat
- 1、spring原理内部最核心的就是IOC了,动态注入,让一个对象的创建不用new了,可以自动的生产,这其实就是利用java里的反射,反射其
- 一、前言在编码过程中,常常需要写打印日志语句,我们期望的是同一个业务的日志都在一块,在出问题的时候好根据日志来排查问题。而现实是在应用运行中
- 本文实例讲述了Android编程之手机壁纸WallPaper设置方法。分享给大家供大家参考,具体如下:/** * Andorid设置手机屏幕
- Word中设置水印时,可使用预设的文字或自定义文字设置为水印效果,但通常添加水印效果时,会对所有页面都设置成统一效果,如果需要对每一页或者某
- 目录一、集合框架的概述二、集合框架(Java集合可分为Collection 和 Map 两种体系)三、Collection接口中的方法的使用
- 进行双重foreach循环mapname是一个Map<String,Map<String,Object>> 对象&l
- 1. 安装JDK解释: JDK是Java编写环境--开发环境注: 安装路径不可出现中文及标点符号。比如:D:\Java\jdk81.1 下载
- 代码很简单,这里就不多废话了。package cc.c;import android.app.Activity;import android
- Android 如何修改APK的默认名称用Android Studio 打包App时生成的名称默认是 app-release.apk(已签名
- 先给大家展示下效果图,对第三方开源 android tickplusdrawable相关知识感兴趣的朋友一起学习吧。Android tick
- Maven依赖:<dependency><groupId>de.rototor.jeuclid</groupI
- 做tcp网络编程,要解析一批批的数据,可是数据是通过Socket连接的InputStream一次次读取的,读取到的不是需要转换的对象,而是要