【Spring Boot】Web开发 — 数据验证

Web开发 — 数据验证

对于应用系统而言,任何客户端传入的数据都不是绝对安全有效的,这就要求我们在服务端接收到数据时也对数据的有效性进行验证,以确保传入的数据安全正确。接下来介绍Spring Boot是如何实现数据验证的。

1.Hibernate Validator简介

数据校验是Web开发中的重要部分,目前数据校验的规范、组件非常多,有JSR-303/JSR-349、Hibernate Validator、Spring Validation。

  • JSR(Java Specification Request)规范是Java EE 6中的一项子规范,也叫作Bean Validation。它指定了一整套基于bean的验证API,通过标注给对象属性添加约束条件。
  • Hibernate Validator是对JSR规范的实现,并增加了一些其他校验注解,如@Email、@Length、@Range等。
  • Spring Validation是Spring为了给开发者提供便捷,对Hibernate Validator进行了二次封装。同时,Spring Validation在SpringMVC模块中添加了自动校验,并将校验信息封装进了特定的类中。

JSR定义了数据验证规范,而Hibernate Validator则是基于JSR规范,实现了各种数据验证的注解以及一些附加的约束注解。Spring Validation则是对Hibernate Validator的封装整合。JSR和Hibernate Validator中的常用注解如表所示。

在这里插入图片描述
表中包含了Hibernate Validator实现的JSR-303定义的验证注解和Hibernate Validator自己定义的验证注解,同时也支持自定义约束注解。所有的注解都包含code和message这两个属性。

  • Message定义数据校验不通过时的错误提示信息。
  • code定义错误的类型。

Spring Boot是从Spring发展而来的,所以自然支持Hibernate Validator和Spring Validation两种方式,默认使用的是Hibernate Validator组件。

2.数据校验

使用Hibernate Validator校验数据需要定义一个接收的数据模型,使用注解的形式描述字段校验的规则。下面以User对象为例演示如何使用Hibernate Validator校验数据。

2.1 JavaBean参数校验

Post请求参数较多时,可以在对应的数据模型(Java Bean)中进行数据校验,通过注解来指定字段校验的规则。下面以具体的实例来进行演示。首先,创建Java Bean实体类:

public class User {
    @NotBlank(message = "姓名不允许为空!")
    @Length(min = 2, max = 1,message = "姓名长度错误,姓名长度2-10!")
    private String name;

    @NotNull(message ="年龄不能为空!")
    @Min(18)
    private int age;

    @NotBlank(message ="地址不能为空!")
    private String address;

    @Pattern(regexp = "((13[0-9])|(14[5,7,9])|(15([0-3]|[5-9]))|(166)|(17[0,1,3,5,6,7,8])|(18[0-9])|(19[8|9]))\\d{8}$", message = "手机号格式错误")
    private String phone;

    @Email(message ="邮箱格式错误")
    private String email;

    //省略get和set方法
}

在示例中,每个注解中的属性message是数据校验不通过时要给出的提示信息,如@Email(message=“邮件格式错误”),当邮件格式校验不通过时,提示邮件格式错误。然后,添加数据校验方法:

    @PostMapping(path ="/check")
    public String check(@RequestBody @Valid User user, BindingResult result) {
        String name = user.getName();
        if(result.hasErrors()) {
            List<ObjectError> list = result.getAllErrors();
            for (ObjectError error : list) {
                System.out.println(error.getCode() + "_" + error.getDefaultMessage());
            }
        }
        return name;
    }

在上面的示例中,在@RequestBody注解后面添加了@Valid注解,然后在后面添加了BindingResult返回验证结果,BindingResult是验证不通过时的结果集合。

注意,BindingResult必须跟在被校验参数之后,若被校验参数之后没有BindingResult对象,则会抛出BindException。

最后,运行验证。

启动项目,在postman中请求/user/check接口,后台输出了数据验证的结果:

Length-密码长度错误,密码长度6-20!
Min-最小不能小于18
Length-姓名长度错误,姓名长度2-10!

通过上面的输出可以看到,应用系统对传入的数据进行了校验,同时也返回了对应的数据校验结果。

2.2 URL参数校验

一般GET请求都是在URL中传入参数。对于这种情况,可以直接通过注解来指定参数的校验规则。下面通过实例进行演示。

@Validated
public class UserController {
    @RequestMapping("/query")
    public String query(@Length(min = 2, max = 1, message ="姓名长度错误,姓名长度2-10!")
                        @RequestParam(name = "name", required = true) String name,
                        @Min(value = 1, message = "年龄最小只能1")
                        @Max(value = 99, message = "年龄最大只能9")
                        @RequestParam(name = "age", required = true) int age) {
        System.out.println(name + " , " + age);
        return name + " , " + age;
    }
}

在上面的示例中,使用@Range、@Min、@Max等注解对URL中传入的参数进行校验。需要注意的是,使用@Valid注解是无效的,需要在方法所在的控制器上添加@Validated注解来使得验证生效。

2.3 JavaBean对象级联校验

对于JavaBean对象中的普通属性字段,我们可以直接使用注解进行数据校验,那如果是关联对象呢?其实也很简单,在属性上添加@Valid注解就可以作为属性对象的内部属性进行验证(验证User对象,可以验证UserDetail的字段)。示例代码如下:

public class User {
    @Size(min = 3, max = 5, message = "list的Size在[3,5]")
    private List<String> list;
    @NotNull
    @Valid
    private Demo3 demo3;
}

public class UserDetail {
    @Length(min = 5,max = 17,message = "length长度在[5,17]之间")
    private String extField;
}

在上面的示例中,在属性上添加@Valid就可以对User中的关联对象UserDetail的字段进行数据校验。

2.4 分组校验

在不同情况下,可能对JavaBean对象的数据校验规则有所不同,有时需要根据数据状态对JavaBean中的某些属性字段进行单独验证。这时就可以使用分组校验功能,即根据状态启用一组约束。Hibernate Validator的注解提供了groups参数,用于指定分组,如果没有指定groups参数,则默认属于javax.validation.groups.Default分组。

下面通过示例演示分组校验。首先,创建分组GroupA和GroupB,示例代码如下:

public interface GroupA {    
}
public interface GroupB {
}

在上面的示例中,我们定义了GroupA和GroupB两个接口作为两个校验规则的分组。然后,创建实体类Person,并在相关的字段中定义校验分组规则,示例代码如下:

public class User {
    @NotBlank(message ="userId不能为空",groups = {GroupA.class})
/**用户id*/
    private Integer userId;
    @NotBlank(message ="用户名不能为空",groups = {GroupA.class})
    /**用户id*/
    private String name;

    @Length(min = 30,max = 40,message = "必须在[30,40]",groups = {GroupB.class})
    @Length(min = 20,max = 30,message = "必须在[20,30]",groups = {GroupA.class})
    /**用户名*/
    private int age;
}

在上面的示例中,userName字段定义了GroupA和GroupB两个分组校验规则。GroupA的校验规则为年龄在20~30,GroupB的校验规则为年龄在30~40。最后,使用校验分组:

@RequestMapping("/save")
public String save(@RequestBody @Validated({GroupA.class, Default.class}) Person person, BindingResult result) {
    System.out.println(JSON.toJSONString(result.getAllErrors()));
return "success";

在上面的示例中,在@Validated注解中增加了{GroupA.class,Default.class}参数,表示对于定义了分组校验的字段使用GroupA校验规则,其他字段使用默认规则。

3.自定义校验

Hibernate Validator支持自定义校验规则。通过自定义校验规则,可以实现一些复杂、特殊的数据验证功能。下面通过示例演示如何创建和使用自定义验证规则。

3.1 声明一个自定义校验注解

首先,定义新的校验注解@CustomAgeValidator,示例代码如下:

    @Min(value = 18, message ="年龄最小不能小于18")
    @Max(value = 120, message ="年龄最大不能超过120")
    @Constraint(validatedBy = {}) //不指定校验器
    @Documented
    @Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface CustomAgeValidator {
        String message() default "年龄大小必须大于18并且小于123";
        Class<?>[] groups() default {};
        Class<? extends Payload>[] payload() default {};
    }

在上面的示例中,我们创建了CustomAgeValidator自定义注解,用于自定义年龄的数据校验规则。

3.2 使用自定义校验注解

创建自定义校验注解CustomAgeValidator之后,在User的age属性上使用自定义组合注解,示例代码如下:

@public class User {
    @NotBlank(message ="姓名不允许为空!")
    @Length(min = 2,max = 10,message ="姓名长度错误,姓名长度2-10!")
    private String name;
    @CustomAgeValidator
    private int age;
    @NotBlank(message ="地址不能为空!")
    private String address;
    @Pattern(regexp = "((13[-9])|(14[5,7,9])|(15([-3]][5-9]))|(166)(17[.1,3,5,6,7,8])l(18[0-9])I(19[8|9]))\\d{8}$", message ="手机号格式错误")
    private String phone;
    @Email(message ="邮箱格式错误")
    private String email;
    //省略get和set
}

在上面的示例中,我们在需要做特殊校验的age字段上添加@CustomAgeValidator自定义注解,这样age字段就会使用我们自定义的校验规则。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/47033.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python爬虫实战(基础篇)—4获取古诗词给孩子学习(附完整代码)

今天我们来获取古诗词网站的一些古诗词来提供给孩子们学习 PS前面几节课的内容在专栏这里&#xff0c;欢迎大家考古&#xff1a;点我 首先我们看一下网站&#xff1a;点我&#xff0c;今天我们来获取一下【唐诗三百首】 第 1 步&#xff1a;网页分析 在网页中我们发现有许多以…

mysql -速成

目录 1.概述 1.3SQL的优点 1.4 SQL 语言的分类 2. 软件的安装与启动 2.1 安装 2.2 MySQL服务的启动和停止 2.3 MySQL服务的登录和退出 ​编辑 2.4 mysql常用命令 2.5 图形化用户结构Sqlyong 3.DQL 语言 3.1 基础查询 3.1.1、语法 3.1.2 特点 3.2 条件查询 3.2.1 …

N位分频器的实现

N位分频器的实现 一、 目的 使用verilog实现n位的分频器&#xff0c;可以是偶数&#xff0c;也可以是奇数 二、 原理 FPGA中n位分频器的工作原理可以简要概括为: 分频器的作用是将输入时钟频率分频,输出低于输入时钟频率的时钟信号。n位分频器可以将输入时钟频率分频2^n倍…

SQL-每日一题【620.有趣的电影】

题目 某城市开了一家新的电影院&#xff0c;吸引了很多人过来看电影。该电影院特别注意用户体验&#xff0c;专门有个 LED显示板做电影推荐&#xff0c;上面公布着影评和相关电影描述。 作为该电影院的信息部主管&#xff0c;您需要编写一个 SQL查询&#xff0c;找出所有影片…

【Spring框架】spring对象注入的三种方法

目录 1.属性注入问题&#xff1a;同类型的Bean存储到容器多个&#xff0c;获取时报错的问题&#xff1b;1.将属性的名字和Bean的名字对应上。2.使用AutoWiredQualifier来筛选bean对象&#xff1b; 属性注入优缺点 2.Setter注入Setter注入优缺点 3.构造方法注入&#xff08;Spri…

【Android知识笔记】UI体系(一)

Activity的显示原理 setContentView 首先开发者Activity的onCreate方法中通常调用的setContentView会委托给Window的setContentView方法: 接下来看Window的创建过程: 可见Window的实现类是PhoneWindow,而PhoneWindow是在Activity创建过程中执行attach Context的时候创建的…

0-超级计算机

超级计算机 概述主要特点处理能力并行处理大规模存储应用领域能耗云超算 中国超算流行体系结构片内异构节点内异构 概述 当谈到超级计算机时&#xff0c;我们指的是性能超高、处理能力强大的计算机系统。 它们通常由数以千计的处理器核心组成&#xff0c;并具备大规模的内存和…

小程序如何将商品添加到分类

​将商品添加到分类是非常重要的功能&#xff0c;可以让商家更方便地管理分类和商品。下面将具体介绍如何将产品添加到分类中。 步骤一&#xff1a;选中商品 在个人中心点击管理入口&#xff0c;然后找到“商品管理”菜单并点击。找到需要添加的商品&#xff0c;然后选中它。…

【网络安全带你练爬虫-100练】第15练:模拟用户登录

目录 一、目标1&#xff1a;理清逻辑 二、目标2&#xff1a;将每一步用代码进行表示 三、网络安全O 一、目标1&#xff1a;理清逻辑 模拟登录的基本流程 1、进入入口程序 2、读取目标URL 3、请求加上线程 4、确定请求数据包 5、请求格式的确认 6、数据的处理与判断 二、目标…

MixFormerV2: Efficient Fully Transformer Tracking

摘要 基于变压器的跟踪器在标准基准测试上取得了很强的精度。然而&#xff0c;它们的效率仍然是在GPU和CPU平台上实际部署的一个障碍。在本文中&#xff0c;为了克服这一问题&#xff0c;我们提出了一个完全变压器跟踪框架&#xff0c;称为MixFormerV2&#xff0c;没有任何密集…

我的2023上半年总结

Hi~C站的小伙伴们好久不见哇&#xff01;釉色终于回到C站&#xff0c;开始要输出了&#xff01;这一篇文章是我的2023上半年的总结&#xff0c;以此&#xff0c;致敬那段迷茫但又不曾被辜负的时光。 文章目录 总括——你愿意花五分钟时间读读我的文章吗学习——制定目标&#…

GB/T 25000.51解读——软件产品的性能效率怎么测?

GB/T 25000.51-2016《软件产品质量要求和测试细则》是申请软件检测CNAS认可一定会用到的一部国家标准。在前面的文章中&#xff0c;我们为大家整体介绍了GB/T 25000.51-2016《软件产品质量要求和测试细则》国家标准的结构和所涵盖的内容以及对软件产品的八大质量特性中的功能性…

电机故障诊断(python程序,模型为CNN结合LSTM)

代码运行环境要求&#xff1a;TensorFlow版本>2.4.0&#xff0c;python版本>3.6.0 运行效果视频&#xff1a;电机故障诊断&#xff08;python代码&#xff09;_哔哩哔哩_bilibili 1.电机常见的故障类型有以下几种&#xff1a; 轴承故障&#xff1a;轴承是电机运转时最容…

新星计划打卡学习:VUE3引入element-plus

目录 1、安装element-plus 2、安装按需导入插件 3、修改配置文件 4、添加页面内容 5、保存并重启项目 1、安装element-plus 官网说要想使用element-plus需要先进行安装&#xff0c;并给出了三种安装方式&#xff0c;我选择了第三种。 报错了&#xff1a; 解决的办法&…

同步、异步、阻塞、非阻塞

一、概念 同步与异步&#xff08;线程间调用&#xff09;的区别&#xff1a;关注的是调用方与被调用方之间的交互方式。同步调用会等待被调用方的结果返回&#xff0c;而异步调用则不会等待结果立即返回&#xff0c;可以通过回调或其他方式获取结果。 阻塞非阻塞&#xff08;…

SpringBoot 和 Vue 参数类型不对应,导致method parameter is not present

org.springframework.web.bind.MissingServletRequestParameterException: Required request parameter id for method parameter type String is not present 客户端&#xff1a; requestUserInfoById()const requestUserInfoById async (id?: string) > {} 服务器端&am…

每天一道C语言编程(2^k进制数)

题目描述 设r是个2^k 进制数&#xff0c;并满足以下条件&#xff1a; &#xff08;1&#xff09;r至少是个2位的2^k 进制数。 &#xff08;2&#xff09;作为2^k 进制数&#xff0c;除最后一位外&#xff0c;r的每一位严格小于它右边相邻的那一位。 &#xff08;3&#xff09;…

大数据课程D2——hadoop的概述

文章作者邮箱&#xff1a;yugongshiyesina.cn 地址&#xff1a;广东惠州 ▲ 本章节目的 ⚪ 了解hadoop的定义和特点&#xff1b; ⚪ 掌握hadoop的基础结构&#xff1b; ⚪ 掌握hadoop的常见命令&#xff1b; ⚪ 了解hadoop的执行流程&#xff1b; 一、简介 1…

《零基础入门学习Python》第057讲:论一只爬虫的自我修养5:正则表达式

如果你在课后有勤加练习&#xff0c;那么你对于字符串的查找应该是已经深恶痛绝了&#xff0c;你发现下载一个网页是很容易的&#xff0c;但是要在网页中查找到你需要的内容&#xff0c;那就是困难的&#xff0c;你发现字符串查找并没有你想象的那么简单&#xff0c;并不是说直…

【Matlab】基于粒子群优化算法优化BP神经网络的数据回归预测(Excel可直接替换数据)

【Matlab】基于粒子群优化算法优化 BP 神经网络的数据回归预测&#xff08;Excel可直接替换数据&#xff09; 1.模型原理2.数学公式3.文件结构4.Excel数据5.分块代码5.1 fun.m5.2 main.m 6.完整代码6.1 fun.m6.2 main.m 7.运行结果 1.模型原理 基于粒子群优化算法&#xff08;…