Spring MVC HttpMessageConverter<T>

SpringMVC 处理 JSON

由于现在我们使用 Ajax 的机会非常多,所以我们有必要来看一下 SpringMVC 是如何处理 JSON 格式的数据的。

我们先来看一个处理 JSON 的程序,再来分析它其中的原理

创建 Employee 实体类

package com.bupt.springmvc.converter.entity;

import javax.validation.constraints.Past;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.format.annotation.DateTimeFormat;

public class Employee
{
    private Integer id;

    @NotEmpty
    private String lastName;

    @Email
    private String email;

  //生成 getter 和 setter 方法,生成带参和不带参的构造方法,重写 toString
}

创建 EmployeeDao 类

package com.bupt.springmvc.converter.Dao;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.springframework.stereotype.Repository;

import com.bupt.springmvc.converter.entity.Employee;

@Repository
public class EmployeeDao
{
    private static Map<Integer, Employee> employees = null;

    static
    {
        employees = new HashMap<Integer, Employee>();

        employees.put(1001, new Employee(1001, "E-AA", "[email protected]"));
        employees.put(1002, new Employee(1002, "E-BB", "[email protected]"));
        employees.put(1003, new Employee(1003, "E-CC", "[email protected]"));
        employees.put(1004, new Employee(1004, "E-DD", "[email protected]"));
        employees.put(1005, new Employee(1005, "E-EE", "[email protected]"));
    }

    public Collection<Employee> getAll()
    {
        return employees.values();
    }
}

配置spring配置文件 springmvc.xml

    <!-- 配置自动扫描的包 -->
    <context:component-scan base-package="com.bupt.springmvc.converter"></context:component-scan>

    <!-- 配置视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/views/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>

    <mvc:default-servlet-handler/>

    <mvc:annotation-driven></mvc:annotation-driven>

编写 index.jsp 页面

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Insert title here</title>
<script type="text/javascript" src="script/jquery-1.9.1.min.js"></script>
<%-- 点击链接触发弹窗,将返回信息显示在弹窗上 --%><script type="text/javascript">
    $(function(){
        $("#testJson").click(function(){
            var url = this.href;
            var args = {};
            $.post(url, args, function(data){
                for(var i = 0; i < data.length; i++)
                {
                    var id = data[i].id;
                    var lastName = data[i].lastName;

                    alert(id + ": " + lastName);
                }
            });
            return false;
        });
    })
</script>
</head>
<body>
    <a href="testJson" id="testJson">Test JSON</a>
</body>
</html>

想要让 Spring 处理 JSON,我们需要几步来完成

1. 首先我们需要导入依赖包:jackson-annotations.jar;jackson-core.jar;jackson-databind.jar

2. 编写目标方法,使其返回 JSON 对应的对象或集合

3. 在方法上添加 @ResponseBody 注解(作用后面会讲)

package com.bupt.springmvc.converter.handler;

import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.bupt.springmvc.converter.Dao.EmployeeDao;
import com.bupt.springmvc.converter.entity.Employee;

@Controller
public class ConverterHandler
{
    @Autowired
    private EmployeeDao employeeDao;

    @ResponseBody
    @RequestMapping("/testJson")
    public Collection<Employee> testJson()
    {
        return employeeDao.getAll();
    }
}

启动 tomcat,访问 index.jsp,点击超链接,弹窗跳出。同时查看返回信息为如图所示的 JSON 格式数据

如此,我们的响应返回的数据格式就是以 JSON 格式返回的。

那这整个过程是怎么完成的呢? HttpMessageConverter<T> 这个接口是整个过程中最为重要的一个环节

HttpMessageConverter<T> 是 SpringMVC 3.0 新增的一个接口,负责将请求信息转换为一个对象(类型为T),将对象(类型为T)输出为响应信息。

HttpMessageConverter<T> 接口定义的方法:

1. Boolean canRead(Class<?> clazz, MediaType mediaType):指定转换器可以读取的对象类型,即转换器是否可将请求信息转换为 clazz 类型的对象,同时指定支持 MIME 类型(text/html, application/json等)

2. Boolean canWrite(Class<?> clazz, MediaType mediaType):指定转换器是否将clazz类型的对象写到响应流中,响应流支持的媒体类型在 MediaType 中定义

3. List<MediaType getSupportMediaType>():该转换器支持的媒体类型

4. T read(Class<? entends T> clazz, HttpInputMessage inputMessage):将请求信息流(inputMessage)转换为 T 类型的对象

5. void write(T t, MediaType contentType, HttpOutputMessage outputMeaasge):将 T 类型的对象写到响应流(outputMeaasge)中,同时指定相应的媒体类型为 contentType

它整个在请求响应中的作用可以用下图来表示

其中 HttpInputMessage 和 HttpOutputMessage 是两个继承于 HttpMessage 的接口,它们都只包含一个方法

InputStream getBody() throws IOExcpetion;

OutputStream getBody() throws IOExcpetion;

HttpMessageConverter<T> 有很多的实现类,下面列出一部分

实现类 功能说明
StringHttpMessageConverter 将请求信息转换成字符串
FormHttpMessageConverter 将表单数据读取到MultiValueMap中          
XmlAwareFormHttpMessageConverter 扩展于 FormHttpMessageConverter,如果部分表单属性是XML数据,可用数据转换器进行读取
ResourceHttpMessageConverter 读取org.springframework.core.io.Resource对象
BufferedImageHttpMessageConverter 读取BufferedImage对象
ByteArrayHttpMessageConverter 读取二进制数据
SourceHttpMessageConverter 读取 javax.xml.transform.Source类型的数据
MarshallingHttpMessageConverter 通过Spring 的 org.springframework.xml.Marshaller 与 Unmarshaller 读取 XML 消息
Jaxb2RootElementHttpMessageConverter 通过 JAXB2 读写 XML 消息,将请求信息转换到标准XmlRootElement 和 XxmlType 直接的类中
MappingJacksonHttpMessageConverter 利用 Jackson 开源包 ObjectMapper 读写 JSON 数据
RssChannelHttpMessageConverter 能够读写 RSS 种子消息

那么 SpringMVC 搭载了哪些实现类呢?

DispatcherServlet 默认装配 RequestMappingHandlerAdapter,而 RequestMappingHandlerAdapter 默认装配如下 HttpMessageConverter

加入 jackson 开源包后,RequestMappingHandlerAdapter 装配的 HttpMessageConverter 如下,处理JSON的Converter就绑定到我们的 SpringMVC 中去了

HttpMessageConverter<T> 到底干了些什么?以及如何确定使用哪种 HttpMessageConverter<T> 的实现类呢

使用 HttpMessageConverter<T> 将请求信息转化并绑定到处理方法的入参中或将响应结果转为对应类型的响应信息,Spring 提供了两种途径:

1. 使用 @RequestBody/@ResponseBody 对处理方法进行标注

2. 使用 HttpEntity<T>/ResponseEntity<T> 作为处理方法的入参或返回值

当控制器处理方法使用到 @RequestBody/@ResponseBody 或 HttpEntity<T>/ResponseEntity<T> 时,Spring 首先根据请求头或响应的 Accept 属性选择匹配的 HttpMessageConverter,进而根据参数类型或泛型类型的过滤得到匹配的 HttpMessageConverter,若找不到可用的 HttpMessageConverter 将报错

其中,@RequestBody/@ReponseBody 不需要成对出现

如何指定返回类型是 JSON

具体可以表述为,当使用 @ReponseBody 修饰时是根据其方法返回值确定具体对应的 converter

    //返回值为 String 类型,使用的 converter 为 ByteArrayHttpMessageConverter
    @ResponseBody
    @RequestMapping("/handler")
    public byte[] handler()

当使用 @RequestBody 修饰时根据的是 入参类型

    //入参类型为 String 类型,使用的 converter 为 StringHttpMessageConverter
    @RequestMapping(value="/handler", method=RequestMethod.POST)
    public String handler(@RequestBody String requestBody)

通过一个文件上传的例子来看一下 @RequestBody/@ReponseBody 的使用

在处理方法类中添加处理方法

    @ResponseBody
    @RequestMapping("/testHttpMessageConverter")
    public String testHttpMessageConverter(@RequestBody String body)
    {
        System.out.println(body);
        return "Time: " + new Date();
    }

在 index.jsp 添加文件上传表单

    <form action="testHttpMessageConverter" method="POST" enctype="multipart/form-data">
        File: <input type="file" name="file"/>
        Desc: <input type="text" name="desc"/><br>
        <input type="submit" value="submit"/>
    </form>

我上传的.txt文件中只有一句话:Write the code Change the world,DESC填写的内容为 ABCD

启动服务器,点击上传文件,控制台和页面输出内容如图

注:此方法不能用于真正的文件上传,因为它将表单内容和文件内容都混为 String 类型,解析时不能区分两者。SpringMVC 中使用的文件上传会在文章最后介绍。

通过一个文件下载的例子来看一下 ResponseEntity<T> 如何使用

WebContext下新建文件夹,内置一个名为 abc.txt 的文件

方法类中新增方法

    @RequestMapping("/testResponseEntity")
    public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException
    {
        byte[] body = null;
        ServletContext servletContext = session.getServletContext();
        InputStream in = servletContext.getResourceAsStream("/files/abc.txt");
        body = new byte[in.available()];
        in.read(body);

        HttpHeaders headers = new HttpHeaders();
        headers.add("Content-Disposition", "attachment;filename=abc.txt");
        HttpStatus statusCode = HttpStatus.OK;

        ResponseEntity<byte[]> response = new ResponseEntity<byte[]>(body, headers, statusCode);
        return response;
    }

index.jsp 新增请求连接

<a href="testResponseEntity">Test ResponseEntity</a>

启动服务器点击链接时,即会弹出下载提示框

文件上传

SpringMVC 为文件上传提供了直接的支持,这种支持是通过即插即用的 MultipartResolver 实现的。Spring 用 Jakarta Commons FileUpload 技术实现了一个 MultipartResolver 实现类:CommonsMultipartResolver。

SpringMVC 上下文中默认没有装配 MultipartResolver,因为默认情况下不能处理文件的上传工作,如果想使用 Spring 的文件上传功能,需要在上下文中配置 MultipartResolver。配置之前我们需要导入 commons-fileupload.jar 和 commons-io.jar 两个jar包

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 请求编码格式,默认为ISO-8859-1 -->
        <property name="defaultEncoding" value="utf-8"/>
        <!-- 上传文件大小上限,单位为字节(1M) -->
        <property name="maxUploadSize" value="1024000"/>
        <!-- 上传文件的临时路径 -->
        <property name="uploadTempDir" value="upload/temp"/>
    </bean>

defaultEncoding 必须和用户 JSP 的 pageEncoding 属性一致,以便正确读取表单的内容。iploadTempDir 是文件上传过程中使用的临时目录,文件上传完成后,临时目录中的临时文件会被自动清除。

SpringMVC 会将上传的文件绑定到 MultipartFile 对象中。MultipartFile 提供了获取上传文件内容、文件名等内容,通过其 transferTo(File dest) 方法还可将文件存储到硬件上

在方法处理器类中编写相应的处理方法

    @RequestMapping("/testFileUpload")
    public String testFileUpload(@RequestParam("desc") String desc, @RequestParam("file") MultipartFile file) throws IOException
    {
        System.out.println("desc: " + desc);
        System.out.println("OriginalFilename: " + file.getOriginalFilename());
        System.out.println("InputStream: " + file.getInputStream());
        file.transferTo(new File("D:/abcd.txt"));
        return "success";
    }

编写 index.jsp 和 success.jsp 页面

    <form action="testFileUpload" method="post" enctype="multipart/form-data">
        File: <input type="file" name="file"/><br>
        Desc: <input type="text" name="desc"><br>
        <input type="submit" value="submit">
    </form>
<body>
    <h4>SUCCESS PAGE</h4>
</body>

选择上传的文件为 test.txt,DESC 填写内容为 ABCD,控制台打印的结果为

查看D盘下的找到dbcd.txt,可以看到其内容与上传文件内容一致。

MultipartFile 中的一些方法说明:

byte[] getBytes():获取文件数据

String getContentType():获取文件 MIME 类型,如image/pjpeg、text/plain等

InputStream getInputStream():获取文件流

String getName():获取表单中文件组件的名字

String getOriginalFileName():获取上传文件的原名

long getSize():获取文件的字节大小,单位为 byte

boolean isEmpty():是否有上传的文件

void transferTo(File dest):可以使用该方法将上传文件保存到一个目标文件中

时间: 2024-10-10 16:37:14

Spring MVC HttpMessageConverter<T>的相关文章

spring mvc -- HttpMessageConverter、DispatcherServlet、[email&#160;protected] @respondBody

When RESTful Web Service is developed using Spring MVC, the application is configured as given below. Among these, implementation is necessary for the portion marked with red frame. Sr. No. Process layer Description (1) Spring MVC (Framework) Spring

Spring MVC 简述:从MVC框架普遍关注的问题说起

任何一个完备的MVC框架都需要解决Web开发过程中的一些共性的问题,比如请求的收集与分发.数据前后台流转与转换,当前最流行的SpringMVC和Struts2也不例外.本文首先概述MVC模式的分层思想与MVC框架普遍关注的问题,并以此为契机结合SpringMVC的入门级案例简要地从原理.架构角度介绍了它对这些问题的处理,包括请求处理流程.消息转换机制和数据绑定机制等核心问题.最后,本文对目前最为流行的两个MVC框架SpringMVC 和 一. MVC 模式与框架 1.MVC 模式 Java We

Spring 4 官方文档学习(十一)Web MVC 框架之配置Spring MVC

在前面的文档中讲解了Spring MVC的特殊beans,以及DispatcherServlet使用的默认实现.在本部分,你会学习两种额外的方式来配置Spring MVC.分别是:MVC Java config 和  MVC XML namespace. 原文: Section 22.2.1, "Special Bean Types In the WebApplicationContext" and Section 22.2.2, "Default DispatcherSer

Spring MVC一些配置信息解析

springMVC框架请求响应步骤 第一步:发起请求到前端控制器(DispatcherServlet) 第二步:前端控制器请求HandlerMapping查找Handler 可以根据xml配置.注解进行查找 第三步:处理器映射器HandlerMapping向前端控制器返回Handler 第四步:前端控制器调用处理器适配器(HandlerAdapter)去执行Handler 第五步:处理器适配器去处理Handler 第六步:Handler处理完给适配器返回ModelAndView 第七步:处理器适

Spring MVC 4常用的那些注解

Spring从2.5版本开始在编程中引入注解,用户可以使用@RequestMapping, @RequestParam, @ModelAttribute等等这样类似的注解.到目前为止,Spring的版本虽然发生了很大的变化,但注解的特性却是一直延续下来,并不断扩展,让广大的开发人员的双手变的更轻松起来,这都离不开Annotation的强大作用,今天我们就一起来看看Spring MVC 4中常用的那些注解吧. 1. @Controller Controller控制器是通过服务接口定义的提供访问应用

Spring MVC中基于注解的 Controller

终于来到了基于注解的 Spring MVC 了.之前我们所讲到的 handler,需要根据 url 并通过 HandlerMapping 来映射出相应的 handler 并调用相应的方法以响应请求.实际上,ControllerClassNameHandlerMapping, MultiActionController 和选择恰当的 methodNameResolver(如 InternalPathMethodNameResolver) 就已经可以在很大程度上帮助我们省去不少的 XML 配置,谁让

从content-type设置看Spring MVC处理header的一个坑

我们经常需要在HttpResponse中设置一些headers,我们使用Spring MVC框架的时候我们如何给Response设置Header呢? Sooooooooooooo easy, 看下面的代码: @RequestMapping(value = "/rulelist", method = RequestMethod.GET) @ResponseBody public String getRuleList(HttpServletRequest request, HttpServ

Spring mvc 原理浅析

2.2. 数据的绑定 前面说过了,SpringMVC是方法级的映射,那么Spring是如何处理方法签名的,又是如何将表单数据绑定到方法参数中的?下面我们就来讨论这个问题.2.2.1. 处理方法签名 首先,我们可以在方法签名中放入@CookieValue注解参数,Spring自动将Cookie值绑定到参数中:同理@RequestHeader可 以绑定报文头的属性值:同时我们还可以将Servlet API如HttpServletRequest.HttpServletResponse.HttpSess

Spring MVC常用的注解类

一.注解类配置 要使用springmvc的注解类,需要在springmvc.xml配置文件中用context:component-scan/扫描: ? 二.五大重要的注解类 1.RequestMapping注解 RequestMapping注解类的使用方法 在Controller控制器类的类定义和方法定义处都可以标注@RequestMapping注解 DispatcherServlet截获请求后,就可以通过控制器上的@RequestMapping提供的映射信息确定请求所对应的处理方法 packa