springboot validator枚举值校验功能实现
这篇文章主要介绍了springbootvalidator枚举值校验功能实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
一、前言
在spring项目中,校验参数功能使用hibernatevalidator是一个不错的选择,我们的项目中也是使用它来进行校验的,省去了很多难看的校验逻辑,使代码的可读性也大大增加,本章将带你使用hibernatevalidator自定义注解功能实现一个枚举值校验的逻辑。
二、需求
我们先明确下我们的需求,在程序开发过程中,我们经常会有一个对象的属性值只能出现在一组常量中的校验需求,例如:用户性别字段gender只能等于MALE/FEMALE这两个其中一个值,用户账号的状态status只能等于:
NORMAL/DISABLED/DELETED其中一个等等,那么我们怎么能更好的校验这个参数呢?我们想拥有一个java注解,把它标记在所要校验的字段上,当开启hibernatevalidator校验时,就可以校验其字段值是否正确。
三、实现方案
上面提到的一组常量值,我们第一反应应该是定义一个枚举类,尽量不要放在一个统一的constants类下,这样当系统一旦庞大起来,常量是很难维护和查找的,所以前期代码也应该有一些规范性约束,这里我们约定一组常量值时使用枚举,并把该枚举类放在对应的类对象里(以上述所说的用户功能为例,我们应该把GenerEnum、UserStatusEnum枚举放在User.java下,方便查找)
这里我们定义一个叫EnumValue.java的注解类,其下有两个主要参数一个是enumClass用于指定枚举类,enumMethod指定要校验的方法,下面我们看代码实现。
四、代码实现
packagecom.zhuma.demo.annotation;
importjava.lang.annotation.ElementType;
importjava.lang.annotation.Retention;
importjava.lang.annotation.RetentionPolicy;
importjava.lang.annotation.Target;
importjava.lang.reflect.InvocationTargetException;
importjava.lang.reflect.Method;
importjavax.validation.Constraint;
importjavax.validation.ConstraintValidator;
importjavax.validation.ConstraintValidatorContext;
importjavax.validation.Payload;
importorg.assertj.core.util.Strings;
/**
*@desc校验枚举值有效性
*
*@authorzhumaer
*@since10/17/20173:13PM
*/
@Target({ElementType.METHOD,ElementType.FIELD,ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=EnumValue.Validator.class)
public@interfaceEnumValue{
Stringmessage()default"{custom.value.invalid}";
Class>[]groups()default{};
Class[]payload()default{};
Class>enumClass();
StringenumMethod();
classValidatorimplementsConstraintValidator{
privateClass>enumClass;
privateStringenumMethod;
@Override
publicvoidinitialize(EnumValueenumValue){
enumMethod=enumValue.enumMethod();
enumClass=enumValue.enumClass();
}
@Override
publicbooleanisValid(Objectvalue,ConstraintValidatorContextconstraintValidatorContext){
if(value==null){
returnBoolean.TRUE;
}
if(enumClass==null||enumMethod==null){
returnBoolean.TRUE;
}
Class>valueClass=value.getClass();
try{
Methodmethod=enumClass.getMethod(enumMethod,valueClass);
if(!Boolean.TYPE.equals(method.getReturnType())&&!Boolean.class.equals(method.getReturnType())){
thrownewRuntimeException(Strings.formatIfArgs("%smethodreturnisnotbooleantypeinthe%sclass",enumMethod,enumClass));
}
if(!Modifier.isStatic(method.getModifiers())){
thrownewRuntimeException(Strings.formatIfArgs("%smethodisnotstaticmethodinthe%sclass",enumMethod,enumClass));
}
Booleanresult=(Boolean)method.invoke(null,value);
returnresult==null?false:result;
}catch(IllegalAccessException|IllegalArgumentException|InvocationTargetExceptione){
thrownewRuntimeException(e);
}catch(NoSuchMethodException|SecurityExceptione){
thrownewRuntimeException(Strings.formatIfArgs("This%s(%s)methoddoesnotexistinthe%s",enumMethod,valueClass,enumClass),e);
}
}
}
}
备注
1)自定义注解需要实现ConstraintValidator校验类,这里我们定义一个叫Validator的类来实现它,同时实现它下面的两个方法initialize、isValid,一个是初始化参数的方法,另一个就是校验逻辑的方法,本例子中我们将校验类定义在该注解内,用@Constraint(validatedBy=EnumValue.Validator.class)注解指定校验类,内部逻辑实现比较简单就是使用了静态类反射调用验证方法的方式。
2)对于被校验的方法我们要求,它必须是返回值类型为Boolean或boolean,并且必须是一个静态的方法,返回返回值为null时我们认为是校验不通过的,按false逻辑走。
五、使用演示
校验的目标对象类
packagecom.zhuma.demo.model.po;
importjava.io.Serializable;
importjava.util.Date;
importjavax.validation.constraints.Pattern;
importorg.hibernate.validator.constraints.Length;
importorg.hibernate.validator.constraints.NotBlank;
importorg.hibernate.validator.constraints.Range;
importcom.zhuma.demo.annotation.EnumValue;
importcom.zhuma.demo.validator.CreateGroup;
/**
*@desc用户PO
*@authorzhumaer
*@since6/15/20172:48PM
*/
publicclassUserimplementsSerializable{
privatestaticfinallongserialVersionUID=2594274431751408585L;
/**
*用户ID
*/
privateLongid;
/**
*登录密码
*/
@NotBlank
privateStringpwd;
/**
*昵称
*/
@NotBlank
@Length(min=1,max=64)
privateStringnickname;
/**
*头像
*/
privateStringimg;
/**
*电话
*/
@Pattern(regexp="^1[3-9]\\d{9}$")
privateStringphone;
/**
*账号状态
*/
@EnumValue(enumClass=UserStatusEnum.class,enumMethod="isValidName")
privateStringstatus;
/**
*最新的登录时间
*/
privateDatelatestLoginTime;
/**
*最新的登录IP
*/
privateStringlatestLoginIp;
privateDatecreateTime;
privateDateupdateTime;
/**
*用户状态枚举
*/
publicenumUserStatusEnum{
/**正常的*/
NORMAL,
/**禁用的*/
DISABLED,
/**已删除的*/
DELETED;
/**
*判断参数合法性
*/
publicstaticbooleanisValidName(Stringname){
for(UserStatusEnumuserStatusEnum:UserStatusEnum.values()){
if(userStatusEnum.name().equals(name)){
returntrue;
}
}
returnfalse;
}
}
//省略getter、setter方法
}
controller类
packagecom.zhuma.demo.web.user;
importjava.util.Date;
importorg.springframework.http.HttpStatus;
importorg.springframework.validation.annotation.Validated;
importorg.springframework.web.bind.annotation.PostMapping;
importorg.springframework.web.bind.annotation.RequestBody;
importorg.springframework.web.bind.annotation.RequestMapping;
importorg.springframework.web.bind.annotation.ResponseStatus;
importorg.springframework.web.bind.annotation.RestController;
importcom.zhuma.demo.model.po.User;
/**
*@desc用户管理控制器
*
*@authorzhumaer
*@since6/20/201716:37PM
*/
@RestController
@RequestMapping("/users")
publicclassUserController{
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
publicUseraddUser(@Validated@RequestBodyUseruser){
user.setId(10000L);
user.setCreateTime(newDate());
returnuser;
}
}
校验结果
最后
好啦,一个简单的校验枚举值的注解功能完成了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。