面试题:@Controller 与 @RestController 区别

@Controller 与 @RestController 注解详解与区别(Spring Boot 面试必背)

前言

在 Spring Boot / SpringMVC 后端开发中,@Controller 与 @RestController 是最基础且高频使用的控制器注解,也是初级后端面试中必考的知识点。很多初学者容易混淆两者的用法,常常出现"页面跳转失败""接口返回JSON报错""404异常"等问题。

本文将从「注解本质、核心作用、跳转逻辑、代码示例、源码解析、核心区别、坑点避坑、面试问答」8个维度,全方位拆解两个注解,重点讲清大家最易困惑的"页面跳转逻辑",帮你彻底分清用法、吃透考点,看完直接能用于开发和面试。

一、@Controller 注解详解

1. 基本定义

@Controller 是 SpringMVC 原生注解(Spring 2.5+ 引入),核心作用是 标记一个类为 Web 控制器,将该类交由 Spring 容器管理。它负责接收前端发送的 HTTP 请求、调用业务逻辑层处理请求,默认行为是返回视图名称,实现页面跳转,是传统前后端不分离项目的核心控制器注解。

2. 核心特性

  • 标识性:被 @Controller 标记的类,会被 Spring 扫描并实例化为控制器 Bean,成为 SpringMVC 处理请求的核心组件。
  • 默认返回值:方法返回值默认为「视图名」,SpringMVC 会通过视图解析器(如 Thymeleaf、JSP 解析器)拼接路径,最终跳转到对应页面。
  • JSON 返回方式:若需要返回 JSON/XML 数据(而非跳转页面),必须在对应方法上手动添加 @ResponseBody 注解,否则 Spring 会将返回值当作视图名解析,导致报错。
  • 适用场景:传统前后端不分离项目(如 JSP、Thymeleaf 模板渲染的后台管理系统),需要实现页面跳转、表单提交与重定向的场景。

3. 代码示例

下面以最常见的"跳转首页"为例,逐行解释代码作用,重点讲清「谁负责匹配请求、谁负责跳转页面」:

复制代码
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

// 标记当前类为SpringMVC控制器,交由Spring容器管理
@Controller
// 类级别的请求映射:所有该类的接口都需加上 "/page" 前缀
@RequestMapping("/page")
public class PageController {

    // 方法级别的请求映射:匹配前端访问路径 "/page/index"
    @GetMapping("/index")
    public String toIndex() {
        // 返回视图名 "index",这是实现页面跳转的核心
        return "index";
    }
}
关键疑问解答

页面跳转是 @GetMapping("/index") 的结果,还是 return "index"; 的结果?

答案:@GetMapping("/index") 负责匹配请求,return "index"; 负责真正跳转页面,两者分工明确,缺一不可,完整流程如下:

  1. 前端发起请求:浏览器访问 http://localhost:8080/page/index(假设项目端口为8080);
  2. 请求匹配:SpringMVC 先通过类上的 @RequestMapping("/page"),再通过方法上的 @GetMapping("/index"),拼接出完整路径 /page/index,找到 toIndex() 方法并执行;
  3. 视图名返回:方法执行完毕后,return "index" 会将字符串 "index" 作为「视图名」返回给 SpringMVC;
  4. 页面定位与跳转:SpringMVC 调用视图解析器,拼接路径(以 Thymeleaf 为例,默认配置为 classpath:/templates/ + 视图名 + .html),即 classpath:/templates/index.html,最终找到对应页面并渲染,完成跳转。

补充:若视图解析器配置的前缀是 /WEB-INF/jsp/、后缀是 .jsp,则 return "index" 会定位到 /WEB-INF/jsp/index.jsp页面。

4. @Controller 返回 JSON 数据的示例

如果用 @Controller 想返回 JSON 数据,必须在方法上添加 @ResponseBody 注解,否则会报错(Spring 会把返回的 Map 当作视图名解析,找不到对应页面):

复制代码
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;
import java.util.Map;

@Controller
@RequestMapping("/user")
public class UserController {

    // 手动添加 @ResponseBody,指定该方法返回 JSON 数据
    @GetMapping("/info")
    @ResponseBody
    public Map<String, Object> getUserInfo() {
        Map<String, Object> user = new HashMap<>();
        user.put("id", 1001);
        user.put("name", "张三");
        user.put("age", 25);
        // 返回的 Map 会被 Spring 自动序列化为 JSON 写入响应体
        return user;
    }
}

二、@RestController 注解详解

1. 基本定义

@RestController 是 Spring 4.0 新增的组合注解,核心作用是 用于前后端分离项目的 RESTful API 开发,它等价于「@Controller + @ResponseBody」的组合,无需手动给方法添加 @ResponseBody,默认所有方法都返回 JSON/XML 数据,不跳转页面。

2. 核心特性

  • 组合性:源码中明确标注了 @Controller 和 @ResponseBody 两个注解,本质是两者的"简化写法",减少代码冗余。
  • 默认返回值:所有方法默认自带 @ResponseBody 效果,返回值会被 Spring 自动序列化为 JSON/XML 数据,写入 HTTP 响应体,不会经过视图解析器,无法跳转页面。
  • 适用场景:前后端分离项目(如 Vue、React、小程序对接后端接口),仅需要返回数据、不需要页面跳转的场景,是开发 RESTful API 的首选注解。
  • Spring 版本要求:仅支持 Spring 4.0 及以上版本(Spring Boot 1.0+ 已默认集成,可直接使用)。

3. 源码解析

打开 @RestController 的源码,就能清晰看到它的本质,相当于"一键添加两个注解":

复制代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Controller // 继承 @Controller 的控制器功能
@ResponseBody // 继承 @ResponseBody 的 JSON 序列化功能
public @interface RestController {
    String value() default ""; // 可指定控制器的Bean名称,默认空
}

4. 代码示例(RESTful API 开发)

无需手动添加 @ResponseBody,方法返回值直接转为 JSON,适配前后端分离接口调用:

复制代码
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;

// 组合注解:等价于 @Controller + @ResponseBody
@RestController
@RequestMapping("/api/user")
public class ApiUserController {

    // 无需加 @ResponseBody,默认返回 JSON
    @GetMapping("/{id}")
    public Map<String, Object> getUserById(@PathVariable Integer id) {
        Map<String, Object> user = new HashMap<>();
        user.put("id", id);
        user.put("name", "李四");
        user.put("gender", "男");
        user.put("address", "北京市");
        return user;
    }

    // 所有方法都默认返回 JSON
    @GetMapping("/list")
    public Map<String, Object> getUserList() {
        Map<String, Object> result = new HashMap<>();
        result.put("code", 200);
        result.put("msg", "success");
        result.put("data", new String[]{"张三", "李四", "王五"});
        return result;
    }
}

三、@Controller 与 @RestController 核心区别

为了方便记忆和面试作答,整理了清晰的对比表格,覆盖所有核心维度:

对比维度 @Controller @RestController
注解本质 SpringMVC 原生控制器注解 组合注解(@Controller + @ResponseBody)
默认返回值 视图名(用于页面跳转) JSON/XML 数据(用于接口响应)
@ResponseBody 需求 返回 JSON 需手动添加(方法级) 默认自带(类级生效,无需添加)
视图解析 会经过视图解析器,可跳转页面 不经过视图解析器,无法跳转页面
Spring 版本 Spring 2.5+ Spring 4.0+
适用场景 传统前后端不分离(页面跳转) 前后端分离(RESTful API 开发)
常见异常 未加 @ResponseBody 返回 404(视图找不到) 试图跳转页面失败(返回字符串被当作 JSON)

一句话总结:@Controller 用于页面跳转,返回 JSON 需加 @ResponseBody;@RestController 用于接口开发,默认所有方法返回 JSON,无法跳转页面。

四、常见坑点与避坑指南

坑点 1:@RestController 试图跳转页面,报 404

错误场景:用 @RestController 标记控制器,方法 return "index",想跳转 index.html 页面,结果报 404。

原因:@RestController 自带 @ResponseBody,return "index" 会被当作 JSON 字符串返回,不会经过视图解析器,自然找不到页面。

解决方案:页面跳转必须用 @Controller 标记控制器,不要用 @RestController。

坑点 2:@Controller 未加 @ResponseBody,返回 JSON 报 404

错误场景:@Controller 标记的方法,返回 Map/实体类(想返回 JSON),未加 @ResponseBody,报 404。

原因:Spring 会将返回的 Map/实体类当作"视图名"解析,找不到对应视图,所以报 404。

解决方案:在返回 JSON 的方法上,手动添加 @ResponseBody 注解。

坑点 3:同一个控制器混用页面跳转和接口返回

错误场景:一个控制器用 @Controller 标记,既有跳转页面的方法,也有返回 JSON 的方法,但部分返回 JSON 的方法忘记加 @ResponseBody。

解决方案:拆分控制器,专人专责------页面跳转控制器用 @Controller,API 接口控制器用 @RestController;若必须混用,确保所有返回 JSON 的方法都加 @ResponseBody。

五、使用场景选择

  1. 传统 Web 项目(JSP/Thymeleaf 模板):需要页面跳转、表单提交、重定向 → 用 @Controller。
  2. 前后端分离项目(Vue/React/小程序):仅提供接口、返回数据,不涉及页面渲染 → 用 @RestController。
  3. 混合场景(极少用):同一个项目既有页面跳转,又有少量接口 → 用 @Controller + 接口方法加 @ResponseBody。

六、面试高频问答

Q1:@RestController 的作用是什么?

A:@RestController 是 Spring 4.0 新增的组合注解,等价于 @Controller + @ResponseBody,用于 RESTful API 开发;它会将控制器交由 Spring 容器管理,且所有方法默认返回 JSON/XML 数据,无需手动添加 @ResponseBody,无法跳转页面。

Q2:@Controller 如何返回 JSON 数据?

A:在 @Controller 标记的方法上,手动添加 @ResponseBody 注解,Spring 会自动将方法的返回值(Map、实体类等)序列化为 JSON 数据,写入 HTTP 响应体。

Q3:@Controller 和 @RestController 的最大区别是什么?

A:最大区别是「是否默认自带 @ResponseBody」:@Controller 默认返回视图名,用于页面跳转;@RestController 默认自带 @ResponseBody,返回 JSON 数据,用于接口开发,无法跳转页面。

Q4:用 @RestController 能实现页面跳转吗?怎么实现?

A:不能直接实现。因为 @RestController 自带 @ResponseBody,返回值会被当作 JSON 解析;若非要用它跳转页面,需手动在方法上添加 @ResponseBody(抵消类级注解),且返回 ModelAndView 对象,但这种用法不推荐,建议直接用 @Controller。

七、总结

  1. 核心区分:@Controller 管"页面跳转",@RestController 管"接口数据",两者本质是"是否默认包含 @ResponseBody"。

  2. 开发建议:前后端分离优先用 @RestController,传统项目用 @Controller,避免混用导致异常。

  3. 面试重点:记住"@RestController = @Controller + @ResponseBody",以及两者的返回值差异、适用场景,就能应对绝大多数相关面试题。

  4. 避坑关键:不要用 @RestController 跳转页面,不要忘记给 @Controller 的 JSON 方法加 @ResponseBody。

相关推荐
system_error_x1 小时前
SpringBoot 集成 Thymeleaf 简洁入门
java·spring boot·后端
驭渊的小故事2 小时前
Spring AI Alibaba 实战:从maven依赖治理到声明式工具调用
java·人工智能·spring
Elastic 中国社区官方博客2 小时前
我们如何通过 70 多个拉取请求,将 OpenTelemetry Java agent 迁移到 invokedynamic
java·大数据·开发语言·elasticsearch·搜索引擎·全文检索·es
tyn1882 小时前
记录本地安装nacos服务的方法及异常
java·开发语言
步行cgn3 小时前
Spring MVC 视图机制的核心接口与类
java·开发语言·后端·spring·mvc
y1su3 小时前
Leetcode 字符串模板
java·数据结构·算法·leetcode·职场和发展·动态规划
我命由我123454 小时前
Python 开发 - Python 的 pathlib
java·开发语言·后端·python·学习·java-ee·学习方法
苜蓿muxu5 小时前
Java 字符串拼接:+、StringBuilder、StringBuffer的区别
java
摇滚侠5 小时前
《Java并发编程之美》第 4 章 Java 并发包中原子操作类原理剖析 阅读笔记 7
java·笔记·python