SpringBoot API参数校验

本文涉及的产品
RDS DuckDB + QuickBI 企业套餐,8核32GB + QuickBI 专业版
RDS AI 助手,专业版
PolarDB Agent Express,2核4GB
简介: 本文精讲SpringBoot API参数校验三大核心能力:① Body请求体自动校验(@Valid+嵌套校验);② Query查询参数校验(@Validated);③ 全局统一错误返回(ResultVO+异常处理器)。含可直接上线的完整代码、关键注解、高频避坑点及标准化规范,零冗余,强落地。(239字)

一、核心说明

本文整理了SpringBoot项目开发中,API参数校验最核心的三项实战能力,均为企业项目通用落地方案。内容精简实用,无冗余理论,包含可直接上线使用的完整代码、开发规则、易错点及统一返回规范,适配日常开发、功能迭代及接口标准化整改场景。

三大核心:请求体Body自动化校验、查询参数Query自动化校验、全局统一错误返回格式

1.必备前置依赖
SpringBoot2.3+ 必须手动引入,提供所有校验注解能力

<?xml version="1.0" encoding="UTF-8"?>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
        <version>2.7.0</version>
    </dependency>
</dependencies>

二、请求体(Body)参数校验【POST/PUT】

  1. 核心规则
    主要用于POST、PUT请求的复杂入参场景,支持对象、嵌套对象、集合类参数校验。通过@Valid注解开启自动化校验,覆盖全部基础校验规则,开发中无需手写大量if判断,代码更简洁规范。
  2. 核心校验注解区分(必记)
  • @NotNull:数值、对象非空
  • @NotBlank:字符串非空
  • @NotEmpty:集合、字符串非空
  • @Min/@Max:数值范围限制
  • @Size:字符串/集合长度限制
  • @Pattern:正则格式校验

3.核心DTO代码

from dataclasses import dataclass
from typing import List, Optional
from decimal import Decimal
import re

class ValidationError(Exception):
    def __init__(self, field, message):
        self.field = field
        self.message = message
        super().__init__(f"{field}: {message}")

@dataclass
class OrderItemDTO:
    goods_id: int
    count: int

    def validate(self):
        errors = []

        if self.goods_id is None:
            errors.append(ValidationError("goodsId", "商品ID不能为空"))
        elif self.goods_id < 1:
            errors.append(ValidationError("goodsId", "商品ID非法"))

        if self.count is None:
            errors.append(ValidationError("count", "购买数量不能为空"))
        elif self.count < 1:
            errors.append(ValidationError("count", "数量不能小于1"))

        if errors:
            raise ValueError("; ".join([f"{e.field}: {e.message}" for e in errors]))

@dataclass
class OrderCreateDTO:
    user_id: int
    phone: str
    amount: Decimal
    item_list: List[OrderItemDTO]
    remark: Optional[str] = None

    def validate(self):
        errors = []

        # 用户ID校验
        if self.user_id is None:
            errors.append(ValidationError("userId", "用户ID不能为空"))
        elif self.user_id < 1:
            errors.append(ValidationError("userId", "用户ID取值非法"))

        # 手机号校验
        if not self.phone or not self.phone.strip():
            errors.append(ValidationError("phone", "手机号不能为空"))
        elif not re.match(r"^1[3-9]\d{9}$", self.phone):
            errors.append(ValidationError("phone", "手机号格式错误"))

        # 订单金额校验
        if self.amount is None:
            errors.append(ValidationError("amount", "订单金额必须大于0"))
        elif self.amount <= 0:
            errors.append(ValidationError("amount", "订单金额必须大于0"))

        # 备注长度校验
        if self.remark and len(self.remark) > 500:
            errors.append(ValidationError("remark", "备注不能超过500字符"))

        # 商品列表校验
        if not self.item_list:
            errors.append(ValidationError("itemList", "商品列表不能为空"))
        else:
            for i, item in enumerate(self.item_list):
                try:
                    item.validate()
                except ValueError as e:
                    errors.append(ValidationError(f"itemList[{i}]", str(e)))

        if errors:
            raise ValueError("; ".join([f"{e.field}: {e.message}" for e in errors]))

# 使用示例
if __name__ == "__main__":
    # 创建订单项目
    item1 = OrderItemDTO(goods_id=123, count=2)
    item2 = OrderItemDTO(goods_id=456, count=1)

    # 创建订单
    order = OrderCreateDTO(
        user_id=1001,
        phone="13812345678",
        amount=Decimal("99.99"),
        item_list=[item1, item2],
        remark="请尽快发货"
    )

    try:
        order.validate()
        print("订单验证通过")
    except ValueError as e:
        print(f"验证失败: {e}")
  1. Controller开启校验

package com.example.controller;

import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;

@RestController
@RequestMapping("/api/order")
public class OrderController {
   

    @PostMapping("/create")
    public ResultVO<String> createOrder(@Valid @RequestBody OrderCreateDTO orderDTO) {
   
        return ResultVO.success("订单创建成功");
    }
}

开发高频易错点:如果参数中存在嵌套对象、集合嵌套,仅在顶层参数加@Valid无法生效,嵌套层级必须单独添加@Valid注解,否则子参数校验失效,出现参数穿透问题

三、查询参数(Query)校验

适用于GET请求的分页查询、条件筛选、排序等简单参数场景,是查询参数专属校验方式。和请求体校验用法有明显区别,不需要在方法参数上加@Valid

1.分页参数DTO


from dataclasses import dataclass
from typing import Optional

class ValidationError(Exception):
    def __init__(self, field, message):
        self.field = field
        self.message = message
        super().__init__(f"{field}: {message}")

@dataclass
class PageQueryDTO:
    pageNum: int = 1
    pageSize: int = 10
    sortField: Optional[str] = None
    sortType: Optional[str] = None

    def validate(self):
        errors = []

        # 页码校验
        if self.pageNum is None or self.pageNum < 1:
            errors.append(ValidationError("pageNum", "页码不能小于1"))

        # 每页大小校验
        if self.pageSize is None or self.pageSize < 1:
            errors.append(ValidationError("pageSize", "每页大小不能小于1"))
        elif self.pageSize > 100:
            errors.append(ValidationError("pageSize", "每页最大100条,防止全表查询"))

        # 排序字段校验
        if self.sortField:
            import re
            if not re.match(r"^[a-zA-Z0-9_]{1,30}$", self.sortField):
                errors.append(ValidationError("sortField", "排序字段非法"))

        # 排序方式校验
        if self.sortType:
            if self.sortType.lower() not in ["asc", "desc"]:
                errors.append(ValidationError("sortType", "排序方式仅支持asc/desc"))

        if errors:
            raise ValueError("; ".join([f"{e.field}: {e.message}" for e in errors]))

2.Controller开启校验

// 仅需在类上加@Validated,全局开启Query/路径参数校验
@Validated
@RestController
@RequestMapping("/api/user")
public class UserController {
   
    @GetMapping("/page")
    public ResultVO<Object> getUserPage(PageQueryDTO pageQueryDTO) {
   
        return ResultVO.success("查询成功", null);
    }
}

四、全局统一错误返回格式

项目原生的参数校验异常会直接抛出堆栈信息,前端无法解析、页面展示异常,还会暴露项目结构。通过全局统一异常处理,可统一接口返回格式,屏蔽错误堆栈,提示信息精准友好,适配前后端联调规范
1.统一返回实体ResultVO


from typing import TypeVar, Generic, Optional

T = TypeVar('T')

class ResultVO(Generic[T]):
    """API结果封装类"""

    def __init__(self, code: int = None, msg: str = None, data: T = None):
        self.code = code
        self.msg = msg
        self.data = data

    @classmethod
    def success(cls, msg: str, data: T = None):
        """成功响应"""
        result = cls()
        result.code = 200
        result.msg = msg
        result.data = data
        return result

    @classmethod
    def success_simple(cls, msg: str):
        """成功响应(无数据)"""
        return cls.success(msg, None)

    @classmethod
    def param_error(cls, msg: str):
        """参数错误响应"""
        result = cls()
        result.code = 400
        result.msg = msg
        return result

    @classmethod
    def error(cls, msg: str):
        """系统异常响应"""
        result = cls()
        result.code = 500
        result.msg = msg
        return result

    def to_dict(self):
        """转为字典格式"""
        return {
   
            'code': self.code,
            'msg': self.msg,
            'data': self.data
        }

# 使用示例
if __name__ == "__main__":
    # 成功响应
    success_result = ResultVO.success("操作成功", {
   "id": 1, "name": "test"})
    print(success_result.to_dict())

    # 参数错误响应
    param_error_result = ResultVO.param_error("参数校验失败")
    print(param_error_result.to_dict())

    # 系统错误响应
    error_result = ResultVO.error("系统异常")
    print(error_result.to_dict())

全局异常处理器


from flask import Flask, request, jsonify
from werkzeug.exceptions import HTTPException
import logging

app = Flask(__name__)

class ValidationError(Exception):
    """参数校验异常"""
    def __init__(self, message):
        self.message = message
        super().__init__(message)

class ResultVO:
    """API结果封装类"""

    @staticmethod
    def param_error(msg: str):
        return {
   
            'code': 400,
            'msg': msg,
            'data': None
        }

    @staticmethod
    def error(msg: str):
        return {
   
            'code': 500,
            'msg': msg,
            'data': None
        }

    @staticmethod
    def success(msg: str, data=None):
        return {
   
            'code': 200,
            'msg': msg,
            'data': data
        }

@app.errorhandler(ValidationError)
def handle_validation_error(error):
    """处理参数校验异常"""
    return jsonify(ResultVO.param_error(error.message)), 400

@app.errorhandler(HTTPException)
def handle_http_exception(error):
    """处理HTTP异常"""
    return jsonify(ResultVO.param_error(f"请求错误: {error.description}")), error.code

@app.errorhandler(Exception)
def handle_all_exceptions(error):
    """全局异常处理器"""
    # 记录错误日志
    logging.error(f"系统错误: {str(error)}", exc_info=True)
    return jsonify(ResultVO.error("系统繁忙,请稍后重试")), 500

# 示例路由用于测试
@app.route('/test-validation', methods=['POST'])
def test_validation():
    data = request.get_json() or {
   }

    # 模拟参数校验
    if not data.get('name'):
        raise ValidationError("姓名不能为空")

    if not isinstance(data.get('age'), int) or data['age'] < 0:
        raise ValidationError("年龄必须为非负整数")

    return jsonify(ResultVO.success("验证通过"))

if __name__ == '__main__':
    app.run(debug=True)

总结

这套API参数校验方案是SpringBoot项目的标准化通用方案,核心由请求体校验、查询参数校验、统一异常返回三部分组成,覆盖绝大多数接口开发场景。针对新增、修改类POST/PUT接口,采用@Valid注解实现复杂嵌套参数的全自动校验,从源头避免参数漏验、非法参数穿透业务层的问题;针对GET查询、分页接口,通过类注解@Validated快速完成简单参数的合法性校验,有效防止越界查询、非法字段查询导致的数据库性能问题。
配合全局异常处理器,统一拦截所有参数校验异常,规整接口返回格式,隐藏底层异常堆栈,既保障了系统安全性,又提升了前后端联调效率。整体方案摒弃了传统手动参数判断的繁琐写法,实现了参数校验前置、异常统一兜底、返回格式标准化的开发闭环,代码简洁、维护性强,完全适配生产环境落地使用

目录
相关文章
|
2天前
|
人工智能 自然语言处理 文字识别
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
Qwen3.7-Max是阿里云百炼面向智能体时代推出的新一代旗舰模型,对标GPT-5.5、Claude Opus 4.7等闭源旗舰。该模型支持百万级token上下文窗口,具备顶级推理能力、多模态搜索与视觉理解增强、流式输出低延迟响应等核心优势,覆盖编程、办公、长周期自主执行等复杂场景。同时支持OpenAI接口兼容,便于系统快速迁移。用户可通过Token Plan团队或节省计划等订阅方式灵活调用,适合企业级高要求场景使用。
7899 34
阿里云百炼Qwen3.7-Max简介:能力、优势、支持订阅计划参考
|
2天前
|
数据采集 人工智能 前端开发
让 Coding Agent 从黑盒到透明:阿里云 Agent 观测审计数据采集实践
AI Agent 规模化落地带来执行黑盒、行为难追溯、成本难度量三大难题。阿里云基于 OTel 标准,面向 Coding Agent、个人通用助理和框架型 Agent,推出 LoongSuite Pilot、插件及探针等无侵入采集方案,让 Agent 实现可看见、可分析、可审计、可治理。
679 145
|
2天前
|
人工智能 缓存 自然语言处理
阿里Qwen3.7-Max评测:Agent能力显著提升,耗时与调用成本大幅下降
阿里云百炼推出面向智能体的旗舰大模型Qwen3.7-Max,具备长周期自主执行能力,显著提升编程、办公自动化等复杂任务处理水平;支持MCP集成与多框架兼容,并以限时5折+100万Tokens免费试用大幅降低使用门槛,助力企业高效落地AI应用。在阿里云百炼平台快速体验:https://t.aliyun.com/U/fPVHqY
1898 10
|
2天前
|
人工智能 运维 JavaScript
阿里云Qoder CN(原通义灵码)全解析 产品形态、版本划分与技术适配说明
在AI辅助开发与智能办公工具持续普及的当下,阿里云旗下原通义灵码正式更名为Qoder CN,同时延伸出QoderWork CN、Qoder CN CLI、Qoder CN Mobile等多款配套产品,形成覆盖代码开发、日常办公、终端交互、移动端使用的完整工具矩阵。Qoder CN核心定位为AI智能编码助手,深度适配主流代码编辑器、集成开发环境以及终端场景;QoderWork CN则偏向桌面端综合办公辅助,二者面向不同使用场景,划分了多个版本档位,搭配差异化资源配额、功能权限与计费规则,同时兼容多款主流大模型。
475 4
|
2天前
|
人工智能 安全 定位技术
CodeGraph深度解析 让Claude Code工具调用直降七成的核心原理与实操教程
如今以Claude Code为代表的AI编程智能体已经成为开发者日常编码、项目重构、漏洞修复的必备工具。但在长期使用过程中,几乎所有开发者都会遇到同一个明显痛点:AI虽然具备强大的代码生成与分析能力,却常常陷入盲目探索的循环中。
1293 2
|
2天前
|
JavaScript 定位技术 API
CodeGraph 爆火:编程 Agent 需要的不是更多上下文,而是一张提前画好的代码地图
CodeGraph 是一款爆火的本地代码智能工具,通过 tree-sitter 解析 AST 构建结构化知识图谱(存于 SQLite),为编程 Agent 提前生成“代码地图”。它显著降低 Agent 在中大型项目中的探索成本——实测工具调用减少71%、Token 降57%、速度提升46%,支持19+语言及主流框架路由识别,完全离线、无需 API Key。
423 1
CodeGraph 爆火:编程 Agent 需要的不是更多上下文,而是一张提前画好的代码地图
|
2天前
|
人工智能 弹性计算 运维
阿里云发布堡垒机智能运维Agent,运维交互进入自然语言新时代
支持自然语言运维,提升效率与安全双保障。
1178 1
|
2天前
|
存储 安全 Java
AgentScope Java 2.0:打造分布式、企业级智能体底座
AgentScope 2.0 面向分布式部署、稳定运行、权限安全等企业级需求全面升级,打造支持多租户隔离与长期稳定运行的企业级智能体底座。
|
2天前
|
存储 定位技术 数据库
CodeGraph 如何让 Claude Code减少 7 成工具调用?
CodeGraph 为 Coding Agent 提供本地代码知识图谱,把函数、类、调用链和框架路由提前整理成“项目地图”,减少盲目搜索和文件读取。它不是新 Agent,而是上下文基础设施,让 Agent 更快找到正确代码路径,平均减少 7 成工具调用。
1335 4
|
2天前
|
人工智能 运维 API
2026年阿里云百炼通义千问Qwen3.7-plus深度介绍 功能特性、使用优势及618大促订阅方案指南
大模型技术的普及,让AI能力逐步融入个人办公、内容创作、代码编写、企业运营、教育培训等各类场景。不同定位的模型对应不同使用需求,旗舰级模型性能强劲但使用成本偏高,轻量化模型价格低廉却难以胜任复杂任务,而介于两者之间的中端主力模型,凭借均衡的能力、亲民的定价、广泛的场景适配性,成为绝大多数个人用户、小型团队、中小企业的首选。
579 1