【springboot】validator枚举值校验
转自:
https://blog.csdn.net/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 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 {}; 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 = 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.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.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;
} }
校验结果


最后
好啦,一个简单的校验枚举值的注解功能完成了。
【springboot】validator枚举值校验的更多相关文章
- SpringBoot 如何进行参数校验,老鸟们都这么玩的!
大家好,我是飘渺. 前几天写了一篇 SpringBoot如何统一后端返回格式?老鸟们都是这样玩的! 阅读效果还不错,而且被很多号主都转载过,今天我们继续第二篇,来聊聊在SprinBoot中如何集成参数 ...
- SpringBoot 如何进行参数校验
为什么需要参数校验 在日常的接口开发中,为了防止非法参数对业务造成影响,经常需要对接口的参数进行校验,例如登录的时候需要校验用户名和密码是否为空,添加用户的时候校验用户邮箱地址.手机号码格式是否正确. ...
- SpringBoot 使用validation数据校验
后端对数据进行验证 添加包 hibernate-validator <!-- https://mvnrepository.com/artifact/org.hibernate.validator ...
- SpringBoot入门 (十一) 数据校验
本文记录学习在SpringBoot中做数据校验. 一 什么是数据校验 数据校验就是在应用程序中,对输入进来得数据做语义分析判断,阻挡不符合规则得数据,放行符合规则得数据,以确保被保存得数据符合我们得数 ...
- SpringBoot中BeanValidation数据校验与优雅处理详解
目录 本篇要点 后端参数校验的必要性 不使用Validator的参数处理逻辑 Validator框架提供的便利 SpringBoot自动配置ValidationAutoConfiguration Va ...
- 测试开发专题:如何在spring-boot中进行参数校验
上文我们讨论了spring-boot如何去获取前端传递过来的参数,那传递过来总不能直接使用,需要对这些参数进行校验,符合程序的要求才会进行下一步的处理,所以本篇文章我们主要讨论spring-boot中 ...
- validator库参数校验
目录 validator库参数校验若干实用技巧 基本示例 翻译校验错误提示信息 自定义错误提示信息的字段名 自定义结构体校验方法 自定义字段校验方法 自定义翻译方法 validator库参数校验若干实 ...
- gin使用validator库参数校验若干实用技巧
validator库参数校验若干实用技巧 本文介绍了使用validator库做参数校验的一些十分实用的使用技巧,包括翻译校验错误提示信息.自定义提示信息的字段名称.自定义校验方法等. validato ...
- Golang使用validator进行数据校验及自定义翻译器
Golang使用validator进行数据校验及自定义翻译器 包下载:go get github.com/go-playground/validator/v10 一.概述 在接口开发经常会遇到一个问题 ...
随机推荐
- C语言变量为何先定义后使用
C语言中,对变量的使用,首先要先定义.说明其数据类型.原因可能如下: 1不同类型的变量,其编码表示方式可能不同. 2不同类型的变量,其占有的空间大小不同.不事先说明无法在内存中开辟空间.
- 祝贺|合肥.NET俱乐部第二期技术沙龙活动圆满成功
热烈祝贺合肥.NET俱乐部第二期技术沙龙圆满成功,感恩参与活动的每一位小伙伴!正是因为有你们才促成了这次聚会的成功.现对此次活动进行简单回顾并附上精彩的活动图片,每一位参与活动者名单,以及此次活动讲师 ...
- 利用postman进行api接口开发
场景: api接口开发时,经常使用一些工具来帮助设计开发.Yapi主要是在设计阶段进行api接口设计,统一前后端参数请求和返回体:swagger主要在开发阶段,用来显示实际上后端开发进度和接口情况:p ...
- JIT in MegEngine
作者:王彪 | 旷视框架部异构计算组工程师 一.背景 什么是天元 旷视天元(MegEngine)是一个深度学习框架,它主要包含训练和推理两方面内容.训练侧一般使用 Python 搭建网络:而推理侧考虑 ...
- 20初识前端HTML(1)
1 .HTML 1.1 网页的组成 文字 图片 链接 等元素构成.除了这些元素之外 网页中还可以包含音频 视频 等 1.2 WEB前端开发的流程 现在主流的开发流程: 前后端分离的开发模式. 美工:p ...
- Nature | 多层次蛋白质组学综合分析冠状病毒侵染宿主细胞的分子机制
冠状病毒是一种自然界普遍存在的单股正链RNA病毒,电镜下呈日冕状或皇冠状,故命名为冠状病毒.在本世纪初短短20年中,共爆发了三次冠状病毒疫情,即2003年SARS-CoV.2012年MERS-CoV和 ...
- RHCSA_DAY05
计算机硬件组成部分 输入设备:键盘.鼠标.触控屏等 主机设备:主板.中央处理器(CPU).主存储器(内存).网卡.声卡.显示卡等 输出设备:屏幕.耳机.打印机.投影仪等 外部存储设备:硬盘.软盘.光盘 ...
- 【LeetCode】738. 单调递增的数字
738. 单调递增的数字 知识点:字符串:贪心 题目描述 给定一个非负整数 N,找出小于或等于 N 的最大的整数,同时这个整数需要满足其各个位数上的数字是单调递增. (当且仅当每个相邻位数上的数字 x ...
- 你的ES数据备份了吗?
前言: 无论使用哪种存储软件,定期的备份数据都是重中之重,在使用ElasticSearch的时候,随着数据日益积累,存放es数据的磁盘空间也捉襟见肘, 此时对于业务功能使用不到的索引数据,又不能直接删 ...
- Promise/A+规范-翻译
Promise 表示一个异步操作的最终结果,与之进行交互的方式主要是 then 方法,该方法注册了两个回调函数,用于接收 promise 的终值或本 promise 不能执行的原因. 本规范详细列出了 ...