一、返回JSON
-
加入Jar包:
-
编写目标方法,使其返回 JSON 对应的对象或集合,并在在方法上添加 @ResponseBody 注解。具体代码如下:
/** * 返回 JSON 对应的对象或集合 */ @ResponseBody @RequestMapping("/testJackson") public User testJackson() { return new User(100, "aa", "abc123", true, 1001.2, new Date(), "[email protected]"); }
@ResponseBody 表示该方法的返回结果直接写入 HTTP response body 中,一般在异步获取数据时使用(也就是AJAX),在使用 @RequestMapping后,返回值通常解析为跳转路径,但是加上 @ResponseBody 后返回结果不会被解析为跳转路径,而是直接写入 HTTP response body 中。 比如异步获取 json 数据,加上 @ResponseBody 后,会直接返回 json 数据。
-
运行结果如下所示:
JSON数据如下所示:
二、运行原理
在返回JSON的示例中,JSON的返回与HttpMessageConverter<T>接口相关。该接口是 Spring3.0 新添加的一个接口,负责将请求信息转换为一个对象(类型为 T),将对象(类型为 T)输出为响应信息。具体的过程如下图所示:
我们在页面点击请求时,HttpInpyutMessage类会将请求报文转为输入流并由HttpMessageConverter的子类转换器转换为Java对象,然后在由SpringMVC进行处理后会将Java对象通过HttpMessageConverter的子类转换器转换输入流,并生成响应报文。
三、HttpMessageConverter接口
接口方法
HttpMessageConverter<T>接口定义的方法:
- Boolean canRead(Class<?> clazz,MediaType mediaType): 指定转换器可以读取的对象类型,即转换器是否可将请求信息转换为 clazz 类型的对象,同时指定支持 MIME 类型(text/html,applaiction/json等)
- Boolean canWrite(Class<?> clazz,MediaType mediaType):指定转换器是否可将 clazz 类型的对象写到响应流中,响应流支持的媒体类型在MediaType 中定义。
- LIst<MediaType> getSupportMediaTypes():该转换器支持的媒体类型。
- T read(Class<? extends T> clazz,HttpInputMessage inputMessage):将请求信息流转换为 T 类型的对象。
- void write(T t,MediaType contnetType,HttpOutputMessgae outputMessage):将T类型的对象写到响应流中,同时指定相应的媒体类型为 contentType。
接口实现类
HttpMessageConverter有如下的实现类。
DispatcherServlet 默认装配RequestMappingHandlerAdapter ,而RequestMappingHandlerAdapter 默认装配如下HttpMessageConverter:
在加入 jackson jar 包后, RequestMappingHandlerAdapter装配的 HttpMessageConverter 如下:
上述返回JSON的示例,其底层使用的则是HttpMessageConverter的子类MappingJackson2HttpMessageConverter转化器处理的。
四、模拟文件上传
1.在请求页面编写如下代码:
<!-- 模拟文件上传 -->
<!--
enctype 属性规定在发送到服务器之前应该如何对表单数据进行编码。
默认地,表单数据会编码为 "application/x-www-form-urlencoded"。
就是说,在发送到服务器之前,所有字符都会进行编码(空格转换为 "+" 加号,
特殊符号转换为 ASCII HEX 值)。
multipart/form-dat:不对字符编码。在使用包含文件上传控件的表单时,必须使用该值。
-->
<form action="testHttpMessageConverter" method="POST" enctype="multipart/form-data">
File:<input type="file" name="file"/>
Desc:<input type="text" name="desc"/>
<input type="submit"value="Submit"/>
</form>
2.在控制器类中编写如下目标方法,对请求进行处理:
/**
* 模拟数据上传
*/
@ResponseBody
@RequestMapping("/testHttpMessageConverter")
public String testHttpMessageConverter(@RequestBody String requestBody) {
System.out.println(requestBody);
return "Success!";
}
注意: @RequestBody是作用在形参列表上,用于将前台发送过来固定格式的数据通过系统默认配置的 HttpMessageConverter进行解析(这里是HttpMessageConverter的子类StringHttpMessageConverter),然后封装到入参requestBody上。
3.需要在MVC文件中配置<mvc:annotation-driven /> ,<mvc:annotation-driven /> 会自动注册RequestMappingHandlerMapping、RequestMappingHandlerAdapter 与ExceptionHandlerExceptionResolver 三个bean。正如前面所提到的RequestMappingHandlerAdapter默认装配了HttpMessageConverter。
4.当在页面选择要上传的文件并输入描述文本并点击提交后,服务器端会打印如下数据并将"Success!"文本返回给客户端并显示在页面上。
使用 HttpMessageConverter<T> 将请求信息转化并绑定到处理方法的入参中或将响应结果转为对应类型的响应信息,Spring 提供了两种途径:
- @RequestBody / @ResponseBody 对处理方法进行标注。(上面示例使用的)
- 使用 HttpEntity<T> / ResponseEntity<T> 作为处理方法的入参或返回值。(下面的文件下载示例)
注意:@RequestBody 和 @ResponseBody 不一定要成对出现。
五、文件下载
1.首先需要在请求页面编写文件下载请求链接代码:
<!-- 模拟文件下载 -->
<a href="testResponseEntity">Test ResponseEntity</a>
2.接着在控制器类中编写如下目标方法,对请求进行处理:
/**
* 模拟数据下载
* @throws IOException
*/
@RequestMapping("/testResponseEntity")
public ResponseEntity<byte[]> testResponseEntity(HttpSession session) throws IOException {
byte[] body = null;
ServletContext servletContext = session.getServletContext();
//读取WebContent下的files/demo.txt并将文件数据读取流中
InputStream in = servletContext.getResourceAsStream("/files/demo.txt");
body = new byte[in.available()];
in.read(body);
//设置文件下载响应头
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "attachment;filename=demo.txt");
//设置状态码
HttpStatus statusCode = HttpStatus.OK;
//ResponseEntity设置响应头和状态码,并封装文件数据返回
ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(body, headers, statusCode);
return responseEntity;
}
3.在MVC文件中配置<mvc:annotation-driven />后即可点击链接进行文件的下载了。
提示:当控制器处理方法使用到 @RequestBody/@ResponseBody 或HttpEntity<T>/ResponseEntity<T> 时, Spring 首先根据请求头或响应头的Accept 属性选择匹配的 HttpMessageConverter, 进而根据参数类型或泛型类型的过滤得到匹配的HttpMessageConverter, 若找不到可用的HttpMessageConverter 将报错。