Java注解的妙用

/ Java / 0 条评论 / 420 浏览

在现在的项目开发中,经常会用到注解,比如Spring的@Autowired,SpringMVC的@Controller@RequestMapping等等,大部分人只知道用,不知道这些注解的怎么发挥作用。有没有想过手动写一个注解,完成参数校验呢?

简介

注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

作用分类:

①编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】

② 代码分析:通过代码里标识的元数据对代码进行分析【使用反射】

③编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】

分类

Java注解根据标记位置分为三类。

注解类上需要加入:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)

依次是,标记的位置,注解生存周期。

标记在方法上

运行时有效

实战

在编写注解之前需要了解,你的参数校验需要做哪些工作。

此次校验是标记在变量上的,主要功能包括:

这几条包含了大部分的数据校验的功能。

开始

编写注解:Validation.java

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Validation {
  //校验失败报错信息
  String value();

  //最大值
  String max();

  //最小值
  String min();

  //正则表达式
  String pattern();

}

编写校验代码:

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Check {

  public static void check(Object o) {
    if (null == o) {
      return;
    }
    Class clazz = o.getClass();
    List<Field> fieldList = new ArrayList<Field>();
    while (clazz != null) {
      fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
      clazz = clazz.getSuperclass();
    }
    fieldList.forEach(field -> {
      field.setAccessible(true);
      try {
        Object value = field.get(o);
        Validation annotation = field.getAnnotation(Validation.class);
        if (null == annotation) {
          return;
        }
        checkNotNull(value, annotation);
        checkPattern(value, annotation);
        checkMax(value, annotation);
        checkMin(value, annotation);
      } catch (IllegalArgumentException e) {
        e.printStackTrace();
        //数据解析失败
      } catch (IllegalAccessException e) {
        e.printStackTrace();
      }
    });
  }

  private static double objectToDubule(Object o) {
    return Double.valueOf(o.toString());
  }


  private static void checkNotNull(Object value, Validation validation) {
    if (validation.notNull() && value == null) {
      throw new RuntimeException(validation.value());
    }
  }

  private static void checkPattern(Object value, Validation validation) {
    if (null != validation.pattern() && validation.pattern().length() > 0) {
      Pattern p = Pattern.compile(validation.pattern());
      Matcher m = p.matcher(value.toString());
      if (!m.matches()) {
        throw new RuntimeException(validation.value());
      }
    }
  }

  private static void checkMax(Object value, Validation validation) {
    if (validation.max() > 0) {
      if (value instanceof String) {
        if (value.toString().length() < validation.max()) {
          throw new RuntimeException(validation.value());
        }
      } else {
        if (objectToDubule(value) > validation.max()) {
          throw new RuntimeException(validation.value());
        }
      }
    }
  }

  private static void checkMin(Object value, Validation validation) {
    if (validation.max() >= 0) {
      if (value instanceof String) {
        if (value.toString().length() > validation.min()) {
          throw new RuntimeException(validation.value());
        }
      } else {
        if (objectToDubule(value) < validation.min()) {
          throw new RuntimeException(validation.value());
        }
      }
    }
  }
}

测试

编写CheckTest.java

import org.junit.Test;

public class CheckTest {
  @Test
  public void check() {
    TestData data = new TestData();
    data.arg = 20;
    data.setMobile("1368989889");
    data.setName("test");
    Check.check(data);
    System.out.println("校验通过");

  }


  class TestData {
    @Validation(value = "名称校验失败", notNull = true)
    private String name;
    @Validation(value = "手机号校验失败", notNull = true, pattern = "^1(3[0-9]|4[0-9]|5[0-35-9]|8[0-9]|7[0-9]|6[0-9]|9[0-9])\\d{8}$")
    private String mobile;
    @Validation(value = "年龄校验失败", notNull = true, max = 60, min = 18)
    private Integer arg;

    public String getName() {
      return name;
    }

    public void setName(String name) {
      this.name = name;
    }

    public String getMobile() {
      return mobile;
    }

    public void setMobile(String mobile) {
      this.mobile = mobile;
    }

    public Integer getArg() {
      return arg;
    }

    public void setArg(Integer arg) {
      this.arg = arg;
    }
  }
}

运行截图:

手机号错误

数据正确