【springboot】validator枚举值校验
转⾃:
blog.csdn/aiyaya_/article/details/78588200
⼀、前⾔
在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 flect.InvocationTargetException;
import flect.Method;
import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;
import 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 {};
Class<? extends Enum<?>> enumClass();
String enumMethod();
class Validator implements ConstraintValidator<EnumValue, Object> {
private Class<? extends Enum<?>> enumClass;
private String enumMethod;
@Override
public void initialize(EnumValue enumValue) {
enumMethod = umMethod();
enumClass = umClass();
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) {
if (value == null) {
return Boolean.TRUE;
}
if (enumClass == null || enumMethod == null) {
return Boolean.TRUE;
}
Class<?> valueClass = Class();
Method method = Method(enumMethod, valueClass);
if (!Boolean.TYPE.ReturnType()) && !Boolean.class.ReturnType())) {
throw new RuntimeException(Strings.formatIfArgs("%s method return is not boolean type in the %s class", enumMethod, enumClass));
}
if(!Modifier.Modifiers())) {
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.del.po;
import java.io.Serializable;
import java.util.Date;
import straints.Pattern;
import org.straints.Length;
import org.straints.NotBlank;
import org.straints.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;
/**
* 昵称
*/
@NotBlankspring boot选择题
@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.PostMapping; 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.del.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;
}
}
校验结果
好啦,⼀个简单的校验枚举值的注解功能完成了。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论