一、实验目的

本次实验按照 L10_参数验证.pptx 的要求,在 RuoYi 项目中分析后端参数验证的完整执行链路:前端提交数据、Controller 触发验证、实体类上的校验注解执行、全局异常处理器捕获异常、前端显示错误提示、日志文件记录错误信息。

本报告包含两个例子:

  1. 按 PPT 方式触发一个新的参数验证异常:以用户管理中的邮箱格式、手机号长度为例。
  2. 参考官方文档分析自定义参数验证注解:以 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 或接口重放绕过前端限制。

触发方式:

  1. 登录 RuoYi 后台。
  2. 进入“系统管理 -> 用户管理 -> 新增”。
  3. 打开浏览器开发者工具,临时删除手机号输入框的 maxlength="11",或者在 Network 中重放请求。
  4. 提交异常数据,例如:

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; }

触发方式:

  1. 进入“系统管理 -> 用户管理 -> 新增”。
  2. 在用户昵称或登录账号中提交脚本字符,例如:

text

userName = <script>alert(1)</script>

  1. 由于 SysUserController.add(@Validated @RequestBody SysUser user) 触发验证,@Xss 会调用 XssValidator。
  2. 校验器发现输入中包含 HTML 标签,返回 false。
  3. 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) 返回第一个错误信息给前端
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐