HttpMessageConverter<T>工作原理:
HttpMessageConverter<T> 是 Spring3.0 新添加的一个接口,负责将请求信息转换为一个对象(类型为 T)并绑定到处理方法的入参中,或将对象(类型为T)输出为响应信息。对此SpringMVC提供了两种实现途径:
- 使用@RequestBody/@ResponseBody注解对处理方法进行标注。
使用HttpEntity<T>/ResponseEntity<T>作为处理方法的入参或返回值。
当控制器处理方法使用到@RequestBody/@ResponseBody 或者 HttpEntity<T>/ResponseEntity<T>时,Spring首先根据请求头或响应头的Accept属性选择匹配的HttpMessageConverter,进而根据参数类型或泛型类型的过滤得到匹配的HttpMessageConverter,若找不到可用的HttpMessageConverter将会报错。
下图展示了HttpMessageConverter<T>的工作原理:
DispatcherServlet默认装配了RequestMappingHandlerAdapter,我们查看Spring源码发现RequestMappingHandlerAdapter默认装配了如下的HttpMessageConverter:
HttpMessageConverter<T>使用示例
在开始介绍HttpMessageConverter<T>的用法之前,需要先导入jar包:
在导入以上jar包后,RequestMappingHandlerAdapter会自动额外装配一个HttpMessageConverter对象,用于在Java对象和JSON对象之间进行转换:
下面的三个示例分别展示了@ResponseBody、@RequestBody和ResponseEntity<T>的使用方法,HttpEntity<T>用法类似。
示例一:通过@RequestBody注解将目标方法返回的Java对象转为HttpOutputMessage,并在页面中通过AJAX获取:
jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>index jsp</title>
<script type="text/javascript"
src="${pageContext.request.contextPath }/scripts/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
$(function() {
$("#testJson").click(function() {
var url = $(this).attr("href");
var arg = {
"time" : new Date()
};
$.get(url, arg, function(data) {
for (var i = 0; i < data.length; i++)
alert(data[i].id + ":" + data[i].lastName);
});
return false;
});
})
</script>
</head>
<body>
<a href="testJson" id="testJson">Test Json</a>
</body>
</html>
controller:
@ResponseBody
@RequestMapping("/testJson")
public Collection<Employee> testJson(){
return employeeDao.getAll();
}
运行后浏览器会依次弹出“data[i].id + “:” + data[i].lastName”的提示信息:
…
示例二:通过@RequestBody注解实现实现文件上传的功能:
jsp:
<form action="testRequestBody" method="post" enctype="multipart/form-data">
File:<input type="file" name="file" />
Description:<input type="text" name="des" />
<input type="submit" value="Submit" />
</form>
controller:
@ResponseBody
@RequestMapping("/testRequestBody")
public String testRequestBody(@RequestBody String body){
System.out.println(body);
//return "helloworld!"+new Date()保证了方法执行完后不会匹配任何一个页面
return "helloworld!"+new Date();
}
运行程序,我们上传一个test.txt文件,其中存储了某一jsp页面的信息,并在Description中输入文本值“MY TEXT”:
提交之后,HttpMessageConverter会把上传的文件和文本值转换为一个String类型的对象,并在控制台输出:
而且浏览器上也显示了helloworld!+时间:
注意,如果在spring的配置文件中注册了CommonsMultipartResolver类型的bean实例,如下:
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
</bean>
那么@RequestBody就不能正常将上传的文件类型转换为String类型在控制台输出了,原因暂时我还不太清楚。
示例三:通过@ResponseEntity<T>实现文件下载的功能:
jsp:
<a href="testResponseEntity">Test ResponseEntity</a>
在根目录下的file目录下保存了示例二中的test.txt:
controller:
@ResponseBody
@RequestMapping("/testResponseEntity")
public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException{
byte[] body = null;
ServletContext context = session.getServletContext();
InputStream in = context.getResourceAsStream("/file/test.txt");
body = new byte[in.available()];
in.read(body);
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "attachment;filename=test.txt");
HttpStatus statusCode = HttpStatus.OK;
ResponseEntity<byte[]> entity = new ResponseEntity<byte[]>(body, headers, statusCode);
return entity;
}
运行程序,点击超链接Test ResponseEntity后发现可以正确下载test.txt文件。