如何接收前端参数

Spring Boot 入门:如何接收前端参数

大家好呀!上一篇我们学会了让接口返回 JSON 数据,小伙伴会不会有疑问:"前端怎么给后端传数据呀?比如我想根据用户 ID 查对应的用户信息,该怎么写?" 今天这篇就聚焦 "接收前端参数" 这个核心需求,用 3 个最常用的场景 + 具体案例,手把手教你搞定,看完就能直接用在项目里!

一、先搞懂:前端会怎么传参数?

在写代码前,我们先花 2 分钟搞清楚前端给后端传参数的 3 种常见方式,因为不同的传参方式,后端接收的写法不一样:

1. 路径传参(比如 http://localhost:8080/user/1

参数直接拼在 URL 路径里,像上面的 "1" 就是用户 ID,这种方式适合传单个、简单的参数(比如 ID、编号),URL 看起来很简洁。

2. 问号传参(比如 http://localhost:8080/product?name=手机&price=3000

参数用 "?" 开头,多个参数用 "&" 分隔,这种方式适合传多个可选参数(比如商品搜索时的名称、价格范围)。

3. 请求体传参(JSON 格式)

参数放在请求的 "body" 里,不是拼在 URL 上,格式是 JSON,这种方式适合传复杂、多字段的参数(比如用户注册时的姓名、手机号、密码,或者提交订单时的多个商品信息),安全性更高,参数也更灵活。

这 3 种方式覆盖了 90% 以上的开发场景,接下来我们逐个讲解后端怎么接收~

二、准备工作:复用之前的项目和实体类

我们还是在之前的「first-springboot-project」项目里操作,不用新建项目,直接复用已经创建好的:

  • 实体类:User(用户 ID、姓名、年龄、手机号)、Product(商品 ID、名称、价格、库存);
  • 控制器:可以在之前的JsonController里加方法,也可以新建ParamController(推荐新建,分类更清晰),这里我们选择新建。

先确认项目能正常运行,没有报错~

三、场景 1:路径传参(接收单个参数,如用户 ID)

最常见的需求:前端传用户 ID(比如 "1"),后端根据 ID 查询对应的用户信息并返回。

1. 写接口:用 @PathVariable 接收路径参数

新建ParamController,在里面写一个根据用户 ID 查用户的接口:

kotlin 复制代码
package com.example.firstspringbootproject.controller;

import com.example.firstspringbootproject.entity.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ParamController {

    /*
     接口1:路径传参------根据用户ID查询用户
     访问路径:/user/{userId},其中{userId}是占位符,表示这里要传用户ID
     @PathVariable("userId"):把路径里{userId}的值,赋值给方法参数Integer userId
     */
    @GetMapping("/user/{userId}")
    public User getUserById(@PathVariable("userId") Integer userId) {

        // 注意:这里只是模拟查询(实际项目会从数据库查),根据传的userId返回不同用户
        if (userId == 1) {
            // 返回ID为1的用户
            return new User(1, "小明", 20, "13800138000");
        } else if (userId == 2) {
            // 返回ID为2的用户
            return new User(2, "小红", 19, "13900139000");
        } else {
            // 没有匹配的用户,返回null(实际项目会返回"用户不存在"的提示)
            return null;
        }
    }
}

2. 关键说明(重点看这 2 处):

  • 路径占位符@GetMapping("/user/{userId}") 里的 {userId} 是 "占位符",表示这个位置要传参数,参数名可以自己定(比如{id}也可以);
  • @PathVariable 注解@PathVariable("userId") 用来 "提取" 路径里占位符的值,括号里的 "userId" 要和路径里{userId}的名称完全一致 ,然后赋值给后面的Integer userId参数。

3. 测试接口(用浏览器或 Apifox)

测试 1:查询 ID 为 1 的用户
  • 浏览器地址栏输入:http://localhost:8080/user/1
  • 返回结果(JSON):{"id":1,"name":"小明","age":20,"phone":"13800138000"},正确!
测试 2:查询 ID 为 2 的用户
  • 输入:http://localhost:8080/user/2
  • 返回:{"id":2,"name":"小红","age":19,"phone":"13900139000"},正确!
测试 3:查询不存在的 ID(比如 3)
  • 输入:http://localhost:8080/user/3
  • 返回:null(符合我们代码里的逻辑)。

四、场景 2:问号传参(接收多个可选参数,如商品搜索)

需求:前端传商品名称(可选)和价格上限(可选),后端根据参数筛选商品列表(比如只传名称 "手机",就返回所有手机;只传价格上限 3000,就返回所有低于 3000 的商品;两个都传,就返回符合条件的手机)。

1. 写接口:用 @RequestParam 接收问号参数

ParamController里加一个商品搜索接口:

java 复制代码
package com.example.firstspringbootproject.controller;

import com.example.firstspringbootproject.entity.Product;
import com.example.firstspringbootproject.entity.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;

@RestController
public class ParamController {
    /*
     接口2:问号传参------商品搜索(名称和价格上限都是可选参数)
     访问路径示例:/product/search?name=手机&maxPrice=3000
     @RequestParam(required = false):表示这个参数是可选的,不传也不会报错
     defaultValue = "": 表示如果参数没传,默认值是空字符串(针对String类型)
     */
    @GetMapping("/product/search")
    public List<Product> searchProduct(@RequestParam(required = false, defaultValue = "") String name, @RequestParam(required = false) Double maxPrice) {

        //1.创建商品数据库
        List<Product> productDB = new ArrayList<>();
        productDB.add(new Product(101, "华为手机", 3999.0, 100));
        productDB.add(new Product(102, "苹果平板", 5999.0, 50));
        productDB.add(new Product(103, "小米耳机", 299.0, 200));
        productDB.add(new Product(104, "OPPO手机", 2999.0, 80));

        // 2. 创建一个空列表,用来装筛选后的商品
        List<Product> result = new ArrayList<>();

        // 3. 遍历"商品数据库",根据参数筛选
        for (Product product : productDB) {
            // 条件1:商品名称包含传入的name(如果name不为空)
            boolean matchName = product.getProductName().contains(name);
            // 条件2:商品价格小于等于传入的maxPrice(如果maxPrice不为空)
            boolean matchPrice = (maxPrice == null) || (product.getPrice() <= maxPrice);
            // 两个条件都满足,就加入结果列表
            if (matchName && matchPrice) {
                result.add(product);
            }
        }

        // 4. 返回筛选后的商品列表(Spring Boot自动转JSON)
        return result;

    }
}

2. 关键说明(重点看 @RequestParam):

  • required = false:表示这个参数是 "可选的",前端可以不传(如果不写这个属性,默认是required = true,前端不传就会报错);
  • defaultValue = "":给参数设置 "默认值",比如 name 的默认值是空字符串,这样即使前端不传 name,也不会是 null,避免后续代码报错;
  • 参数名对应@RequestParam 括号里可以写参数名(比如@RequestParam("productName")),如果括号里不写,默认会找和方法参数名(比如name)一致的前端参数。

3. 测试接口(多场景测试,更能理解)

测试 1:只传 "商品名称"(搜索 "手机")
  • 访问路径:http://localhost:8080/product/search?name=手机
  • 筛选逻辑:名称包含 "手机",价格不限制;
  • 返回结果:华为手机(3999)和 OPPO 手机(2999),正确!
测试 2:只传 "价格上限"(maxPrice=3000)
  • 访问路径:http://localhost:8080/product/search?maxPrice=3000
  • 筛选逻辑:价格≤3000,名称不限制;
  • 返回结果:小米耳机(299)和 OPPO 手机(2999),正确!
测试 3:两个参数都传(name = 手机 & maxPrice=3000)
  • 访问路径:http://localhost:8080/product/search?name=手机&maxPrice=3000
  • 筛选逻辑:名称包含 "手机" 且价格≤3000;
  • 返回结果:只有 OPPO 手机(2999),正确!
测试 4:两个参数都不传
  • 访问路径:http://localhost:8080/product/search
  • 筛选逻辑:所有商品都符合条件;
  • 返回结果:所有 4 个商品,正确!

五、场景 3:请求体传参(接收复杂 JSON 参数,如用户注册)

需求:用户注册时,前端传一个 JSON 格式的用户信息(包含姓名、年龄、手机号),后端接收这些参数,模拟 "保存用户",然后返回 "注册成功" 的提示和保存后的用户信息(包含自动生成的用户 ID)。

1. 写接口:用 "实体类" 接收请求体参数

ParamController里加一个用户注册接口:

java 复制代码
package com.example.firstspringbootproject.controller;

import com.example.firstspringbootproject.entity.Product;
import com.example.firstspringbootproject.entity.User;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;

@RestController
public class ParamController {

    // 模拟"用户数据库":存注册后的用户
    private List<User>userDB =new ArrayList<>();

    // 模拟自增ID:每次注册新用户,ID+1
    private Integer nextUserId = 3; // 之前已有ID=1、2的用户,所以从3开始

    /*
     * 接口3:请求体传参------用户注册(接收JSON格式的用户信息)
     *  @PostMapping:表示这个接口用POST请求(前端传请求体一般用POST,不用GET)
     *  @RequestBody:表示把请求体里的JSON数据,转换成User对象
     */
    @PostMapping("/user/register")
    public String registerUser(@RequestBody User user) {

        // 1. 给新用户设置自增ID(前端没传,后端自动生成)
        user.setId(nextUserId);
        nextUserId++; // 下次注册ID+1
        // 2. 模拟"保存用户":把用户添加到"用户数据库"
        userDB.add(user);
        // 3. 返回注册成功的提示(包含用户信息)
        return "注册成功!你的用户信息:" +

                "ID=" + user.getId() +

                ",姓名=" + user.getName() +

                ",年龄=" + user.getAge() +

                ",手机号=" + user.getPhone();

    }
}

2. 关键说明(重点看这 2 个注解):

  • @PostMapping:接收前端的 POST 请求(GET 请求一般用来 "查询" 数据,POST 请求用来 "提交" 数据,比如注册、提交订单,这是开发中的规范);
  • @RequestBody:把前端请求体里的 JSON 数据,自动转换成User实体类对象 ------ 这里的关键是:JSON 里的字段名要和User类的属性名完全一致 (比如 JSON 里的 "name" 对应 User 类的private String name),否则无法正确赋值。

3. 测试接口(必须用 Apifox,浏览器没法传请求体)

测试步骤:
  1. 打开 Apifox,点击左上角「+」新建快捷请求;
  2. 「Method」选择「POST」,「URL」输入:http://localhost:8080/user/register
  3. 点击「Body」→ 选择「json」→ 右侧下拉框选择「JSON」,在输入框里写前端要传的 JSON 数据:
json 复制代码
{
    "name": "小李",
    "age": 22,
    "phone": "13700137000"
}
  1. 点击右上角「Send」,查看返回结果:
  • 「Response Body」里会显示:注册成功!你的用户信息:ID=3,姓名=小李,年龄=22,手机号=13700137000
  • 状态码是 200,表示请求成功。
再测试一次:
  • 再传一个 JSON:
json 复制代码
{
    "name": "小李",
    "age": 21,
    "phone": "13600136000"
}
  • 返回结果:注册成功!你的用户信息:ID=4,姓名=小张,年龄=21,手机号=13600136000,ID 自动增长,正确!

六、常见问题:接收参数时的小坑和解决方案

1. 路径传参时,参数名和占位符不一致,导致接收不到值?

  • 比如路径是/user/{id},但注解写的是@PathVariable("userId"),这样就会匹配失败;
  • 解决方案:确保@PathVariable括号里的名称,和路径里{}的名称完全一致(比如@PathVariable("id"))。

2. 问号传参时,前端传了参数,但后端接收的是 null?

  • 原因 :前端传的参数名和后端@RequestParam里的参数名不一致(比如前端传product_name,后端用name);

3. 请求体传参时,实体类属性值是 null?

  • 原因 :JSON 里的字段名和实体类属性名不一致(比如 JSON 里是 "userName",实体类是 "name");

七、总结:3 种传参方式怎么选?

今天我们学完了接收前端参数的 3 种核心方式,最后用一张表帮你快速判断该用哪种:

传参方式 注解 / 方式 适用场景 示例 URL/JSON
路径传参 @PathVariable 单个、简单参数(如 ID、编号) http://localhost:8080/user/1
问号传参 @RequestParam 多个可选参数(如搜索条件) http://localhost:8080/product/search?name=手机&maxPrice=3000
请求体传参 @RequestBody + 实体类 复杂、多字段参数(如注册、提交订单) {"name":"小李","age":22,"phone":"13700137000"}

下一篇文章,我会教大家怎么 "连接数据库"(比如用 MySQL),把之前模拟的 "商品数据库""用户数据库" 换成真实的数据库,让接口能真正操作数据库里的数据,这才是企业开发的真实场景!感兴趣的小伙伴点个关注,下次更新不迷路~

如果操作中遇到问题,欢迎在评论区留言,我会一一回复~

相关推荐
独自破碎E2 小时前
从括号匹配到字符串解码:递归思想的巧妙应用
android·java·开发语言
忧郁的橙子.2 小时前
二、Rabbit MQ 高级
java·开发语言
考虑考虑2 小时前
Redis8中新特性:TopK获取最高排名的数据
redis·后端
Chan163 小时前
【 Java八股文面试 | JVM篇 内存结构、类加载、垃圾回收与性能调优 】
java·jvm·spring boot·后端·spring·idea
kevinzeng3 小时前
JdbcTemplate常用方法
后端
yunxi_053 小时前
分布式文件服务实战稿:从本地存储到对象存储的架构升级
后端·面试
百锦再3 小时前
第15章 并发编程
android·java·开发语言·python·rust·django·go
Chan163 小时前
【 Java八股文面试 | Redis篇 缓存问题、持久化、分布式锁 】
java·数据库·redis·后端·spring·缓存·面试
q***47183 小时前
Spring Boot 整合 Druid 并开启监控
java·spring boot·后端