_controller_validate

controller 中我们首先对所有的请求进行日志记录,身份校验,参数校验之后直接把过滤后的数据丢给 logic(serviceImpl) 。这样子一来 controller 只是充当了 路由 + 过滤器 的作用,如果之后修改 API ,前端的请求地址不需要修改,只要在 logic(serviceImpl) 中修改或者重新一个方法就行了。

springboot 前端参数校验 1 2 3

在 Spring Boot 项目中,参数校验是一个非常重要的环节,主要使用 JSR-303/JSR-380 规范的实现(如 Hibernate Validator)来完成。在Spring Boot中,前端参数校验通常通过 JSR 380(Bean Validation 2.0) 实现,结合 Hibernate Validator(默认实现)和 Spring 的自动配置,可以实现对前端传递参数的校验。以下是如何在 Spring Boot 中实现前端参数校验的详细步骤:


1. 添加依赖

pom.xml 文件中添加 spring-boot-starter-validation 依赖:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId>
</dependency>

2. 创建 DTO 类并添加校验注解

使用 JSR 380 提供的注解对字段进行校验,例如 @NotNull, @Size, @Email, @Pattern 等。

示例:用户数据校验
import javax.validation.constraints.*;public class UserDTO {@NotNull(message = "用户名不能为空")@Size(min = 3, max = 20, message = "用户名长度必须在3到20个字符之间")private String username;@NotNull(message = "邮箱不能为空")@Email(message = "邮箱格式不正确")private String email;@NotNull(message = "年龄不能为空")@Min(value = 18, message = "年龄必须大于或等于18岁")@Max(value = 100, message = "年龄必须小于或等于100岁")private Integer age;@Pattern(regexp = "^[0-9]+$", message = "电话号码只能包含数字")private String phone;// Getters and Setters
}

3. 在 Controller 中使用 @Valid 注解

在控制器中,使用 @Valid 注解对请求体进行校验。如果校验失败,Spring 会自动抛出 MethodArgumentNotValidException

示例:控制器方法
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;@RestController
@RequestMapping("/api/users")
public class UserController {@PostMappingpublic ResponseEntity<String> createUser(@Valid @RequestBody UserDTO userDTO) {// 如果校验通过,执行逻辑return ResponseEntity.ok("用户创建成功: " + userDTO.getUsername());}
}

4. 全局异常处理

为了返回更友好的错误信息,可以通过 @ControllerAdvice / @RestControllerAdvice @ExceptionHandler 捕获校验异常并自定义返回格式。

示例:全局异常处理器

使用@ControllerAdvice和@ExceptionHandler来处理MethodArgumentNotValidException以返回自定义错误消息:

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;import java.util.HashMap;
import java.util.Map;@ControllerAdvice
public class GlobalExceptionHandler {@ResponseStatus(HttpStatus.BAD_REQUEST)@ExceptionHandler(MethodArgumentNotValidException.class)public Map<String, String> handleValidationExceptions(MethodArgumentNotValidException ex) {Map<String, String> errors = new HashMap<>();ex.getBindingResult().getAllErrors().forEach((error) -> {String fieldName = ((FieldError) error).getField();String errorMessage = error.getDefaultMessage();errors.put(fieldName, errorMessage);});return errors;}
}

使用@RestControllerAdvice和@ExceptionHandler来处理MethodArgumentNotValidException和ConstraintViolationException以返回自定义错误消息:

import org.springframework.web.bind.annotation.ExceptionHandler;  
import org.springframework.web.bind.annotation.RestControllerAdvice;  
import org.springframework.validation.BindException;  
import org.springframework.validation.FieldError;  
import javax.validation.ConstraintViolationException;  
import java.util.HashMap;  
import java.util.Map;  @RestControllerAdvice  // 等同于 @ControllerAdvice + @ResponseBody
public class GlobalExceptionHandler {  @ExceptionHandler(MethodArgumentNotValidException.class)  public ResponseEntity<Map<String, String>> handleValidationExceptions(  MethodArgumentNotValidException ex) {  Map<String, String> errors = new HashMap<>();  ex.getBindingResult().getAllErrors().forEach((error) -> {  String fieldName = ((FieldError) error).getField();  String errorMessage = error.getDefaultMessage();  errors.put(fieldName, errorMessage);  });  return ResponseEntity.badRequest().body(errors);  }  @ExceptionHandler(ConstraintViolationException.class)  public ResponseEntity<Map<String, String>> handleConstraintViolation(  ConstraintViolationException ex) {  Map<String, String> errors = new HashMap<>();  ex.getConstraintViolations().forEach(violation -> {  String fieldName = violation.getPropertyPath().toString();  String errorMessage = violation.getMessage();  errors.put(fieldName, errorMessage);  });  return ResponseEntity.badRequest().body(errors);  }  
}  

5. 配置校验规则(可选)

如果需要自定义校验规则,可以实现 ConstraintValidator 接口。

示例:自定义校验注解
创建注解
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;@Documented
@Constraint(validatedBy = PhoneValidator.class)
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidPhone {String message() default "电话号码格式不正确";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};
}
创建校验逻辑
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;public class PhoneValidator implements ConstraintValidator<ValidPhone, String> {@Overridepublic boolean isValid(String value, ConstraintValidatorContext context) {// 校验逻辑:电话号码只能包含数字,且长度为10-15return value != null && value.matches("^[0-9]{10,15}$");}
}
使用自定义注解
public class UserDTO {@ValidPhoneprivate String phone;// 其他字段
}

6. 示例请求与响应

请求示例
// 使用 axios 发送请求  
async function createUser(userData) {  try {  const response = await axios.post('/api/users', userData);  console.log('创建成功:', response.data);  } catch (error) {  if (error.response && error.response.data) {  // 处理验证错误  const validationErrors = error.response.data;  Object.keys(validationErrors).forEach(field => {  console.error(`${field}: ${validationErrors[field]}`);  });  }  }  
}  
正确请求
{"username": "JohnDoe","email": "john.doe@example.com","age": 25,"phone": "1234567890"
}
错误请求
{"username": "JD","email": "invalid-email","age": 15,"phone": "abc123"
}
错误响应示例
{"username": "用户名长度必须在3到20个字符之间","email": "邮箱格式不正确","age": "年龄必须大于或等于18岁","phone": "电话号码格式不正确"
}

常用校验注解

注解功能说明
@NotNull验证字段不能为空
@NotEmpty验证字段不能为空且长度大于0(字符串), 不能为空(字符串长度不为0或集合大小不为0)
@NotBlank验证字段不能为空且必须包含非空白字符, 不能为空(去除首尾空格后长度不为0)
@Size验证字符串、集合等的长度或大小范围
@Min / @Max验证数字的最小值和最大值
@Email验证邮箱格式
@Pattern使用正则表达式验证字段
@Digits验证数字的整数位数和小数位数
@Past / @Future验证日期必须是过去或未来
@Positive正数
@Negative负数

总结

通过 Spring Boot 的 spring-boot-starter-validation 和 Hibernate Validator,可以轻松实现前端参数校验。结合注解、全局异常处理器和自定义校验规则,可以满足大多数场景的需求,确保数据的完整性和正确性。

以上内容提供了一个完整的 Spring Boot 参数校验方案。主要包括:

  1. 依赖配置:添加必要的验证依赖
  2. 实体类验证:使用注解定义验证规则
  3. 控制器验证:使用 @Valid@Validated 开启验证
  4. 异常处理:统一处理验证异常
  5. 常用注解说明:列举了常用的验证注解
  6. 前端调用示例:展示了如何处理验证结果

一些重要说明:

  1. @Valid@Validated 的区别:
    • @Valid 是 JSR-303 规范的标准注解
    • @Validated 是 Spring 提供的注解,支持分组校验
  2. 嵌套验证:
    • 对象中包含其他对象时,需要在字段上添加 @Valid 注解
  3. 分组验证:
    • 可以通过定义接口来实现不同场景下的验证规则
  4. 自定义验证:
    • 可以通过 @Constraint 注解创建自定义验证规则

@Valid @Validated

在Spring Boot中,@Valid@Validated 是两种用于触发参数校验的注解,它们都可以用来验证前端传递的参数,但它们有一些细微的区别和适用场景。以下是对两者的详细对比和使用说明:


1. @Valid

@ValidJSR 380(Bean Validation 2.0) 规范的一部分,由 Java 提供,通常用于触发 Hibernate Validator 的校验逻辑。

特点
  • 来源javax.validation.Valid
  • 作用范围
    • 用于校验 Java Bean(如 DTO 对象)。
    • 可以嵌套校验(即校验对象中的嵌套对象)。
    • 不支持分组验证
    • 可以用在方法参数和字段
  • 分组校验:不支持分组校验(需要用 @Validated)。
  • 常用场景:用于校验简单的请求参数或嵌套对象。
示例
校验简单对象
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;public class UserDTO {@NotNull(message = "用户名不能为空")@Size(min = 3, max = 20, message = "用户名长度必须在3到20个字符之间")private String username;@NotNull(message = "邮箱不能为空")private String email;// Getters and Setters
}
在控制器中使用 @Valid
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;@RestController
@RequestMapping("/users")
public class UserController {@PostMappingpublic String createUser(@Valid @RequestBody UserDTO userDTO) {return "用户创建成功: " + userDTO.getUsername();}
}

2. @Validated

@Validated 是 Spring 提供的注解,功能更加强大,除了支持基本的校验功能外,还支持 分组校验

特点
  • 来源org.springframework.validation.annotation.Validated
  • 作用范围
    • 用于校验 Java Bean(如 DTO 对象)。
    • 支持分组校验。
    • 可以用在类型、方法和方法参数
    • 不支持嵌套验证(除非结合@Valid)
  • 分组校验:支持分组校验(通过 groups 属性指定校验分组)。
  • 常用场景:用于需要分组校验的复杂场景。
示例
分组校验
定义校验分组
public interface CreateGroup {}
public interface UpdateGroup {}
在 DTO 中指定分组
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;public class UserDTO {@NotNull(groups = CreateGroup.class, message = "用户名不能为空")@Size(min = 3, max = 20, groups = {CreateGroup.class, UpdateGroup.class}, message = "用户名长度必须在3到20个字符之间")private String username;@NotNull(groups = UpdateGroup.class, message = "邮箱不能为空")private String email;// Getters and Setters
}
在控制器中使用 @Validated
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/users")
public class UserController {// 创建用户时校验 CreateGroup 分组@PostMappingpublic String createUser(@Validated(CreateGroup.class) @RequestBody UserDTO userDTO) {return "用户创建成功: " + userDTO.getUsername();}// 更新用户时校验 UpdateGroup 分组@PutMappingpublic String updateUser(@Validated(UpdateGroup.class) @RequestBody UserDTO userDTO) {return "用户更新成功: " + userDTO.getUsername();}
}

3. @Valid 和 @Validated 的区别

特性@Valid@Validated
来源javax.validation.Validorg.springframework.validation.annotation.Validated
分组校验不支持支持
嵌套校验支持支持
适用场景简单校验复杂校验(需要分组时)
校验触发位置由 Bean Validation 规范触发由 Spring 的校验机制触发

4. 嵌套校验

无论是 @Valid 还是 @Validated,都支持嵌套校验。只需在嵌套对象的字段上添加 @Valid 注解即可。

示例
import javax.validation.Valid;
import javax.validation.constraints.NotNull;public class UserDTO {  @NotNull(message = "用户名不能为空")  private String username;  @NotNull(message = "地址不能为空")  private String address;  // getters and setters  
}  public class OrderDTO {@NotNull(message = "订单ID不能为空")private String orderId;@Valid // 必须加@Valid才能验证嵌套对象 UserDTO@NotNull(message = "用户信息不能为空")private UserDTO user;// Getters and Setters
}

在控制器中:

@PostMapping("/orders")
public String createOrder(@Valid @RequestBody OrderDTO orderDTO) {return "订单创建成功";
}

方法级别验证

@Service  
@Validated  // 类级别需要添加@Validated  
public class UserService {  public void createUser(@NotNull(message = "用户名不能为空") String username,  @Min(value = 0, message = "年龄不能为负数") int age) {  // 处理逻辑  }  @Validated(Create.class)  // 方法级别的分组验证  public void saveUser(@Valid UserDTO userDTO) {  // 处理逻辑  }  
}  

5. 总结

  • @Valid

    • 用于简单校验。
    • 支持嵌套校验。
    • 不支持分组校验。
    • 更加通用,适用于大多数场景。
  • @Validated

    • 支持分组校验。
    • 适用于复杂校验场景(如不同操作需要不同的校验规则)。
    • 是 Spring 提供的扩展功能。

在实际开发中,如果不需要分组校验,@Valid 足够满足需求;如果需要分组校验,则必须使用 @Validated

6. 建议

  1. Controller层验证
    • 使用@Valid进行基础的请求体验证
    • 如果需要分组验证,使用@Validated
  2. Service层验证
    • 使用@Validated在类级别开启验证
    • 使用参数级别的约束注解进行验证
  3. 嵌套验证
    • 需要验证嵌套对象时,确保使用@Valid
  4. 分组验证
    • 当同一个DTO在不同场景下有不同的验证规则时,使用@Validated配合验证分组
  5. 异常处理
    • 确保同时处理MethodArgumentNotValidExceptionConstraintViolationException

通过合理使用这两个注解,可以实现更灵活和强大的参数验证功能。

参考:


  1. https://blog.csdn.net/weixin_45541665/article/details/139411351 ↩︎

  2. https://blog.csdn.net/Zyw907155124/article/details/139414414 ↩︎

  3. https://www.bilibili.com/video/BV1824y1f7tJ/?vd_source=d17e678df6de64f39874a3291030831b ↩︎

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

57. Three.js案例-创建一个带有聚光灯和旋转立方体的3D场景

57. Three.js案例-创建一个带有聚光灯和旋转立方体的3D场景 实现效果 该案例实现了使用Three.js创建一个带有聚光灯和旋转立方体的3D场景。 知识点 WebGLRenderer&#xff08;WebGL渲染器&#xff09; THREE.WebGLRenderer 是 Three.js 中用于将场景渲染为 WebGL 内容的核…

Idea-离线安装SonarLint插件地址

地址&#xff1a; SonarQube for IDE - IntelliJ IDEs Plugin | Marketplace 选择Install Plugin from Disk..&#xff0c;选中下载好的插件&#xff0c;然后重启idea

MyBatis面试-1

1、什么是MyBatis&#xff1f; MyBatis是一个半ORM框架(对象关系映射)。---》Hibernate全ORM框架 ---》基于JDBC封装的框架 专注于SQL语句&#xff0c;不用关心JDBC操作的其他流程 2、MyBatis有什么优点 基于SQL语句的编程&#xff0c;相对来说会更加的灵活和JDBC相比&#…

Unity:删除注册表内的项目记录

然后WinR按键输入regedit 打开注册表 在注册表 HKEY CURRENT USER—>SOFTWARE—>Unity—>UnityEditor—>DefaultCompany —>language_Test 中&#xff0c;删除我们的之前存储的语言环境数据。在 “ 三、文本调用和替换 ” 测试时已经将语言环境存储到注册表中了…

历代iPhone运行内存大小和电池容量信息

系列设备名称充电端口标配充电线PD快充无线充电 (W)标配充电器电池容量 (mAh)发布时间RAM运存iPhone 16iPhone 16 Pro MaxUSB Type-CUSB-C to USB-C支持25无47472024/9/108GB LPDDR5XiPhone 16 ProUSB Type-CUSB-C to USB-C支持25无35772024/9/108GB LPDDR5XiPhone 16 PlusUSB …

JAVA学习记录3

文章为个人学习记录&#xff0c;仅供参考&#xff0c;如有错误请指出。 上期说到使用记事本编写Java程序太过繁琐&#xff0c;所以我们后面都将使用IDEA进行代码的编写、编译和运行。 如何下载安装IDEA&#xff1f; 这个的下载途径也很多&#xff0c;我还是推荐去官网下载(h…

CSS——22.静态伪类(伪类是选择不同元素状态)

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>静态伪类</title> </head><body><a href"#">我爱学习</a></body> </html>单击链接前的样式 左键单击&#xff08;且…

如何在 Hive SQL 中处理复杂的数据类型?

目录 一、复杂数据类型简介 二、创建表时使用复杂数据类型 三、插入数据到复杂数据类型的表 四、查询复杂数据类型

Mysql 性能优化:索引条件下推(ICP)

MySQL 索引下推&#xff08;Index Condition Pushdown&#xff0c;ICP&#xff09;是一种查询优化技术&#xff0c;旨在提高使用索引的查询效率。它是在 MySQL 5.6 中引入的&#xff0c;通过将部分 WHERE 子句的过滤条件下推到索引扫描阶段来减少不必要的回表操作&#xff0c;从…

Linux 环境(Ubuntu)部署 Hadoop 环境

前置准备 准备三台机器 cat /etc/hosts 192.168.1.7 hadoop-master 192.168.1.11 hadoop-slave01 192.168.1.12 hadoop-slave02Linux 环境 cat /etc/os-release PRETTY_NAME"Ubuntu 24.10" NAME"Ubuntu" VERSION_ID"24.10" VERSION"24.…

IDEA中Maven依赖包导入失败报红的潜在原因

在上网试了别人的八个问题总结之后依然没有解决&#xff1a; IDEA中Maven依赖包导入失败报红问题总结最有效8种解决方案_idea导入依赖还是报红-CSDN博客https://blog.csdn.net/qq_43705131/article/details/106165960 江郎才尽之后突然想到一个原因&#xff1a;<dep…

JavaScrip中对于数组的操作的方法(!!是否改变原数组)

1. push() 功能&#xff1a;向数组的末尾添加一个或多个元素&#xff0c;并返回新数组的长度。&#xff08;改变原数组&#xff09;示例&#xff1a; let arr [1, 2, 3]; arr.push(4); // [1, 2, 3, 4] 2. pop() 功能&#xff1a;移除数组的最后一个元素&#xff0c;并返回…

C语言基本知识复习浓缩版:标识符、函数、进制、数据类型

C语言基本知识复习浓缩版&#xff1a;标识符、函数、进制、数据类型 【c语言期末复习3小时速成【完整全集】期末速成含考试题c语言期末速成突击复习C语言补考C语言期末大一】 B站看到的复习C语言视频&#xff0c;感觉非常棒&#xff0c;就跟着进行了一下学习。众所周知&#…

GMDH自组织网络模型时间序列预测,可预测未来

GMDH自组织网络模型时间序列预测&#xff0c;可预测未来 目录 GMDH自组织网络模型时间序列预测&#xff0c;可预测未来效果一览基本介绍模型构建程序设计学习总结参考资料 效果一览 基本介绍 GMDH自组织网络模型是自组织数据挖掘中的一种模型方法&#xff0c;是基于计算机科学和…

【docker系列】可视化Docker 管理工具——Portainer

1. 介绍 Portainer是一个可视化的Docker操作界面&#xff0c;提供状态显示面板、应用模板快速部署、容器镜像网络数据卷的基本操作&#xff08;包括上传下载镜像&#xff0c;创建容器等操作&#xff09;、事件日志显示、容器控制台操作、Swarm集群和服务等集中管理和操作、登录…

开源靶场1

我来为您介绍一些知名的开源漏洞靶场平台: DVWA (Damn Vulnerable Web Application) 最流行的 Web 漏洞靶场之一包含 SQL 注入、XSS、文件包含等常见漏洞基于 PHP MySQL适合 Web 安全入门学习 WebGoat OWASP 开源项目基于 Java包含大量 Web 安全漏洞练习提供详细的教程和解…

Linux/Ubuntu/银河麒麟 arm64 飞腾FT2000 下使用 arm64版本 linuxdeployqt 打包Qt程序

文章目录 一、前言二、环境三、准备1、下载Linuxdeployqt源码2、下载Appimagetool-aarch64.AppImage四、编译linuxdeployqt1.配置环境变量2.编译linuxdeployqt五、安装patchelf六、配置Appimagetool七、打包Qt程序重要提示:测试启动应用八、其他九、最后一、前言 因为项目需要…

OpenCV相机标定与3D重建(49)将视差图(disparity map)重投影到三维空间中函数reprojectImageTo3D()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 将视差图像重投影到3D空间。 cv::reprojectImageTo3D 是 OpenCV 库中的一个函数&#xff0c;用于将视差图&#xff08;disparity map&#xff09…

Python 通过命令行在 unittest.TestCase 中运行单元测试

文章目录 unittest 模块简介编写单元测试在命令行中运行所有测试在命令行中运行单个测试使用装饰器跳过测试总结常用断言方法 unittest 模块简介 unittest是Python标准库中的一个模块&#xff0c;用于编写和运行单元测试。它提供了一个单元测试框架&#xff0c;使得编写测试用…

Rabbitmq Fanout如何保证不重复消费及应用场景

rabbitmq fanout业务场景&#xff0c;一个交换机对应多个队列&#xff0c;不会重复消费吗 在 RabbitMQ 中&#xff0c;使用 Fanout 类型的交换机时&#xff0c;确实可以将一个交换机绑定到多个队列。每当有消息发布到这个交换机时&#xff0c;交换机会把消息广播到所有绑定的队…