Spring使用AOP完成統(tǒng)一結(jié)果封裝實(shí)例demo
Spring使用AOP完成統(tǒng)一結(jié)果封裝
起因:自己寫(xiě)項(xiàng)目的時(shí)候忍受不了每個(gè)方法都要寫(xiě)一個(gè)retrun Result.success();
和 retrun Result.error();
,同時(shí)想到項(xiàng)目運(yùn)行時(shí)異常的統(tǒng)一捕捉處理,于是我就在想有沒(méi)有一種方法能夠快捷有效的實(shí)現(xiàn)統(tǒng)一返回結(jié)果格式的方法。同時(shí)也能夠比較方便的設(shè)置各種參數(shù)方便使用,于是我就想到AOP。
Demo實(shí)現(xiàn)
引入依賴(lài)
<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,將不會(huì)封裝返回結(jié)果)
/** * @interface自定義注解 * @Target: 注解的作用目標(biāo) PARAMETER:方法參數(shù) METHOD:方法 TYPE:類(lèi)、接口 * * @Retention:注解的保留位置 RUNTIME 種類(lèi)型的Annotations將被JVM保留, * * 能在運(yùn)行時(shí)被JVM或其他使用反射機(jī)制的代碼所讀取和使用 */ @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)
/** * 通用返回類(lèi) * * @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()); } }
切面實(shí)現(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
注解用于定義一個(gè)切面,上述代碼中的切面表示com.study.project.controller
包及其子包下的所有類(lèi)和方法@Around(“pointAspect()”)
表示此方法應(yīng)用于 pointAspect
切面,@Around
表示在切點(diǎn)的前后都執(zhí)行此方法
這中間其實(shí)還有一個(gè)小插曲,我本來(lái)想用JoinPoint
類(lèi),并使用@After
后置通知的方法,結(jié)果我發(fā)現(xiàn)我在后置通知的JoinPoint
里面無(wú)法獲取方法的接口result,所以后面就換了ProceedingJoinPoint
類(lèi),這個(gè)類(lèi)有一個(gè)特殊的方法proceed()
可以直接獲取方法的返回值。
Controller實(shí)現(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é)果
到此為止,我們就實(shí)現(xiàn)了統(tǒng)一的結(jié)果封裝。
到此這篇關(guān)于Spring使用AOP完成統(tǒng)一結(jié)果封裝的文章就介紹到這了,更多相關(guān)Spring使用AOP統(tǒng)一結(jié)果封裝內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Spring AOP與AspectJ的對(duì)比及應(yīng)用詳解
- SpringBoot使用AOP與注解實(shí)現(xiàn)請(qǐng)求參數(shù)自動(dòng)填充流程詳解
- Spring AOP統(tǒng)一功能處理示例代碼
- Spring?AOP實(shí)現(xiàn)用戶(hù)登錄統(tǒng)一驗(yàn)證功能
- Spring AOP源碼深入分析
- Spring AOP如何自定義注解實(shí)現(xiàn)審計(jì)或日志記錄(完整代碼)
- Spring?AOP實(shí)現(xiàn)聲明式事務(wù)機(jī)制源碼解析
- Spring AOP的概念與實(shí)現(xiàn)過(guò)程詳解
相關(guān)文章
Java中?equals?重寫(xiě)時(shí)為什么一定也要重寫(xiě)?hashCode
這篇文章主要介紹了Java中?equals?重寫(xiě)時(shí)為什么一定也要重寫(xiě)?hashCode,equals?方法和?hashCode?方法是?Object?類(lèi)中的兩個(gè)基礎(chǔ)方法,它們共同協(xié)作來(lái)判斷兩個(gè)對(duì)象是否相等,所以之間到底有什么聯(lián)系呢,接下來(lái)和小編一起進(jìn)入文章學(xué)習(xí)該內(nèi)容吧2022-05-05AndroidStudio無(wú)法新建Java工程的簡(jiǎn)單解決辦法
AS創(chuàng)建java工程是非常麻煩的,AS沒(méi)有提供直接創(chuàng)建java工程的方法且常常無(wú)法新建,這篇文章主要給大家介紹了關(guān)于AndroidStudio無(wú)法新建Java工程的簡(jiǎn)單解決辦法,需要的朋友可以參考下2024-06-06MyBatisPlus中@TableField注解的基本使用
這篇文章主要介紹了MyBatisPlus中@TableField注解的基本使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07java.net.MalformedURLException異常的解決方法
下面小編就為大家?guī)?lái)一篇java.net.MalformedURLException異常的解決方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05RedisKey的失效監(jiān)聽(tīng)器KeyExpirationEventMessageListener問(wèn)題
這篇文章主要介紹了RedisKey的失效監(jiān)聽(tīng)器KeyExpirationEventMessageListener問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05java之super關(guān)鍵字用法實(shí)例解析
這篇文章主要介紹了java之super關(guān)鍵字用法實(shí)例解析,較為詳細(xì)的分析了super關(guān)鍵字的用法及內(nèi)存分布,需要的朋友可以參考下2014-09-09解決在for循環(huán)中remove list報(bào)錯(cuò)越界的問(wèn)題
這篇文章主要介紹了解決在for循環(huán)中remove list報(bào)錯(cuò)越界的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-12-12