转自:

  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指定要校验的方法,下面我们看代码实现。

四、代码实现

  1. package com.zhuma.demo.annotation;
  2.  
  3. import java.lang.annotation.ElementType;
  4. import java.lang.annotation.Retention;
  5. import java.lang.annotation.RetentionPolicy;
  6. import java.lang.annotation.Target;
  7. import java.lang.reflect.InvocationTargetException;
  8. import java.lang.reflect.Method;
  9.  
  10. import javax.validation.Constraint;
  11. import javax.validation.ConstraintValidator;
  12. import javax.validation.ConstraintValidatorContext;
  13. import javax.validation.Payload;
  14.  
  15. import org.assertj.core.util.Strings;
  16.  
  17. /**
  18. * @desc 校验枚举值有效性
  19. *
  20. * @author zhumaer
  21. * @since 10/17/2017 3:13 PM
  22. */
  23. @Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
  24. @Retention(RetentionPolicy.RUNTIME)
  25. @Constraint(validatedBy = EnumValue.Validator.class)
  26. public @interface EnumValue {
  27.  
  28. String message() default "{custom.value.invalid}";
  29.  
  30. Class<?>[] groups() default {};
  31.  
  32. Class<? extends Payload>[] payload() default {};
  33.  
  34. Class<? extends Enum<?>> enumClass();
  35.  
  36. String enumMethod();
  37.  
  38. class Validator implements ConstraintValidator<EnumValue, Object> {
  39.  
  40. private Class<? extends Enum<?>> enumClass;
  41. private String enumMethod;
  42.  
  43. @Override
  44. public void initialize(EnumValue enumValue) {
  45. enumMethod = enumValue.enumMethod();
  46. enumClass = enumValue.enumClass();
  47. }
  48.  
  49. @Override
  50. public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) {
  51. if (value == null) {
  52. return Boolean.TRUE;
  53. }
  54.  
  55. if (enumClass == null || enumMethod == null) {
  56. return Boolean.TRUE;
  57. }
  58.  
  59. Class<?> valueClass = value.getClass();
  60.  
  61. try {
  62. Method method = enumClass.getMethod(enumMethod, valueClass);
  63. if (!Boolean.TYPE.equals(method.getReturnType()) && !Boolean.class.equals(method.getReturnType())) {
  64. throw new RuntimeException(Strings.formatIfArgs("%s method return is not boolean type in the %s class", enumMethod, enumClass));
  65. }
  66.  
  67. if(!Modifier.isStatic(method.getModifiers())) {
  68. throw new RuntimeException(Strings.formatIfArgs("%s method is not static method in the %s class", enumMethod, enumClass));
  69. }
  70.  
  71. Boolean result = (Boolean)method.invoke(null, value);
  72. return result == null ? false : result;
  73. } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
  74. throw new RuntimeException(e);
  75. } catch (NoSuchMethodException | SecurityException e) {
  76. throw new RuntimeException(Strings.formatIfArgs("This %s(%s) method does not exist in the %s", enumMethod, valueClass, enumClass), e);
  77. }
  78. }
  79.  
  80. }
  81. }

备注

1) 自定义注解需要实现ConstraintValidator校验类,这里我们定义一个叫Validator的类来实现它,同时实现它下面的两个方法initialize、isValid,一个是初始化参数的方法,另一个就是校验逻辑的方法,本例子中我们将校验类定义在该注解内,用@Constraint(validatedBy = EnumValue.Validator.class)注解指定校验类,内部逻辑实现比较简单就是使用了静态类反射调用验证方法的方式。
2) 对于被校验的方法我们要求,它必须是返回值类型为Boolean或boolean,并且必须是一个静态的方法,返回返回值为null时我们认为是校验不通过的,按false逻辑走。

五、使用演示

校验的目标对象类

  1. package com.zhuma.demo.model.po;
  2.  
  3. import java.io.Serializable;
  4. import java.util.Date;
  5.  
  6. import javax.validation.constraints.Pattern;
  7.  
  8. import org.hibernate.validator.constraints.Length;
  9. import org.hibernate.validator.constraints.NotBlank;
  10. import org.hibernate.validator.constraints.Range;
  11.  
  12. import com.zhuma.demo.annotation.EnumValue;
  13. import com.zhuma.demo.validator.CreateGroup;
  14.  
  15. /**
  16. * @desc 用户PO
  17.  
  18. * @author zhumaer
  19. * @since 6/15/2017 2:48 PM
  20. */
  21. public class User implements Serializable {
  22.  
  23. private static final long serialVersionUID = 2594274431751408585L;
  24.  
  25. /**
  26. * 用户ID
  27. */
  28. private Long id;
  29.  
  30. /**
  31. * 登录密码
  32. */
  33. @NotBlank
  34. private String pwd;
  35.  
  36. /**
  37. * 昵称
  38. */
  39. @NotBlank
  40. @Length(min=1, max=64)
  41. private String nickname;
  42.  
  43. /**
  44. * 头像
  45. */
  46. private String img;
  47.  
  48. /**
  49. * 电话
  50. */
  51. @Pattern(regexp = "^1[3-9]\\d{9}$")
  52. private String phone;
  53.  
  54. /**
  55. * 账号状态
  56. */
  57. @EnumValue(enumClass=UserStatusEnum.class, enumMethod="isValidName")
  58. private String status;
  59.  
  60. /**
  61. * 最新的登录时间
  62. */
  63. private Date latestLoginTime;
  64.  
  65. /**
  66. * 最新的登录IP
  67. */
  68. private String latestLoginIp;
  69.  
  70. private Date createTime;
  71. private Date updateTime;
  72.  
  73. /**
  74. * 用户状态枚举
  75. */
  76. public enum UserStatusEnum {
  77. /**正常的*/
  78. NORMAL,
  79. /**禁用的*/
  80. DISABLED,
  81. /**已删除的*/
  82. DELETED;
  83.  
  84. /**
  85. * 判断参数合法性
  86. */
  87. public static boolean isValidName(String name) {
  88. for (UserStatusEnum userStatusEnum : UserStatusEnum.values()) {
  89. if (userStatusEnum.name().equals(name)) {
  90. return true;
  91. }
  92. }
  93. return false;
  94. }
  95. }
  96.  
  97. //省略getter、setter方法
  98.  
  99. }  

controller类

  1. package com.zhuma.demo.web.user;
  2.  
  3. import java.util.Date;
  4.  
  5. import org.springframework.http.HttpStatus;
  6. import org.springframework.validation.annotation.Validated;
  7. import org.springframework.web.bind.annotation.PostMapping;
  8. import org.springframework.web.bind.annotation.RequestBody;
  9. import org.springframework.web.bind.annotation.RequestMapping;
  10. import org.springframework.web.bind.annotation.ResponseStatus;
  11. import org.springframework.web.bind.annotation.RestController;
  12.  
  13. import com.zhuma.demo.model.po.User;
  14.  
  15. /**
  16. * @desc 用户管理控制器
  17. *
  18. * @author zhumaer
  19. * @since 6/20/2017 16:37 PM
  20. */
  21. @RestController
  22. @RequestMapping("/users")
  23. public class UserController {
  24.  
  25. @PostMapping
  26. @ResponseStatus(HttpStatus.CREATED)
  27. public User addUser(@Validated @RequestBody User user) {
  28. user.setId(10000L);
  29. user.setCreateTime(new Date());
  30. return user;
  31. }
  32.  
  33. }  

校验结果

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

【springboot】validator枚举值校验的更多相关文章

  1. SpringBoot 如何进行参数校验,老鸟们都这么玩的!

    大家好,我是飘渺. 前几天写了一篇 SpringBoot如何统一后端返回格式?老鸟们都是这样玩的! 阅读效果还不错,而且被很多号主都转载过,今天我们继续第二篇,来聊聊在SprinBoot中如何集成参数 ...

  2. SpringBoot 如何进行参数校验

    为什么需要参数校验 在日常的接口开发中,为了防止非法参数对业务造成影响,经常需要对接口的参数进行校验,例如登录的时候需要校验用户名和密码是否为空,添加用户的时候校验用户邮箱地址.手机号码格式是否正确. ...

  3. SpringBoot 使用validation数据校验

    后端对数据进行验证 添加包 hibernate-validator <!-- https://mvnrepository.com/artifact/org.hibernate.validator ...

  4. SpringBoot入门 (十一) 数据校验

    本文记录学习在SpringBoot中做数据校验. 一 什么是数据校验 数据校验就是在应用程序中,对输入进来得数据做语义分析判断,阻挡不符合规则得数据,放行符合规则得数据,以确保被保存得数据符合我们得数 ...

  5. SpringBoot中BeanValidation数据校验与优雅处理详解

    目录 本篇要点 后端参数校验的必要性 不使用Validator的参数处理逻辑 Validator框架提供的便利 SpringBoot自动配置ValidationAutoConfiguration Va ...

  6. 测试开发专题:如何在spring-boot中进行参数校验

    上文我们讨论了spring-boot如何去获取前端传递过来的参数,那传递过来总不能直接使用,需要对这些参数进行校验,符合程序的要求才会进行下一步的处理,所以本篇文章我们主要讨论spring-boot中 ...

  7. validator库参数校验

    目录 validator库参数校验若干实用技巧 基本示例 翻译校验错误提示信息 自定义错误提示信息的字段名 自定义结构体校验方法 自定义字段校验方法 自定义翻译方法 validator库参数校验若干实 ...

  8. gin使用validator库参数校验若干实用技巧

    validator库参数校验若干实用技巧 本文介绍了使用validator库做参数校验的一些十分实用的使用技巧,包括翻译校验错误提示信息.自定义提示信息的字段名称.自定义校验方法等. validato ...

  9. Golang使用validator进行数据校验及自定义翻译器

    Golang使用validator进行数据校验及自定义翻译器 包下载:go get github.com/go-playground/validator/v10 一.概述 在接口开发经常会遇到一个问题 ...

随机推荐

  1. CF1458D Flip and Reverse[题解]

    Flip and Reverse 题目大意 给定一个 \(01\) 字符串,有机会进行若干次操作,对于每一次操作: 选择该字符串的子串,要求是该子串内包含数量相同的 \(0\) , \(1\) 字符. ...

  2. java+selenium UI自动化001

    selenium是一个用于Web应用程序测试的工具,可以用来模拟用户在浏览器上的操作. 支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Googl ...

  3. PYTHON 利用ImagePipeline专门爬取图片

    自定义file_path()函数,即可以原有图像文件名为名来保存,并分类保存 def file_path(self, request, response=None, info=None): image ...

  4. 深度学习之逻辑回归的实现 -- sigmoid

    1 什么是逻辑回归 1.1逻辑回归与线性回归的区别: 线性回归预测的是一个连续的值,不论是单变量还是多变量(比如多层感知器),他都返回的是一个连续的值,放在图中就是条连续的曲线,他常用来表示的数学方法 ...

  5. Docker搭建Redis5.0并挂载数据

    记录 Docker 搭建 Redis5.0 并挂载数据过程,搭建参考自 Docker Hub 系列文章欢迎访问:https://www.itwxe.com/posts/9e76db89/ 一.简单挂载 ...

  6. SpringBoot默认首页跳转设置

    大家在使用SpringBoot时候会遇到将系统接口入门设置为"/",那么这个就是我们常见的默认首页跳转的设置.解决的方式有两种 第一种方式:controller里添加一个" ...

  7. 【LeetCode】1207. 独一无二的出现次数

    1207. 独一无二的出现次数 知识点:set:哈希表 题目描述 给你一个整数数组 arr,请你帮忙统计数组中每个数的出现次数. 如果每个数的出现次数都是独一无二的,就返回 true:否则返回 fal ...

  8. ES6 let const关键字

    在es6中,引入了let和const关键字: 1.letES6 新增了let命令,用来声明变量.它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效. (1)在块级作用域里有效(比 ...

  9. 学习Git的基本业务逻辑

    1,基本业务逻辑(假设针对index.html文件中内容): 1,在init版本库之前已写好开头部分:index 对index进行git init版本库: 进入到文件夹中,git init git a ...

  10. SSM框架中mapper层,增删改查,如何实现

    1.批量修改 <!-- 批量修改 MySQL--> <update id="updateBatch" parameterType="java.lang. ...