Spring使用AOP完成統(tǒng)一結(jié)果封裝實例demo
Spring使用AOP完成統(tǒng)一結(jié)果封裝
起因:自己寫項目的時候忍受不了每個方法都要寫一個retrun Result.success();
和 retrun Result.error();
,同時想到項目運行時異常的統(tǒng)一捕捉處理,于是我就在想有沒有一種方法能夠快捷有效的實現(xiàn)統(tǒng)一返回結(jié)果格式的方法。同時也能夠比較方便的設(shè)置各種參數(shù)方便使用,于是我就想到AOP。
Demo實現(xiàn)
引入依賴
<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,將不會封裝返回結(jié)果)
/** * @interface自定義注解 * @Target: 注解的作用目標(biāo) PARAMETER:方法參數(shù) 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; /** * 狀態(tài)碼信息 */ private final String message; /** * 狀態(tài)碼描述(詳情) */ 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 用于定義統(tǒng)一返回結(jié)果結(jié)構(gòu)
/** * 通用返回類 * * @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()); } }
切面實現(xiàn)
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() { } /** * 環(huán)繞通知 * * @param joinPoint */ @Around("pointAspect()") public Object doAfter(ProceedingJoinPoint joinPoint) throws Throwable { // 轉(zhuǎn)換為method MethodSignature signature = (MethodSignature) joinPoint.getSignature(); Method method = signature.getMethod(); // 包裝結(jié)果 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; } // 設(shè)置了不需要包裝的接口 NoResult noResult = method.getAnnotation(NoResult.class); if (noResult == null) { noResult = method.getDeclaringClass().getAnnotation(NoResult.class); } if (noResult != null) { return result; } // 非restful風(fēng)格接口不需要包裝 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()”)
表示此方法應(yīng)用于 pointAspect
切面,@Around
表示在切點的前后都執(zhí)行此方法
這中間其實還有一個小插曲,我本來想用JoinPoint
類,并使用@After
后置通知的方法,結(jié)果我發(fā)現(xiàn)我在后置通知的JoinPoint
里面無法獲取方法的接口result,所以后面就換了ProceedingJoinPoint
類,這個類有一個特殊的方法proceed()
可以直接獲取方法的返回值。
Controller實現(xiàn)
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; } }
結(jié)果
到此為止,我們就實現(xiàn)了統(tǒng)一的結(jié)果封裝。
到此這篇關(guān)于Spring使用AOP完成統(tǒng)一結(jié)果封裝的文章就介紹到這了,更多相關(guān)Spring使用AOP統(tǒng)一結(jié)果封裝內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java中?equals?重寫時為什么一定也要重寫?hashCode
這篇文章主要介紹了Java中?equals?重寫時為什么一定也要重寫?hashCode,equals?方法和?hashCode?方法是?Object?類中的兩個基礎(chǔ)方法,它們共同協(xié)作來判斷兩個對象是否相等,所以之間到底有什么聯(lián)系呢,接下來和小編一起進入文章學(xué)習(xí)該內(nèi)容吧2022-05-05AndroidStudio無法新建Java工程的簡單解決辦法
AS創(chuàng)建java工程是非常麻煩的,AS沒有提供直接創(chuàng)建java工程的方法且常常無法新建,這篇文章主要給大家介紹了關(guān)于AndroidStudio無法新建Java工程的簡單解決辦法,需要的朋友可以參考下2024-06-06MyBatisPlus中@TableField注解的基本使用
這篇文章主要介紹了MyBatisPlus中@TableField注解的基本使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-07-07java.net.MalformedURLException異常的解決方法
下面小編就為大家?guī)硪黄猨ava.net.MalformedURLException異常的解決方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-05-05RedisKey的失效監(jiān)聽器KeyExpirationEventMessageListener問題
這篇文章主要介紹了RedisKey的失效監(jiān)聽器KeyExpirationEventMessageListener問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05解決在for循環(huán)中remove list報錯越界的問題
這篇文章主要介紹了解決在for循環(huán)中remove list報錯越界的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12