在 Spring MVC 开发中,控制器如何响应客户端请求是每个开发者必须掌握的核心技能。无论你是刚接触 Java 后端,还是正在转向微服务架构,理解响应机制都能让你事半功倍。本文将从静态页面返回、注解区别、数据定制三个维度,深入剖析 Spring MVC 的响应处理,并穿插与其他语言(如 Go、C++、Python、TypeScript)的对比,帮助你建立完整的知识体系。

1. 返回静态页面:从基础到细节

首先,我们从一个最简单的场景开始:返回一个静态 HTML 页面。假设你有一个自定义的 index.html 文件,放置在资源目录下:

在这里插入图片描述

后端代码通常如下所示,使用 @RestController 注解的控制器直接返回字符串:

@RequestMapping("/page")
@RestController
public class PageController {
//    返回一个静态的 html 页面
@RequestMapping("/p1")
public String p1(){
return "index.html";
}
}

此时,浏览器会显示页面的原始内容,因为响应头中的 Content-Typetext/plain,浏览器将其当作纯文本渲染。那么,如何让浏览器真正解析 HTML?有两种修改方式:

修改返回的数据

第一种方式是直接修改返回的字符串内容,例如拼接 HTML 标签:

@RequestMapping("/page")
@RestController
public class PageController {
//    返回一个静态的 html 页面
@RequestMapping("/p1")
public String p1(){
return "/index.html";
}
}

这样虽然能显示简单格式,但依然不是真正的页面跳转。更好的方式是调整注解和路径。

修改注解与路径

@RestController 改为 @Controller,并将返回的字符串从 "index.html" 改为 "/index.html"

@RequestMapping("/page")
//@RestController
@Controller
public class PageController {
//    返回一个静态的 html 页面
@RequestMapping("/p1")
public String p1(){
return "index.html";
}
}
@RequestMapping("/page")
//@RestController
@Controller
public class PageController {
//    返回一个静态的 html 页面
@RequestMapping("/p1")
public String p1(){
return "/index.html";
}
}

此时,Spring 会将字符串解析为视图名称,并查找对应的静态资源,最终返回真正的 HTML 页面。这里有一个实践建议:前后端路径统一加上前导斜杠,避免歧义。不过,在前后端分离的架构中,后端很少直接返回页面,这个功能更多用于单体应用或简单原型。

小贴士:如果你使用过 Python 的 Flask 或 Go 的 net/http,会发现它们也有类似的路由与模板引擎机制,但 Spring MVC 的视图解析器更为强大,支持多种模板引擎(如 Thymeleaf、FreeMarker)。

2. 深入理解 @RestController、@Controller 与 @ResponseBody

很多初学者对这三个注解感到困惑,其实它们的关系非常清晰。我们先看 Spring 的默认扫描路径:启动类所在目录及其子目录,只有被扫描到的类才会被注册为 Bean。

在这里插入图片描述

核心公式:@RestController = @Controller + @ResponseBody。下面逐一拆解:

  • @Controller@Controller):标记类为 MVC 控制器,通常用于返回视图名称。它只能用于类,不能用于方法。
  • @ResponseBody@ResponseBody):将方法的返回值直接写入 HTTP 响应体,而不是解析为视图。可用于类或方法。
  • @RestController@RestController):组合注解,类中所有方法默认返回 JSON/XML 数据,而不是视图。
在这里插入图片描述

⚠️ 特别注意:@ResponseBody 不能单独使用,必须配合 @Controller 才有意义。如果你用过 TypeScript 的 Express 框架,可以类比为 res.json()res.render() 的区别。

实际用法总结

  1. 一个类中既需要返回页面又需要返回数据:类上使用 @Controller,方法上按需添加 @ResponseBody
  2. 一个类全部返回数据:直接使用 @RestController,或 @Controller + 所有方法加 @ResponseBody
  3. 一个类全部返回视图:类上使用 @Controller,但在前后端分离的今天,这种做法已不常见。

延伸思考:在 C++ 的 Web 框架(如 Drogon)中,路由处理函数的返回值通常直接作为响应体,这与 @RestController 的行为类似,但 Spring 的注解驱动模型更灵活。

3. 定制响应:HTML 片段、Content-Type 与状态码

除了返回完整页面,我们经常需要返回 HTML 片段,或者自定义响应头。Spring MVC 提供了丰富的 API 来精细控制响应。

返回 HTML 片段

通过代码直接返回一个 HTML 片段,浏览器默认的 Content-Typetext/html,因此会正确渲染:

@ResponseBody
@RequestMapping("/p2")
public String p2(){
return "<h1>我是一级标题</h1>";
}
在这里插入图片描述

修改 Content-Type

如果希望浏览器将响应当作纯文本,可以手动修改 Content-Type

@ResponseBody
@RequestMapping(value = "/p3",produces = "text/plain")
public String p3(){
return "<h1>我是一级标题</h1>";
}
在这里插入图片描述

此时浏览器会显示纯文本内容,而不是渲染 HTML。这在返回 JSON 或 XML 时尤其重要。

返回对象:默认 JSON

当控制器方法返回一个对象时,Spring 会自动将其序列化为 JSON,Content-Type 默认为 application/json

@ResponseBody
@RequestMapping("/p4")
public User p4(){
User user = new User("张三",18,"男生");
return user;
}
在这里插入图片描述

抓包可以看到响应头:

在这里插入图片描述

为什么默认是 JSON?因为 JSON 是前后端数据交互的事实标准,方便 JavaScript 直接处理。如果你熟悉 Python 的 FastAPI,也会发现它默认返回 JSON,但 Spring 的序列化机制更依赖 Jackson 库。

设置响应状态码

我们可以通过 @ResponseStatus 注解或编程方式设置状态码:

@ResponseBody
@RequestMapping("/p5")
public User setStatus(HttpServletResponse response){
response.setStatus(404);
return new User("张三",18,"男生");
}

抓包结果:

在这里插入图片描述

状态码与页面展示没有直接关系。例如,404 状态码并不代表页面必须显示错误信息,而是由前端根据状态码自定义设计。B 站就有专门的 404 页面:

在这里插入图片描述

设置 Header 数据

通过 HttpServletResponse 对象,可以添加自定义响应头:

@ResponseBody
@RequestMapping("/p6")
public String setHeader(HttpServletResponse response){
response.setHeader("username","hhs");
return "设置 Header 成功";
}

抓包结果:

在这里插入图片描述

这在实现跨域、缓存控制或携带业务元数据时非常有用。在 Go 的 Gin 框架中,也有类似的 Header() 方法,但 Spring 的注解方式更声明式。

4. 实践建议与常见陷阱

基于以上内容,这里给出几点实践建议:

  • 优先使用 @RestController:在前后端分离项目中,几乎不需要返回视图,直接返回 JSON 即可。
  • 路径规范:静态资源路径统一加 /,避免因路径解析不一致导致 404。
  • 明确 Content-Type:当返回对象时,确保依赖注入 Jackson 依赖,否则会报错。
  • 状态码语义:不要滥用 200,应根据业务结果返回合适的 4xx/5xx 状态码。

如果你正在学习 Spring MVC,建议结合一个简单的登录或计算器案例来练习,这样能更快掌握响应处理的精髓。

[AFFILIATE_SLOT_1]

5. 总结

本文详细介绍了 Spring MVC 中返回静态页面的两种方式、@RestController / @Controller / @ResponseBody 的区别与用法,以及如何定制响应数据的 Content-Type、状态码和 Header。核心要点是:注解决定返回值语义,API 控制响应细节。掌握这些,你就能灵活应对各种前后端交互场景。

最后,如果你觉得文章有帮助,欢迎点赞评论。下一篇将带来 Spring MVC 综合案例:计算器与登录功能实现,敬请期待!

[AFFILIATE_SLOT_2]