_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

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

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

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;且…

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

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

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

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

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

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

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

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

pg数据库运维经验2024

这篇文章主要是讲pg运维常见问题&#xff0c;两三年见一次的疑难杂症就不说了。 主要是技术性运维总结&#xff0c;主打通俗易懂和快速上手&#xff0c;尽量避免源码层面等深入分析。 SQL性能与执行计划 执行计划突变 pg官方不支持hint功能&#xff0c;并且计划永远不支持&…

Hadoop 实战笔记(一) -- Windows 安装 Hadoop 3.x

环境准备 安装 JAVA 1.8 Java环境搭建之JDK下载及安装下载 Hadoop 3.3.5 安装包 Hadoop 下载&#xff1a;https://archive.apache.org/dist/hadoop/common/ 一、JAVA JDK 环境检查 二、Hadoop(HDFS)环境搭建 1. 解压安装文件 hadoop-3.3.5.tar 2. 配置环境变量 HADOOP_HO…

个人博客搭建(二)—Typora+PicGo+OSS

个人博客站—运维鹿: http://www.kervin24.top CSDN博客—做个超努力的小奚&#xff1a; 做个超努力的小奚-CSDN博客 一、前言 博客搭建完一直没有更新&#xff0c;因为WordPress自带的文档编辑器不方便&#xff0c;以前用CSDN写作的时候&#xff0c;习惯了Typora。最近对比了…

【向量数据库】搜索算法

最近几年&#xff0c;一种叫做向量数据库的产品&#xff0c;正趁着AI的热潮开始崭露头角。伴随着AI时代的到来&#xff0c;向量将成为一种重要的数据形式&#xff0c;而传统数据库并不适合用来存储和检索向量数据&#xff0c;因此我们大约需要一种专门设计的数据库来处理这些问…

ARM CCA机密计算安全模型之安全生命周期管理

安全之安全(security)博客目录导读 目录 一、固件启用的调试 二、CCA系统安全生命周期 三、重新供应 四、可信子系统与CCA HES 启用 CCA&#xff08;机密计算架构&#xff09;的安全系统是指 CCA 平台的实现处于可信状态。 由于多种原因&#xff0c;CCA 启用系统可能处于不…

k8s排错集:zk集群的pod报错 Init:CrashLoopBackOff无法启动

zk三节点集群&#xff0c;zk-0无法启动 statefulset 进到该node节点上查看容器的报错日志&#xff0c;发现在初始化container的时候一个命令有问题 查看正常zk集群的pod的资源配置文件 解决办法&#xff1a; 修改资源配置文件 应该修改为 chown -R 1000:1000 /zkenv kubec…

Golang的并发编程框架比较

# Golang的并发编程框架比较 中的并发编程 在现代软件开发中&#xff0c;处理高并发的能力愈发重要。Golang作为一门支持并发编程的编程语言&#xff0c;提供了丰富的并发编程框架和工具&#xff0c;使得开发者能够更轻松地处理并发任务。本文将介绍Golang中几种常用的并发编程…

【Web】软件系统安全赛CachedVisitor——记一次二开工具的经历

明天开始考试周&#xff0c;百无聊赖开了一把CTF&#xff0c;还顺带体验了下二开工具&#xff0c;让无聊的Z3很开心&#x1f642; CachedVisitor这题 大概描述一下&#xff1a;从main.lua加载一段visit.script中被##LUA_START##(.-)##LUA_END##包裹的lua代码 main.lua loca…

单纯形法的学习笔记

文章目录 A. 单纯形法概述1. 优化模型示例 B. 理论基础C. 算法思想D. 实现算法1. 线性规划的标准型2. 顶点解的理解及表示2.1 在标准型中变量取值为零的意义2.2 顶点解的表示 3. 最优性判断4. 解的更新5. 完成迭代过程 E. 单纯形法的基本概念与本文对照F. 文档源码 前言&#x…

【VBA】【EXCEL】将某列内容横向粘贴到指定行

Sub CopyRowToColumn()On Error GoTo ErrorHandler 添加错误处理Application.ScreenUpdating FalseApplication.Calculation xlCalculationManualApplication.EnableEvents False 禁用事件处理Dim lastCol As LongDim lastRow As LongDim i As Long, colCount As LongDim …

JS进阶--JS听到了不灭的回响

作用域 作用域&#xff08;scope&#xff09;规定了变量能够被访问的“范围”&#xff0c;离开了这个“范围”变量便不能被访问 作用域分为局部和全局 局部作用域 局部作用域分为函数和块 那 什么是块作用域呢&#xff1f; 在 JavaScript 中使用 { } 包裹的代码称为代码块…