面试题:@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。

相关推荐
用户298698530141 小时前
Java 提取 HTML 文本内容:两种轻量级实现方案对比
java·后端
lihao lihao1 小时前
Linux文件与fd
java·linux·算法
Java爱好狂.2 小时前
Redis高级笔记:原理+集群+应用+拓展+源码
java·数据库·redis·spring·java面试·后端开发·java八股文
lee_curry2 小时前
jvm中的内存模型
java·jvm·内存模型
tltwuyulw2 小时前
Java的函数式编程(三)
java·后端
ch.ju2 小时前
Java程序设计(第3版)第二章——嵌套循环
java
直奔標竿2 小时前
Java开发者AI转型第九课!突破知识边界!企业级 RAG (检索增强生成) 核心架构与 ETL 管道初探
java·开发语言·人工智能·后端·spring
程途知微2 小时前
ThreadLocal底层原理
java·后端
宝耶2 小时前
[特殊字符] 操作日志模块复习笔记
java·开发语言·jvm