Spring MVC 如何定义一个 Controller? @Controller 和 @RestController 注解有什么区别?

我们来详细解释一下如何在 Spring MVC 中定义 Controller,以及 @Controller@RestController 的区别和使用场景。

如何定义一个 Controller?

在 Spring MVC 中,Controller 扮演着 MVC 模式中 “C” 的角色。它负责接收来自客户端(通常是浏览器或 API 消费者)的 HTTP 请求,处理这些请求(可能需要调用 Service 层进行业务逻辑处理),并最终决定返回什么响应给客户端。

定义一个 Controller 非常简单,主要包含以下步骤:

  1. 创建一个 Java 类:这只是一个普通的 Java 类。
  2. 使用 @Controller@RestController 注解:在这个类上添加 @Controller@RestController 注解。这会告诉 Spring IoC 容器,这个类是一个 Spring MVC Controller 组件,需要被扫描和管理。
  3. 定义处理请求的方法(Handler Methods):在 Controller 类中创建公共方法(public methods)。
  4. 使用映射注解:在这些方法上使用 @RequestMapping 或其更具体的变体(如 @GetMapping, @PostMapping, @PutMapping, @DeleteMapping, @PatchMapping)来指定这个方法处理哪些 URL 路径和 HTTP 方法的请求。
  5. 处理请求和返回响应:方法内部可以包含处理请求的逻辑,例如读取请求参数、路径变量、请求体,调用服务层,并最终返回一个响应。这个响应可以是一个视图名称(由视图解析器处理)、一个包含模型数据的对象(自动序列化为 JSON/XML),或者一个 ResponseEntity 对象来更精细地控制响应状态码和头信息。

基本示例 (@Controller):

package com.example.mywebapp.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller // 标记此类为 Spring MVC Controller
public class GreetingController {

    // 处理对 "/greeting" 路径的 GET 请求
    @GetMapping("/greeting")
    public String greeting(@RequestParam(name="name", required=false, defaultValue="World") String name, Model model) {
        // 将数据添加到 Model 中,使其在视图中可用
        model.addAttribute("nameAttribute", name);
        // 返回视图的逻辑名称 ("greeting")
        // Spring MVC 会查找名为 "greeting" 的视图(例如 greeting.html 或 greeting.jsp)来渲染
        return "greeting";
    }
}

@Controller 和 @RestController 的区别

这两个注解都用于标记一个类为 Spring MVC Controller,但它们在处理方法返回值方面有关键的区别:

  1. @Controller:

    • 用途: 主要用于传统的 Spring MVC 应用,其目标是返回一个视图(View),通常是 HTML 页面,由服务器端渲染(如使用 Thymeleaf, JSP, FreeMarker 等模板引擎)。
    • 返回值处理:
      • 默认情况下,@Controller 中方法返回的 String 会被 Spring MVC 的 ViewResolver 解释为逻辑视图名称。Spring 会根据配置的视图解析器去查找并渲染对应的视图模板。
      • 如果想让 @Controller 中的某个方法直接返回数据(如 JSON 或 XML)而不是视图名称,需要在该方法上显式添加 @ResponseBody 注解@ResponseBody 告诉 Spring 将方法的返回值直接写入 HTTP 响应体中,而不是将其解释为视图名称。Spring 会使用配置的消息转换器(Message Converters,如 Jackson)来序列化返回值。
  2. @RestController:

    • 用途: 主要用于构建 RESTful Web Services(API),这些服务通常返回数据(如 JSON 或 XML)给客户端(如前端 JavaScript 框架、移动应用或其他后端服务),而不是渲染 HTML 视图。
    • 返回值处理: @RestController 是一个组合注解,它本身包含了 @Controller@ResponseBody
      • 这意味着,在一个用 @RestController 注解的类中,所有的处理方法(handler methods)默认都带有 @ResponseBody 的行为。
      • 方法的返回值会被自动序列化(通常为 JSON,如果类路径下有 Jackson 库)并写入 HTTP 响应体。你不需要在每个方法上单独添加 @ResponseBody 注解。

总结表格:

特性@Controller@RestController (@Controller + @ResponseBody)
主要用途传统 Web 应用,返回视图 (HTML)构建 RESTful API,返回数据 (JSON/XML)
默认返回值处理解释为视图名称,由 ViewResolver 处理直接写入响应体,由 HttpMessageConverter 序列化
返回数据需加需要在方法上加 @ResponseBody不需要,已默认包含 @ResponseBody 行为
组合注解是 (@Controller + @ResponseBody)

使用场景?

选择哪个注解取决于你的 Controller 的主要目的:

  • 使用 @Controller :

    • 正在构建一个传统的、服务器端渲染的 Web 应用程序。
    • Controller 主要负责返回需要由模板引擎(如 Thymeleaf, JSP)渲染的视图名称
    • Controller 中只有少数方法需要直接返回数据(这时可以在这些特定方法上使用 @ResponseBody)。
  • 使用 @RestController :

    • 构建一个 RESTful API,目的是为客户端(如单页应用、移动应用、其他微服务)提供数据。
    • Controller 中所有或绝大多数方法都需要直接返回数据(通常是 JSON 或 XML)而不是视图。
    • 简化代码,避免在每个方法上都写 @ResponseBody

示例 (@RestController):

package com.example.myapi.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import com.example.myapi.model.User; // 假设有一个 User Pojo

@RestController // 标记此类为 REST Controller,所有方法默认返回数据
public class UserController {

    // 处理对 "/api/users/{id}" 路径的 GET 请求
    @GetMapping("/api/users/{id}")
    public User getUserById(@PathVariable Long id) {
        // 假设 userService.findById(id) 返回一个 User 对象
        // User userService = ...;
        // User user = userService.findById(id);

        // 模拟返回一个 User 对象
        User user = new User(id, "John Doe", "john.doe@example.com");

        // 这个 User 对象会被自动序列化为 JSON 并写入响应体
        return user;
    }

    // 处理对 "/api/status" 路径的 GET 请求
    @GetMapping("/api/status")
    public String getStatus() {
        // 即使返回 String,也会被直接写入响应体,而不是作为视图名
        return "API is running";
    }
}

在这个 @RestController 示例中,getUserById 方法返回的 User 对象会被 Spring 自动转换为 JSON 格式的响应体。getStatus 方法返回的字符串 "API is running" 也会被直接作为纯文本写入响应体,而不是被视图解析器处理。

开发中根据我们的应用类型(返回 HTML 视图还是返回 API 数据)来选择合适的注解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰糖心书房

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值