Spring Boot 中 @Controller与 @RestController的区别及 404 错误解析

在开发 Spring Boot 应用时,经常会遇到一个问题:明明写了接口方法,但访问时却返回:

json 复制代码
{
  "timestamp": "2025-08-24 11:28:59",
  "status": 404,
  "error": "Not Found",
  "message": "No message available",
  "path": "/api/keyword/"
}

很多初学者会以为是路径错了,其实很多情况下是 注解类型使用不当 导致的。本文就结合一个关键字查询接口示例,来分析原因和解决方案。


1️⃣ 问题复现

假设你写了一个 Controller:

java 复制代码
@Controller
@RequestMapping("/api/keyword")
public class KeywordController {

    @GetMapping("/{id}")
    public Result<Keyword> getById(@PathVariable int id) {
        return keywordService.getKeywordById(id);
    }

    @GetMapping
    public Result<List<Keyword>> getAll() {
        return keywordService.getAll();
    }
}

前端请求:

复制代码
GET /api/keyword/

结果报 404 错误。


2️⃣ 原因分析

  1. @Controller 是传统的 MVC 控制器 注解,用于返回 视图(HTML、JSP、Thymeleaf 页面等)。

  2. 当你在方法中直接返回对象(如 Result<Keyword>)时,@Controller 并不会自动将对象序列化为 JSON。

  3. 访问 /api/keyword/ 时:

    • Spring 尝试解析返回值,找对应的视图模板(比如 Result<Keyword> 对应的页面)
    • 找不到对应模板 → 返回 404(No message available)

所以问题是 返回类型无法被处理


3️⃣ 解决方案

方案 1:使用 @ResponseBody

在每个方法上加 @ResponseBody

java 复制代码
@Controller
@RequestMapping("/api/keyword")
public class KeywordController {

    @GetMapping("/{id}")
    @ResponseBody
    public Result<Keyword> getById(@PathVariable int id) {
        return keywordService.getKeywordById(id);
    }

    @GetMapping
    @ResponseBody
    public Result<List<Keyword>> getAll() {
        return keywordService.getAll();
    }
}
  • @ResponseBody 告诉 Spring 将返回值序列化为 JSON,而不是去找视图模板。

方案 2:直接使用 @RestController(推荐)

java 复制代码
@RestController
@RequestMapping("/api/keyword")
public class KeywordController {

    @GetMapping("/{id}")
    public Result<Keyword> getById(@PathVariable int id) {
        return keywordService.getKeywordById(id);
    }

    @GetMapping
    public Result<List<Keyword>> getAll() {
        return keywordService.getAll();
    }
}
  • @RestController = @Controller + @ResponseBody,自动处理返回值为 JSON。
  • 更适合做 RESTful 接口,不需要返回视图页面。
  • 前端直接请求 /api/keyword/api/keyword/1 就不会再报 404。

4️⃣ 总结

注解 功能 使用场景
@Controller MVC 控制器,返回视图 页面渲染(HTML、Thymeleaf、JSP)
@RestController REST 控制器,返回 JSON 接口服务(REST API)

关键点:

  • 如果返回对象而不是页面,必须让 Spring 知道要序列化@ResponseBody@RestController
  • 避免误用 @Controller 返回 JSON,否则会出现 404(找不到视图)

5️⃣ 建议

  1. 对于 纯后端接口 (返回 JSON 数据),统一用 @RestController,代码简洁。
  2. 对于 传统 MVC 页面 ,使用 @Controller + 模板引擎(Thymeleaf/JSP)。
  3. 避免前端请求路径和控制器映射不一致,尤其注意 / 和空路径。
  4. 如果接口返回对象,请确认返回值已经被序列化,否则会出现类似 404 的错误。