返回JSON数据格式和HttpMessageConverter
返回JSON数据格式
现在的开发中,几乎都是前后端分离的形式,越来越多的请求使用Ajax的异步请求,而不再是传统的跳转,
使用Ajax异步请求之后,我们后端处理结果大多以JSON的形式进行响应,响应给前端,前端得到响应结果后,
进行处理和渲染。在SpringMVC中,使用JSON非常的简单,SpringMVC中可以将集合等数据自动的转换成JSON数据格式,当然我们需要加入JSON相关的jar包。
jackson-annotations-2.1.5.jar
jackson-core-2.1.5.jar
jackson-databind-2.1.5.jar
<%@ 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>Insert title here</title>
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.10.1.js"></script>
<script type="text/javascript">
$(function(){
$("#testJson").click(function(){
var url = $(this).attr("href");
$.post(url,function(data){
console.log(data);
})
return false;
});
});
</script>
</head>
<body>
<a id="testJson" href="${pageContext.request.contextPath }/testJson">testJson</a>
</body>
</html>
package com.wanbangee.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
//spring新的5版本有此注解@RestController,就是 @Controller + @ResponseBody两个注解的结合体
@Controller
public class HttpMessageController {
//表示此方法的返回值作为响应内容,而不是作为视图信息,以前返回的信息要么就是视图信息要么就是ModelAndView
@ResponseBody //表示将请求处理器目标方法的返回值,作为响应结果,响应到前端页面
@RequestMapping("testJson")
public String testJson() {
return "hello World";
}
}
或者用下面这个测试
package com.wanbangee.controller;
import java.util.List;
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.wanbangee.entrties.Emp;
import com.wanbangee.service.EmpService;
//spring新的5版本有此注解@RestController,就是 @Controller + @ResponseBody两个注解的结合体
@Controller
public class HttpMessageController {
@Autowired
private EmpService empService;
//表示此方法的返回值作为响应内容,而不是作为视图信息,以前返回的信息要么就是视图信息要么就是ModelAndView
@ResponseBody //表示将请求处理器目标方法的返回值,作为响应结果,响应到前端页面
@RequestMapping("/testJson")
public List<Emp> selectEmp(){
// List<Emp> emps = this.empService.selectAllEmp();
// return emps;
return this.empService.selectAllEmp();
}
}
传统方式:
package com.wanbangee.controller;
import java.io.PrintWriter;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.wanbangee.entrties.Emp;
import com.wanbangee.service.EmpService;
@Controller
public class HttpMessageController {
@Autowired
private EmpService empService;
@RequestMapping("testJson")
public void testJson(HttpServletResponse response) throws Exception {
response.setContentType("text/html;charset=utf-8");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
List<Emp> emps = this.empService.selectAllEmp();
out.print(emps);
out.close();
}
}
HttpMessageConverter原理
HttpMessageConverter是Spring3.0之后添加的一个新的接口,
负责将请求信息转换成一个对象,也负责将一个对象转换为响应信息。
流程:
HttpMessageConverter的使用
1. 使用HttpMessageConverter将请求信息转换并绑定到处理器目标方法的入参或者将响应结果转化为对应的类型响应信息,Spring提供了两种途径:
- 使用@RequestBody/@ResponseBody 对请求处理器目标方法进行注解
- 使用HttpEntity<T>/ResponseEntity<T>作为请求处理器目标方法的入参和返回值
2.当请求处理器方法出使用到@RequestBody/@ResponseBody或者HttpEntity<T>/ResponseEntity<T>的时候,SpringMVC首先根据请求头或者响应头的Accept属性选择匹配的HttpMessageConverter,进而根据参数类型或者泛型的类型的过滤得到匹配的HttpMessageConverter,如果找不到,则报错。
3.我们的@RequestBody/@ResponseBody 或HttpEntity<T>/ResponseEntity<T>不需要成对出现。
4.@RequestBody注解和目标方法入参为HttpEntity<T>效果一样,
@ResponseBody注解和目标方法返回值为ResponseEntity<T>效果一样。
5.@ResponseBody使用在方法上,@RequestBody使用在方法入参中
范例:使用ResponseEntity作为返回值,完成JSON数据的响应,和@ResponseBody注解的效果一样,
那么在开发中一般使用@ResponseBody注解方式
@Controller
public class HttpMessageController {
@Autowired
private EmpService empService;
//@ResponseBody //表示将请求处理器目标方法的返回值,作为响应结果,响应到前端页面
@RequestMapping("testJson")
public ResponseEntity<List<Emp>> testJson(){
List<Emp> emps = this.empService.selectAllEmp();//查询数据
ResponseEntity<List<Emp>> responseEntity = new ResponseEntity<>(emps,HttpStatus.OK);
//准备响应数据
return responseEntity;
}
}
读取文件的内容
范例:@RequestBody 使用,读取文件的内容(文件会乱码,中文图片都会乱码,英文不会乱码)
<form action="testRequestBody" method="post" enctype="multipart/form-data">
empName:<input type="text" name="empName">
empPic:<input type="file" name="empPic">//提交文件要封装,提交文件用postman测试接口测不了
<input type="submit" value="Submit">
</form>
使用@RequestBody注解:
@ResponseBody
@RequestMapping("testRequestBody")
public List<Emp> testRequestBody(@RequestBody String string) {
System.out.println(string);
List<Emp> emps = this.empService.selectAllEmp();
return emps;
//return "Hello World";//返回前端页面信息
//不用List<Emp> emps = this.empService.selectAllEmp(); return emps;也行
}
目标方法入参为HttpEntity<T>的方式:
@ResponseBody
@RequestMapping("testRequestBody")
public List<Emp> testRequestBody(HttpEntity<String> string) {
System.out.println(string);
List<Emp> emps = this.empService.selectAllEmp();
return emps;
}
文件下载
文件下载建议使用原生代码下载,即下面的下载方式1,它的执行效率更高。
框架和原生开发代码量差不多的情况下用原生开发,框架主要是节省代码量,底层还是原生开发,
框架开发很绕,绕来绕去没有原生开发直接方便。
<a href="${pageContext.request.contextPath }/downLoad">downLoad</a>
在WebContent目录下new 个file文件夹用于存放图片
//下载方式1,使用原生开发完成文件下载功能
@RequestMapping("downLoad")
public void downLoad1(HttpServletRequest request,HttpServletResponse response) throws IOException {
String path = request.getServletContext().getRealPath("/file") + File.separator + "1.PNG";
File file = new File(path);
InputStream in = new FileInputStream(file);
byte b[] = new byte[(int)file.length()];
in.read(b);
in.close();
response.setHeader("Content-Disposition", "attachment;filename=1.PNG");
//设置头信息,表示下载
OutputStream out = response.getOutputStream();
out.write(b);
out.close();
}
//下载方式2,使用@ResponseBody完成文件下载功能
@ResponseBody
@RequestMapping("downLoad")
public byte[] downLoad1(HttpServletRequest request,HttpServletResponse response) throws IOException {
String path = request.getServletContext().getRealPath("/file") + File.separator + "1.PNG";
File file = new File(path);
InputStream in = new FileInputStream(file);
byte b[] = new byte[(int)file.length()];
in.read(b);
in.close();
response.setHeader("Content-Disposition", "attachment;filename=1.PNG"); //设置头信息,表示下载
return b;
}
//下载方式3,使用ResponseEntity完成文件下载功能
@RequestMapping("downLoad")
public ResponseEntity<byte[]> downLoad1(HttpServletRequest request) throws IOException {
String path = request.getServletContext().getRealPath("/file") + File.separator + "1.PNG";
File file = new File(path);
InputStream in = new FileInputStream(file);
byte b[] = new byte[(int)file.length()];
in.read(b);
in.close();
//response.setHeader("Content-Disposition", "attachment;filename=1.PNG");
//设置头信息,表示下载
//既然是下载,要设置响应头信息
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "attachment;filename=1.PNG");
ResponseEntity<byte[]> re = new ResponseEntity<>(b,headers,HttpStatus.OK);
return re;
}
总结
在返回JSON格式的数据的时候,必须要加入JSON开发包,然后在DispatcherServlet中才会存在JSON的消息转换器;
对于HttpMessageConverter,我们要知道使用@RequestBody注解目标方法的入参、使用@ResponseBody注解目标方法,表示指定请求内容或者是相应内容到底使用哪个消息转换器。
对于HttpEntity和ResponseEntity只不过是@RequestBody 和@ResponseBody 的不同写法,这两个类需要指定泛型,此泛型就表示调用哪个对应的消息转换器。