需求
现在有一个对象是直接从数据库中查询出来了的,有很多的地方在使用,但是在调用某个接口的市要要求某些字段不能为空
解决思路
这种问题如果字段很少可以直接添加逻辑判断,但是如果字段很多怎么处理呢,如果字段有名称等修改或是对象会有新的字段添加删除怎么处理呢,如果用直接判断的方式必然会显得代码臃肿,且维护不变,最好的方式就是希望能有一个公用方法可以直接对对象进行空值判断,只需要对不能为空的字段添加一定标识即可,那么如何识别这个字段是否可以为空呢,注解无疑时最好的选择,既不会影响代码美观而且修改也比较方便,如果不需要直接在对象类里删除注解即可,而使用了注解就必然需要有处理注解的方法,必然会涉及到反射屈去注解,下面我们一起来了解一下什么是注解
什么是注解
Java 注解是在 JDK5 时引入的新特性,注解(也被称为元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。注解类型定义指定了一种新的类型,一种特殊的接口类型。 在关键词 interface 前加 @ 符号也就是用 @interface 来区分注解的定义和普通的接口声明。目前大部分框架(如 Spring Boot 等)都通过使用注解简化了代码并提高的编码效率。
什么是反射
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
功能实现
1.定义一个注解
package com.yx.annotation;
import java.lang.annotation.*;
/**
* @author yx
* 自定义注解,当有这个注解是使用定义的判断方法可以判断带注解的参数是否为空
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NotNullValue {
String value() default "";
}
创建对象
package com.yx.bean;
import com.yx.annotation.NotNullValue;
import lombok.Data;
import lombok.ToString;
/**
* @author yx
* @date 2020/4/28 9:32
* Description
*/
@Data
@ToString
public class User {
private int id;
/**
* 这里要求userName的值不能等于test
*/
@NotNullValue(value = "test")
private String userName;
private String userNo;
}
创建需要判断的工具类
package com.yx.utils;
import com.yx.annotation.NotNullValue;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* @author yx
* @date 2020/5/12 20:46
* Description
*/
public class NotNullUtil {
public static void checkNull(Object obj) throws Exception {
//获取对象类型:class com.yx.bean.User
Class<?> aClass = obj.getClass();
//获取对象的简写:User
String simpleName = aClass.getSimpleName();
//获取对象有哪些属性信息
Field[] declaredFields = aClass.getDeclaredFields();
//对每个属性进行判断
for (Field field : declaredFields) {
//判断这个属性是否有NotNullValue注解,如果有对其进行处理
boolean annotationPresent = field.isAnnotationPresent(NotNullValue.class);
if (annotationPresent) {
//获取参数名称
String name = field.getName();
//获取get方法名称
String getName = "get" + higherFirstChar(name);
//获取get方法
Method method = aClass.getMethod(getName);
//使用反射获取该参数的值
Object result = method.invoke(obj);
//经获取这个注解的信息
NotNullValue annotation = field.getAnnotation(NotNullValue.class);
System.out.println(result);
//判断是否为这些值,这里我的逻辑为不能为空和不能为指定的值,当然也可以自己设定
String value = annotation.value();
if (result == null || result.equals(value) || result.equals("") || result.equals("null")) {
throw new Exception(simpleName + "对象" + name + "的值不符合要求,当前的值为:" + result);
}
}
}
}
/**
* 把字符串的首位小字母转换成大写字母
* @param str
* @return
*/
public static String higherFirstChar(String str) throws Exception {
char[] chars = str.toCharArray();
if ((chars[0] < 97) || (chars[0] > 122)) {
throw new Exception("变量名必须使用驼峰命名规则首字母小写,变量名称为:" + str);
}
chars[0] -= 32;
return String.valueOf(chars);
}
}
创建测试类测试效果
package com.yx;
import com.yx.bean.User;
import com.yx.utils.NotNullUtil;
/**
* @author yx
* @date 2020/4/28 9:34
* Description
*/
public class TestAnnotation {
public static void main(String[] args) throws Exception {
//为了更多使用反射这里不用传统的new创建对象
String path = "com.yx.bean.User";
//加载类
Class<?> aClass = Class.forName(path);
//创建对象转换成需要的对象
User user = (User) aClass.newInstance();
try {
user.setUserName("name");
System.out.println("有值的user" + user);
NotNullUtil.checkNull(user);
} catch (Exception e) {
e.printStackTrace();
}
try {
user.setUserName("test");
System.out.println("值为test的user" + user);
NotNullUtil.checkNull(user);
} catch (Exception e) {
e.printStackTrace();
}
try {
user.setUserName("");
System.out.println("空的user:" + user);
NotNullUtil.checkNull(user);
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果如下
博客主要是为了自己复习时方便查找,如果有机会也希望能帮到看到文章的小伙伴们,码字不易,谢谢。