广告
返回顶部
首页 > 资讯 > 精选 >spring自定义校验注解ConstraintValidator的示例分析
  • 582
分享到

spring自定义校验注解ConstraintValidator的示例分析

2023-06-20 12:06:34 582人浏览 独家记忆
摘要

这篇文章主要介绍spring自定义校验注解ConstraintValidator的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、前言系统执行业务逻辑之前,会对输入数据进行校验,检测数据是否有效合法的。所以

这篇文章主要介绍spring自定义校验注解ConstraintValidator的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

一、前言

系统执行业务逻辑之前,会对输入数据进行校验,检测数据是否有效合法的。所以我们可能会写大量的if else等判断逻辑,特别是在不同方法出现相同的数据时,校验的逻辑代码会反复出现,导致代码冗余,阅读性和可维护性极差。

jsR-303是Java为Bean数据合法性校验提供的标准框架,它定义了一整套校验注解,可以标注在成员变量,属性方法等之上。

hibernate-validator就提供了这套标准的实现,我们在用SpringBoot开发WEB应用时,会引入spring-boot-starter-web依赖,它默认会引入spring-boot-starter-validation依赖,而spring-boot-starter-validation中就引用了hibernate-validator依赖。

spring自定义校验注解ConstraintValidator的示例分析

但是,在比较高版本的spring-boot-starter-web中,默认不再引用spring-boot-starter-validation,自然也就不会默认引入到hibernate-validator依赖,需要我们手动添加依赖。

<dependency>    <groupId>org.hibernate.validator</groupId>    <artifactId>hibernate-validator</artifactId>    <version>6.1.7.Final</version></dependency>

hibernate-validator中有很多非常简单好用的校验注解,例如NotNull,@NotEmpty,@Min,@Max,@Email,@PositiveOrZero等等。这些注解能解决我们大部分的数据校验问题。如下所示:

package com.nobody.dto;import lombok.Data;import javax.validation.constraints.*;@Datapublic class UserDTO {    @NotBlank(message = "姓名不能为空")    private String name;    @Min(value = 18, message = "年龄不能小于18")    private int age;@NotEmpty(message = "邮箱不能为空")    @Email(message = "邮箱格式不正确")    private String email;}

二、自定义参数校验器

但是,hibernate-validator中的这些注解不一定能满足我们全部的需求,我们想校验的逻辑比这复杂。所以,我们可以自定义自己的参数校验器。

首先引入依赖是必不可少的。

<dependency>    <groupId>org.hibernate.validator</groupId>    <artifactId>hibernate-validator</artifactId>    <version>6.1.7.Final</version></dependency>

最近不是基金很火吗,一大批的韭菜疯狂地涌入买基金的浪潮中。我就以用户开户为例,首先要校验此用户是不是成年人(即不能小于18岁),以及名字是不是以"新韭菜"开头的,符合条件的才允许开户。

定义一个注解,用于校验用户的姓名是不是以“新韭菜”开头的。

package com.nobody.annotation;import com.nobody.validator.IsLeekValidator;import javax.validation.Constraint;import javax.validation.Payload;import java.lang.annotation.*;@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)@Documented@Constraint(validatedBy = IsLeekValidator.class) // 指定我们自定义的校验类public @interface IsLeek {        boolean required() default true;        String message() default "此用户不是韭零后,无法开户!";        Class<?>[] groups() default {};        Class<? extends Payload>[] payload() default {};}

定义校验类,实现ConstraintValidator接口,接口使用了泛型,需要指定两个参数,第一个是自定义注解,第二个是需要校验的数据类型。重写2个方法,initialize方法主要做一些初始化操作,它的参数是我们使用到的注解,可以获取到运行时的注解信息。isValid方法就是要实现的校验逻辑,被注解的对象会传入此方法中。

package com.nobody.validator;import com.nobody.annotation.IsLeek;import org.springframework.util.StringUtils;import javax.validation.ConstraintValidator;import javax.validation.ConstraintValidatorContext;public class IsLeekValidator implements ConstraintValidator<IsLeek, String> {    // 是否强制校验    private boolean required;    @Override    public void initialize(IsLeek constraintAnnotation) {        this.required = constraintAnnotation.required();    }    @Override    public boolean isValid(String name, ConstraintValidatorContext constraintValidatorContext) {        if (required) {            // 名字以"新韭菜"开头的则校验通过            return !StringUtils.isEmpty(name) && name.startsWith("新韭菜");        }        return false;    }}

三、使用自定义注解

通过以上几个步骤,我们自定义的校验注解就完成了,我们使用测试下效果。

package com.nobody.dto;import com.nobody.annotation.IsLeek;import lombok.Data;import javax.validation.constraints.*;@Datapublic class UserDTO {    @NotBlank(message = "姓名不能为空")    @IsLeek // 我们自定义的注解    private String name;    @Min(value = 18, message = "年龄不能小于18")    private int age;    @NotEmpty(message = "邮箱不能为空")    @Email(message = "邮箱格式不正确")    private String email;}

写个接口,模拟用户开户业务,调用测试。注意,记得加上@Valid注解开启校验,不然不生效。

package com.nobody.controller;import com.nobody.dto.UserDTO;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.RestController;import javax.validation.Valid;@RestController@RequestMapping("user")public class UserController {    @PostMapping("add")    public UserDTO add(@RequestBody @Valid UserDTO userDTO) {        System.out.println(">>> 用户开户成功...");        return userDTO;    }}

如果参数校验不通过,会抛出MethodArgumentNotValidException异常,我们全局处理下然后返回给接口。

package com.nobody.exception;import javax.servlet.Http.httpservletRequest;import org.springframework.web.bind.MethodArgumentNotValidException;import org.springframework.web.bind.annotation.ControllerAdvice;import org.springframework.web.bind.annotation.ExceptionHandler;import org.springframework.web.bind.annotation.ResponseBody;import lombok.extern.slf4j.Slf4j;@ControllerAdvice@Slf4jpublic class GlobalExceptionHandler {    // 处理接口参数数据格式错误异常    @ExceptionHandler(value = MethodArgumentNotValidException.class)    @ResponseBody    public Object errorHandler(HttpServletRequest request, MethodArgumentNotValidException e) {        return e.getBindingResult().getAllErrors();    }}

我们先测试用户姓名不带"新韭菜"前缀的进行测试,发现校验不通过,证明注解生效了。

POST http://localhost:8080/user/add

Content-Type: application/JSON

{"name": "小绿", "age": 19, "email": "845136542@qq.com"}

[  {    "codes": [      "IsLeek.userDTO.name",      "IsLeek.name",      "IsLeek.java.lang.String",      "IsLeek"    ],    "arguments": [      {        "codes": [          "userDTO.name",          "name"        ],        "arguments": null,        "defaultMessage": "name",        "code": "name"      },      true    ],    "defaultMessage": "此用户不是韭零后,无法开户!",    "objectName": "userDTO",    "field": "name",    "rejectedValue": "小绿",    "bindingFailure": false,    "code": "IsLeek"  }

如果多个参数校验失败,报错信息也都能获得。如下所示,姓名和邮箱都校验失败。

POST http://localhost:8080/user/add

Content-Type: application/json

{"name": "小绿", "age": 19, "email": "84513654"}

[  {    "codes": [      "Email.userDTO.email",      "Email.email",      "Email.java.lang.String",      "Email"    ],    "arguments": [      {        "codes": [          "userDTO.email",          "email"        ],        "arguments": null,        "defaultMessage": "email",        "code": "email"      },      [],      {        "defaultMessage": ".*",        "codes": [          ".*"        ],        "arguments": null      }    ],    "defaultMessage": "邮箱格式不正确",    "objectName": "userDTO",    "field": "email",    "rejectedValue": "84513654",    "bindingFailure": false,    "code": "Email"  },  {    "codes": [      "IsLeek.userDTO.name",      "IsLeek.name",      "IsLeek.java.lang.String",      "IsLeek"    ],    "arguments": [      {        "codes": [          "userDTO.name",          "name"        ],        "arguments": null,        "defaultMessage": "name",        "code": "name"      },      true    ],    "defaultMessage": "此用户不是韭零后,无法开户!",    "objectName": "userDTO",    "field": "name",    "rejectedValue": "小绿",    "bindingFailure": false,    "code": "IsLeek"  }]

以下是所有参数校验通过的情况:

POST http://localhost:8080/user/add

Content-Type: application/json

{"name": "新韭菜小绿", "age": 19, "email": "84513654@qq.com"}

{

  "name": "新韭菜小绿",

  "age": 19,

  "email": "84513654@qq.com"

}

我们可能会将UserDTO对象用在不同的接口中接收参数,比如在新增和修改接口中。在新增接口中,不需要校验userId;在修改接口中需要校验userId。那注解中的groups字段就派上用场了。groups和@Validated配合能控制哪些注解需不需要开启校验。

我们首先定义2个groups分组接口Update和Create,并且继承Default接口。当然也可以不继承Default接口,因为使用注解时不显示指定groups的值,则默认为groups = {Default.class}。所以继承了Default接口,在用@Validated(Create.class)时,也会校验groups = {Default.class}的注解。

package com.nobody.annotation;import javax.validation.groups.Default;public interface Create extends Default {}
package com.nobody.annotation;import javax.validation.groups.Default;public interface Update extends Default {}

在用到注解的地方,填写groups的值。

package com.nobody.dto;import com.nobody.annotation.Create;import com.nobody.annotation.IsLeek;import com.nobody.annotation.Update;import lombok.Data;import javax.validation.constraints.*;@Datapublic class UserDTO {    @NotBlank(message = "用户ID不能为空", groups = Update.class)    private String userId;    @NotBlank(message = "姓名不能为空", groups = {Update.class, Create.class})    @IsLeek    private String name;    @Min(value = 18, message = "年龄不能小于18")    private int age;    @NotEmpty(message = "邮箱不能为空")    @Email(message = "邮箱格式不正确")    private String email;}

最后,在需要声明校验的地方,通过@Validated的指定即可。

package com.nobody.controller;import com.nobody.annotation.Create;import com.nobody.annotation.Update;import com.nobody.dto.UserDTO;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.RestController;@RestController@RequestMapping("user")public class UserController {    @PostMapping("add")    public Object add(@RequestBody @Validated(Create.class) UserDTO userDTO) {        System.out.println(">>> 用户开户成功...");        return userDTO;    }    @PostMapping("update")    public Object update(@RequestBody @Validated(Update.class) UserDTO userDTO) {        System.out.println(">>> 用户信息修改成功...");        return userDTO;    }}

调用add接口时,即使不传userId也能通过,即不对userId进行校验。

POST http://localhost:8080/user/add

Content-Type: application/json

{"name": "新韭菜小绿", "age": 18, "email": "84513654@qq.com"}

调用update接口时,不传userId,会校验不通过。

POST http://localhost:8080/user/update

Content-Type: application/json

{"name": "新韭菜小绿", "age": 18, "email": "84513654@qq.com"}

[  {    "codes": [      "NotBlank.userDTO.userId",      "NotBlank.userId",      "NotBlank.java.lang.String",      "NotBlank"    ],    "arguments": [      {        "codes": [          "userDTO.userId",          "userId"        ],        "arguments": null,        "defaultMessage": "userId",        "code": "userId"      }    ],    "defaultMessage": "用户ID不能为空",    "objectName": "userDTO",    "field": "userId",    "rejectedValue": null,    "bindingFailure": false,    "code": "NotBlank"  }]

以上是“spring自定义校验注解ConstraintValidator的示例分析”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注编程网精选频道!

--结束END--

本文标题: spring自定义校验注解ConstraintValidator的示例分析

本文链接: https://www.lsjlt.com/news/296586.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • spring自定义校验注解ConstraintValidator的示例分析
    这篇文章主要介绍spring自定义校验注解ConstraintValidator的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、前言系统执行业务逻辑之前,会对输入数据进行校验,检测数据是否有效合法的。所以...
    99+
    2023-06-20
  • 浅谈自定义校验注解ConstraintValidator
    目录一、前言二、自定义参数校验器三、使用自定义注解一、前言 系统执行业务逻辑之前,会对输入数据进行校验,检测数据是否有效合法的。所以我们可能会写大量的if else等判断逻辑,特别是...
    99+
    2022-11-12
  • ConstraintValidator类如何实现自定义注解校验前端传参
    前言 今天项目碰到这么一个问题,前端传递的json格式到我的微服务后端转换为vo类,其中有一个Integer的字段后端希望它在固定的几个数里面取值,例如只能取值1、2、4。 一般咱们...
    99+
    2022-11-12
  • SpringBoot自定义注解之脱敏注解的示例分析
    这篇文章将为大家详细讲解有关SpringBoot自定义注解之脱敏注解的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。自定义注解之脱敏注解数据脱敏是指对某些敏感信息通过脱敏规则进行数据的变形,实现敏...
    99+
    2023-06-22
  • Spring AOP 实现自定义注解的示例
    目录1. 注解如下:2. 切面自工作后,除了一些小项目配置事务使用过 AOP,真正自己写 AOP 机会很少,另一方面在工作后还没有写过自定义注解,一直很好奇注解是怎么实现他想要的功能...
    99+
    2022-11-12
  • Nest.js参数校验和自定义返回数据格式的示例分析
    这篇文章主要介绍Nest.js参数校验和自定义返回数据格式的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!0x0 参数校验参数校验大部分业务是使用 Nest.js 中的管道 方法实现,具体可以查阅文档 。不过...
    99+
    2023-06-14
  • Spring自定义XML schema 扩展的示例分析
    小编给大家分享一下Spring自定义XML schema 扩展的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!Spring整合dubbo的事例<be...
    99+
    2023-06-15
  • 关于spring的自定义缓存注解分析
    目录为什么要自定义缓存注解?自定义缓存注解CachedCacheUpdateCacheInvalidateCachedAspectCacheUpdateAspectCach...
    99+
    2023-05-20
    spring 注解 spring 自定义缓存
  • 如何通过自定义spring invalidator注解校验数据合法性
    目录自定义spring invalidator注解校验数据合法性1、定义校验属性字符串长度的注解2、实现校验逻辑,校验失败后返回错误提示3、在模型字段属性上增加校验的注解4、提供统一...
    99+
    2022-11-13
  • 怎么通过自定义spring invalidator注解校验数据合法性
    今天小编给大家分享一下怎么通过自定义spring invalidator注解校验数据合法性的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面...
    99+
    2023-07-02
  • 基于自定义校验注解(controller、method、(groups)分组的使用)
    目录1、首先创建两个自定义校验注解类2、校验注解的使用1>、controller中的使用2>、方法中触发注解3>、分组groups的使用单个注解用在方法上(@Val...
    99+
    2022-11-12
  • phpunit自定义的示例分析
    这篇文章主要介绍phpunit自定义的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!下载:wget  https://phar.phpunit.de/ph...
    99+
    2022-10-19
  • SpringBoot自定义注解实现Token校验的方法
    1.定义Token的注解,需要Token校验的接口,方法上加上此注解 import java.lang.annotation.ElementType; import java.l...
    99+
    2022-11-11
  • Spring自定义注解配置简单日志示例
    目录一、创建自定义注解二、解析注解三、使用自定义注解java在jdk1.5中引入了注解,spring框架也正好把java注解发挥得淋漓尽致。 下面会讲解Spring中自定义注解的简单...
    99+
    2023-05-19
    Spring 自定义注解 Spring 日志注解
  • Spring注解解析之@ImportResource的示例分析
    这篇文章给大家分享的是有关Spring注解解析之@ImportResource的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一、ImportResource1.1 定义包和类首先定义一个不会被Compo...
    99+
    2023-06-15
  • Spring@Autowired注解与自动装配的示例分析
    这篇文章主要介绍了Spring@Autowired注解与自动装配的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1 配置文件的方法我们编写spring 框架的代码时候...
    99+
    2023-05-31
    spring @autowired
  • spring常用注解的示例分析
    这篇文章给大家分享的是有关spring常用注解的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1 、将普通类加入容器形成Bean的注解日常开发中主要使用到的定义Bean的注解包括(XML方式配置bean暂...
    99+
    2023-05-30
    spring
  • spring注解之@profile的示例分析
    这篇文章给大家分享的是有关spring注解之@profile的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。spring中@profile与maven中的profile很相似,通过配置来改变参数。例如在开...
    99+
    2023-05-31
    spring profile
  • Java 自定义注解在登录验证的应用示例
    目录java注解@Retention@Target登录注解 @Logined注解需求在拦截器上获取 @Logined 注解总结java注解 从 JDK 5开始,Java 增加了注解...
    99+
    2022-11-12
  • Vue自定义指令的示例分析
    这篇文章主要介绍Vue自定义指令的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!在 AngularJs 中,它的指令使用 directive ( name,factor_fu...
    99+
    2022-10-19
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作