简单的自定义注解的使用,此处的demo是一个参数校验工具,出现这个的缘由就是javax.validation中的validation-api在项目中引用时,由于项目太老,版本太低,用不了javax.validation中的参数校验类。于是就考虑自己写一个,然后就是这里的简单的自定义注解的使用。
1、定义注解
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Desc: 非NULL注解,校验参数不为NULL
* @Author: WANGJINHUI
* @Date: 2019-4-29
*/
@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NotNull {
/**
* @Desc: 当参数为NULL时,给出提示信息
* @Param:
* @Return: java.lang.String 提示信息
* @Author: WANGJINHUI
* @Date: 2019-4-29
*/
String message() default "";
/**
* @Desc: 对注解进行分组,校验的时候,可以指定只对某组类型进行参数校验
* @Param:
* @Return: java.lang.Class<?>[]
* @Author: WANGJINHUI
* @Date: 2019-4-29
*/
Class<?>[] groups() default {};
}
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Desc: 非空注解,用于参数非空校验
* @Author: WANGJINHUI
* @Date: 2019-4-29
*/
@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NotEmpty {
/**
* @Desc: 当参数为空时,给出提示信息
* @Param:
* @Return: java.lang.String 提示信息
* @Author: WANGJINHUI
* @Date: 2019-4-29
*/
String message() default "";
/**
* @Desc: 对注解进行分组,校验的时候,可以指定只对某组类型进行参数校验
* @Param:
* @Return: java.lang.Class<?>[]
* @Author: WANGJINHUI
* @Date: 2019-4-29
*/
Class<?>[] groups() default {};
}
2、定义测试类,开始使用注解
/**
* @Desc: 服务系统入驻ADD参数类
* @Author: WANGJINHUI
* @Date: 2019-4-28
*/
public class ApplySystemAddDTO {
private static final long serialVersionUID = 1L;
private String deptCode; // 部门代码
private String grpCode; // 组代码
@NotEmpty(message = "部门不能为空")
private String deptName; // 部门
@NotEmpty(message = "组不能为空")
private String grpName; // 组
@NotEmpty(message = "部门及组说明不能为空")
private String ownerDesc; // 说明
public String getDeptCode() {
return deptCode;
}
public void setDeptCode(String deptCode) {
this.deptCode = deptCode;
}
public String getGrpCode() {
return grpCode;
}
public void setGrpCode(String grpCode) {
this.grpCode = grpCode;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public String getGrpName() {
return grpName;
}
public void setGrpName(String grpName) {
this.grpName = grpName;
}
public String getOwnerDesc() {
return ownerDesc;
}
public void setOwnerDesc(String ownerDesc) {
this.ownerDesc = ownerDesc;
}
}
3、定义类,使用扫描注解,自定义注解的功能
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* @Desc: 参数校验工具类
* @Author: WANGJINHUI
* @Date: 2019-4-29
*/
public class ValidationUtil {
private static final Log logger = LogFactory.getLog(ValidationUtil.class);
/**
* @Desc: 参数校验,遍历时只要遍历到了符合条件的参数,就直接返回对应参数的提示信息,结束遍历
* @Param: t 需要校验的参数对象
* @Return: java.lang.String 返回的提示信息
* @Author: WANGJINHUI
* @Date: 2019-4-29
*/
public static <T> String validateOne(T t) {
Class clazz = t.getClass();
// 获取所有的属性
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
// 判断是否使用了指定的注解,不同的注解,需要处理的逻辑不一样
if (field.isAnnotationPresent(NotEmpty.class)) {
// 获取自己的所有注解
for (Annotation annotation : field.getDeclaredAnnotations()) {
// 循环遍历时当遍历到非空注解,就执行接下来的非空处理逻辑
if (annotation.annotationType().equals(NotEmpty.class)) {
// 判断非空注解对应的属性的值为空
if (StringUtils.isBlank((String) getFieldValueByName(field.getName(), t))) {
return ((NotEmpty) annotation).message();
}
}
}
} else if (field.isAnnotationPresent(NotNull.class)) {
// 获取自己的所有注解
for (Annotation annotation : field.getDeclaredAnnotations()) {
// 循环遍历时当遍历到非NULL注解,就执行接下来的非空处理逻辑
if (annotation.annotationType().equals(NotNull.class)) {
// 判断非空注解对应的属性的值为NULL
if (getFieldValueByName(field.getName(), t) == null) {
return ((NotNull) annotation).message();
}
}
}
}
}
return null;
}
/**
* @Desc: 参数校验,遍历时将所有符合条件的参数的提示信息组装为一个List<String>返回
* @Param: t 需要校验的参数对象
* @Return: java.util.List<java.lang.String> 返回的提示信息
* @Author: WANGJINHUI
* @Date: 2019-4-29
*/
public static <T> List<String> validateAll(T t) {
List<String> messageList = new ArrayList<String>();
Class clazz = t.getClass();
// 获取所有的属性
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
// 判断是否使用了指定的注解,不同的注解,需要处理的逻辑不一样
if (field.isAnnotationPresent(NotEmpty.class)) {
// 获取自己的所有注解
for (Annotation annotation : field.getDeclaredAnnotations()) {
// 循环遍历时当遍历到非空注解,就执行接下来的非空处理逻辑
if (annotation.annotationType().equals(NotEmpty.class)) {
// 判断非空注解对应的属性的值为空
if (StringUtils.isBlank((String) getFieldValueByName(field.getName(), t))) {
messageList.add(((NotEmpty) annotation).message());
}
}
}
} else if (field.isAnnotationPresent(NotNull.class)) {
// 获取自己的所有注解
for (Annotation annotation : field.getDeclaredAnnotations()) {
// 循环遍历时当遍历到非NULL注解,就执行接下来的非空处理逻辑
if (annotation.annotationType().equals(NotNull.class)) {
// 判断非空注解对应的属性的值为NULL
if (getFieldValueByName(field.getName(), t) == null) {
messageList.add(((NotNull) annotation).message());
}
}
}
}
}
return messageList;
}
/**
* @Desc: 根据属性名称查找对应的属性值
* @Param: fieldName 需要查找的属性名称
* @Param: o 属性所在的类的对象
* @Return: java.lang.Object 属性的值
* @Author: WANGJINHUI
* @Date: 2019-4-29
*/
private static Object getFieldValueByName(String fieldName, Object o) {
try {
String firstLetter = fieldName.substring(0, 1).toUpperCase();
String getter = "get" + firstLetter + fieldName.substring(1);
Method method = o.getClass().getMethod(getter, new Class[] {});
Object value = method.invoke(o, new Object[] {});
return value;
} catch (Exception e) {
logger.error("根据fieldName为找到value", e);
return e.getMessage();
}
}
}
然后这个参数校验类就编写完成,自己再去写一个demo就可以来测试了,这个里面用到了自己定义的注解