SpringMVC 供应了 @ResponseBody 表明,用来标注 Controller 方法的返回的格式为 JSON,将 Java 工具或凑集转为 JSON 格式的数据。
方法返回的工具通过适当的转换器转换为指定的格式之后,写入到 response 工具的 body 区,常日用来返回 JSON 数据或者是 XML 数据。
把稳:在利用此表明之后不会再走视图处理器,而是直接将数据写入到输入流中,它的效果等同于通过 response工具输出指定格式的数据。
利用案例
下面是要完成的效果:要求目标方法,目标方法返回一个json格式的数据
(1)引入处理JSON须要的jar包,把稳spring5.x 须要利用jackson-2.9.x.jar 的包。
(2)创建 json.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head> <title>json提交</title> <!--引入jquery--> <script type="text/javascript" src="script/jquery-3.6.0.min.js"></script> <!--利用jquery的ajax--> <script type="text/javascript"> $(function () { //给id=getJson的超链接绑定一个事宜 $("#getJson").click(function () { var href = this.href; var args = {"time": new Date()}; $.get( href,//要求url args,//发送韶光,防止浏览器缓存 function (data) { console.log("data=", data) }, "json"//指定返回的格式 ) return false;//超链接不跳转 }) }) </script></head><body><h1>要求一个json数据</h1><a href="<%=request.getContextPath()%>/json/dog" id="getJson">点击获取json数据</a></body></html>
(3)创建 Javabean 作为返回的数据
package com.li.web.json.entity; / @author 李 @version 1.0 /public class Dog { private String name; private String address; public Dog() { } public Dog(String name, String address) { this.name = name; this.address = address; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "Dog{" + "name='" + name + '\'' + ", address='" + address + '\'' + '}'; }}
(4)创建 JsonHandler 处理要求
package com.li.web.json; import com.li.web.json.entity.Dog;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.ResponseBody; / @author 李 @version 1.0 /@Controllerpublic class JsonHandler { / 1.目标方法的 @ResponseBody表明表示返回的数据是json格式 2.SpringMVC 底层根据目标方法@ResponseBody,返回指定格式 返回的格式根据http要求来处理 3.底层事理之前在实现SpringMVC底层机制时讲过, 这里原生的SpringMVC利用了转换器 HttpMessageConverter @return / @RequestMapping(value = "/json/dog") @ResponseBody public Dog getJson(){ //返回工具 //SpringMVC 会根据你的设置,转成json格式数据返回 Dog dog = new Dog(); dog.setName("大黄狗"); dog.setAddress("小新的家"); return dog; }}
(5)启动tomcat,访问json.jsp页面。点击超链接,返回如下信息:
2.JSON处理-@RequestBody
和 @ResponseBody 表明相反,@RequestBody 表明是将客户端提交的 json数据,封装成 Javabean 工具。
把稳:@RequestBody 用于润色参数。
运用案例
在前端页面发出一个json数据,后端吸收数据,并利用 @RequestBody 表明将 json 数据转成 Javabean 工具,然后利用 @ResponseBody 表明将该 Javabean 工具转回 json 数据,返回给前端。
(1)修正json.jsp,增加发送 json 数据代码
这里利用 ajax 要求的 contentType 指定发送格式为 json,发送要求时会被封装到要求头中。这样后端在吸收时,根据 contentType 能知道数据是 json 格式的。
<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head> <title>json提交</title> <!--引入jquery--> <script type="text/javascript" src="script/jquery-3.6.0.min.js"></script> <!--利用jquery的ajax--> <script type="text/javascript"> $(function () { //绑定按键点击事宜,提交json数据 $("button[name='but1']").click(function () { var url = "/springmvc/save2"; var username = $("#username").val(); var age = $("#age").val(); //将 username和 age封装成 json字符串 var args = {"username": username, "age": age};//json工具 //将json工具封装成json字符串 var jsonString = JSON.stringify(args);//json字符串 $.ajax({ url:url, data:jsonString, type:"POST", success:function (data) { console.log("返回的data=",data) }, //指定发送数据的编码和格式 contentType:"application/json;charset=utf-8" }) }) }) </script></head><body><h1>发出一个json数据</h1>u:<input id="username" type="text"/><br/>a:<input id="age" type="text"/><br/><button name="but1">添加用户</button></body></html>
(2)User.java
package com.li.web.json.entity; / @author 李 @version 1.0 /public class User { private String username; private Integer age; public User() { } public User(String username, Integer age) { this.username = username; this.age = age; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "User{" + "username='" + username + '\'' + ", age=" + age + '}'; }}
(3)JsonHandler.java
package com.li.web.json; import com.li.web.json.entity.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.ResponseBody; / @author 李 @version 1.0 /@Controllerpublic class JsonHandler { / 1.在形参指定了 @RequestBody 表明 2.SpringMVC 就会将提交的json字符串数据添补给指定的Javabean @param user 指定的Javabean工具 @return 这里利用了 @ResponseBody 表明,因此返回的也是json / @RequestMapping(value = "/save2") @ResponseBody public User save2(@RequestBody User user) { //将前端传过来的数据以json的格式返回浏览器 System.out.println("user=" + user); return user; }}
(4)启动tomcat,访问json.jsp,提交和返回的数据如下:
后台输出:
解释后端成功拿到了前端发送的 json 数据,并将其添补到了指定的Javabean工具中。然后又将 Javabean 工具转成了 json 格式的数据返回前端。
3.JSON处理-把稳事变和细节目标方法正常返回 Json 须要的数据,可以是一个工具,也可以是一个凑集@ResponseBody 表明也可以用于润色于 Controller 上,这样会对 Controller 中所有方法生效@ResponseBody 和 @Controller 可以直接写成一个表明 @RestController4.HttpMessageConverter< T>基本解释SpringMVC 处理 JSON 底层实现是依赖 HttpMessageConverter<T>来进行转换的
事情机制简图全体过程为:
要求报文发送到后端,HttpInputMessage 的实现子类会将要求报文封装起来,然后找到对应的转换器进行转换,然后封装成对应的 Java 工具给到目标方法。
目标方法返回,找到指定格式对应的转换器,转换器将返回的数据再进行转换,将转换后的数据封装到 HttpOutputMessage ,然后返回给客户端。
这里的 HttpMessageConverter(转换器),HttpInputMessage 和 HttpOutputMessage 都是接口,下面有很多实现子类,会根据要求/相应报文头来找到匹配子类。
处理JSON-底层实现(HttpMessageConverter< T>)利用 HttpMessageConverter<T> 将要求信息转换并绑定到处理方法的入参中,或将相应结果转为对应类型的相应信息,Spring 供应了两种路子:利用 @RequestBody / @ResponseBody 对目标方法或方法参数进行标注利用 HttpEntity<T> / ResponseEntity<T> 作为目标方法的入参或返回值当掌握器处理方法利用到 @RequestBody / @ResponseBody 或 HttpEntity<T> / ResponseEntity<T>时,Spring 首先根据要求头或相应头的 Accept 属性选择匹配的 HttpMessageConverter,进而根据参数类型或泛型类型的过滤得到匹配的转换器 HttpMessageConverter,若找不到可用的转换器,将会报错。debug源码
以处理JSON-@RequestBody的例子为案例:
(1)快捷键 ctrl+n 在 IDEA 中搜索 AbstractJackson2HttpMessageConverter 类,在该类的 readJavaType() 方法中打上断点,点击 debug
(2)浏览器访问 json.jsp 页面,填写数据并点击按钮
(3)后台光标跳转到断点处,此时方法参数 inputMessage 的数据如下,解释此时 http 要求的内容已经被封装到了给工具中。
方法参数 javaType 用于指定 inputMessage 的相应数据添补到什么样的 Java 类型中
(4)点击 step over,方法首先获取http要求数据指定的类型 contentType
(5)在获取了指定的数据类型后,将数据进行转换
(6)点击 step over:
(7)在目标方法中添加断点,点击 resume,可以看到光标跳转到断点处,此时目标方法就拿到了由 json 数据添补后的 Javabean 工具
(8)在 AbstractJackson2HttpMessageConverter 类的 writeInternal() 方法中打上断点,点击 resume,光标跳转到如下位置:
由于我们在目标方法利用了 @ResponseBody 表明,因此返回的时候不再见进入视图处理器,而是通过转换器,将返回的 user 工具转换为指定的 json 格式数据。下图的 HttpOutputMessage 工具便是用于存放转换后的数据。
获取要转换的格式:
利用 selectObjectMapper 方法将工具转换为指定格式:
后面便是进行一些处理,然后将数据返回给客户端。
(9)然后浏览器得到指定格式的数据:
5.文件下载-ResponseEntity< T>解释
在SpringMVC 中,通过返回 ResponseEntity<T> 的类型,可以实现文件的下载功能
利用 ResponseEntity< T> 下载文件,底层仍旧是上面 HttpMessageConverter< T> 的机制。
利用案例
实现效果如下:在前端页面点击超链接,可以实现文件下载。
在项目的web目录下创建一个img目录,放入一张图片作为要下载的文件
(1)修正 json.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %><html><head> <title>文件下载</title></head><body><h1>下载文件的测试</h1><a href="<%=request.getContextPath()%>/downFile">点击下载文件</a></body></html>
(2)修正 JsonHandler.java,增加方法,用于相应下载文件的要求
文件下载相应头的设置:
content-type:设置相应内容的格式content-disposition:设置如何处理相应的内容,一样平常有两种办法:inline:直接在页面显示attchment:以附件形式下载package com.li.web.json; import org.springframework.http.HttpHeaders;import org.springframework.http.HttpStatus;import org.springframework.http.ResponseEntity;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpSession;import java.io.IOException;import java.io.InputStream; / @author 李 @version 1.0 /@Controllerpublic class JsonHandler { / 这里的构建形参session紧张是为了获取输出流 @param session @return / @RequestMapping(value = "/downFile") public ResponseEntity<byte[]> downFile(HttpSession session) throws IOException { //先获取下载文件的 InputStream InputStream resourceAsStream = session.getServletContext().getResourceAsStream("/img/view.jpg"); //开辟 byte 数组 //resourceAsStream.available() 返回可读取的字节数的估计值 byte[] bytes = new byte[resourceAsStream.available()]; //将要下载的文件数据保存到 bytes 数组 resourceAsStream.read(bytes); / ResponseEntity 的布局器: public ResponseEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers, HttpStatus status) { this(body, headers, (Object) status); } body 便是要回送的数据内容 headers 便是回送数据的编码以及该当以何种办法进行处理 status 代表状态 / //1.创建返回的 HttpStatus status HttpStatus httpStatus = HttpStatus.OK; //2.创建 headers,指定浏览器应该以附件形式操作返回的数据 HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.add("Content-Disposition", "attachment;filename=view.jpg"); //3.构建 ResponseEntity 工具 ResponseEntity<byte[]> responseEntity = new ResponseEntity<>(bytes, httpHeaders, httpStatus); return responseEntity; }}
(3)测试,点击下载链接,显示成功下载图片
tomcat 真正的事情目录是 out,要担保 out 目录下存在该文件,才能下载成功
6.练习将之前的数据格式化、验证以及国际化、json 处理、文件下载干系代码自己过一遍将 debug 过的 HttpMessageConverter 源码再走一遍,加深理解画出数据类型转换校验核心类 DataBinder 的事情机制示意图debug 一下 validate 得到验证 errors 信息,加深理解