HttpMessageConverter

HttpMessageConverter,报文转换器,即将请求报文转换为Java对象或者将Java对象转换为响应报文。

请求报文转换为Java对象Java对象转换为响应报文
@RequestBody@ResponseBody
RequestEntityResponseEntity
  • @RequestBody,将请求体转换为Java对象。注意哈,如果请求报文中没有请求体,会报错:“Required request body is missing”
  • RequestEntity,将整个请求报文转换为Java对象。完整的请求报文,包含请求行、请求头和请求体。
  • @ResponseBody,用来标注控制器方法,控制器方法返回给浏览器的响应报文的Content-Type为application/json。
  • ResponseEntity,用来表示控制器方法返回值的类型,适用场景:文件的上传和下载。
@RequestBody和RequestEntity
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Home</title>
</head>
<body>
    <button onclick="testRequestBody()">测试@RequestBody</button><br/>
    <button onclick="testRequestEntity()">测试RequestEntity</button>
    <script th:src="@{/static/js/axios.min.js}"></script>
    <script th:inline="javascript">
        //获取上下文路径
        var contextPath = /*[[@{/}]]*/'';

        function testRequestBody(){
            axios({
                method:"post",
                url:contextPath+"testRequestBody",
                data:{
                    "username":"admin",
                    "password":"123456"
                }
            })
        }

        function testRequestEntity(){
            axios({
                method:"post",
                url:contextPath+"testRequestEntity",
                data:{
                    "username":"admin",
                    "password":"123456"
                }
            })
        }
    </script>
</body>
</html>
package com.example.mvc.controller;

import com.example.mvc.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.RequestMethod;

@Controller
public class TestController{
    @RequestMapping(value = "/testRequestBody",method = RequestMethod.POST)
    public String testRequestBody(@RequestBody User user){
        System.out.println(user);
        System.out.println(user.getUsername()+","+user.getPassword());
        return "success";
    }

    @RequestMapping(value = "/testRequestEntity",method = RequestMethod.POST)
    public String testRequestEntity(RequestEntity requestEntity){
        System.out.println("url="+requestEntity.getUrl());
        System.out.println("method="+requestEntity.getMethod());
        System.out.println("headers="+requestEntity.getHeaders());
        System.out.println("body"+requestEntity.getBody());
        return "success";
    }
}

启动应用,分别点击测试@RequestBody测试RequestEntity,idea控制台依次打印出如下信息:

14:56:08.127 [http-nio-8080-exec-5] DEBUG org.springframework.web.servlet.DispatcherServlet - POST "/demo6/testRequestBody", parameters={}
14:56:08.128 [http-nio-8080-exec-5] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped to com.example.mvc.controller.TestController#testRequestBody(User)
14:56:08.227 [http-nio-8080-exec-5] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor - Read "application/json;charset=UTF-8" to [User(id=null, username=admin, password=123456)]
User(id=null, username=admin, password=123456)
admin,123456
14:56:15.205 [http-nio-8080-exec-6] DEBUG org.springframework.web.servlet.DispatcherServlet - POST "/demo6/testRequestEntity", parameters={}
14:56:15.205 [http-nio-8080-exec-6] DEBUG org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping - Mapped to com.example.mvc.controller.TestController#testRequestEntity(RequestEntity)
14:56:15.217 [http-nio-8080-exec-6] DEBUG org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor - Read "application/json;charset=UTF-8" to [{username=admin, password=123456}]
url=http://localhost:8080/demo6/testRequestEntity
method=POST
headers=[host:"localhost:8080", connection:"keep-alive", content-length:"40", sec-ch-ua:"" Not A;Brand";v="99", "Chromium";v="96", "Google Chrome";v="96"", accept:"application/json, text/plain, */*", sec-ch-ua-mobile:"?0", user-agent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36", sec-ch-ua-platform:""Windows"", origin:"http://localhost:8080", sec-fetch-site:"same-origin", sec-fetch-mode:"cors", sec-fetch-dest:"empty", referer:"http://localhost:8080/demo6/", accept-encoding:"gzip, deflate, br", accept-language:"zh-CN,zh;q=0.9,en;q=0.8", cookie:"Idea-ac70e2ce=07de2674-103f-44e4-baab-b1bd358ffa55", Content-Type:"application/json;charset=UTF-8"]
body{username=admin, password=123456}
@ResponseBody和@RestController

@ResponseBody用来标注控制器方法,该控制器方法的返回值作为响应报文返回给浏览器。
举个例子,来比较下 使用了@ResponseBody标注控制器方法 和 没有使用@ResponseBody标注控制器方法 时,返回给浏览器的响应报文有什么区别。

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Home</title>
</head>
<body>
    <button onclick="testRequestBody()">没有用@ResponseBody标注控制器方法</button><br/>
    <button onclick="testResponseBody()">使用了@ResponseBody标注控制器方法</button><br/>
    <script th:src="@{/static/js/axios.min.js}"></script>
    <script th:inline="javascript">
        //获取上下文路径
        var contextPath = /*[[@{/}]]*/'';

        function testRequestBody(){
            axios({
                method:"post",
                url:contextPath+"testRequestBody",
                data:{
                    "username":"admin",
                    "password":"123456"
                }
            })
        }
        function testResponseBody(){
            axios({
                method:"post",
                url:contextPath+"testResponseBody",
                data:{
                    "username":"admin",
                    "password":"123456"
                }
            })
        }

    </script>
</body>
</html>
package com.example.mvc.controller;

import com.example.mvc.bean.User;
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.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class TestController{
    @RequestMapping(value = "/testRequestBody",method = RequestMethod.POST)
    public String testRequestBody(@RequestBody User user){
        System.out.println(user);
        System.out.println(user.getUsername()+","+user.getPassword());
        return "success";
    }
    @RequestMapping(value = "/testResponseBody",method = RequestMethod.POST)
    @ResponseBody
    public String testResponseBody(@RequestBody User user){
        System.out.println(user);
        System.out.println(user.getUsername()+","+user.getPassword());
        return "success";
    }
}

在这里插入图片描述

在这里插入图片描述
可以明显的看到,
没有用@ResponseBody标识的控制器方法,返回给浏览器的响应报文的Content-Type是text/html
使用了@ResponseBody标识的控制器方法,返回给浏览器的响应报文的Content-Type是application/json

RestFul接口返回的一般都是json数据,要想控制器方法返回的Java对象以json数据格式的形式响应给浏览器,必须

  1. 添加依赖jackson-databind
<dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-databind</artifactId>
   <version>2.13.0</version>
</dependency>
  1. 开启注解驱动
<mvc:annotation-driven/>
  1. 控制器方法添加@ResponseBody注解
  2. 控制器方法的返回值是一个Java对象

看个具体实例就更好理解了。

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Home</title>
</head>
<body>
    <a th:href="@{/testJson}">测试json</a><br/>
    <button onclick="testAxios()">测试axios</button>

    <script th:src="@{/static/js/axios.min.js}"></script>
    <script th:inline="javascript">
        //获取上下文路径
        var contextPath = /*[[@{/}]]*/'';

        function testAxios(){
            axios({
                method:"post",
                url:contextPath+"/testAxios",
                data:{
                    "username":"admin",
                    "password":"123456"
                }
            }).then(function(resp){
                console.log(resp);
                console.log(resp.data);
            })
        }
    </script>
</body>
</html>
package com.example.mvc.controller;

import com.example.mvc.bean.User;
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.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class TestController {
    @RequestMapping(value = "/testJson", method = RequestMethod.GET)
    @ResponseBody
    public User testJson() {
        User user = new User(1, "admin", "123456");
        return user;
    }

    @RequestMapping(value = "/testAxios", method = RequestMethod.POST)
    @ResponseBody
    public User testAxios(@RequestBody User user) {
        User newUser = new User(2, user.getUsername(), user.getPassword());
        return newUser;
    }
}

在这里插入图片描述

@RestController是SpringMVC提供的一个复合注解,相当于@Controller+@ResponseBody。
@RestController标注在某个类上,相当于

  1. @Controlller标注了这个类;
  2. @ResponseBody标注了这个类中的所有方法。
ResponseEntity
下载文件

在webapp目录下新建目录static,并在static下新建子目录img用于存放静态图片,比如1.png。

<!-- index.html -->
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Home</title>
</head>
<body>
    <a th:href="@{/download}">下载图片</a>
</body>
</html>
package com.example.mvc.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 org.springframework.web.bind.annotation.RequestMethod;

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

@Controller
public class TestController {
    @RequestMapping(value = "/download",method = RequestMethod.GET)
    public ResponseEntity<byte[]> download(HttpSession session) throws IOException {
        ServletContext context = session.getServletContext();

        //获取文件部署在服务器上的真实路径
        String realPath = context.getRealPath("/static/img/1.png");

        //创建输入流
        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.png");
        //设置响应状态码
        HttpStatus statusCode = HttpStatus.OK;
        //创建ResponseEntity对象
        ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes,headers,statusCode);

        //关闭流
        is.close();
        return responseEntity;
    }
}

在这里插入图片描述

上传文件

首先,pom.xml中添加文件上传需要的依赖:common-fileupload。

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
</dependency>

然后,在springMVC.xml中配置文件上传解析器,该解析器将上传的文件封装为MultipartFile类型。

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>

最后,就是修改html和java代码。

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Home</title>
</head>
<body>
    <a th:href="@{/download}">下载图片</a>
    <form th:action="@{/upload}" method="post" enctype="multipart/form-data">
        头像:<input type="file" name="photo" /><br/>
        <input type="submit" />
    </form>
</body>
</html>
package com.example.mvc.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 org.springframework.web.bind.annotation.RequestMethod;
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;

@Controller
public class TestController {
    @RequestMapping(value = "/download",method = RequestMethod.GET)
    public ResponseEntity<byte[]> download(HttpSession session) throws IOException {
        ServletContext context = session.getServletContext();

        //获取文件部署在服务器上的真实路径
        String realPath = context.getRealPath("/static/img/1.png");

        //创建输入流
        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.png");
        //设置响应状态码
        HttpStatus statusCode = HttpStatus.OK;
        //创建ResponseEntity对象
        ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes,headers,statusCode);

        //关闭流
        is.close();

        return responseEntity;
    }

    @RequestMapping("/upload")
    public String upload(MultipartFile photo,HttpSession httpSession) throws IOException {
//        System.out.println(photo.getName());
//        System.out.println(photo.getOriginalFilename());
        String filename = photo.getOriginalFilename();
        ServletContext servletContext = httpSession.getServletContext();
        String photoPath = servletContext.getRealPath("photo");
        File file = new File(photoPath);
        //判断photoPath所对应的路径是否存在
        if(!file.exists()){
            //若不存在,则创建目录
            file.mkdir();
        }
        String finalPath = photoPath + File.separator + filename;
        photo.transferTo(new File(finalPath));
        return "success";
    }
}

在这里插入图片描述
解决文件上传重名问题:上传后的文件不再使用原来的名字,使用uuid和后缀拼接得到新的文件名。

@RequestMapping("/upload")
public String upload(MultipartFile photo,HttpSession httpSession) throws IOException {
//        System.out.println(photo.getName());
//        System.out.println(photo.getOriginalFilename());
    //获取上传的文件的文件名
    String filename = photo.getOriginalFilename();
    //获取上传的文件的后缀名
    String suffixname = filename.substring(filename.lastIndexOf("."));
    //使用uuid作为文件名
    String uuid = UUID.randomUUID().toString();
    //将uuid和后缀名拼接作为最终的文件名
    filename = uuid + suffixname;
    ServletContext servletContext = httpSession.getServletContext();
    String photoPath = servletContext.getRealPath("photo");
    File file = new File(photoPath);
    //判断photoPath所对应的路径是否存在
    if(!file.exists()){
        //若不存在,则创建目录
        file.mkdir();
    }
    String finalPath = photoPath + File.separator + filename;
    photo.transferTo(new File(finalPath));
    return "success";
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值