Spring使用AOP完成統(tǒng)一結果封裝實例demo
Spring使用AOP完成統(tǒng)一結果封裝
起因:自己寫項目的時候忍受不了每個方法都要寫一個retrun Result.success();和 retrun Result.error();,同時想到項目運行時異常的統(tǒng)一捕捉處理,于是我就在想有沒有一種方法能夠快捷有效的實現(xiàn)統(tǒng)一返回結果格式的方法。同時也能夠比較方便的設置各種參數(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,將不會封裝返回結果)
/**
* @interface自定義注解
* @Target: 注解的作用目標 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)一返回結果結構
/**
* 通用返回類
*
* @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 {
// 轉換為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 表示在切點的前后都執(zhí)行此方法
這中間其實還有一個小插曲,我本來想用JoinPoint類,并使用@After后置通知的方法,結果我發(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;
}
}結果



到此為止,我們就實現(xiàn)了統(tǒng)一的結果封裝。
到此這篇關于Spring使用AOP完成統(tǒng)一結果封裝的文章就介紹到這了,更多相關Spring使用AOP統(tǒng)一結果封裝內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Spring?boot?security權限管理集成cas單點登錄功能的實現(xiàn)
這篇文章主要介紹了Spring?boot?security權限管理集成cas單點登錄,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-03-03
Java用 Rhino/Nashorn 代替第三方 JSON 轉換庫
本篇文章主要介紹了Java用 Rhino/Nashorn 代替第三方 JSON 轉換庫,非常具有實用價值,需要的朋友可以參考下2017-05-05
Java wait和notifyAll實現(xiàn)簡單的阻塞隊列
這篇文章主要介紹了Java wait和notifyAll實現(xiàn)簡單的阻塞隊列,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-10-10
SpringBoot配置logback.xml 多環(huán)境的操作步驟
最近在研究springboot的日志,所以記錄一下,做一下總結,今天重點給大家介紹SpringBoot配置logback.xml 多環(huán)境的操作步驟,要實現(xiàn)多環(huán)境的配置,主要是依賴于springboot的application.yml文件去實現(xiàn),感興趣的朋友跟隨小編一起看看吧2021-05-05

