当前位置: 首页 > news >正文

【W10】Spring Boot 参数验证详解:从问题引入到源码分析

本次为W10作业,本文基于若依(RuoYi)框架,深入讲解 Spring Boot 中参数验证的完整流程,包括如何触发验证、前后端交互、源码分析以及生产环境的日志排查

一、问题引入

场景描述

假如要在程序里对接口的函数参数进行限制,大家有哪些解决方案?

比如如下SysUserphonenumber字段,限制它每次从前端传过来的长度不超过 20:

publicclassSysUser{privateStringphonenumber;// 限制长度不超过20}

传统做法:各种判断

在 Controller 或 Service 中写if判断:

if(user.getPhonenumber()!=null&&user.getPhonenumber().length()>20){returnAjaxResult.error("手机号长度不能超过20个字符");}

缺点

SysUser作为另一个函数的形参时:

  • 代码冗余:每个函数内都需要判断一次
  • 维护困难:若一个属性判断代码要修改,所有涉及到的地方都要改一次

二、触发验证实例简介

演示入口

系统管理 → 角色管理 → 修改

操作步骤

进入角色修改页面,看输入不同长度的数据会有怎样的效果。


三、触发验证抛出异常

1. 触发方式

角色名称改为超过 30 个字符的字符串:

1234567890123456789012345678901

(共 31 个字符,超过 30 的限制)

2. 前端现象

点击确定后,弹出提示框:

角色名称长度不能超过 30 个字符

3. 后端现象

IDEA 的 Run Tab 输出如下 Log:

22:35:08.308 [http-nio-8080-exec-17] ERROR c.r.f.w.e.GlobalExceptionHandler - [validExceptionHandler,104] - Validation failed for argument [0] in public com.ruoyi.common.core.domain.AjaxResult com.ruoyi.web.controller.system.SysRoleController.edit(com.ruoyi.common.core.domain.entity.SysRole): [Field error in object 'sysRole' on field 'roleName': rejected value [1234567890123456789012345678901]; codes [Size.sysRole.roleName,Size.roleName,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [sysRole.roleName,roleName]; arguments []; default message [roleName],30,0]; default message [角色名称长度不能超过30个字符]]

Log 关键信息解读

序号问题答案
1ERROR 关键字说明什么?有捕获异常 Exception
2谁捕获了异常?GlobalExceptionHandler
3哪里抛出的异常?com.ruoyi.web.controller.system.SysRoleController.edit(...)
4具体谁抛出了什么异常?Field error in object ‘sysRole’ on field ‘roleName’: rejected value […]
5抛出的异常类型?MethodArgumentNotValidException

四、源码分析

1. 前端代码

(1)输入框限制

前端对输入框有限制,不能为空:

<el-form-item label="角色名称" prop="roleName"> <el-input v-model="form.roleName" placeholder="请输入角色名称" /> </el-form-item>
rules:{roleName:[{required:true,message:"角色名称不能为空",trigger:"blur"}]}
(2)发起请求

确定后,通过updateRole函数对 URI 为/system/role发起 HTTP PUT 操作,请求 body 为 data:

/** 修改角色 */exportfunctionupdateRole(data){returnrequest({url:'/system/role',method:'put',data:data})}

从浏览器开发者工具可以看到,整体的 HTTP 请求 URL 为:

http://localhost/dev-api/system/role

请求流程:

┌─────────────┐ 发起 HTTP 请求 ┌─────────────┐ │ 前端浏览器 │ ─────────────────→ │ 后端服务器 │ │ │ ←───────────────── │ │ └─────────────┘ 回应 HTTP 响应 └─────────────┘
(3)后端返回信息后的前端处理逻辑

返回code为 500 时,输出错误提示 Message 框:

request.then(response=>{if(response.code===500){this.$modal.msgError(response.msg)}})

2. 后端代码

(1)Controller 代码
@RestController@RequestMapping("/system/role")publicclassSysRoleControllerextendsBaseController{@AutowiredprivateISysRoleServiceroleService;/** * 修改保存角色 */@PreAuthorize("@ss.hasPermi('system:role:edit')")@Log(title="角色管理",businessType=BusinessType.UPDATE)@PutMappingpublicAjaxResultedit(@Validated@RequestBodySysRolerole){if(!roleService.checkRoleNameUnique(role)){returnerror("修改角色'"+role.getRoleName()+"'失败,角色名称已存在");}elseif(!roleService.checkRoleKeyUnique(role)){returnerror("修改角色'"+role.getRoleName()+"'失败,权限字符已存在");}role.setUpdateBy(getUsername());returntoAjax(roleService.updateRole(role));}}

关键注解:@Validated

(2)SysRole 类对属性 roleName 的限制
publicclassSysRoleextendsBaseEntity{/** 角色名称 */@NotBlank(message="角色名称不能为空")@Size(min=0,max=30,message="角色名称长度不能超过30个字符")privateStringroleName;// ... 其他属性}

roleName不满足两个注解@NotBlank@Size限制时,会抛出异常。

(3)异常处理
@RestControllerAdvicepublicclassGlobalExceptionHandler{privatestaticfinalLoggerlog=LoggerFactory.getLogger(GlobalExceptionHandler.class);/** * 自定义验证异常 */@ExceptionHandler(MethodArgumentNotValidException.class)publicObjectvalidExceptionHandler(MethodArgumentNotValidExceptione){log.error(e.getMessage(),e);Stringmessage=e.getBindingResult().getFieldError().getDefaultMessage();returnAjaxResult.error(message);}}

3. 报错分析

结合前面后端报错信息,当SysRole属性roleName不满足约束时,会抛出异常MethodArgumentNotValidException

异常处理链路:

1. 请求到达 Controller ↓ 2. @Validated 触发参数验证 ↓ 3. roleName 长度超过30,验证失败 ↓ 4. 抛出 MethodArgumentNotValidException ↓ 5. GlobalExceptionHandler 捕获异常 ↓ 6. 返回错误信息给前端 (code=500, msg="角色名称长度不能超过30个字符")

五、后端持久化 Log 查看报错信息

生产环境问题

当生产环境时(即后台服务部署到服务器上,没有开发环境),无法看到 IDEA 的 Log 信息,需要通过 Log 文件查看出错信息,排查问题。

Log 文件路径与内容

Log 文件路径通常在项目配置的日志目录下(如logs/目录):

/server/ruoyi/logs/ ├── sys-error.log # 错误日志 ├── sys-info.log # 信息日志 └── sys-user/ # 业务模块日志

查看sys-error.log文件可看到相同的报错信息。


六、小结

后端参数验证生效且程序抛出异常不崩溃,需要如下4 个条件

序号条件代码示例
1参数验证注解修饰在所需类属性的 getter 或属性上@NotBlank@Size
2使用注解@Validated修饰接口函数的对应类的形参@Validated @RequestBody SysRole role
3@RestControllerAdvice注册全局异常处理类@RestControllerAdvice
4正确处理类型MethodArgumentNotValidException异常@ExceptionHandler(MethodArgumentNotValidException.class)

七、踩坑记录

踩过的坑:有些参数验证注解(如@NotNull)使用在基础类型(它自己有默认值)上不生效。尽量用基础类型的包装类型


http://www.jsqmd.com/news/768938/

相关文章:

  • 我们如何设计iPaaS连接器?聊聊数环通背后的技术思考
  • 《机器人与自动化新闻》发布无人机物流行业深度趋势分析报告
  • 【养马】心得(20260506)
  • 构建统一AI API网关:聚合GPT、Claude、Gemini等模型的核心架构与实践
  • 上海海事大学考研辅导班机构选择:排行榜单与哪家好评测 - michalwang
  • 科研选题避坑指南:如何像自然辩证法里说的那样,提出一个真正有价值的‘科学问题’
  • Flutter状态管理高级技巧
  • STM32F407VET6新手避坑指南:从LED、按键到SysTick,手把手教你搭建第一个工程
  • Mermaid Live Editor:实时图表编辑的终极解决方案
  • LinkSwift:八大网盘直链下载的终极解决方案完全指南
  • Docker边缘部署资源占用过高问题(ARM64架构下内存泄漏深度溯源)
  • 中天光合叶绿素:给作物一片“超级绿叶”,让丰收更稳更优
  • WooCommerce购物车按钮重定向技巧
  • 【每日一题】差分数组
  • Flutter网络请求高级技巧
  • 零基础教程:已知 IP 如何反查域名?方法全都教给你
  • VSG vs 下垂 vs VF 控制策略对比
  • 观察Taotoken在流量高峰期的API路由与容错表现
  • 避坑指南:Arduino连接GPS模块(NEO-6M)时,为什么串口没数据?
  • SDMA控制器架构与高效数据传输实现
  • 虚拟电厂 + 微电网,万亿能源新赛道已来临
  • 保姆级教程:用Python+OpenCV从零搭建双目测距系统(含完整代码与避坑指南)
  • 2026年收藏:10款降AI率工具亲测(含免费版),帮你降低AI率避坑 - 降AI实验室
  • 对比直接使用厂商API观察通过Taotoken中转的月度账单清晰度
  • 突破百度网盘限速:如何用Python脚本实现10倍下载速度?
  • 不用懂代码!OpenClaw 本地 AI 轻松部署
  • AssetStudio完整指南:三步解锁Unity游戏资源提取与转换
  • 3分钟快速掌握PowerToys文本提取器:告别手动输入的高效OCR工具
  • 别再乱调了!Stable Diffusion图生图降噪强度(Denoising Strength)保姆级调参指南
  • 为什么头部金融客户已强制要求MCP 2026认证?——5类高危编排场景的合规性验证清单(含GDPR/等保2.0映射表)