springboot validator枚举值校验功能实现

网友投稿 600 2022-12-17


springboot validator枚举值校验功能实现

这篇文章主要介绍了springboot validator枚举值校验功能实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

一、前言

在spring项目中,校验参数功能使用hibernate validator是一个不错的选择,我们的项目中也是使用它来进行校验的,省去了很多难看的校验逻辑,使代码的可读性也大大增加,本章将带你使用hibernate validator自定义注解功能实现一个 枚举值校验的逻辑。

二、需求

我们先明确下我们的需求,在程序开发过程中,我们经常会有一个对象的属性值只能出现在一组常量中的校验需求,例如:用户性别字段gender只能等于MALE/FEMALE这两个其中一个值,用户账号的状态status只能等于:

NORMAL/DISABLED/DELETED其中一个等等,那么我们怎么能更好的校验这个参数呢?我们想拥有一个java注解,把它标记在所要校验的字段上,当开启hibernate validator校验时,就可以校验其字段值是否正确。

三、实现方案

上面提到的一组常量值,我们第一反应应该是定义一个枚举类,尽量不要放在一个统一的constants类下,这样当系统一旦庞大起来,常量是很难维护和查找的,所以前期代码也应该有一些规范性约束,这里我们约定一组常量值时使用枚举,并把该枚举类放在对应的类对象里(以上述所说的用户功能为例,我们应该把GenerEnum、UserStatusEnum枚举放在User.java下,方便查找)

这里我们定义一个叫EnumValue.java的注解类,其下有两个主要参数一个是enumClass用于指定枚举类,enumMethod指定要校验的方法,下面我们看代码实现。

四、代码实现

package com.zhuma.demo.annotation;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

import javax.validation.Constraint;

import javax.validation.ConstraintValidator;

import javax.validation.ConstraintValidatorContext;

import javax.validation.Payload;

import org.assertj.core.util.Strings;

/**

* @desc 校验枚举值有效性

*

* @author zhumaer

* @since 10/17/2017 3:13 PM

*/

@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })

@Retention(RetentionPolicy.RUNTIME)

@Constraint(validatedBy = EnumValue.Validator.class)

public @interface EnumValue {

String message() default "{custom.value.invalid}";

Class>[] groups() default {};

Class extends Payload>[] payload() default {};

ClaLxjIhdhss extends Enum>> enumClass();

String enumMethod();

class Validator implements ConstraintValidator {

private Class extends Enum>> enumClass;

private String enumMethod;

@Override

public void initialize(EnumValue enumValue) {

enumMethod = enumValue.enumMethod();

enumClass = enumValue.enumClass();

}

@Override

public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) {

if (value == null) {

return Boolean.TRUE;

}

if (enumClass == null || enumMethod == null) {

return Boolean.TRUE;

}

Class> valueClass = value.getClass();

try {

Method method = enumClass.getMethod(enumMethod, valueClass);

if (!Boolean.TYPE.equals(method.getReturnType()) && !Boolean.class.equals(method.getReturnType())) {

throw new RuntimeException(Strings.formatIfArgs("%s method return is not boolean type in the %s class", enumMethod, enumClass));

}

if(!Modifier.isStatic(method.getModifiers())) {

throw new RuntimeException(Strings.formatIfArgs("%s method is not static method in the %s class", enumMethod, enumClass));

}

Boolean result = (Boolean)method.invoke(null, value);

return result == null ? false : result;

} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {

throw new RuntimeException(e);

} catch (NoSuchMethodException | SecurityException e) {

throw new RuntimeException(Strings.formatIfArgs("This %s(%s) method does not exist in the %s", enumMethod, valueClass, enumClass), e);

}

}

}

}

备注

1) 自定义注解需要实现ConstraintValidator校验类,这里我们定义一个叫Validator的类来实现它,同时实现它下面的两个方法initialize、isValid,一个是初始化参数的方法,另一个就是校验逻辑的方法,本例子中我们将校验类定义在该注解内,用@Constraint(validatedBy = EnumValue.Validator.class)注解指定校验类,内部逻辑实现比较简单就是使用了静态类反射调用验证方法的方式。

2) 对于被校验的方法我们要求,它必须是返回值类型为Boolean或boolean,并且必须是一个静态的方法,返回返回值为null时我们认为是校验不通过的,按false逻辑走。

五、使用演示

校验的目标对象类

package com.zhuma.demo.model.po;

import java.io.Serializable;

import java.util.Date;

import javax.validation.constraints.Pattern;

import org.hibernate.validator.constraints.Length;

import org.hibernate.validator.constraints.NotBlank;

import org.hibernate.validator.constraints.Range;

import com.zhuma.demo.annotation.EnumValue;

import com.zhuma.demo.validator.CreateGroup;

/**

* @desc 用户PO

* @author zhumaer

* @since 6/15/2017 2:48 PM

*/

public class User implements Serializable {

private static final long serialVersionUID = 2594274431751408585L;

/**

* 用户ID

*/

private Long id;

/**

* 登录密码

*/

@NotBlank

private String pwd;

/**

* 昵称

*/

@NotBlank

@Length(min=1, max=64)

private String nickname;

/**

* 头像

*/

private String img;

/**

* 电话

*/

@Pattern(regexp = "^1[3-9]\\d{9}$")

private String phone;

/**

* 账号状态

*/

@EnumValue(enumClass=UserStatusEnum.class, enumMethod="isValidName")

private String status;

/**

* 最新的登录时间

*/

private Date latestLoginTime;

/**

* 最新的登录IP

*/

private String latestLoginIp;

private Date createTime;

private Date updateTime;

/**

* 用户状态枚举

*/

public enum UserStatusEnum {

/**正常的*/

NORMAL,

/**禁用的*/

DISABLED,

/**已删除的*/

DELETED;

/**

* 判断参数合法性

*/

public static boolean isValidName(String name) {

for (UserStatusEnum userStatusEnum : UserStatusEnum.values()) {

if (userStatusEnum.name().equals(name)) {

return true;

}

}

return false;

}

}

//省略getter、setter方法

}

controller类

package com.zhuma.demo.web.user;

import java.util.Date;

import org.springframework.http.HttpStatus;

import org.springframework.validation.annotation.Validated;

import org.springframework.web.bind.annotation.PostMappihttp://ng;

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.ResponseStatus;

import org.springframework.web.bind.annotation.RestController;

import com.zhuma.demo.model.po.User;

/**

* @desc 用户管理控制器

*

* @author zhumaer

* @since 6/20/2017 16:37 PM

*/

@RestController

@RequestMapping("/users")

public class UserController {

@PostMapping

@ResponseStatus(HttpStatus.CREATED)

public User addUser(@Validated @RequestBody User user) {

user.setId(10000L);

user.setCreateTime(new Date());

return user;

}

}

校验结果

最后

好啦,一个简单的校验枚举值的注解功能完成了。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:springboot全局异常处理代码实例
下一篇:Java模拟多线程实现抢票代码实例
相关文章

 发表评论

暂时没有评论,来抢沙发吧~