HttpMessageConverter详解

  • Post author:
  • Post category:其他




七、HttpMessageConverter详解

HttpMessageConverter,报文信息转换器。

作用:

1、将请求报文转化为java对象

2、将java对象转化为响应报文

HttpMessageConverter提供了两个注解和两个类供我们使用:@RequestBody、@ResponseBody;RequestEntity、ResponseEntity。

下面就让我们详细来学学吧。

首先,新建一个Moodle,然后修改pom.xml内容如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>rest_mvc</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <packaging>war</packaging>

    <dependencies>
        <!--SpringMVC-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.9</version>
        </dependency>

        <!--ServletAPI-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <!--Spring5和Thymeleaf整合包-->
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
            <version>3.0.12.RELEASE</version>
        </dependency>
    </dependencies>

</project>

然后写我们的springMVC.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       https://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!--扫描组件-->
    <context:component-scan base-package="com.example"/>

    <!--配置Thymeleaf视图解析器(针对h5文件,抄就完了)-->
    <bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
        <property name="order" value="1"/>
        <property name="characterEncoding" value="UTF-8"/>
        <property name="templateEngine">
            <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
                <property name="templateResolver">
                    <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
                        <!--视图前缀-->
                        <property name="prefix" value="/WEB-INF/templates/"/>
                        <!--视图后缀-->
                        <property name="suffix" value=".html"/>
                        <property name="templateMode" value="HTML5"/>
                        <property name="characterEncoding" value="UTF-8"/>
                    </bean>
                </property>
            </bean>
        </property>
    </bean>

    <!--
        处理静态资源,如html、js、css、jpg
        若只设置该标签,则只访问静态资源,其他请求无法访问
        此时必须设置<mvc:annotation-driven/>解决问题
    -->
    <mvc:default-servlet-handler/>

    <!--开启mvc注解驱动-->
    <mvc:annotation-driven>
        <mvc:message-converters>
            <!--处理响应中文乱码问题-->
            <bean class="org.springframework.http.converter.StringHttpMessageConverter">
                <property name="defaultCharset" value="UTF-8"/>
                <property name="supportedMediaTypes">
                    <list>
                        <value>text/html</value>
                        <value>application/json</value>
                    </list>
                </property>
            </bean>
        </mvc:message-converters>
    </mvc:annotation-driven>
</beans>



7.1 @RequestBody注解

@RequestBody可以获取请求体,需要在控制器方法设置一个形参,使用@RequestBody进行标识,当前请求的请求体就会为当前注解所标识的形参赋值。

直接给代码演示吧:

先写我们的首页index.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
    <h1>首页</h1>
    <form th:action="@{/testRequestBody}" method="post">
      <input type="text" name="username"><br>
      <input type="password" name="password"><br>
      <input type="submit" value="提交"><br>
    </form>
</body>
</html>

然后写一个成功后跳转的页面success.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>成功</title>
</head>
<body>
  <h1>操作成功!!!</h1>
</body>
</html>

最后写我们的控制器方法:

package com.example.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class HttpController {

    @GetMapping("/")
    public String toIndex(){
        return "index";
    }

    @PostMapping("/testRequestBody")
    public ModelAndView testRequestBody(ModelAndView modelAndView, @RequestBody String requestBody){
        System.out.println("requestBody:"+requestBody);
        modelAndView.setViewName("success");
        return modelAndView;
    }
}

启动服务器:

在这里插入图片描述

点击提交成功跳转到success页面,然后后台输出:

在这里插入图片描述



7.2 RequestEntity类

RequestEntity类是封装请求报文的一种类型,需要在控制器方法的形参中设置该类型的形参,当前请求的请求报文就会赋值给该形参,可以通过getHeaders()方法获取请求头信息,用getBody()获取请求体信息。

废话不多说,直接贴代码:

先修改index页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
    <h1>首页</h1>
    <h2>测试requestBody</h2>
    <form th:action="@{/testRequestBody}" method="post">
      <input type="text" name="username"><br>
      <input type="password" name="password"><br>
      <input type="submit" value="提交"><br>
    </form>
    
    <h2>测试requestEntity</h2>
    <form th:action="@{/testRequestEntity}" method="post">
        <input type="text" name="username2"><br>
        <input type="password" name="password2"><br>
        <input type="submit" value="提交"><br>
    </form>
</body>
</html>

然后添加控制器方法:

    @PostMapping("/testRequestEntity")
    public ModelAndView testRequestEntity(ModelAndView modelAndView, RequestEntity<String> requestEntity){
        System.out.println("request-head:"+requestEntity.getHeaders());
        System.out.println("request-body:"+requestEntity.getBody());
        modelAndView.setViewName("success");
        return modelAndView;
    }

输入:

在这里插入图片描述

输出结果:(请求头很长很长)

在这里插入图片描述

请求头输出如下:

request-head:[host:“localhost:8080”, connection:“keep-alive”, content-length:“34”, cache-control:“max-age=0”, sec-ch-ua:”“Google Chrome”;v=“93”, ” Not;A Brand”;v=“99”, “Chromium”;v=“93″”, sec-ch-ua-mobile:”?0″, upgrade-insecure-requests:“1”, origin:“http://localhost:8080”, user-agent:“Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4542.2 Safari/537.36”, accept:“text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,

/

;q=0.8,application/signed-exchange;v=b3;q=0.9”, sec-fetch-site:“same-origin”, sec-fetch-mode:“navigate”, sec-fetch-user:”?1″, sec-fetch-dest:“document”, referer:“http://localhost:8080/httpMsg/”, accept-encoding:“gzip, deflate, br”, accept-language:“zh-CN,zh;q=0.9”, Content-Type:“application/x-www-form-urlencoded;charset=UTF-8”]



7.3 @ResponseBody注解

@ResponseBody注解用于标识一个控制器方法,可以将该方法的返回值直接作为响应报文的响应体响应浏览器。



7.3.1 @ResponseBody注解返回字符串

为了让人容易理解,这里给一个返回字符串形式的例子。

先写Controller方法

    @RequestMapping("/testResponseBody")
    @ResponseBody
    public String testResponseBody(){
        return "success";
    }

然后在index页面,写一个跳转的超链接:

    <h2>测试ResponseBody传字符串</h2>
    <a th:href="@{/testResponseBody}">测试ResponseBody传字符串</a><br>

重启服务器。

在这里插入图片描述

我们知道,如果没加@ResponseBody注解,我们应该跳转到success.html页面,但是,当加了ResponseBody注解后,显示的确实:

在这里插入图片描述

这是因为,我们设置了ResponseBody注解之后,返回值就不再被拦截后加什么前后缀了,而是作为响应报文响应给服务器。

此时就相当于在之前JavaWeb中,在servlet中写了方法:

    public void testResponseBody(HttpServletResponse response) throws IOException {
        response.getWriter().write("success");
    }



7.3.2 @ResponseBody注解返回JSON字符串对象

我们的@ResponseBody注解的方法返回的值我们已经知道会作为响应报文了。但是,我们一般更多的是用来返回一个JSON对象,充当接口也好,充当别的也罢,返回更多的还是对象。

下面,就直接用代码演示啦。

先导入我们JSON的依赖:

        <!--JSON数据绑定-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.12.3</version>
        </dependency>

然后写我们的User类:

package com.example.po;

public class User {
    private Integer id;
    private String username;
    private String password;
    private Integer age;
    private String sex;

    public User() {
    }

    public User(Integer id, String username, String password, Integer age, String sex) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.age = age;
        this.sex = sex;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}

然后写控制器方法:

    @RequestMapping("/testResponseUser")
    @ResponseBody
    public User testResponseUser(){
        return new User(1001,"Keeling","10086",18,"男");
    }

最后在首页写超链接:

    <h2>测试ResponseBody传JSON对象</h2>
    <a th:href="@{/testResponseUser}">测试ResponseBody传JSON对象</a><br>

重启服务器:

在这里插入图片描述

这个其实就是一个JSON字符串,我们导入的JSON的包帮我们把我们的User对象转化为JSON字符串类型,然后作为响应报文返回给浏览器。

在这里插入图片描述

总结一下@ResponseBody处理JSON步骤如下:

  1. 导入jackson依赖
  2. 在SpringMVC配置文件中添加

    <mvc:annotation-driven />
  3. 在处理器上使用@ResponseBody注解
  4. 直接在控制器方法中返回我们自己的类对象



7.4 使用ajax获取响应报文

首先添加jquery文件:

在这里插入图片描述

在首页引入jquery,然后加个超链接(写别的,例如按钮其实也可以):

    <h2>测试Ajax接收ResponseBody传输的JSON对象</h2>
    <a id="ReceiveAjax" th:href="@{/}">测试Ajax接收ResponseBody传输的JSON对象</a><br>
	<script type="text/javascript" th:src="@{/}+'/static/js/jquery-3.6.0.js'"></script>
    <script type="text/javascript">
        $(function () {
            $("#ReceiveAjax").click(function (event){
                $.ajax({
                    url:"http://localhost:8080/httpMsg/testResponseUser",
                    data:"",
                    success:function (data){
                        console.log(data)
                    }
                });
                event.preventDefault();
            })
        })
    </script>

重启服务器:

点击按钮就可以获取刚才的JSON对象响应报文信息。

想要获取他的id值,username值,只需要在success回调函数中用data.id、data.username获取即可。

在这里插入图片描述



7.5 @RestController注解

以后会很重要,很常用的一个注解——@RestController。这个注解是SpringMVC提供的一个复合注解,标识在控制器的类上,相当于为这个类添加@Controller注解,并且为这个类中所有的方法添加@ResponseBody注解。



7.6 ResponseEntity类

ResponseEntity用于控制器方法的返回值类型,该控制器方法的返回值就是响应到服务器的响应报文。



7.6.1 ResponseEntity实现文件下载

首先我们把我们要下载的图片放到这里:

在这里插入图片描述

直接贴代码吧。

先写一个Controller类:

FileUpAndDownController.java

package com.example.controller;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpSession;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

@Controller
public class FileUpAndDownController {

    @RequestMapping("/file")
    public String toFile(){
        return "file";
    }

    @RequestMapping("/testDownload")
    public ResponseEntity<byte[]> testDownload(HttpSession session) throws IOException {
        /*获取ServletContext对象*/
        ServletContext context = session.getServletContext();
        /*获取服务器中文件的真实路径*/
        String path = context.getRealPath("/static/img/cat.jpg");
        /*创建输入流*/
        InputStream inputStream = new FileInputStream(path);
        /*创建字节数组*/
        byte[] buffer = new byte[inputStream.available()];
        /*将流读取到字节数组中*/
        inputStream.read(buffer);
        /*创建HttpHeaders对象设置响应头信息*/
        MultiValueMap<String, String> headers = new HttpHeaders();
        /*设置下载的方式和文件名*/
        headers.add("Content-Disposition", "attachment;filename=hello.jpg");
        /*设置响应状态码*/
        HttpStatus status = HttpStatus.OK;
        /*创建ResponseEntity对象*/
        ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(buffer,headers,status);
        /*关闭输入流*/
        inputStream.close();
        return responseEntity;
    }
}

然后写一个file.html文件:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>文件的下载和上传</title>
</head>
<body>
    <h2>测试文件下载</h2>
    <a th:href="@{/testDownload}">点击下载cat.jsp</a><br>
</body>
</html>

重启服务器后

在这里插入图片描述

下载成功。

在这里插入图片描述

简单介绍一下,一个从服务器下载文件的程序,一般只需要修改下面两处即可。

在这里插入图片描述



7.7 SpringMVC实现文件上传

要实现上传功能,首先,我们需要添加这个jar包:

        <!--文件上传-->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.4</version>
        </dependency>

然后我们配置我们的SpringMVC配置文件,添加下面这个Bean:

    <!--配置文件上传解析器,将上传的文件封装为MultipartFile-->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>

之后在我们的file.html文件中添加如下内容

    <h2>测试文件上传</h2>
    <!--
        enctype="multipart/form-data"表示通过二进制形式传输
        只有这样,服务器才能成功接收文件
    -->
    <form th:action="@{/testUpload}" method="post" enctype="multipart/form-data">
        图片:<input type="file" name="photo"><br>
        <input type="submit" value="提交">
    </form>

然后写我们的控制器方法:

    /**
     *  SpringMVC将我们当前上传的文件封装到MultipartFile中
     *  然后使用该对象的transferTo方法实现上传即可
     */
    @RequestMapping("/testUpload")
    public ModelAndView testUpload(MultipartFile photo, HttpSession session, ModelAndView modelAndView) throws IOException {
        /*获取上传的文件名*/
        String name = photo.getOriginalFilename();
        /*获取上传文件的后缀名*/
        String suffix = name.substring(name.lastIndexOf("."));
        /*将UUID作为文件名*/
        String uuid = UUID.randomUUID().toString();
        //将uuid和后缀名拼接后成为最终的文件名
        name = uuid + suffix;
        /*获取服务器中upload目录的路径*/
        ServletContext context = session.getServletContext();
        String photoPath = context.getRealPath("upload");
        /*判断photoPath所对应路径是否存在*/
        File file = new File(photoPath);
        //不存在创建目录
        if (!file.exists()){
            file.mkdir();
        }
        /*
            设置上传后的文件路径(包括文件名)
            File.separator表示的是文件的分隔符
        */
        String filePath = photoPath + File.separator + name;
        /*将该文件上传到服务器*/
        photo.transferTo(new File(filePath));
        modelAndView.setViewName("success");
        return modelAndView;
    }

重启服务器:

选择自己本地的图片进行上传,我这里传了三四张

在这里插入图片描述

然后我们到target目录下,可以看到:

在这里插入图片描述



版权声明:本文为weixin_44741023原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。