RuoYi 参数验证实验报告
一、实验目的
本次实验按照 L10_参数验证.pptx 的要求,在 RuoYi 项目中分析后端参数验证的完整执行链路:前端提交数据、Controller 触发验证、实体类上的校验注解执行、全局异常处理器捕获异常、前端显示错误提示、日志文件记录错误信息。
本报告包含两个例子:
- 按 PPT 方式触发一个新的参数验证异常:以用户管理中的邮箱格式、手机号长度为例。
- 参考官方文档分析自定义参数验证注解:以 RuoYi 内置的 @Xss 注解为例,触发脚本字符校验异常。
二、Spring Boot 启动环境
参数验证能够生效的前提是 Spring Boot 应用正常启动,Spring MVC、Bean Validation、全局异常处理器等组件被 Spring 容器扫描并注册。
源码位置:ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
java
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) public class RuoYiApplication { public static void main(String[] args) { SpringApplication.run(RuoYiApplication.class, args); System.out.println("(♥◠‿◠)ノ゙ 若依启动成功 ლ(´ڡ`ლ)゙"); } }
作用说明:
- @SpringBootApplication 是 Spring Boot 启动注解,包含自动配置、组件扫描等能力。
- SpringApplication.run(...) 启动 Spring 容器,项目中的 Controller、Service、异常处理器、校验相关类会被加载。
- exclude = { DataSourceAutoConfiguration.class } 表示排除默认数据源自动配置,RuoYi 使用自己的 Druid 数据源配置。
截图备注:
| 截图编号 | 截图位置 | 需要标注的内容 |
|---|---|---|
| 图1 | IDEA 打开 RuoYiApplication.java | 框出 @SpringBootApplication 和 SpringApplication.run(...),备注“Spring 环境启动入口” |
三、例子一:触发新的参数验证异常
PPT 中使用的是角色名称 roleName 超过 30 个字符。本实验换一个新的例子,使用用户管理中的邮箱和手机号字段触发异常。
1. 前端页面限制
源码位置:ruoyi-ui/src/views/system/user/index.vue
vue

作用说明:
- maxlength="11" 是前端对手机号输入长度的限制。
- :rules="rules" 会让 Element UI 表单按 rules 对输入值做前端校验。
- 前端校验属于用户体验层面的限制,不能代替后端校验,因为用户可以通过浏览器开发者工具、Postman 或接口重放绕过前端限制。
触发方式:
- 登录 RuoYi 后台。
- 进入“系统管理 -> 用户管理 -> 新增”。
- 打开浏览器开发者工具,临时删除手机号输入框的 maxlength="11",或者在 Network 中重放请求。
- 提交异常数据,例如:
text
email = abc phonenumber = 123456789012
截图备注:
| 截图编号 | 截图位置 | 需要标注的内容 |
|---|---|---|
| 图2 | 用户新增页面 | 标注邮箱或手机号输入框,备注“前端输入异常参数” |
| 图3 | 浏览器 F12 Network | 标注请求地址 /system/user,标注请求方法 POST 或 PUT,标注请求体中的 email=abc 或超长手机号 |
2. Controller 触发后端参数验证
源码位置:ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
java
@RequiresPermissions("system:user:add") @Log(title = "用户管理", businessType = BusinessType.INSERT) @PostMapping public AjaxResult add(@Validated @RequestBody SysUser user) { deptService.checkDeptDataScope(user.getDeptId()); roleService.checkRoleDataScope(user.getRoleIds()); return toAjax(userService.insertUser(user)); }
作用说明:
- @PostMapping 表示该方法处理新增用户的 POST 请求,请求地址是 /system/user。
- @RequestBody 表示前端提交的 JSON 请求体会被转换为 SysUser 对象。
- @Validated @RequestBody SysUser user 是触发参数验证的关键。当前端提交的 JSON 参数绑定到 SysUser 对象时,Spring 会读取 SysUser 属性或 getter 方法上的校验注解。
- 如果参数不符合注解限制,Controller 方法不会继续正常执行业务逻辑,而是抛出参数绑定/校验异常。
截图备注:
| 截图编号 | 截图位置 | 需要标注的内容 |
|---|---|---|
| 图4 | IDEA 打开 SysUserController.java | 框出 @PostMapping、@Validated @RequestBody SysUser user,备注“后端验证触发点” |
3. 实体类上的校验注解
源码位置:ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
java
@Email(message = "邮箱格式不正确") @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符") public String getEmail() { return email; } @Size(min = 0, max = 11, message = "手机号码长度不能超过11个字符") public String getPhonenumber() { return phonenumber; }
作用说明:
- @Email 用于限制邮箱字段必须符合邮箱格式。
- @Size 用于限制字符串长度。
- RuoYi 把注解写在 getter 方法上,Spring Validation 会在绑定 SysUser 对象时读取这些注解。
- 当 email=abc 时,@Email 校验失败,会返回“邮箱格式不正确”。
- 当手机号超过 11 个字符时,@Size(max = 11) 校验失败,会返回“手机号码长度不能超过11个字符”。
截图备注:
| 截图编号 | 截图位置 | 需要标注的内容 |
|---|---|---|
| 图5 | IDEA 打开 SysUser.java | 框出 @Email、@Size(max = 11),备注“字段校验规则” |
四、全局异常处理和日志
源码位置:ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java
java
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) { log.error(e.getMessage(), e); String message = e.getBindingResult().getFieldError().getDefaultMessage(); return AjaxResult.error(message); } }
作用说明:
- @RestControllerAdvice 注册全局异常处理器。
- @ExceptionHandler(MethodArgumentNotValidException.class) 表示专门处理 @RequestBody 请求体参数校验失败异常。
- e.getBindingResult().getFieldError().getDefaultMessage() 取出第一个字段校验失败信息。
- AjaxResult.error(message) 将错误信息包装成统一 JSON 格式返回给前端。
和 PPT 的对应说明:
- 当前 RuoYi-Vue-master 前端提交 JSON 请求体,后端使用 @RequestBody 接收对象。
- 这种方式校验失败时会抛出 MethodArgumentNotValidException,和 PPT 中的异常类型一致。
日志配置源码位置:ruoyi-admin/src/main/resources/logback.xml
xml
<property name="log.path" value="/home/ruoyi/logs" /> <appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${log.path}/sys-error.log</file> </appender>
作用说明:
- log.path 定义日志输出目录。
- sys-error.log 用于保存错误日志。
- 当生产环境无法直接查看 IDEA Run 面板时,可以通过日志文件排查参数验证异常。
截图备注:
| 截图编号 | 截图位置 | 需要标注的内容 |
|---|---|---|
| 图6 | 前端错误提示框 | 标注后端返回的错误信息,例如“邮箱格式不正确” |
| 图7 | IDEA Run 控制台或 sys-error.log | 标注 GlobalExceptionHandler、MethodArgumentNotValidException、字段错误信息 |
| 图8 | IDEA 打开 GlobalExceptionHandler.java | 框出 @RestControllerAdvice 和 @ExceptionHandler(MethodArgumentNotValidException.class) |
| 图9 | IDEA 打开 logback.xml | 框出 log.path 和 sys-error.log |
五、例子二:自定义参数验证注解 @Xss
PPT 作业要求参考官方文档,自定义参数验证注解,并触发验证抛出异常。RuoYi 已经内置了一个完整的自定义校验注解 @Xss,可以直接作为分析对象。
1. 自定义注解定义
源码位置:ruoyi-common/src/main/java/com/ruoyi/common/xss/Xss.java
java
@Retention(RetentionPolicy.RUNTIME) @Target(value = { ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER }) @Constraint(validatedBy = { XssValidator.class }) public @interface Xss { String message() default "不允许任何脚本运行"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
作用说明:
- @Retention(RetentionPolicy.RUNTIME) 表示注解在运行时仍然保留,方便校验框架读取。
- Target(...) 表示注解可以使用在方法、字段、构造器、参数上。
- @Constraint(validatedBy = { XssValidator.class }) 是自定义校验注解的核心,指定真正的校验逻辑由 XssValidator 执行。
- message 是校验失败后返回给前端的默认错误信息。
截图备注:
| 截图编号 | 截图位置 | 需要标注的内容 |
|---|---|---|
| 图10 | IDEA 打开 Xss.java | 框出 @Constraint(validatedBy = { XssValidator.class }),备注“绑定自定义校验器” |
2. 自定义校验器实现
源码位置:ruoyi-common/src/main/java/com/ruoyi/common/xss/XssValidator.java
java
public class XssValidator implements ConstraintValidator<Xss, String> { private static final String HTML_PATTERN = "<(\\S*?)[^>]*>.*?|<.*? />"; @Override public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) { if (StringUtils.isBlank(value)) { return true; } return !containsHtml(value); } }
作用说明:
- ConstraintValidator<Xss, String> 表示该校验器服务于 @Xss 注解,并校验字符串类型。
- isValid(...) 返回 true 表示校验通过,返回 false 表示校验失败。
- 空值直接通过,说明 @Xss 只负责判断是否包含 HTML/脚本字符,不负责非空校验。
- containsHtml(value) 使用正则判断输入中是否包含 HTML 标签。
截图备注:
| 截图编号 | 截图位置 | 需要标注的内容 |
|---|---|---|
| 图11 | IDEA 打开 XssValidator.java | 框出 ConstraintValidator<Xss, String> 和 isValid(...),备注“真正执行校验逻辑” |
3. 自定义注解的使用位置
源码位置:ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
java
@Xss(message = "登录账号不能包含脚本字符") @NotBlank(message = "登录账号不能为空") @Size(min = 0, max = 30, message = "登录账号长度不能超过30个字符") public String getLoginName() { return loginName; } @Xss(message = "用户昵称不能包含脚本字符") @Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符") public String getUserName() { return userName; }
触发方式:
- 进入“系统管理 -> 用户管理 -> 新增”。
- 在用户昵称或登录账号中提交脚本字符,例如:
text
userName = <script>alert(1)</script>
- 由于 SysUserController.add(@Validated @RequestBody SysUser user) 触发验证,@Xss 会调用 XssValidator。
- 校验器发现输入中包含 HTML 标签,返回 false。
- GlobalExceptionHandler 捕获 MethodArgumentNotValidException,前端显示“用户昵称不能包含脚本字符”。
截图备注:
| 截图编号 | 截图位置 | 需要标注的内容 |
|---|---|---|
| 图12 | 用户新增页面或 F12 请求参数 | 标注 userName=<script>alert(1)</script> |
| 图13 | 前端错误提示框 | 标注“用户昵称不能包含脚本字符” |
| 图14 | IDEA Run 控制台或 sys-error.log | 标注 MethodArgumentNotValidException 和 用户昵称不能包含脚本字符 |
六、完整执行逻辑总结
参数验证完整链路如下:
text
SpringApplication.run 启动项目 ↓ Spring 扫描 Controller、实体校验注解、全局异常处理器 ↓ 前端提交用户表单 ↓ SysUserController.add(@Validated @RequestBody SysUser user) ↓ Spring Validation 读取 SysUser getter 上的 @Email、@Size、@Xss ↓ 参数不合法,抛出 MethodArgumentNotValidException ↓ GlobalExceptionHandler.handleMethodArgumentNotValidException 捕获异常 ↓ 返回 AjaxResult.error(message) ↓ 前端弹出错误提示,后端日志写入 sys-error.log
本实验满足 PPT 小结中的条件:
| PPT 条件 | RuoYi 对应代码 | 说明 |
|---|---|---|
| 参数验证注解修饰属性或 getter | SysUser#getEmail、SysUser#getPhonenumber、SysUser#getUserName | 使用 @Email、@Size、@Xss |
| 使用 @Validated 修饰接口形参 | SysUserController.add(@Validated @RequestBody SysUser user) | 触发后端校验 |
| 注册全局异常处理类 | GlobalExceptionHandler 上的 @RestControllerAdvice | 统一处理异常 |
| 正确处理验证异常 | @ExceptionHandler(MethodArgumentNotValidException.class) | 返回第一个错误信息给前端 |
更多推荐



所有评论(0)