Spring使用AOP完成統(tǒng)一結(jié)果封裝實(shí)例demo
Spring使用AOP完成統(tǒng)一結(jié)果封裝
起因:自己寫項(xiàng)目的時(shí)候忍受不了每個(gè)方法都要寫一個(gè)retrun Result.success();和 retrun Result.error();,同時(shí)想到項(xiàng)目運(yùn)行時(shí)異常的統(tǒng)一捕捉處理,于是我就在想有沒有一種方法能夠快捷有效的實(shí)現(xiàn)統(tǒng)一返回結(jié)果格式的方法。同時(shí)也能夠比較方便的設(shè)置各種參數(shù)方便使用,于是我就想到AOP。
Demo實(shí)現(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,將不會(huì)封裝返回結(jié)果)
/**
* @interface自定義注解
* @Target: 注解的作用目標(biāo) PARAMETER:方法參數(shù) METHOD:方法 TYPE:類、接口
*
* @Retention:注解的保留位置 RUNTIME 種類型的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)
/**
* 通用返回類
*
* @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包及其子包下的所有類和方法@Around(“pointAspect()”) 表示此方法應(yīng)用于 pointAspect切面,@Around 表示在切點(diǎn)的前后都執(zhí)行此方法
這中間其實(shí)還有一個(gè)小插曲,我本來想用JoinPoint類,并使用@After后置通知的方法,結(jié)果我發(fā)現(xiàn)我在后置通知的JoinPoint里面無法獲取方法的接口result,所以后面就換了ProceedingJoinPoint類,這個(gè)類有一個(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)用戶登錄統(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ān)文章
Java中?equals?重寫時(shí)為什么一定也要重寫?hashCode
這篇文章主要介紹了Java中?equals?重寫時(shí)為什么一定也要重寫?hashCode,equals?方法和?hashCode?方法是?Object?類中的兩個(gè)基礎(chǔ)方法,它們共同協(xié)作來判斷兩個(gè)對(duì)象是否相等,所以之間到底有什么聯(lián)系呢,接下來和小編一起進(jìn)入文章學(xué)習(xí)該內(nèi)容吧2022-05-05
AndroidStudio無法新建Java工程的簡單解決辦法
AS創(chuàng)建java工程是非常麻煩的,AS沒有提供直接創(chuàng)建java工程的方法且常常無法新建,這篇文章主要給大家介紹了關(guān)于AndroidStudio無法新建Java工程的簡單解決辦法,需要的朋友可以參考下2024-06-06
MyBatisPlus中@TableField注解的基本使用
這篇文章主要介紹了MyBatisPlus中@TableField注解的基本使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07
java.net.MalformedURLException異常的解決方法
下面小編就為大家?guī)硪黄猨ava.net.MalformedURLException異常的解決方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-05-05
RedisKey的失效監(jiān)聽器KeyExpirationEventMessageListener問題
這篇文章主要介紹了RedisKey的失效監(jiān)聽器KeyExpirationEventMessageListener問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05
java之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ò)越界的問題
這篇文章主要介紹了解決在for循環(huán)中remove list報(bào)錯(cuò)越界的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-12-12

