SpringBoot 实战 (十五) | 服务端参数校验之一

简介: 估计很多朋友都认为参数校验是客户端的职责,不关服务端的事。其实这是错误的,学过 Web 安全的都知道,客户端的验证只是第一道关卡。它的参数验证并不是安全的,一旦被有心人抓到可乘之机,他就可以有各种方法来摸拟系统的 Http 请求,访问数据库的关键数据。轻则导致服务器宕机,重则泄露数据。所以,这时就需要设置第二道关卡,服务端验证了。

老项目的服务端校验


@RestController
@RequestMapping("/student")
public class ValidateOneController {
    @GetMapping("/id")
    public Student findStudentById(Integer id){
        if(id == null){
              logger.error("id 不能为空!");
              throw new NullPointerException("id 不能为空");
        }
        return studentService.findStudentById(id);
    }
}


看以上代码,就一个的校验就如此麻烦。那我们是否有好的统一校验方法呢?鉴于 SpringBoot 无所不能。答案当然是有的。


其中,Bean Validator 和 Hibernate Validator 就是两套用于验证的框架,二者都遵循 JSR-303 ,可以混着用,鉴于二者的某些 Validator 注解有差别,例如 @Length 在 Bean Validator 中是没有的,所以这里我选择混合用。


JSR-303


JSR-303 是JAVA EE 6 中的一项子规范,叫做 Bean Validation,Hibernate Validator 是 Bean Validation 的参考实现, Hibernate Validator 提供了 JSR 303 规范中所有内置 Constraint(约束) 的实现,除此之外还有一些附加的 Constraint 。这些 Constraint (约束) 全都通过注解的方式实现,请看下面两个表。


Bean Validation 中内置的约束:


注解 作用
@Null 被注解参数必须为空
@NotNull 被注解参数不能为空
@AssertTrue 被注解参数必须为 True
@AssertFalse 被注解参数必须为 False
@Min(value) 被注解参数必须是数字,且其值必须大于等于 value
@Max(value) 被注解参数必须是数字,且其值必须小于等于 value
@DecimaMin(value) 被注解参数必须是数字,且其值必须大于等于 value
@DecimaMax(value) 被注解参数必须是数字,且其值必须小于等于 value
@Size(max, min) 被注解参数大小必须在指定范围内
@Past 被注解参数必须是一个过去的日期
@Future 被注解参数必须是一个将来的日期
@Pattern(value) 被注解参数必须符合指定的正则表达式
@Digits(integer, fraction) 被注解参数必须是数字,且其值必须在可接受范围内
@NotBlank 被注解参数的值不为空(不为 null、去除首位空格后长度为 0),不同于 @NotEmpty,@NotBlank 只应用于字符串且在比较时会去除字符串的空格


Hibernate Validator 附加的约束:


注解 作用
@NotEmpty 被注解参数的值不为 null 且不为空(字符串长度不为0、集合大小不为0)
@Email 被注解参数必须是电子邮箱地址
@Length 被注解的字符串长度必须在指定范围内
@Range 被注解的参数必须在指定范围内


准备工作


  • SpringBoot 2.1.3
  • IDEA
  • JDK8


Pom 文件依赖


<!-- web 启动类 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- test 单元测试类 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<!-- lombok 依赖用于简化 bean -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>


实体类


用于测试,加入了参数校验规则。


@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private Integer id;
    @NotBlank(message = "学生名字不能为空")
    @Length(min = 2, max = 10, message = "name 长度必须在 {min} - {max} 之间")
    private String name;
    @NotNull(message = "年龄不允许为空")
    @Min(value = 0, message = "年龄不能低于 {value} 岁")
    private Integer age;
}


Controller 层


写了两个方法,一个用于校验普通参数,一个用于校验对象


@Validated //开启数据校验,添加在类上用于校验方法,添加在方法参数中用于校验参数对象。(添加在方法上无效)
@RestController
@RequestMapping("/student")
public class ValidateOneController {
    /**
     * 普通参数校验
     * @param name
     * @return
     */
    @GetMapping("/name")
    public String findStudentByName(@NotBlank(message = "学生名字不能为空")
    @Length(min = 2, max = 10, message = "name 长度必须在 {min} - {max} 之间")String name){
        return "success";
    }
    /**
     * 对象校验
     * @param student
     * @return
     */
    @PostMapping("/add")
    public String addStudent(@Validated @RequestBody Student student){
        return "success";
    }
}


Postman 测试


校验普通参数测试结果:


下图可以看见,我没有在 http://localhost:8080/student/name 地址后添加 name 参数,传到后台马上就校验出异常了。而这个异常信息就是我定义的校验异常信息。

640.jpg

校验对象测试结果:

640.png

结果有点长:


下图可以看见,我访问 http://localhost:8080/student/add 传入了参数对象,但对象是不能通过校验规则的,比如 age 参数为负数,name 参数长度太大,传到后台马上就校验出异常了。而这个异常信息就是我定义的校验异常信息。

640.png

完整代码


https://github.com/turoDog/Demo/tree/master/springboot_validateone_demo


如果觉得对你有帮助,请给个 Star 再走呗,非常感谢。


后语


如果本文对你哪怕有一丁点帮助,请帮忙点好看。你的好看是我坚持写作的动力。

相关文章
|
4月前
|
网络协议 Java
SpringBoot快速搭建TCP服务端和客户端
由于工作需要,研究了SpringBoot搭建TCP通信的过程,对于工程需要的小伙伴,只是想快速搭建一个可用的服务.其他的教程看了许多,感觉讲得太复杂,很容易弄乱,这里我只讲效率,展示快速搭建过程。
358 58
|
2月前
|
前端开发 Java 数据库连接
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
SpringBoot参数校验底层原理和实操。深度历险、深度解析(图解+秒懂+史上最全)
|
6月前
|
缓存 NoSQL Java
基于SpringBoot的Redis开发实战教程
Redis在Spring Boot中的应用非常广泛,其高性能和灵活性使其成为构建高效分布式系统的理想选择。通过深入理解本文的内容,您可以更好地利用Redis的特性,为应用程序提供高效的缓存和消息处理能力。
436 79
|
4月前
|
监控 Java 调度
SpringBoot中@Scheduled和Quartz的区别是什么?分布式定时任务框架选型实战
本文对比分析了SpringBoot中的`@Scheduled`与Quartz定时任务框架。`@Scheduled`轻量易用,适合单机简单场景,但存在多实例重复执行、无持久化等缺陷;Quartz功能强大,支持分布式调度、任务持久化、动态调整和失败重试,适用于复杂企业级需求。文章通过特性对比、代码示例及常见问题解答,帮助开发者理解两者差异,合理选择方案。记住口诀:单机简单用注解,多节点上Quartz;若是任务要可靠,持久化配置不能少。
433 4
|
4月前
|
Java
SpringBoot快速搭建WebSocket服务端和客户端
由于工作需要,研究了SpringBoot搭建WebSocket双向通信的过程,其他的教程看了许多,感觉讲得太复杂,很容易弄乱,这里我只展示快速搭建过程。
1201 1
|
5月前
|
缓存 安全 Java
深入解析HTTP请求方法:Spring Boot实战与最佳实践
这篇博客结合了HTTP规范、Spring Boot实现和实际工程经验,通过代码示例、对比表格和架构图等方式,系统性地讲解了不同HTTP方法的应用场景和最佳实践。
458 5
|
7月前
|
Java Spring
SpringBoot 实战 不同参数调用不同实现
本文介绍了如何在实际工作中根据不同的入参调用不同的实现,采用`map+enum`的方式实现优雅且严谨的解决方案。通过Spring Boot框架中的工厂模式或策略模式,避免了使用冗长的`if...else...`语句。文中详细展示了定义接口、实现类、枚举类以及控制器调用的代码示例,确保用户输入的合法性并简化了代码逻辑。
162 1
SpringBoot 实战 不同参数调用不同实现
|
7月前
|
JavaScript 前端开发 Java
Jeesite5:Star24k,Spring Boot 3.3+Vue3实战开源项目,架构深度拆解!让企业级项目开发效率提升300%的秘密武器
Jeesite5 是一个基于 Spring Boot 3.3 和 Vue3 的企业级快速开发平台,集成了众多优秀开源项目,如 MyBatis Plus、Bootstrap、JQuery 等。它提供了模块化设计、权限管理、多数据库支持、代码生成器和国际化等功能,极大地提高了企业级项目的开发效率。Jeesite5 广泛应用于企业管理系统、电商平台、客户关系管理和知识管理等领域。通过其强大的功能和灵活性,Jeesite5 成为了企业级开发的首选框架之一。访问 [Gitee 页面](https://gitee.com/thinkgem/jeesite5) 获取更多信息。
283 0
Jeesite5:Star24k,Spring Boot 3.3+Vue3实战开源项目,架构深度拆解!让企业级项目开发效率提升300%的秘密武器
|
11月前
|
JSON 前端开发 Java
Spring MVC——获取参数和响应
本文介绍了如何在Spring框架中通过不同的注解和方法获取URL参数、上传文件、处理cookie和session、以及响应不同类型的数据。具体内容包括使用`@PathVariable`获取URL中的参数,使用`MultipartFile`上传文件,通过`HttpServletRequest`和`@CookieValue`获取cookie,通过`HttpSession`和`@SessionAttribute`获取session,以及如何返回静态页面、HTML代码片段、JSON数据,并设置HTTP状态码和响应头。
189 1
Spring MVC——获取参数和响应
|
11月前
|
自然语言处理 Java API
Spring Boot 接入大模型实战:通义千问赋能智能应用快速构建
【10月更文挑战第23天】在人工智能(AI)技术飞速发展的今天,大模型如通义千问(阿里云推出的生成式对话引擎)等已成为推动智能应用创新的重要力量。然而,对于许多开发者而言,如何高效、便捷地接入这些大模型并构建出功能丰富的智能应用仍是一个挑战。
1935 6