springMVC03-报文信息转换器:HttpMessageConverter
HttpMessageConverter报文信息转换器(请求:@RequestBody、RequestEntity;响应:servletAPI响应、@ResponseBody、ResponseEntity【文件的上传和下载】、@RestController),json回顾,axios简介
一、HttpMessageConverter
HttpMessageConverter:报文信息转换器,是 SpringMVC 的一个 接口(策略模式),用于:
-
将请求体(request body)转换为 Java 对象(反序列化)
-
将 Java 对象转换为响应体(response body)(序列化)
简单理解它就是:处理请求/响应体的“翻译器”。
| 场景 | HttpMessageConverter 做的事 | 举例 |
|---|---|---|
| 请求时(客户端 → 服务端) | 把 JSON/XML/文本 → Java 对象(反序列化) | 把 JSON 请求体转成 User 对象 |
| 响应时(服务端 → 客户端) | 把 Java 对象 → JSON/XML/文本(序列化) | 把 List<User> 转为 JSON 响应 |
HttpMessageConverter提供了两个注解和两个类型:
@RequestBody,@ResponseBody,RequestEntity, ResponseEntity。
RequestEntity:整个请求实体,可以是:请求头+请求体
1-1、@RequestBody —— 请求体转 Java 对象
示例1:
@PostMapping("/user")
public String addUser(@RequestBody String requestBody) {
// username=Tom&password=123456
System.out.println("requestBody:"+requestBody);
return "success";
}
【注意】:
1、此时的返回内容是:username=Tom&password=123456,但是若是形参直接用User对象,则会报错,应为:表单默认的提交方式是:application/x-www-form-urlencoded,而要从请求体中读取 JSON内容,需要提交方式是:'Content-Type': 'application/json'
2、虽然配置了<mvc:default-servlet-handler/>,使得项目可以直接访问静态资源html文件,但是,这个html页面是 直接被 Tomcat 的 DefaultServlet 加载的,并没有经过 SpringMVC,也就 不会处理 Thymeleaf 模板语法,比如:<form th:action="@{/testRequestBody}" method="post">,这里的
th:action不会生效,所以点击提交后,form 的action根本没正确生效!导致请求根本就没发到你想要的/testRequestBody,更别说进入 Controller 了!静态页面 vs 模板页面路径区别
放置目录 类型 是否能渲染 Thymeleaf /webapp/static/或/static/静态资源 ❌ 不会渲染 th:*标签/WEB-INF/templates/模板(推荐) ✅ 会渲染 Thymeleaf
示例2:
@PostMapping(value = "/history/save")
@ResponseBody
public Result<?> saveHistory(@RequestBody ChatHistoryVO chatHistoryVO) {
return chatService.saveHistory(chatHistoryVO);
}
1-2、RequestEntity—— 封装请求体 + 请求头等信息
RequestEntity 封装请求报文的一种类型,需要在控制器方法的形参中设置该类型的形参,当前请求的请求报文就会赋值给该形参,可以通过 getHeaders () 获取请求头信息,通过 getBody () 获取请求体信息。
@PostMapping("/data")
public String postData(RequestEntity<String> requestEntity) {
System.out.println("请求体内容:" + requestEntity.getBody());
System.out.println("请求头:" + requestEntity.getHeaders());
return "ok";
}
1-3、通过servletAPI响应浏览器数据
@RequestMapping("/testResponse")
public void testResponse(HttpServletResponse response) throws IOException {
response.getWriter().print("hello HttpServletResponse");
}
此时,页面会打印内容!
响应的响应体就是我们在浏览器中能看到的内容。
1-4、@ResponseBody —— Java 对象转响应体(直接输出)
示例1:返回文本数据
@RequestMapping("/testResponseBody")
@ResponseBody
public String testResponseBody(){
// 加上了@ResponseBody,这个返回的success123就是响应体
// 去掉@ResponseBody,这个返回的success123才是视图名称!
return "success123";
}
返回内容:

示例2:返回对象信息
@RequestMapping("/testResponseBody2")
@ResponseBody
public User testResponseBody2(){
return new User("admin123", "123", "admin");
}
【注意】:
此时,浏览器会报错,因为,浏览器并不知道我们的对象类型,所以,要转换成json格式,要导入jar包!
<!-- json依赖 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.12.1</version> </dependency>
返回信息:json格式的字符串!

本身浏览器能够接受的服务器的返回格式就是字符串!
在 SpringMVC 中,如果你用
@ResponseBody注解将 Java 对象 作为响应返回:
✔️ Spring 会自动使用 HttpMessageConverter(比如
MappingJackson2HttpMessageConverter)把这个 Java 对象转换成 JSON 字符串。✔️ 无论你用 表单提交、AJAX 请求、Axios 还是其他方式,只要浏览器收到了这个响应,它看到的就是 JSON 字符串。看得到但用不了。
❗但如果你想在浏览器中动态处理这个 JSON(比如展示到网页上某个
<div>里),你确实需要用 JavaScript 的 AJAX / fetch / Axios 等方式来发起请求并处理响应。
1、springMVC处理JSON
在 SpringMVC 的核心配置文件中开启 mvc 的注解驱动,此时在 HandlerAdaptor 中会自动装配一个消息转换器:MappingJackson2HttpMessageConverter,可以将响应到浏览器的 Java 对象转换为 Json 格式的字符串
<mvc:annotation-driven />
在处理器方法上使用 @ResponseBody 注解进行标识
将 Java 对象直接作为控制器方法的返回值返回,就会自动转换为 Json 格式的字符串。(不是走视图解析器)
1-5、@RestController 注解
@RestController 注解是 springMVC 提供的一个复合注解,标识在控制器的类上,就相当于为类添加了 @Controller 注解,并且为其中的每个方法添加了 @ResponseBody 注解。
因为@ResponseBody非常常用!
示例:
import org.springframework.web.bind.annotation.*;
@RestController
public class UserController {
// GET 请求:http://localhost:8080/user
@GetMapping("/user")
public User getUser() {
return new User("Alice", 25);
}
// POST 请求:接收 JSON 参数并返回
@PostMapping("/login")
public String login(@RequestBody User user) {
if ("admin".equals(user.getName()) && user.getAge() == 123) {
return "登录成功";
} else {
return "用户名或密码错误";
}
}
}
1-6、ResponseEntity
1、什么是 ResponseEntity?
ResponseEntity用于控制器方法的返回值类型,该控制器方法的返回值就是响应到浏览器的响应报文。
ResponseEntity<T> 是 Spring 提供的一个响应封装类,它可以让你:
-
指定响应体(body);
-
设置响应状态码(status);(可以是自定义状态码)
-
添加响应头(headers)。
一句话总结:
比
@ResponseBody更高级的响应返回方式,更灵活、更完整。
2、为什么用 ResponseEntity?
| 用法 | 是否能做到 |
|---|---|
| 返回一个对象作为 JSON | ✅ @ResponseBody、@RestController 都可以 |
| 返回 404、500 等状态码 | ❌ @ResponseBody 不方便 |
| 自定义响应头(如 Content-Type) | ❌ 不方便 |
| 完整控制 body + status + headers | ✅ ResponseEntity 轻松实现 |
示例:
@PostMapping("/login")
public ResponseEntity<String> login(@RequestBody User user) {
if ("admin".equals(user.getName()) && user.getAge() == 123) {
return ResponseEntity.ok("登录成功"); // 200
} else {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
.body("用户名或密码错误"); // 401
}
}
可以把
@RestController和ResponseEntity搭配使用
3、文件的下载
因为“文件下载需要设置响应头和状态码”,而 ResponseEntity 可以很方便做到这些,所以它在 文件下载场景中特别有用。
文件的上传和下载,本质就是文件的复制(客户端、服务器)!
示例:
<h1>ResponseEntity 实现文件的下载</h1>
<a th:href="@{/fileDown}">001.jpg文件下载</a>
@RequestMapping("/fileDown")
public ResponseEntity<byte[]> fileDown(HttpSession session) throws IOException {
// 获取servletContext对象
ServletContext servletContext = session.getServletContext();
// 获取服务器中文件的真实路径(当前项目部署到服务器中的真实路径)
String realPath = servletContext.getRealPath("/static/img/001.jpg");
System.out.println(realPath);
// 创建输入流
FileInputStream fileInputStream = new FileInputStream(realPath);
// 以文件的整个字节创建byte[]
byte[] bytes = new byte[fileInputStream.available()];
// 将流读到字节数组中
fileInputStream.read(bytes);
// 创建httpHeaders对象设置响应头信息
MultiValueMap<String, String> headers = new HttpHeaders();
// 除了filename的值,其余的内容固定!
// example.txt是下载的文件名
headers.add("Content-Disposition", "attachment; filename=example.jpg");
// 设置响应状态码
HttpStatus status = HttpStatus.OK;
ResponseEntity<byte[]> responseEntity = new ResponseEntity<byte[]>(bytes, headers, status);
// 关闭流
fileInputStream.close();
return responseEntity;
}
【备注】:输入,输出流
流类型 方法 用途 输入流 FileInputStream或ServletContext.getResourceAsStream()从磁盘或资源中读取文件内容 输出流 HttpServletResponse.getOutputStream()输出到客户端浏览器
站在内存的角度看,把资源读出来 / 写进去!
4、文件的上传:MultipartFile
上传时,通常用 MultipartFile 接收。
(1)、MultipartFile 是什么?
MultipartFile 是 Spring 提供的接口,用于处理前端上传的文件。
它代表 一个上传的文件,通常配合 <form enctype="multipart/form-data"> 使用。
在 Controller 中,只要你在方法参数里写上:
public String upload(@RequestParam("file") MultipartFile file)
SpringMVC 就会自动帮你把上传的文件封装成 MultipartFile 对象。
(2)、常用方法:
| 方法 | 说明 |
|---|---|
getName() |
获取字段名(表单中的 name) |
getOriginalFilename() |
获取上传时的原始文件名 |
getContentType() |
获取文件的 MIME 类型(如 image/png) |
getSize() |
获取文件大小(单位:字节) |
isEmpty() |
是否上传了文件 |
getBytes() |
获取文件内容,返回 byte[] |
getInputStream() |
获取文件内容的输入流 |
transferTo(File dest) |
保存文件到目标位置 |
(3)、多文件上传:MultipartFile[]
@PostMapping("/uploadMultiple")
public String uploadMultiple(@RequestParam("files") MultipartFile[] files) {
for (MultipartFile file : files) {
if (!file.isEmpty()) {
System.out.println("上传:" + file.getOriginalFilename());
// file.transferTo(...);
}
}
return "上传完成";
}
HTML 表单要这样写:
<form method="post" enctype="multipart/form-data" action="/uploadMultiple">
<input type="file" name="files" multiple>
<button type="submit">上传多个</button>
</form>
(4)、注意
| 问题 | 说明 |
|---|---|
前端表单中必须写 enctype="multipart/form-data" |
否则后端收不到文件 |
后端方法参数必须写 @RequestParam("file") |
参数名要和 input 的 name 匹配 |
| 文件太大上传失败 | 检查是否配置了上传文件大小限制,如 multipartResolver 设置 |
| 文件被覆盖 | 可自行重命名文件,比如:加时间戳、UUID |
【完整的步骤】:
步骤一:添加pom.xml依赖
<!-- 文件上传功能需要 Apache Commons FileUpload -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
步骤二:Spring 配置文件中启用 MultipartResolver(其实就是一个<bean>)
<!-- 处理文件上传的 Bean -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="5242880"/> <!-- 5MB -->
</bean>
【注意】:
id是固定的!
步骤三:编写前端代码:

步骤四:后台代码(用@RequestParam获取上传的文件)
@PostMapping("/fileUpload")
public String fileUpload(@RequestParam("photo") MultipartFile photo, HttpSession session) throws IOException {
String originalFilename = photo.getOriginalFilename();
ServletContext servletContext = session.getServletContext();
String realPath = servletContext.getRealPath("photo");
File file = new File(realPath);
if(!file.exists()){
file.mkdir();
}
// 不知道当前系统的文件地址分隔符是什么斜线,可以用:File.separator
String finalPath = realPath + File.separator + originalFilename;
// 文件上传
photo.transferTo(new File(finalPath));
return "success";
}
步骤五:使用UUID生成文件名

5、【补充】:servletContext.getRealPath
servletContext.getRealPath("xxxxx") 获取的是 Web 应用中,相对路径 "xxxxx" 对应的 绝对路径(在服务器文件系统中的路径)。
举个例子:假设你的 Web 应用部署在服务器的这个路径下:
/Users/wangsi/javaCode/my-webapp/
你的项目结构大概是这样:

当你启动 Web 服务器(如 Tomcat)后,ServletContext.getRealPath("photo") 返回的路径 就是部署后的实际文件系统路径,比如:
/Users/wangsi/javaCode/my-webapp/target/my-webapp/photo
(1)、关键点总结:
| 内容 | 含义 |
|---|---|
"photo" |
相对于 Web 根目录的路径 |
getRealPath("photo") |
返回 "photo" 文件夹在服务器硬盘上的绝对路径 |
| 返回类型 | String,如:/usr/local/tomcat/webapps/your-app/photo |
| 前提 | 这个路径必须真实存在,且应用必须是以 exploded(解压)方式部署。 |
(2)、注意事项:
-
打包成 WAR 部署到服务器时,如果是压缩包形式,
getRealPath()可能会返回null。 -
getRealPath()通常用于开发或调试环境,不推荐用于生产环境中的文件访问逻辑。
如需在生产环境读取资源文件,推荐用这种方式:
InputStream in = servletContext.getResourceAsStream("/photo/test.jpg");
它能在 WAR 包中读取资源,而不依赖于实际文件路径。
二、JSON回顾
JSON 是一种轻量级的数据交换格式,用于在不同系统(特别是前后端之间)传递结构化数据。
它的格式来源于 JavaScript,但如今已被几乎所有编程语言支持(包括 Java、Python、R 等)。
XML也是数据交换格式,但是由于生成的数据量比json大,而且解析较为困难,导致,json用的更多,xml更多是作为配置文件使用!
2-1、JSON 的基本语法结构
JSON 数据结构只有两种:
-
对象(Object):键值对集合,用花括号
{}表示。 -
数组(Array):值的有序集合,用方括号
[]表示。
1. JSON 对象(类似 Java 的 Map<String, Object>):
{
"name": "Alice",
"age": 25,
"isStudent": true
}
2. JSON 数组(类似 Java 的 List<Object>):
[
"apple",
"banana",
"cherry"
]
3. 更复杂的嵌套结构:
{
"person": {
"name": "Bob",
"contacts": ["bob@example.com", "123456"],
"address": {
"city": "Kuala Lumpur",
"postcode": "50000"
}
}
}
2-2、JSON 的数据类型(只有这几种)
| 类型 | 示例 |
|---|---|
| 字符串 | "hello" |
| 数字 | 42, 3.14 |
| 布尔值 | true, false |
| 空值 | null |
| 对象(Object) | { "key": "value" } |
| 数组(Array) | [1, 2, 3] |
2-3、JSON 的常见用途
| 场景 | 说明 |
|---|---|
| 前后端数据通信 | Web开发中,前端发送 JSON 给后端 |
| 配置文件 | 比如 .eslintrc.json, package.json 等 |
| 存储结构化数据(NoSQL) | MongoDB 就使用 JSON-like 的 BSON 格式 |
| API 响应格式(RESTful API) | 大部分接口返回 JSON 响应 |
2-4、Java 处理 JSON 示例
常用库:Jackson / Gson / org.json
// 用 Jackson 将对象转 JSON 字符串
ObjectMapper mapper = new ObjectMapper();
User user = new User("Alice", 25);
String json = mapper.writeValueAsString(user);
// 反序列化 JSON 字符串为 Java 对象
User parsed = mapper.readValue(json, User.class);
2-5、Python 处理 JSON 示例
import json
# Python 对象转 JSON 字符串
data = {"name": "Alice", "age": 25}
json_str = json.dumps(data)
# JSON 字符串转 Python 对象
parsed_data = json.loads(json_str)
2-6、注意事项
-
JSON 中 键必须是双引号包裹的字符串(不能省略)
{"name": "Tom"} ✅ {name: "Tom"} ❌ 错误 -
JSON 没有注释功能(不像 Java 里可以
// 注释)
三、AJAX讲解
3-1、什么是 AJAX?
AJAX(Asynchronous JavaScript and XML)是前端技术的一种组合,可以让网页在不刷新整个页面的情况下,与服务器交换数据并更新部分内容。
它的核心目标是:实现异步请求。
虽然名字里有 XML,但现在最常用的格式其实是 JSON。
3-2、为什么要用 AJAX?
1、没有 AJAX 时的传统流程:
-
用户点击一个按钮;
-
整个页面发送请求到服务器;
-
服务器返回一个完整的新页面;
-
页面刷新,重新加载。
2、用 AJAX 后:
-
用户点击按钮;
-
浏览器使用 JS 发送 AJAX 请求;
-
服务器返回数据(通常是 JSON);
-
用 JS 动态更新网页的一部分(不用刷新页面)!
3-3、AJAX 的核心组成
| 技术 | 说明 |
|---|---|
| JavaScript | 发起请求、处理响应 |
| XMLHttpRequest 或 Fetch API | 发起 HTTP 请求 |
| HTML DOM | 用于动态修改网页内容(不刷新) |
| JSON | 最常用的数据格式(也可用 XML) |
| 后端语言 | 处理请求返回数据(如 Java、Python) |
3-4、前端库封装了 AJAX
| 库/框架 | 示例 |
|---|---|
| jQuery | $.get("/api", callback) |
| Axios | axios.get("/api").then(res => {}) |
| Vue/React | fetch/axios 或封装好的 API |
axios是目前前端最热门的ajax请求库!
示例:
<h1>springMVC handle ajax request</h1>
<div id="app">
<a th:href="@{/testAxios}" @click="testAxios">springMVC handle ajax request</a>
<div id="result"></div>
</div>
<!-- 引入 Vue -->
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<!-- 引入 axios -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
new Vue({
el: '#app',
methods: {
testAxios: function (event) {
// 取消超链接的默认行为
event.preventDefault();
axios({
methods: 'post',
url: event.target.href,
params: {
username:'admin123',
password:'123456'
}
}).then(
function (response) {
//alert(response.data);
document.getElementById("result").innerText =
"role:" + response.data.role;
}
)
}
}
})
</script>
@RequestMapping("/testAxios")
@ResponseBody
public User testAxios(String username, String password){
System.out.println("username = " + username + ", password=" + password);
return new User("admin123", "123", "admin");
}更多推荐




所有评论(0)