自定义注解完成参数校验
在现在的项目开发中,经常会用到注解,比如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();
ListField fieldList = new ArrayListField();
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;
}
}
}
运行截图:
手机号错误
数据正确