Spring MVC:设置响应

news/2025/1/22 9:37:49/

目录

引言

1. 返回静态页面

1.1 Spring 默认扫描路径

1.2 @RestController

1.2.1 @Controller => 返回页面

1.2.2 @ResponseBody

2. 返回 HTML

2.1 @RequestMapping

2.1.1 produces(修改响应的 Content-Type)

 2.1.2 其他属性

3. 返回 JSON

4. 设置状态码

4.1 HttpServletResponse

5. 设置 Header 


引言

前面的几篇博文中, 介绍的都是和请求相关的内容, 通过 Spring 的方法来接收请求中相关信息.

本篇博客介绍响应相关的知识, 通过 Spring 来设置响应中的值, 向客户端返回设置好的响应.

1. 返回静态页面

我们首先使用 html 写一个前端页面, 再通过 Spring 方法, 将这个 html 页面作为响应的内容, 展示给用户.

显然, 方法返回的只是一个字符串, 并非 html 展示的页面.

如何将 html 页面返回给客户端呢?? 这需要修改 类注解.

若方法返回的是一个页面, 则需要将原来的类注解 @RestController 修改为 @Controller.

接下来, 对涉及到的几个注解逐个进行解释.

1.1 Spring 默认扫描路径

我们知道, 每一个路径, 都对应了一个方法. 当服务器收到客户端的请求时, Spring 就会根据请求中的资源路径, 寻找该路径对应的方法, 进而计算响应结果, 最后返回响应.

而 Spring 中有大量的方法存在, 包括使用 Maven 引入的第三方库, 都存在于 Spring 中. 若 Spring 要扫描所有的方法, 一个一个的去进行比对, 确定哪个是资源路径所对应的方法的话, 那工作量是巨大的.

因此, Spring 有一个默认扫描路径: 只扫描启动类所在的目录, 及其子目录.

若请求中资源路径对应的方法, 属于启动类所在目录或子目录时, 会被 Spring 扫描到:

而当请求中资源路径所对应的方法, 不属于启动类所在目录或子目录时, 则 Spring 不会扫描, 客户端就会显示错误:

因此, Spring 也当然不会扫描 Maven 中第三方库中的方法.

有了默认的扫描路径, 大大降低了 Spring 的工作量, 提升了开发效率.

1.2 @RestController

虽然 Spring 有默认的扫描路径, 但是当项目很大时, 这个路径下也是会有很多的方法存在的.

于是, 可以使用 @RestController 对类进行标记, Spring 只需扫描被 @RestController 标记的类.

因此, Spring 的扫描对象为: 默认扫描路径中的类 && 使用 @RestController 进行标记的类

当默认路径下的类没有使用 @RestController 进行标记时, 那么 Spring 也不会进行扫描, 进一步减少了 Spring 的工作量.

@RestController 的特性如下:

  1. 类注解. 只能对类进行使用
  2. 存活于运行阶段. (整个项目运行时, 都存在)
  3. 包含 @Controller 和 @ResponseBody

其中, @Controller 表示返回的是页面. @ResponseBody 表示返回的是数据.

@RestController 也表示返回的是数据.

由于 @RestController = @Controller + @ResponseBody, 因此, 左右两侧的注解效果相同:

1.2.1 @Controller => 返回页面

@Controller 是一个类注解(只能给类使用), 并且使用此注解标记类时, 表示该类中的所有方法(@ResponseBody 标记的方法除外, 见下文), 返回的均是页面.

因此, 我们将类的注释修改为 @Controller, 就可以返回静态页面了:

Spring 会以 resources.static 为该 html 文件的基准路径, 扫描指定路径下的 html 文件, 并返回该 html 构造的页面. 并且, html 文件的路径前要加上 /

不过, 现在后端已经基本不会返回页面了.

java">@RequestMapping("/resp")
@Controller // 表示类中的方法只能返回页面
public class RespController {@ResponseBody // 该方法可以返回数据@RequestMapping("/r1")public String returnPage() {// 返回页面时, 一定要加上 /return "/index.html";}
}

1.2.2 @ResponseBody

@ResponseBody 既是一个类注解, 也是一个方法注解, 表示返回的是数据.

当类注解为 @Controller 时, 类中的方法只能返回页面, 若此时我们想返回数据, 可以对方法使用 @ResponseBody 进行标记, 被标记的方法可以返回数据.

综上, @RestController, @Controller, @ResponseBody 的使用场景如下:

  1. 一个类中, 既有返回页面的方法, 也有返回数据的方法 ==> 使用 @Controller 对类标记, 对返回数据的方法使用 @ResponseBody 标记.
  2. 如果一个类中所有的方法, 返回的都是数据 ==> 使用 @RestController 或者 @Controller + @ResponseBody 对类标记
  3. 如果一个类中所有的方法, 返回的都是页面 ==> 使用 @Controller 对类标记
  4. 类必须有 @Controller 注解才能被 Spring 扫描到(@RestController 包含了 @Controller)

2. 返回 HTML

默认情况下, 响应中的 Content-Type 都是 test/html, 因此, 浏览器收到数据后, 都会按照 html 的格式来解析, 最终展示在页面上.

因此, 如果我们想要给客户端返回一个 HTML 片段, 那我们无需任何操作, 直接返回 HTML 代码即可.

java">// 返回 HTML 片段@ResponseBody@RequestMapping("/r3")public String returnHTML() {return "<h1>这是一个一级标题</h1>";}

2.1 @RequestMapping

@RequestMapping 是一个类注解, 也是一个方法注解, 既可以对类设置路径, 也可以对方法设置路径.

此外, @RequestMapping 还有一些属性.

2.1.1 produces(修改响应的 Content-Type)

但是, 如果我们想要把这个 HTML 代码, 当做一个普通的字符串去返回, 该怎么办呢?

显然, 我们将响应的 Content-Type 类型修改为纯文本格式即可, 即: test/plain

我们可以通过修改 @RequestMapping 中的 produces 属性, 来修改 Content-Type:

这样, 浏览器接收响应后, 就会将 Body 中的内容, 以纯文本的格式来解析, 而不是当做 HTML .

java">    // 返回纯文本@ResponseBody@RequestMapping(value = "/r4", produces = "text/plain") // 修改 Content-Type 为纯文本格式public String returnText() {// 当成普通字符串返回return "<h1>这是一个一级标题</h1>";}

 2.1.2 其他属性

@RequestMapping 中不仅有 produces 这一属性, 还有其他属性. 通过设置这些属性值, 可以对请求或者响应中的内容做出要求:

  1. method: 要求请求的方法必须是什么(如:GET, POST, ....), 否则不处理
  2. params: 要求请求中必须包含哪些参数, 否则不处理
  3. headers: 要求请求的 header 中必须包含哪些 header 信息, 否则不处理
  4. consumes: 要求请求的 Content-Type 必须是什么, 否则不处理
  5. produces: 设置响应的 Content-Type 


3. 返回 JSON

Spring 会根据返回数据的类型, 自动对 Content-Type 进行类型的转换.

上文提到, 当返回的数据是字符串时, 默认的 Content-Type 是 text/html; 若想改成其他类型, 还需要手动进行转换.

但是当我们返回的数据是一个对象时(自定义类对象, List 对象, Map 对象, ....), Spring 都会自动将这个对象序列化为 JSON 格式, 并自动将 Content-Type 转换为 application/json:

java">    // 返回 JSON@ResponseBody@RequestMapping("/r5")public UserInfo returnJson() {// 若返回的数据是一个对象// Spring 会自动将响应中的 Content-Type 转换为 JSON 格式return new UserInfo("dings", "aaa", 1);}

4. 设置状态码

4.1 HttpServletResponse

在后端的 Spring 项目中, 我们既可以通过 HttpServletRequest 来获取请求中的信息, 同样也可以通过 HttpServletResponse 来设置响应中的信息.

因此, 我们可以拿到 HttpServletResponse 对象, 进而通过 setStatus 方法修改响应中的状态码:

java">    // 设置状态码@ResponseBody@RequestMapping("/r6")public String setStatus(HttpServletResponse response) {// 手动将响应中的状态码设置为 404response.setStatus(404);return "设置状态码成功!!";}

注意: 状态码不影响页面的展示!!

不管状态码是什么, 都可以返回我们自定义的内容. 至于为什么有些网站的 404 页面是一些提示内容, 因为那个界面也是维护那个网站的程序员自己代码写的.

程序员当然也可以将 404 页面打扮的很漂亮!! 比如 bilibili:


5. 设置 Header 

后端可以设置响应中的 header, 通过 header 来向客户端传递一些信息.

仍然是通过 HttpServletResponse 设置响应中的 header:
(header 是以键值对的形式存储数据的)

java">    // 设置 header@ResponseBody@RequestMapping("/r7")public String setHeader(HttpServletResponse response) {response.setHeader("myHeader", "hahaha");return "设置 header 成功!!";}

END


http://www.ppmy.cn/news/1565188.html

相关文章

前端入门(html)

目录 一、HTML简介 1、网站 2、网页 3、网页的构成 4、什么是HTML 二、常用浏览器及其内核 1、浏览器 三、web标准 1、为什么需要web标准 2、web标准的构成 一、HTML简介 1、网站 网站是指在因特网上根据一定的规则&#xff0c;使用 HTML 等制作的用于展示特定内容相…

语言集成查询LINQ

定义&#xff1a;语言集成查询 (LINQ) 是一系列直接将查询功能集成到 C# 语言的技术统称&#xff08;用C#语言就能查询&#xff08;数据库&#xff09;等数据源的查询&#xff09; IEnumerable和List的区别&#xff1a;IEnumerable是一个接口&#xff0c;只能用来遍历里面的数…

.NET Core 中如何构建一个弹性HTTP 请求机制

1. 理解弹性 HTTP 请求机制 什么是弹性? 弹性是指系统在面对故障或异常情况时,能够保持或快速恢复到正常状态的能力。在 HTTP 请求的上下文中,弹性意味着当请求失败时,系统能够自动采取一系列措施(如重试、降级、断路等)来确保请求最终成功或优雅地处理失败。 为什么需…

2.C++的变量,输入,输出

C的变量&#xff0c;输入&#xff0c;输出 同其它编程语言一样&#xff0c;C程序要想与用户进行交互&#xff0c;必须有输出&#xff0c;输入&#xff0c;还有存储数据的变量。接下来我们一起来看看在C中如何进行输入输出&#xff0c;以及变量的存储吧。 输出 在编程业界有个…

HotSpot JVM中的两种模式

这里写自定义目录标题 **1. Client 模式****特点**&#xff1a;**优化目标**&#xff1a;**启动参数**&#xff1a; **2. Server 模式****特点**&#xff1a;**优化目标**&#xff1a;**启动参数**&#xff1a; **Client 模式 vs Server 模式&#xff1a;比较****3. 自动选择模…

基于Python django的音乐用户偏好分析及可视化系统设计与实现

1.1 论文背景 随着信息技术的快速发展&#xff0c;在线音乐服务已成为日常生活的重要组成部分。QQ音乐&#xff0c;凭借其创新的音乐推荐算法和独特的社交特性&#xff0c;成功在竞争激烈的市场中获得一席之地。该平台的歌单文化和评论文化不仅满足了用户自尊和自我实现的需求…

区块链 智能合约安全 | 回滚攻击

视频教程在我主页简介和专栏里 目录&#xff1a; 智能合约安全 回滚攻击 总结 智能合约安全 回滚攻击 回滚攻击的本质是”耍赖” 举一个简单的例子,两个人玩石头剪刀布,输了的给对方10块钱,现在A输了,A说这把不算,重来 放在Solidity中,require()函数会检测其中的条件是否满…

为什么数据库不应该使用外键

一、引言 当我们需要持久化地存储数据时&#xff0c;关系型数据库通常是首选。它不仅种类丰富、稳定&#xff0c;而且得到了广泛社区的支持。本文将探讨关系型数据库中的一个重要概念——外键&#xff08;Foreign Key&#xff09;。 二、外键的作用 在关系型数据库中&#xf…