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


猜你喜欢
- 前言 spring事务管理包含两种情况,编程式事务、声明
- 本文实例为大家分享了java客户端登陆服务器用户名验证的具体实现代码,供大家参考,具体内容如下客户端通过键盘录入用户名,服务端对用户名进行验
- 一、简介 TextureMapFragment:用于显示地图片段。 二、示例3--Demo03MapFragment.c
- 一、Monkey 是什么?Monkey 就是SDK中附带的一个工具。二、Monkey 测试的目的?:该工具用于进行压力测试。 然后开发人员结
- JVM是Java Virtual Machine(Java虚拟机)的缩写,JVM是一种用于计算设备的规范,它是一个虚构出来的计算机,是通过在
- 用java swing写的一个简单的五子棋游戏。下面是Main.java。package com.crossing.main;import
- 前言Java作为一种平台无关性的语言,其主要依靠于Java虚拟机——JVM,我们写好的代码会被编译成class文件,再由JVM进行加载、解析
- 话不多说,请看下面//C# 代码int year = DateTime.Now.Year;int month = DateTime.Now.
- .NET开发人员首选的方法,通过COM组件调用Office软件本身来实现文件的创建和读写,但是数据量较大的时候异常缓慢;如下代码所示已经做了
- 最近碰到个项目要使用到滚动选择器,原生的NumberPicker可定制性太差,不大符合UI要求。网上开源的WheelView是用Scroll
- 这篇文章主要介绍了Java ForkJoin框架的原理及用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需
- 前言最近在做一个公共相关的内容,公告里边的内容,打算做成配置化的。但是考虑到存储到数据库,需要建立数据库表;存储到配置组件中,担心配置组件存
- 一、问题描述在使用idea Jrebel续期的时候,修改idea激活服务器地址时,遇到报错:Cannot reactivate, offli
- 在开发过程中,我们可能会经常遇到这样的需求样式:这张图是截取京东消息通知的弹出框,我们可以看到右上方有个三角形的气泡效果,这只是其中一种,三
- 本文实例为大家分享了android view实现横向滑动选择的具体代码,供大家参考,具体内容如下做文字编辑,从网上找来的。Horizonta
- 本文介绍了Android:利用SharedPreferences实现自动登录,具体如下:主要代码:public class LoginAct
- C# DateTime与时间戳的相互转换,包括JavaScript时间戳和Unix的时间戳。1. 什么是时间戳首先要清楚JavaScript
- 本文实例为大家分享了java实现九宫格拼图游戏的具体代码,供大家参考,具体内容如下设计步骤: 先将框架构思出来,首先将拼图游戏的雏
- properties配置文件如下:human.name=Mr.Yuhuman.age=21human.gender=male如何把prope
- ProgressBar进度条当一个应用在后台执行时,前台界面不会有任何信息,这时,用户根本不知道程序是否在执行以及执行的进度等, 因此需要使