spring-mvc 系列:HttpMessageConverter(@RequestBody、RequestEntity、@ResponseBody、@RestController、ResponseEntity、文件上传下载)

发布时间 2023-08-09 00:22:43作者: IT技术派

HttpMessageConverter,报文信息转换器,将请求报文转换为Java对象,或将Java对象转换为响应报文

HttpMessageConverter提供了两个注解和两个类型:@RequestBody,@ResponseBody,RequestEntity,ResponseEntity

一、@RequestBody

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

html

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

java

package com.mcode.api.controller;

import com.mcode.api.bean.User;
import org.springframework.http.RequestEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * ClassName: HttpController
 * Package: com.mcode.api.controller
 * Description:
 *
 * @Author robin
 * @Create 2023/8/8 21:58
 * @Version 1.0
 */

@Controller
public class HttpController {
    @RequestMapping(value = "/testRequestBody")
    public String testRequestBody(@RequestBody String requestBody) {
        System.out.println("requestBody:" + requestBody);
        return "success";
    }
}

输出结果:

image

二、RequestEntity

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

html

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

java

package com.mcode.api.controller;

import com.mcode.api.bean.User;
import org.springframework.http.RequestEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * ClassName: HttpController
 * Package: com.mcode.api.controller
 * Description:
 *
 * @Author robin
 * @Create 2023/8/8 21:58
 * @Version 1.0
 */

@Controller
public class HttpController {
    @RequestMapping(value = "/testRequestBody")
    public String testRequestBody(@RequestBody String requestBody) {
        System.out.println("requestBody:" + requestBody);
        return "success";
    }

    @RequestMapping("/testRequestEntity")
    public  String testRequestEntity(RequestEntity<String> requestEntity) {
        System.out.println("requestHeader:" + requestEntity.getHeaders());
        System.out.println("requestBody:" + requestEntity.getBody());
        return  "success";
    }
}

输出结果:

image

三、@ResponseBody

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

html

<a th:href="@{/testResponseBody}">测试testResponseBody</a>

java

produces = "text/html;charset=UTF-8" 设置返回数据的类型以及编码

package com.mcode.api.controller;

import com.mcode.api.bean.User;
import org.springframework.http.RequestEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * ClassName: HttpController
 * Package: com.mcode.api.controller
 * Description:
 *
 * @Author robin
 * @Create 2023/8/8 21:58
 * @Version 1.0
 */

@Controller
public class HttpController {
    @RequestMapping(value = "/testRequestBody")
    public String testRequestBody(@RequestBody String requestBody) {
        System.out.println("requestBody:" + requestBody);
        return "success";
    }

    @RequestMapping("/testRequestEntity")
    public  String testRequestEntity(RequestEntity<String> requestEntity) {
        System.out.println("requestHeader:" + requestEntity.getHeaders());
        System.out.println("requestBody:" + requestEntity.getBody());
        return  "success";
    }


    @RequestMapping(value = "/testResponseBody",produces = "text/html;charset=UTF-8")
    @ResponseBody
    public String testResponseBody(){
        return  "成功";
    }
}

四、SpringMVC处理json

@ResponseBody处理json的步骤:

a>导入jackson-databind依赖

        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.15.2</version>
        </dependency>

b>在SpringMVC的核心配置文件中开启mvc的注解驱动,此时在HandlerAdaptor中会自动装配一个消息转换器:MappingJackson2HttpMessageConverter,可以将响应到浏览器的Java对象转换为Json格式的字符串

    <!-- 开启MVC注解驱动 -->
    <mvc:annotation-driven/>

c>在处理器方法上使用@ResponseBody注解进行标识

    @RequestMapping("/testResponseBodyJSON")
    @ResponseBody
    public User testResponseBodyJSON(){
        return new User(1,"张三","123456");
    }

d>将Java对象直接作为控制器方法的返回值返回,就会自动转换为Json格式的字符串

输出结果:

image

五、@RestController

@RestController注解是springMVC提供的一个复合注解,标识在控制器的类上,就相当于为类添加了@Controller注解,并且为其中的每个方法添加了@ResponseBody注解

image

六、ResponseEntity

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

七、文件上传和下载

1、文件下载

使用ResponseEntity实现下载文件的功能

html

<a th:href="@{/testDown}">下载1.jpg</a><br>

java

package com.mcode.api.controller;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

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

/**
 * ClassName: FileUpAndDownController
 * Package: com.mcode.api.controller
 * Description:
 *
 * @Author robin
 * @Create 2023/8/8 22:58
 * @Version 1.0
 */
@RestController
public class FileUpAndDownController {

    /**
     * 测试下载
     * @param session
     * @return
     * @throws IOException
     */
     @RequestMapping("/testDown")
     public ResponseEntity<byte[]> testDown(HttpSession session) throws IOException {
         //获取ServletContext对象
         ServletContext servletContext = session.getServletContext();
         //获取服务器中文件的真实路径
         String realPath = servletContext.getRealPath("/static/img/1.jpg");
         System.out.println(realPath);
         //创建输入流
         InputStream is = new FileInputStream(realPath);
         //创建字节数组
         byte[] bytes = new byte[is.available()];
         //将流读到字节数组中
         is.read(bytes);
         //创建HttpHeaders对象设置响应头信息
         MultiValueMap<String, String> headers = new HttpHeaders();
         //设置要下载方式以及下载文件的名字
         headers.add("Content-Disposition", "attachment;filename=1.jpg");
         //设置响应状态码
         HttpStatus statusCode = HttpStatus.OK;
         //创建ResponseEntity对象
         ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, headers, statusCode);
         //关闭输入流
         is.close();
         return responseEntity;
     }

}

2、文件下载

文件上传要求form表单的请求方式必须为post,并且添加属性enctype="multipart/form-data"

SpringMVC中将上传的文件封装到MultipartFile对象中,通过此对象可以获取文件相关信息

上传步骤:

a>添加依赖:

        <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.5</version>
        </dependency>

b>在SpringMVC的配置文件中添加配置:

必须配置id

<!--必须通过文件解析器的解析才能将文件转换为MultipartFile对象-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>

c>控制器方法:

package com.mcode.api.controller;

import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

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

/**
 * ClassName: FileUpAndDownController
 * Package: com.mcode.api.controller
 * Description:
 *
 * @Author robin
 * @Create 2023/8/8 22:58
 * @Version 1.0
 */
@RestController
public class FileUpAndDownController {

    /**
     *  上传文件
     * @param file
     * @param session
     * @return
     * @throws IOException
     */
    @RequestMapping("/testUp")
     public String testUp(MultipartFile file,HttpSession session) throws IOException{
         //获取上传的文件的文件名
         String fileName = file.getOriginalFilename();
         //获取上传的文件的后缀名
         String suffixName = fileName.substring(fileName.lastIndexOf("."));
         //将UUID作为文件名
         String uuid = UUID.randomUUID().toString().replaceAll("-", "");
         //将uuid和后缀名拼接后的结果作为最终的文件名
         fileName = uuid + suffixName;
         //通过ServletContext获取服务器中upload目录的路径
         ServletContext servletContext = session.getServletContext();
         String realPath = servletContext.getRealPath("/upload");
         File upFilePath = new File(realPath);
         //判断upFilePath所对应路径是否存在
         if(!upFilePath.exists()){
             //若不存在,则创建目录
             upFilePath.mkdirs();
         }
         String finalPath = realPath + File.separator + fileName;

         //上传文件
         file.transferTo(new File(finalPath));

         return  fileName;
     }
}

d>html:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>测试上传和下载</title>
</head>
<body>
<a th:href="@{/testDown}">下载1.jpg</a><br>
<form th:action="@{/testUp}" method="post" enctype="multipart/form-data">
    头像:<input type="file" name="file"><br>
    <input type="submit" value="上传">
</form>
</body>
</html>

注:必须在SpringMVC的配置文件中添加CommonsMultipartResolver的bean中配置Id,否则报错

image

八、全部代码

image

pom.xml

<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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mcode.api</groupId>
    <artifactId>java-spring-mvc-demo03</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <!--SpringMVC-->
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.29</version>
        </dependency>

        <!--日志-->
        <!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.4.8</version>
            <scope>test</scope>
        </dependency>
        <!--ServletAPI-->
        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
        <!--Spring5和Thymeleaf整合包-->
        <!-- https://mvnrepository.com/artifact/org.thymeleaf/thymeleaf-spring5 -->
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
            <version>3.0.15.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.15.2</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.5</version>
        </dependency>


    </dependencies>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    
    
    <build>
        <finalName>java-spring-mvc-demo03</finalName>

    </build>
</project>

web.xml

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >


<web-app>
    
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <filter>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>HiddenHttpMethodFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

spring-mvc.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.mcode.api.controller"/>

    <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>

    <!-- 接地跳转到目标页面 -->
    <mvc:view-controller path="/" view-name="index"/>
    <mvc:view-controller path="/file" view-name="file"/>
    <!-- 静态资源处理器 -->
    <mvc:default-servlet-handler/>

    <!-- 开启MVC注解驱动 -->
    <mvc:annotation-driven/>

    <!-- 文件上传 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean> 


</beans>