SpringBoot + validation 接口参数校验的思路详解
作者:乾源 发布时间:2023-10-09 11:59:12
有参数传递的地方都少不了参数校验。在web开发中,前端的参数校验是为了用户体验,后端的参数校验是为了安全。试想一下,如果在controller层中没有经过任何校验的参数通过service层、dao层一路来到了数据库就可能导致严重的后果,最好的结果是查不出数据,严重一点就是报错,如果这些没有被校验的参数中包含了恶意代码,那就可能导致更严重的后果。
实践
一、引入依赖
<!--引入spring-boot-starter-validation-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
二、使用校验
在controller层的参数校验可以分为两种场景:
单个参数校验
实体类参数校验
2.1 单参数校验
/**
* 参数校验测试 控制类
* @author oyc
*/
@RestController
@RequestMapping("user")
@Validated
public class RequestParamsValidatedController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@GetMapping
public User test(@NotNull(message = "姓名不能为空") String name,
@NotNull(message = "年龄不能为空") @Max(value = 99, message = "不能大于200岁") Integer age) {
logger.info("name:" + name + " -age:" + age);
return new User(name, age);
}
}
2.2 实体类参数校验
/**
* 参数校验测试 控制类
* @author oyc
*/
@RestController
@RequestMapping("user")
@Validated
public class RequestParamsValidatedController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@PostMapping
public User save(@Validated User user) {
logger.info(user.toString());
return user;
}
}
package com.oycbest.springbootvalidated.vo;
import javax.validation.constraints.*;
import java.io.Serializable;
/**
* 用户实体类
* @author oyc
*/
public class User implements Serializable {
private String userId;
@NotNull(message = "用户名不能为空")
private String userName;
@NotNull(message = "年龄不能为空")
@Max(value = 100, message = "年龄不能大于100岁")
private int age;
@NotNull(message = "邮箱不能为空")
@Email(message = "邮箱格式不正确")
private String email;
@NotNull(message = "电话号码不能为空")
private String phoneNumber;
public User(@NotNull(message = "用户名不能为空") String userName, int age) {
this.userName = userName;
this.age = age;
}
public User() {
}
public User(String userId, @NotNull(message = "用户名不能为空") String userName, int age, String email, String phoneNumber) {
this.userId = userId;
this.userName = userName;
this.age = age;
this.email = email;
this.phoneNumber = phoneNumber;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
@Override
public String toString() {
return "User{" +
"userId='" + userId + '\'' +
", userName='" + userName + '\'' +
", age=" + age +
", email='" + email + '\'' +
", phoneNumber='" + phoneNumber + '\'' +
'}';
}
}
2.3 定义统一异常处理
package com.oycbest.springbootvalidated.exception;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.List;
import java.util.Set;
/**
* 全局异常处理
*
* @author oyc
*/
@ControllerAdvice
@Component
public class GlobalExceptionHandler {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
@ExceptionHandler
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
public String handle(ValidationException exception) {
logger.error("请求异常:" + exception.getMessage());
if (exception instanceof ConstraintViolationException) {
ConstraintViolationException exs = (ConstraintViolationException) exception;
Set<ConstraintViolation<?>> violations = exs.getConstraintViolations();
for (ConstraintViolation<?> item : violations) {
//打印验证不通过的信息
logger.error("请求异常:" + item.getMessage());
}
}
return "请求异常: " + exception.getMessage();
}
@ResponseBody
@ExceptionHandler(value = BindException.class)
public String bindException(Exception e) {
if (e instanceof BindException) {
BindException exs = (BindException) e;
List<FieldError> fieldErrors = exs.getFieldErrors();
for (FieldError item : fieldErrors) {
logger.error("请求异常:" + item.getDefaultMessage());
}
}
logger.error("数据绑定异常:" + e.getMessage());
return "数据绑定异常";
}
@ResponseBody
@ExceptionHandler(value = Exception.class)
public String defaultException(Exception e) {
logger.error("请求异常:" + e.getMessage());
return "请求异常 " + e.getMessage();
}
}
三、约束性注解(简单)说明
注解 | 功能 |
@AssertFalse | 可以为null,如果不为null的话必须为false |
@AssertTrue | 可以为null,如果不为null的话必须为true |
@DecimalMax | 设置不能超过最大值 |
@DecimalMin | 设置不能超过最小值 |
@Digits | 设置必须是数字且数字整数的位数和小数的位数必须在指定范围内 |
@Future | 日期必须在当前日期的未来 |
@Past | 日期必须在当前日期的过去 |
@Max | 最大不得超过此最大值 |
@Min | 最大不得小于此最小值 |
@NotNull | 不能为null,可以是空 |
@Null | 必须为null |
@Pattern | 必须满足指定的正则表达式 |
@Size | 集合、数组、map等的size()值必须在指定范围内 |
必须是email格式 | |
@Length | 长度必须在指定范围内 |
@NotBlank | 字符串不能为null,字符串trim()后也不能等于“” |
@NotEmpty | 不能为null,集合、数组、map等size()不能为0;字符串trim()后可以等于“” |
@Range | 值必须在指定范围内 |
@URL | 必须是一个URL |
来源:https://blog.csdn.net/u014553029/article/details/109192520
猜你喜欢
- 若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的。 通常情况下, 静
- 本文实例讲述了Java使用备忘录模式实现过关类游戏功能。分享给大家供大家参考,具体如下:一.模式定义备忘录模式,在不破坏封闭的前提下,捕获一
- 十六进制字符串与数值类型之间转换(C# 编程指南) 以下示例演示如何执行下列任务: 获取字符串中每个字符的十六进制值。 获取与十六进制字符串
- IDEA 2020.1 版自动导入MAVEN依赖的方法(新版MAVEN无法自动导入/更新POM依赖、MAVEN设置自动更新、自动更新快捷键)
- Java xml出现错误 javax.xml.transform.TransformerException: java.lang.NullP
- 1. 公共字段自动填充1.1 问题分析在新增员工时需要设置创建时间、创建人、修改时间、修改人等字段,在编辑员工时需要设置修改时间、修改人等字
- 异常分类可查的异常(checked exceptions):Exception下除了RuntimeException外的异常不可查的异常(u
- MyBatis插入Insert、InsertSelective的区别逆向自动生成的mybatis对应配置Mapper文件里面,有两个方法,分
- Java语言的历程丰富多彩,被现在众多程序员和企业广泛使用,不用质疑这是Java的领先技术的结果。Java是Sun公司开发的一种编程语言,S
- 一、反射概述反射机制指的是Java在运行时候有一种自观的能力,能够了解自身的情况为下一步做准备,其想表达的意思就是:在运行状态中,对于任意一
- 定义:动态给一个对象添加一些额外的职责,就象在墙上刷油漆.使用Decorator模式相比用生成子类方式达到功能的扩充显得更为灵活。设计初衷:
- Jmeter 执行Java 请求时,运行结束后报错,Tidying up remote @ Mon Feb 24 19:42:34 CST
- 写在前面在前后端交互过程中,为了保证信息安全,我们往往需要加点用户验证。本文介绍了用springboot简单整合token。springbo
- 前言假设项目打包后,项目结构为:此时如果需要再windows环境中进行项目的启动或关闭,需要频繁的手敲命令,很不方便。此时可以编写.bat脚
- 此处网上最多的做法是需要修改tomcat的参数配置大致如下:<Connector port="8080" prot
- java简易小游戏制作游戏思路:设置人物移动,游戏规则,积分系统,随机移动的怪物,游戏胜负判定,定时器。游戏内容部分package 代码部分
- 前言现在很多web应用,做过web项目的童鞋都知道,web结果由html+js+css组成,html结构都有一定的规范,数据动态交互可以通过
- 1、原理事务的概念想必大家都很清楚,其ACID特性在开发过程中占有重要的地位。同时在并发过程中会出现一些一致性问题,为了解决一致性问题,也出
- Springboot + Vue,定时任务调度的全套实现方案。这里用了quartz这个框架,实现分布式调度任务很不错,关于quarz的使用方
- 这篇文章主要介绍了Spring JDK * 实现过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要