前言:
在 Spring Boot 项目开发中,后端小伙伴可能经常遇到这样诡异的场景:
- 后台日志显示查询到了数据,但前端却一脸懵逼地告诉你 404 Not Found?
- 接口明明写好了,Postman 直接访问却提示找不到?
- 调试半天,最后发现只是一个传参方式的问题?🙃
为什么会出现这种情况?是 后端接口定义的问题,还是 前端请求方式不对?或者是 Spring Boot 机制在悄悄“帮忙”,让空数据变成了 404?
这篇文章将带你 快速排查这个经典问题,并且 总结常见的 Spring Boot 传参方式及注解用法,助你在 联调时一次搞定参数对接,不再踩坑!🔥
复刻场景:请问你能找出问题吗?(答案在文末哦)
后端打印出查询结果但测试却是404?你能找出问题所在吗(注意这里不是端口的问题哦,作者配置的启动端口就是8888)
讲到这里了,作者就不妨来先讲讲各类注解在传参的时候的用法
传参注解的使用大全
在 Spring Boot 开发中,前后端交互时,数据的传递方式有多种形式,主要包括 GET、POST、PUT、DELETE 等 HTTP 方法,以及 Query 参数、Path 变量、RequestBody、Header、Form 表单,对应的注解也有不同的用法。
🟢 1. Query 参数(@RequestParam)
适用场景:一般用于 GET 请求,将参数拼接在 URL 后面,如 ?key=value
示例
GET /user/getUserByName?name=Tom
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/getUserByName")
public String getUserByName(@RequestParam String name) {
return "查询用户:" + name;
}
// @RequestParam 可以提供默认值和非必传参数
@GetMapping("/getUserByAge")
public String getUserByAge(@RequestParam(required = false, defaultValue = "18") int age) {
return "用户年龄:" + age;
}
}
特点
- 适用于 简单参数传递,如
?key=value
形式 - 可以设置
required = false
使参数可选 - 可以设置
defaultValue
以提供默认值
🔵 2. Path 变量(@PathVariable)
适用场景:用于 RESTful 风格 API,参数作为 URL 路径的一部分,如 /user/1001
示例
前端请求
GET /user/1001
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/{id}")
public String getUserById(@PathVariable("id") Long id) {
return "查询用户 ID:" + id;
}
}
特点
- 适用于 RESTful 结构,更加语义化
- 需要在
@GetMapping("/{id}")
的路径中声明参数 @PathVariable("id")
可以省略("id")
,但建议保持一致,增强可读性
🟠 3. RequestBody 方式(@RequestBody)
适用场景:用于 POST/PUT 请求,前端传递 JSON 格式的数据,适合 复杂对象
示例
前端请求(JSON-前后端交互的一种数据格式)
{
"id": 1001,
"name": "Tom",
"age": 25
}
@RestController
@RequestMapping("/user")
public class UserController {
@PostMapping("/add")
public String addUser(@RequestBody User user) {
return "添加用户:" + user.getName();
}
}
特点
- 适用于 复杂数据传输(JSON)
- 需要
@RequestBody
注解将 JSON 解析为Java对象 - 默认情况下,Spring Boot 需要使用
@RequestBody
来解析 JSON 数据,否则会报 415 错误(Unsupported Media Type) - 需要前端设置
Content-Type: application/json
🟣 4. Form 表单数据(@RequestParam 或 @ModelAttribute)
适用场景:前端以 x-www-form-urlencoded
形式提交数据
示例
前端请求
POST /user/register
Content-Type: application/x-www-form-urlencoded
name=Tom&age=25
@PostMapping("/register")
public String registerUser(@RequestParam String name, @RequestParam int age) {
return "注册用户:" + name + ",年龄:" + age;
}
或者使用 @ModelAttribute
,支持对象自动封装:
@PostMapping("/registerUser")
public String registerUser(@ModelAttribute User user) {
return "注册用户:" + user.getName() + ",年龄:" + user.getAge();
}
特点
- 适用于 表单提交
@RequestParam
适合单个参数,@ModelAttribute
适合对象- 前端需使用
application/x-www-form-urlencoded
🟡 5. Header 方式(@RequestHeader)
适用场景:用于 传递 Token、API Key、User-Agent 等请求头信息
示例
前端请求
GET /user/info
Authorization: Bearer abc123
@GetMapping("/info")
public String getUserInfo(@RequestHeader("Authorization") String token) {
return "获取用户信息,Token:" + token;
}
特点
- 适用于 认证信息、请求头参数
@RequestHeader
用于获取指定请求头的值
🟠 6. 多参数组合(混合使用-少见)
有时候,我们需要同时接收 路径参数 + Query 参数 + Body 参数,可以 混合使用 多种方式:
@PostMapping("/update/{id}")
public String updateUser(
@PathVariable("id") Long id,
@RequestParam("role") String role,
@RequestBody User user
) {
return "更新用户 ID:" + id + ",角色:" + role + ",姓名:" + user.getName();
}
示例请求
POST /user/update/1001?role=admin
Content-Type: application/json
{
"name": "Tom",
"age": 26
}
✅ 总结
参数类型 | 方式 | 适用场景 | 主要注解 |
---|---|---|---|
Query 参数 | ?name=Tom | GET 请求参数 | @RequestParam |
Path 变量 | /user/1001 | RESTful 风格 | @PathVariable |
JSON 请求体 | {"name":"Tom","age":25} | POST/PUT 请求 | @RequestBody |
表单提交 | name=Tom&age=25 | POST 表单提交 | @RequestParam / @ModelAttribute |
请求头 | Authorization: Bearer token123 | 传递 Token / API Key | @RequestHeader |
传参时各类可能会出现问题的解决方案(如果出现了问题,请从下面的几个思路逐步检查!!)
✅ 1. 接口 URL 配置错误
/user/findbyid
检查你的 Controller
是否正确定义了路径。例如:
@RestController
@RequestMapping("/user")
public class UserController {
@GetMapping("/findById")
public User findById(@RequestParam Long id) {
// 这里是正常的查询逻辑
return userService.getById(id);
}
}
可能的问题
- 大小写敏感:你的请求路径是
/user/findbyid
,但方法是@GetMapping("/findById")
,F 大写,B 大写,URL 访问是大小写敏感的,应该确保前端请求路径与后端路径完全一致。 - 路径拼写错误:检查是否手误拼错,比如
/findbyid
vs/findById
- 浏览器缓存问题:如果之前请求 404,可能是缓存问题,清理浏览器缓存或使用 Postman、cURL 重新测试。(这个着重注意:edge浏览器有时会出现这个问题!记得点开历史记录清除缓存)
✅ 解决方案 试试访问:
http://localhost:8080/user/findById?id=1
✅ 2. HTTP 方法错误
你的接口是 @GetMapping("/findById")
,但如果前端用的是 POST 请求,那么就会返回 404 Not Found
。
检查前端请求方式
GET /user/findbyid?id=1
如果前端使用了 POST
,但后端是 @GetMapping
,就会导致 405
✅ 解决方案
- 如果前端要用
POST
,后端应该改为
@PostMapping("/findById")
public User findById(@RequestParam Long id) {
return userService.getById(id);
}
- 如果后端是
@GetMapping
,前端应该用 GET 请求。
✅ 3. 方法返回值不符合 REST 规范
如果你的 findById
方法返回的是 null
,Spring Boot 可能会返回 404 Not Found,而不是 null
值。
检查你的返回值
@GetMapping("/findById")
public User findById(@RequestParam Long id) {
User user = userService.getById(id);
System.out.println("查询到的用户:" + user);
return user; // 如果 user 是 null,Spring Boot 可能会返回 404
}
解决方案
如果希望即使数据为空也返回 200
而不是 404
,可以这样:
@GetMapping("/findById")
public ResponseEntity<?> findById(@RequestParam Long id) {
User user = userService.getById(id);
if (user == null) {
return ResponseEntity.ok("用户不存在");
}
return ResponseEntity.ok(user);
}
✅ 4. 返回数据未被 Spring Boot 识别
Spring Boot 需要 @RestController
或 @ResponseBody
才能正确返回 JSON。
@Controller // ❌ 可能只是普通 Controller,而非 REST
@RequestMapping("/user")
public class UserController {
@GetMapping("/findById")
public User findById(@RequestParam Long id) {
return userService.getById(id);
}
}
如果没有 @ResponseBody
,Spring 可能会尝试解析为视图,而不是 JSON。
✅ 解决方案
- 确保使用
@RestController
(等价于@Controller + @ResponseBody
)
@RestController
@RequestMapping("/user")
public class UserController {
如果必须使用 @Controller
,那么应该添加 @ResponseBody
:
@Controller
@RequestMapping("/user")
public class UserController {
@GetMapping("/findById")
@ResponseBody
public User findById(@RequestParam Long id) {
return userService.getById(id);
}
}
✅ 5. 路由冲突或 Spring Boot 过滤器拦截
Spring Boot 可能有 全局拦截器、过滤器,或者其他 Controller
处理了相同路径的请求,导致你的请求被拦截或返回 404
。
解决方案
-
检查
application.properties
是否有拦截器
2.查看是否有 ControllerAdvice
处理全局异常
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(NoHandlerFoundException.class)
public ResponseEntity<String> handleNotFound() {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("接口不存在");
}
}
✅ 6. Spring Boot 404
相关全局配置
在 application.properties
中,检查是否配置了:
server.error.include-message=always
server.error.whitelabel.enabled=false
如果 whitelabel.enabled=true
可能会导致 Spring 自定义错误页面返回 404
。
🛠 总结 & 解决方案
可能原因 | 解决方案 |
---|---|
大小写敏感 | /findById ≠ /findbyid ,保持大小写一致 |
HTTP 方法错误 | @GetMapping("/findById") 不能用 POST 访问 |
返回 null 导致 404 | 使用 ResponseEntity.ok() 处理 |
缺少 @RestController | 使用 @RestController 或 @ResponseBody |
路由冲突 | 确保 /user/findById 不是被其他 Controller 拦截 |
拦截器或过滤器 | 检查 application.properties 及 ControllerAdvice |
你找到第一部分的bug所在之处了吗?(解答)
答对发在评论区的小伙伴有奖励哦----正确答案就是在解决问题的第四步方案!你发现了吗?-我们只需要把@Controller注解改成@RestController即可
因为我们返回的是一个UserVO对象,复杂类型要解析成json数据给前端交互,如果只用
@Controller则会解析为视图对象,但是在前后端分离的项目中基本不用它
修复结果如下:
最后的话:查 Bug 有套路,调接口不迷路!🚀
如果你看到这里,相信你已经对 Spring Boot 接口 404 问题 有了更清晰的认识,同时也掌握了 各种参数传递方式及注解用法。
开发过程中,前后端联调 总会遇到各种坑,但只要掌握排查思路,就能快速定位问题,精准修复 Bug!💪
如果这篇文章对你有帮助,记得点赞 👍、收藏 ⭐、分享 📢,让更多小伙伴少踩坑!也欢迎关注我,后续会持续分享更多 Spring Boot 开发技巧、Bug 查杀指南和最佳实践,让我们一起进步!🚀🔥
👇 你遇到过哪些诡异的接口问题?欢迎评论区交流! 💬