优雅地使用Java一行代码实现对象的空值校验

在实际业务开发中,往往有许多业务逻辑需要对对象进行空值校验。简单的空值校验可以使用if语句,但参数多了,会出现几十行代码用来做空值校验的问题,十分不美观。有小伙伴问,不是可以用状态模式替换if语句吗?状态模式一般用于逻辑判断而不是空值校验,这还是有区别的。本文将介绍如何优雅地使用一行java代码实现对对象的空值校验。

一、效果

 

二、实现思路 

具体的实现思路是,使用反射技术获得并执行传入对象的getter方法,通过判断执行结果校验其参数是否为空,再通过自定义注解的形式取得字段的中文名拼接结果并将其返回。

三、实现步骤

3.1 自定义注解@FieldName

      使用自定义注解标注类对象的字段,使方法能通过反射的形式获取到对象的字段的中文释义

/**
 * 注解 @FieldName  用于标注类对象的字段
 * 使用该注解,甚至可以代替传统的javadoc
 * @author TanzJ
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FieldName {
    //默认值
    String value();
    //对象备注,可要可不要
    String comment() default "";
}

    特别注意的是,此处 @Retention 注解十分重要,他用于定义该注解的生命周期,一般有三个参数选择:

        1、仅编译期:RetentionPolicy.SOURCE

        2、仅Class文件:RetentionPolicy.CLASS

        3、运行期:RetentionPolicy.RUNTIME

    此处我们定义了RetentionPolicy.RUNTIME,原因是在运行期我们需要通过反射来获取对象的value值。

@Target 注解也被称为元注解,他用于定义目标注解所能使用的位置,一般有以下几个参数可供选择:

       1、类或接口:ElementType.TYPE

       2、字段:ElementType.FIELD

       3、方法:ElementType.METHOD

       4、构造方法:ElementType.CONSTRUCTOR

       5、方法参数:ElementType.PARAMETER

    此处我们因为需要对对象的字段进行控制校验,因此定义了ElementType.FIELD。

至此,我们完成了自定义注解的编写,通过该注解,我们甚至可以替换掉传统的javadoc注释。关于自定义注解的更多内容,这里不再过多赘述。

3.2 使用@FieldName注解对象的字段

public class Teacher {
    @FieldName(value = "教工号")
    private String teacherNo;
    @FieldName(value = "教师姓名")
    private String teacherName;
    @FieldName(value = "身份证号",comment = "18位")
    private String identityNo;
    //省略getter与setter
}

3.3 编写结果组件间传输对象 

public class BaseModel {
	@FieldName(value = "操作结果",comment = "操作结果-success/fail")
	private String result;
	@FieldName(value = "返回信息")
	private Object message;
	@FieldName(value = "业务状态码")
	private Integer code;
	//省略getter/setter
}

3.4 编写空值校验器

/**
	 * 对象空值校验器
	 * @param targetObject 传入的目标对象
	 * @param params 需要校验的参数
	 * @return BaseModel success/fail
	 */
public static BaseModel validateParamsBlankAndNull(Object targetObject,String... params) throws NoSuchFieldException {
	Class clazz = targetObject.getClass();
	Integer errorNumber = 0;
	StringBuilder stringBuilder = new StringBuilder();
	for (String param:params){
		param = param.trim();
		Method method = null;
		try {
			//将param首字母大写
			method = clazz.getMethod("get"+param.substring(0,1).toUpperCase()+param.substring(1));
		} catch (NoSuchMethodException e) {
			try {
				method = clazz.getSuperclass().getMethod("get"+param.substring(0,1).toUpperCase()+param.substring(1));
			} catch (NoSuchMethodException e1) {
				return new BaseModel(Constant.FAIL,"参数"+param+"不存在");
			}
		}
		Object result = null;
		try {
			//取得getter执行结果
			result =  method.invoke(targetObject);
		} catch (IllegalAccessException e) {
			logger.error(e.getMessage());
			return new BaseModel(Constant.FAIL,"方法不可执行");
		} catch (InvocationTargetException e) {
			logger.error(e.getMessage());
			return new BaseModel(Constant.FAIL,"传入对象异常");
		}
		if (result==null || "".equals(result)){
			FieldName fieldName = null;
			try {
				fieldName = clazz.getDeclaredField(param).getAnnotation(FieldName.class);
			}catch (NoSuchFieldException e){
				fieldName = clazz.getSuperclass().getDeclaredField(param).getAnnotation(FieldName.class);
			}
			if (fieldName!=null){
				stringBuilder.append(fieldName.value()+"不能为空,");
			}else {
				stringBuilder.append(param+"不能为空,");
			}
			errorNumber++;
		}
	}
	return errorNumber==0 ? new BaseModel(Constant.SUCCESS,"校验通过"):new BaseModel(Constant.FAIL,stringBuilder);
}

3.5 编写单元测试

    @Test
    public void validateParamsBlankAndNull_test() throws NoSuchFieldException {
        Teacher teacher = new Teacher();
        teacher.setTeacherName("TanzJ");
        CommonUtil.validateParamsBlankAndNull(teacher,"teacherNo","teacherName","identityNo");
    }

至此,你可以使用一句

 CommonUtil.validateParamsBlankAndNull(targetObject,params[])

取得返回的result来对目标对象进行空值校验判断操作。

源码地址:

https://github.com/tanzzj/CommonWebNeedUtils

该项目将会封装常用的mybatis通用BaseDAO、分页插件、空值校验工具等,便于服务端开发的工具。

发布了9 篇原创文章 · 获赞 23 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/bbcckkl/article/details/98121085
今日推荐