Spring AOP 自定义注解用于切面参数验证

一、首先先了解一下AOP

  1. AOP(Aspect-Oriented Programming,面向切面编程):是一种新的方法,是对传统OOP(Programming,面向对象编程)的补充

  2. AOP的主要编程对象是切面(asspect),而切面模块化横切关注点。
  3. 在应用AOP编程时,仍需要定义公共功能,但可以明确的定义这个功能在哪里,以什么方式应用,并且不必修改受影响的类,这样一来横切关注点就被模块化到特殊对象(切面)里。
  4. AOP的好处:

           每个事物逻辑位于一个位置,代码不分散,便于维护和升级。

           业务模块更简洁,只包含核心业务代码。

     5.AspectJ:Java社区里最完整最流行的AOP框架

     6.在Spring2.0以上版本中,可以使用基于AspectJ注解或基于XML配置AOP

二、相关注解

          1.Advice(通知、切面): 某个连接点所采用的处理逻辑,也就是向连接点注入的代码, AOP在特定的切入点上执行的增强处理。

                1.1 @Before: 标识一个前置增强方法,相当于BeforeAdvice的功能.
                1.2 @After: final增强,不管是抛出异常或者正常退出都会执行.
                1.3 @AfterReturning: 后置增强,似于AfterReturningAdvice, 方法正常退出时执行.
                1.4 @AfterThrowing: 异常抛出增强,相当于ThrowsAdvice.
                1.5 @Around: 环绕增强,相当于MethodInterceptor.

  2.JointPoint(连接点):程序运行中的某个阶段点,比如方法的调用、异常的抛出等。

 3.Pointcut(切入点): JoinPoint的集合,是程序中需要注入Advice的位置的集合,指明Advice要在什么样的条件下才能被触发,在程序中主要体现为书写切入点表达式。

由下列方式来定义或者通过 &&、 ||、 !、 的方式进行组合:

例:@Pointcut("execution(* com.savage.aop.MessageSender.*(..))")

  • execution:用于匹配方法执行的连接点;
  • within:用于匹配指定类型内的方法执行;
  • this:用于匹配当前AOP代理对象类型的执行方法;注意是AOP代理对象的类型匹配,这样就可能包括引入接口也类型匹配;
  • target:用于匹配当前目标对象类型的执行方法;注意是目标对象的类型匹配,这样就不包括引入接口也类型匹配;
  • args:用于匹配当前执行的方法传入的参数为指定类型的执行方法;
  • @within:用于匹配所以持有指定注解类型内的方法;
  • @target:用于匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解;
  • @args:用于匹配当前执行的方法传入的参数持有指定注解的执行;
  • @annotation:用于匹配当前执行方法持有指定注解的方法;

4.Advisor(增强): 是PointCut和Advice的综合体,完整描述了一个advice将会在pointcut所定义的位置被触发。

5.@Aspect(切面): 通常是一个类的注解,里面可以定义切入点和通知

三、实际操作,切面参数验证

第一步:添加jar包

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>1.8.13</version>
</dependency>

第二步:自定义注解,用于切面参数验证:

package com.codebase.aop;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * @Auther:wanglc
 * @Date: 2020/3/2
 * @Description:
 * @Version:
 */
//@Target注解用于设定注解的使用范围
@Target({ElementType.METHOD})
//@Retention:作用是定义被它定义的注解保留多久,
@Retention(RetentionPolicy.RUNTIME)
public @interface AopInteValidator {

}

第二步:定义,切面验证数据格式

package com.codebase.aop;
import com.codebase.config.ResponseInfo;
import com.codebase.exception.FailedException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.validation.*;
import java.util.*;
/**
 * @Auther:wanglc
 * @Date: 2020/3/2
 * @Description:
 * @Version:
 */
@Aspect
@Component
public class ValidatorAspect {

    @Autowired
    private Validator validator;
    //定义一个方法,用于声明切入表达式。
    @Pointcut("@annotation(com.codebase.aop.AopInteValidator)")
    public void validatorPointcut() {
    }

    @Before("validatorPointcut()")
    public void doBefore(JoinPoint joinPoint) {
        {
            boolean isHave = false;
            Set<ConstraintViolation<Object>> violations = null;
            List result = new ArrayList();
            //取参数
            List<Object> args = Arrays.asList(joinPoint.getArgs());
            if(args.size()>0 && args != null){
                violations = validator.validate(args.get(0));
                List<String> mesList = new ArrayList<String>();
                if (violations.size() > 0) {
                    isHave = true;
                    for (ConstraintViolation<Object> c : violations) {
                        mesList.add(c.getMessageTemplate());
                    }
                    result.add(mesList);
                }
            }
            if (isHave) {
                throw new FailedException(ResponseInfo.FORMAT_ERROR.getErrorCode(),
                        ResponseInfo.FORMAT_ERROR.getErrorMsg(),result);
            }
        }
    }
}
package com.codebase.exception;
import com.codebase.config.ResponseInfo;
import java.util.List;

public class FailedException extends RuntimeException {
    private int code;
    private String messgae;
    private List data;

    public FailedException(String msg) {
        this.code = ResponseInfo.UNKNOW_ERROR.getErrorCode();
        this.messgae = msg;
    }
    public FailedException(int code, String msg) {
        this.code = code;
        this.messgae = msg;
    }
    public FailedException(int code, String msg, List data) {
        this.code = code;
        this.messgae = msg;
        this.data=data;
    }
    public int getCode(){
        return this.code;
    }
    public void setCode(int code){
        this.code = code;
    }
    public String getMessgae() {
        return messgae;
    }
    public List getData(){
        return data;
    }
}
package com.codebase.config;
public enum ResponseInfo {

    SUCCESS(200,"SUCCESS"),

    //用户认证异常
    USERNAME_ERROR(1001,"用户名错误"),
    USERNAME_EMPTY(1002,"用户名不能为空"),
    PASSWORD_ERROR(1003,"密码错误"),
    PASSWORD_EMPTY(1004,"密码不能为空"),
    AUTH_FAILED(1005,"认证失败"),

    //系统错误异常
    UNKNOW_ERROR(8000, "未知错误"),

    PARAM_ERROR(9000, "参数格式错误"),
    FORMAT_ERROR(9001, "格式错误"),
    SERVER_ERROR(9999, "服务器异常");

    private int errorCode;
    private String errorMessage;

    ResponseInfo(int code, String msg) {
        this.errorCode = code;
        this.errorMessage = msg;
    }
    public int getErrorCode() {
        return errorCode;
    }

    public String getErrorMsg() {
        return errorMessage;
    }

    public static String getResponseErrorMsg(String code) {

        for(ResponseInfo responseInfo: ResponseInfo.values()) {

            if(code.equals(responseInfo.getErrorCode())) {

                return responseInfo.getErrorMsg();
            }
        }
        return SERVER_ERROR.getErrorMsg();
    }

    public static int getResponseErrorCode(String msg) {
        if(msg == null) {
            return UNKNOW_ERROR.getErrorCode();
        }
        for(ResponseInfo responseInfo: ResponseInfo.values()) {

            if(msg.equals(responseInfo.getErrorMsg())) {
                return responseInfo.getErrorCode();
            }
        }
        return SERVER_ERROR.getErrorCode();
    }
}

实体类

package com.codebase.bean;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;

import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;

/**
 * @Auther:wanglc
 * @Date: 2020/3/2
 * @Description:
 * @Version:
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    @ApiModelProperty("姓名")
    @NotEmpty(message ="name不能为空")
    @Length(max = 10,message = "name长度不能超过10")
    private String name;
    @ApiModelProperty("邮箱")
    @NotEmpty(message ="email不能为空")
    @Length(max = 12,message = "email长度不能超过12")
    private String email;
    @ApiModelProperty("地址")
    @NotEmpty(message ="addr不能为空")
    @Length(max = 50,message = "addr长度不能超过50")
    private String addr;
    @ApiModelProperty("年龄")
    @NotNull(message = "age不能为空")
    private int age;
}

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值