软件编程
位置:首页>> 软件编程>> java编程>> Spring使用AOP完成统一结果封装实例demo

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(&ldquo;pointAspect()&rdquo;) 表示此方法应用于 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;
   }
}

结果

Spring使用AOP完成统一结果封装实例demo

Spring使用AOP完成统一结果封装实例demo

Spring使用AOP完成统一结果封装实例demo


到此为止,我们就实现了统一的结果封装。

来源:https://blog.csdn.net/qq_43649799/article/details/128887636

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com