Spring 自定义注解

1、@Taget注解详解

@Target说明了Annotation所修饰的对象范围:Annotation可被用于 packagestypes(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。

具体属性如下:

  • ElementType.TYPE:说明该注解只能被声明在一个类前;
  • ElementType.FIELD:说明该注解只能被声明在一个类的字段前;
  • ElementType.METHOD:说明该注解只能被声明在一个类的方法前;
  • ElementType.PARAMETER:说明该注解只能被声明在一个方法参数前;
  • ElementType.CONSTRUCTOR:说明该注解只能声明在一个类的构造方法前;
  • ElementType.LOCAL_VARIABLE:说明该注解只能声明在一个局部变量前;
  • ElementType.ANNOTATION_TYPE:说明该注解只能声明在一个注解类型前;
  • ElementType.PACKAGE:说明该注解只能声明在一个包名前。

2、@Documented的作用

@Documented 注解表明这个注解应该被 javadoc工具记录. 默认情况下,javadoc是不包括注解的. 但如果声明注解时指定了 @Documented,则它会被 javadoc 之类的工具处理, 所以注解类型信息也会被包括在生成的文档中,是一个标记注解,没有成员。

3、@Retention作用

@Retention作用是定义被它所注解的注解保留多久,一共有三种策略,定义在RetentionPolicy枚举中。

属性详解

  • source:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;被编译器忽略;
  • class:注解被保留到class文件,但Jvm加载class文件时候被遗弃,这是默认的生命周期;
  • runtime:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在。

4、@Constraint的作用

  • @Constraint注解用于自定义校验注解中, 必须实现ConstraintValidator接口;接口里面有两个泛型, 第一个是自定义的注解类, 第二个是需要验证的数据类型, 可以用Object, 表示所有类型都支持, 根据不同类型走不同逻辑方法。
  • 接口中必须实现的两个方法:
    • 第一个是初始化验证器, 初始化完成后的结果让isValid调用,
    • 第二个是验证逻辑, 不同的逻辑方法就是在这里实现. 返回true, 则验证通过,false则不通过, 然后会抛出message里面自定义的异常信息。

5、自定义校验注解

5.1、自定义校验注解

import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;
import java.lang.annotation.*;

@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Constraint(validatedBy = CheckField.ParamConstraintValidated.class)
public @interface CheckField {
    String name() default "";
    // 必须有这三个参数
    String message() default "参数不为指定值";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @interface List{
        CheckField [] value();
    }

    class ParamConstraintValidated implements ConstraintValidator<CheckField, String> {
        private String paramConstraint;

        @Override
        public void initialize(CheckField checkField) {
            paramConstraint = checkField.name();
        }

        @Override
        public boolean isValid(String o, ConstraintValidatorContext constraintValidatorContext) {
            if (paramConstraint == o) {
                return true;
            }

            return false;
        }
    }
}

5.2、注解使用类

import com.xdx.annotation.CheckField;
import lombok.*;
import org.hibernate.validator.constraints.Length;

@Data
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class User {
    @CheckField(name = "dasdasddad")
    @Length(max = 2)
    private String uid;

    private String name;

    private int sex;


    @Override
    public String toString() {
        return "User{" +
                "uid='" + uid + '\'' +
                ", name='" + name + '\'' +
                ", sex=" + sex +
                '}';
    }
}

5.3、校验注解的触发

5.3.1、controller中触发

import com.xdx.entity.User;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotBlank;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;

@RestController
@RequestMapping("/aspect")
@Validated
public class AspectController {
    @PostMapping("/hello")
    public String hello() {
        return "Hello Word";
    }

    @PostMapping("/getUser")
    public String getUser(@RequestBody @Valid User user, BindingResult bindingResult) {
        if (chargeAnnotation(user, bindingResult)) {
            return user.toString();
        }

        return "你是错的";
    }

    @PostMapping("/delete")
    public String deleteUser(
            @NotBlank
            @Length(max = 32, message = "asdasdasdasd")
            @RequestParam(value = "id") String id) {
        User user = new User();
        user.setUid("fadzfsfgf");
        return "删除失败";
    }

    public boolean chargeAnnotation(User user, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            bindingResult.getAllErrors().forEach(v -> {
                System.out.println(v.getDefaultMessage());
            });
            return false;
        } else {
            return true;
        }
    }
}

5.3.2、在方法中触发

import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import java.util.Set;


@Component
public class AnnotationCheck <T>{
    /**
     * 方法1:通过静态的方法生成validator器
     */
//    private static Validator validator = Validation.buildDefaultValidatorFactory().getValidator();

    /**
     * 当Spring实例化此服务时,它将自动将一个Validator实例注入构造函数。
     * 此种写法更优秀
     */
    private Validator validator;

    AnnotationCheck(Validator validator) {
        this.validator = validator;
    }

    public void checkAnnotation(T t) {
        //执行验证
        Set<ConstraintViolation<T>> constraintViolations = validator.validate(t);

        //打印校验信息
        if (!CollectionUtils.isEmpty(constraintViolations)) {
            for (ConstraintViolation<T> constraintViolation : constraintViolations) {
                System.out.println(constraintViolation.getPropertyPath().toString() + ": " + constraintViolation.getMessage());
            }
        }
    }
}
测试
@PostMapping("/delete")
@ApiOperation(value = "测试注解是否生效")
public String deleteUser(
        @NotBlank
        @Length(max = 32, message = "asdasdasdasd")
        @RequestParam(value = "id") String id) {
    User user = new User();
    user.setUid("fadzfsfgf");
    annotationCheck.checkAnnotation(user);
    return "删除失败";
}

5.4、自定义注解-groups的使用

5.4.1、新建两个声明接口


/**
 * 可以在一个Model上面添加多套参数验证规则,此接口定义添加Person模型新增时的参数校验规则
 */
public interface CreateAction {
}
/**
 * 可以在一个Model上面添加多套参数验证规则,此接口定义添加Person模型修改时的参数校验规则
 */
public interface UpdateAction {
}

5.4.2、修改实体类

import com.xdx.annotation.CheckField;
import com.xdx.annotation.CreateAction;
import com.xdx.annotation.UpdateAction;
import lombok.*;
import org.hibernate.validator.constraints.Length;

import javax.validation.constraints.Size;
import java.util.Arrays;

@Data
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class User {
    @CheckField(name = "dasdasddad")
    @Length(max = 10)
    private String uid;

    @CheckField.List({
            @CheckField(groups = CreateAction.class, message = "test_____CreateAction"),
            @CheckField(groups = UpdateAction.class, message = "test_____UpdateAction")
    })
    private String name;

    private int sex;

    @Size(min = 2, max = 8)
    private char[] ch;


    @Override
    public String toString() {
        return "User{" +
                "uid='" + uid + '\'' +
                ", name='" + name + '\'' +
                ", sex=" + sex +
                ", ch=" + Arrays.toString(ch) +
                '}';
    }
}

5.4.3、Controller测试

@PostMapping("/getUserGroup")
@ApiOperation(value = "测试注解中的Group是否生效")
public String getUserGroup(@RequestBody @Validated({CreateAction.class}) User user, BindingResult bindingResult) {
    if (chargeAnnotation(user, bindingResult)) {
        return user.toString();
    }

    return "你是错的";
}

public boolean chargeAnnotation(User user, BindingResult bindingResult) {
  if (bindingResult.hasErrors()) {
      bindingResult.getAllErrors().forEach(v -> {
          System.out.println(v.getDefaultMessage());
      });
      return false;
  } else {
      return true;
  }
}

5.4.4、方法测试

5.4.4.1新建一个测试方法

import com.xdx.entity.User;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;

import javax.validation.Valid;

@Validated
@Component
public class CheckMethodGroup {
    @Validated(CreateAction.class)
    public boolean chargeMethodAnnotation(
            @Valid User user) {
        return true;
    }
}

5.4.4.2、Controller测试

@RequestMapping(value = "/getUserGroupMethod")
@ApiOperation(value = "测试自定义校验注解-groups分组-方法")
public String getUserGroupMethod(@RequestBody User user){
    try {
        methodGroup.chargeMethodAnnotation(user);
    } catch (Exception e) {
        return "1231231";
    }

    return "你是错的";
}

6、自定义切面注解

6.1、定义注解类

import java.lang.annotation.*;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CheckMethod {
    String value() default "";
}

6.2、定义注解类的实现类

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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

@Component
@Aspect
@Configuration
public class CheckMethodAspect {
    private static Logger logger = LoggerFactory.getLogger(CheckMethodAspect.class);

    @Pointcut("@annotation(com.xdx.annotation.CheckMethod)")
    private void pointCut() {
//        System.out.println("切面开始了");
    }

    @Before("pointCut() && @annotation(CheckMethod)")
    public void advice(JoinPoint joinPoint, CheckMethod CheckMethod) {
        logger.info("注解作用的方法名: " + joinPoint.getSignature().getName());

        logger.info("所在类的简单类名: " +
                joinPoint.getSignature().getDeclaringType().getSimpleName());

        logger.info("所在类的完整类名: " +
                joinPoint.getSignature().getDeclaringType());
    }
}

3、测试

@CheckMethod("123123123123")
@RequestMapping("/getCheckMethod")
public String getCheckMethod(@RequestBody User user) {
    return user.toString();
}
posted @   惘静  阅读(2130)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示