注解定义
Java注解又称Java标注,是Java语言5.0版本开始支持加入源代码的特殊语法元数据。为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便的使用这些数据。
Java语言中的类、方法、变量、参数和包等都可以被标注。和Javadoc不同,Java标注可以通过反射获取注解内容。在编译器生成类文件时,注解可以被嵌入到字节码中。Java虚拟机可以保留注解内容,在运行时可以获取到注解内容。
元注解
@Target
- 标记注解注释哪种 Java 成员。@Retention
- 标记注解存储方式@Documented
- 标记注解是否包含在Javadoc用户文档中。@Inherited
- 标记注解可以被继承
1.@Target
限制注解的注释类型,类型在 ElementType 中
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE,
/** Field declaration (includes enum constants) */
FIELD,
/** Method declaration */
METHOD,
/** Formal parameter declaration */
PARAMETER,
/** Constructor declaration */
CONSTRUCTOR,
/** Local variable declaration */
LOCAL_VARIABLE,
/** Annotation type declaration */
ANNOTATION_TYPE,
/** Package declaration */
PACKAGE,
/** Type parameter declaration*/
TYPE_PARAMETER,
/** Use of a type*/
TYPE_USE
}
2.@Retention
规定注解的存储方式,要保留多久,参数在 RetentionPolicy 中
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
* 保留在源代码中,编译时忽略
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
* 保留在字节码中,VM 运行时忽略
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
* 运行 VM 时保留,因此可以通过反射进行读取
*/
RUNTIME
}
模拟场景
校验请求参数,参数为手机号,校验其格式的正确与否
1.自定义注解体
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 自定义手机号码校验注解
*
* @author YoonaLt
* @date 2019-10-14
*/
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = AbstractInterfaceRealize.class) // 约束类
public @interface MyAnnotation {
String message() default "数据格式有误";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
注解内的 Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; 不要忘记,且名称固定,否则使用时报错
javax.validation.ConstraintDefinitionException: HV000074: com.yoona.MyAnnotation contains Constraint annotation, but does not contain a payload(或者为groups) parameter.
2.编写注解验证器
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
/**
* 注解验证器
*
* @author YoonaLt
* @date 2019-10-14
*/
public abstract class AbstractInterfaceRealizee implements ConstraintValidator<MyAnnotation, String> {
// ConstraintValidator<MyAnnotation, String> String为要注释的数据的类型
@Override
public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
// 号码长度
int len = 11;
if (value == null || "".equals(value) || value.length() != len) {
return false;
}
// 测试的校验规则
String regex = "^1[3|4|5|7|8][0-9]\\d{4,8}$";
return value.matches(regex);
}
}
3.测试
import com.yoona.custom.MyAnnotation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author YoonaLt
* @date 2019-10-14
*/
@Validated // 这里使用这个注解使我们自定义的注解生效
@RestController
@RequestMapping(value = "test")
public class TestAnnotation {
@GetMapping(value = "test")
public void myTest(@MyAnnotation String number) {
}
}
当参数 number 不符合验证器内的规定时,我们可以看到报错信息
javax.validation.ConstraintViolationException: myTest.number: 数据格式有误
at org.springframework.validation.beanvalidation.MethodValidationInterceptor.invoke(MethodValidationInterceptor.java:116)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
...........................................