Java注解Annotation

1注解使用

1.1注解的使用场景

    业务输入对象需要进行一系列技术的验证如:身份证位数,电话号码位数,手机号位数,邮箱格式的验证,必输字段是否有值等。这些验证如果不抽离出来,整个业务逻辑将会是冗长的,可读性差,维护起来也繁杂,使用注解可以将这些技术性验证抽离出来,使代码更加优雅,便于维护。

1.2定义一个注解

    定义一个注解非常简单,语法与定义一个接口类似:

package bizsource;

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;

@Constraint(validatedBy = ValidateID.class)
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Identification {
    String message() default "身份证号码";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

1.3定义一个注解处理器

    单单定义一个注解,当然不能实现对相应数据类型的校验,需要编写注解对应的注解处理器。注解处理器实现ConstraintValidator接口,实现两个方法,其中isValid()是实际运用到的逻辑编写,该方法对注解将要注解的元素类型值进行校验,利用**@Constraint**元注解在注解类中绑定该注解处理器。

package bizsource;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
/**
*验证类实现ConstraintValidator接口,包含两个参数:注解类和待验证的数据类型
*/
public class ValidateID implements ConstraintValidator<Identification,String> {

    public void initialize(Identification constraintAnnotation) {
		//初始化方法,对注解验证的初始化工作
    }

   public boolean isValid(String value, ConstraintValidatorContext context) {
        //编写验证逻辑(简单校验)
        String regularExpression = "(^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$)|" +
                "(^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}$)";
        boolean matches = value.matches(regularExpression);
        return matches;
    }
}

1.4定义一个注解工具类用于启动注解验证

该类中的validate()方法用于验证传入对象中所有带注解的字段值:

package utils;


import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.groups.Default;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class ValidatorUtil {
    private static Validator validator = Validation.buildDefaultValidatorFactory()
            .getValidator();

    public static <T> Map<String, StringBuffer> validate(T obj) {//待校验对象,可以是使用了注解的bean
        Map<String, StringBuffer> errorMap = null;
        Set<ConstraintViolation<T>> set = validator.validate(obj, Default.class);
        if (set != null && set.size() > 0) {
            errorMap = new HashMap<String, StringBuffer>();
            String property = null;
            for (ConstraintViolation<T> cv : set) {
                //这里循环获取错误信息,可以自定义格式
                property = cv.getPropertyPath().toString();
                if (errorMap.get(property) != null) {
                    errorMap.get(property).append("," + cv.getMessage());
                } else {
                    StringBuffer sb = new StringBuffer();
                    sb.append(cv.getMessage());
                    errorMap.put(property, sb);
                }
            }
        }
        return errorMap;
    }
}

1.5测试

package app;

import bizsource.StudentInfo;
import utils.ValidatorUtil;

import java.util.Map;

public class ValidatorTest {
    public static void main(String[] args) {
        StudentInfo s = new StudentInfo();
        long startTime = System.currentTimeMillis();
        print(ValidatorUtil.validate(s));
        System.out.println("===============耗时(毫秒)=" + (System.currentTimeMillis() - startTime));

        s.setUserName("xinxin");
        s.setAge("18a");
        s.setBirthday("2016-9-1");
        s.setMoney(1000.00001);
        startTime = System.currentTimeMillis();
        //带有注解bean被验证
        print(ValidatorUtil.validate(s));
        System.out.println("===============耗时(毫秒)=" + (System.currentTimeMillis() - startTime));


    }

    private static void print(Map<String, StringBuffer> errorMap) {
        if (errorMap != null) {
            for (Map.Entry<String, StringBuffer> m : errorMap.entrySet()) {
                System.out.println(m.getKey() + ":" + m.getValue().toString());
            }
        }

    }
}

2注解原理

2.1三个基本注解与四个元注解

Java中内置了三种标准注解:

  • @Override表示当前方法将覆盖超类中的方法;
  • @Deprecated如果使用了该注解注解的元素编译器将会发出警告信息;
  • @SuppressWarnings关闭不当的编译器警告信息。

java提供四种元注解,负责新注解的创建:

  • @Target表示注解可以用于什么地方,参数是ElementType枚举类,可以是CONSTRUCTOR构造器说明,FIELD域声明, LOCAL_VARIABLE局部变量声明,METHOD方法声明, PACKAGE饱声明 ,PARAMETER参数声明,TYPE类,接口或enum声明;
  • @Retention表示需要在什么级别保存该注解信息,可选的RetentionPolicy参数包括SOURCE注解将被编译器丢弃;CLASS注解在class文件中可用,但是会被虚拟机丢弃;RUNTIME虚拟机在运行期也保留注解,因此可以通过反射读取注解的信息;
  • @Documented将注解包含在Javadoc中;
  • @Inherited允许子类继承父类中的注解

2.2注解中的元素类型限制

如1.2的注解类中使用的元素有message,groups,payload,这些元素的类型是有要求的,注解元素的可用类型如下所示:

  • 所有基本类型
  • String
  • Class
  • enum
  • Annotation
  • 以上类型的数组
    如果使用其他类型编译器将会报错。
    值得注意的是元素类型可以使用Annotation类型,这也就是说注解是可以嵌套的。

2.3嵌套注解

package bizsource;

import javax.validation.Constraint;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Constraint(validatedBy = UserValidate.class)
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UserAnno {
    String name() default "";
    Identification identification() default @Identification;
}

嵌套注解怎么使用?

2.3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值