7.Spring MVC JSON数据交互
- 前后端分离时,后端提供接口,前端进行数据渲染,那么中间需要如何传递数据呢?
- Spring MVC 在数据绑定的过程中需要对传递数据的格式和类型进行转换,它既可以转换 String 等类型的数据,也可以转换 JSON 等其他类型的数据
7.1 JSON 概述
- JSON(JavaScript Object Notation, JS 对象标记)是一种轻量级的数据交换格式。与 XML 一样,JSON 也是基于纯文本的数据格式。JSON是一个序列化的对象或数组。
- JS任何支持的类型都可以通过 JSON 来表示,例如字符串、数字、对象、数组等。但是对象和数组是比较特殊且常用的两种类型
对象在 JS 中是使用花括号包裹 {} 起来的内容,数据结构为 {key1:value1, key2:value2, …} 的键值对结构
对象在json中以
{
开始、以}
结束,中间部分、多个以英文,
分隔的 key/value 对构成,key 和 value 之间以英文:
分隔。对象结构的语法结构如下:JSON键值对是用来保存JS对象的一种方式,和js对象写法类似
{
key1:value1,
key2:value2,
}
用例:
{``"firstName"``: ``"Brett"``, ``"lastName"``: ``"McLaughlin"``}
其中,key 必须为 String 类型,值可以是对象、数组、数字、字符串或者三个字面量(false、null、true)中的一个。值中的字面值中的英文必须使用小写。
数组在 JS 中是方括号 [] 包裹起来的内容,数据结构为 [“java”, “javascript”, “vb”, …] 的索引结构。在 JS 中,数组是一种比较特殊的数据类型,它也可以像对象那样使用键值对,但还是索引使用得多。同样,值的类型可以是任意类型。
- 表示数组:和普通的 JS 数组一样,JSON 表示数组的方式也是使用方括号 []。如何用括号将记录组合成一个值?
{ ``"people":[ ``{``"firstName": "Brett", ``"lastName":"McLaughlin" ``}, ``{ ``"firstName":"Jason",``"lastName":"Hunter"``}``]``}
在这个示例中,只有一个名为 people的变量,值是包含两个条目的数组,每个条目是一个人的记录,其中包含名和姓
- 一些合法的JSON数组实例:
{``"a"``: 1, ``"b"``: [1, 2, 3]}
[1, 2, ``"3"``, {``"a"``: 4}]
3.14
"plain_text"
- 上述两种(对象、数组)数据结构也可以分别组合构成更加复杂的数据结构
{
"id":"202207030808",
"name":"张三",
"hobby":["音乐","足球"],
"address":{
"country":"china",
"zip-code":"10000"
}
}
7.2 JSON 与 JS 对象的关系
- JSON (括号最外层带引号)是 JS 对象(括号最外层不带引号)的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串
var` `obj = {a: ``'Hello'``, b: ``'World'``}; ``//这是一个对象,注意键名也是可以使用引号包裹的
var` `json = ``'{"a": "Hello", "b": "World"}'``; ``//这是一个 JSON 字符串,本质是一个字符串
7.3 JSON 和 JS 对象互转
- 要实现从JSON字符串转换为JS对象,使用 JSON.parse() 方法:
var` `obj = JSON.parse(``'{"a": "Hello", "b": "World"}'``); ``//结果是 {a: 'Hello', b: 'World'}
- 要实现从JS对象转换为JSON字符串,使用 JSON.stringify() 方法:
var` `json = JSON.stringify({a: ``'Hello'``, b: ``'World'``}); ``//结果是 '{"a": "Hello", "b": "World"}'
注意:
7.4 JSON 数据转换
实现浏览器与控制器类之间的 JSON 数据交互,Spring MVC 提供了 MappingJackson2HttpMessageConverter 实现类默认处理 JSON 格式请求响应。该实现类利用 Jackson 开源包读写 JSON 数据,将 Java 对象转换为 JSON 对象和 XML 文档,同时也可以将 JSON 对象和 XML 文档转换为 Java 对象。
给前端json格式的字符串,需要在方法上面加一个@ResponseBody注解,这样返回的字符串不会经过视图解析器,然后引入jackson依赖,spring会自动帮你把返回值转化为json格式,或者直接添加@restcontroller注解
使用注解开发时需要用到两个重要的 JSON 格式转换注解
- @RequestBody:用于将请求体中的数据绑定到方法的形参中,该注解应用在方法的形参上。 响应体的意思就是服务器要响应的内容,代表这不是一个视图,所以不会走视图解析器
- @ResponseBody:用于直接返回 return 对象或字符串,该注解应用在方法上。阻止视图解析器解析。配合@Controller使用
@ResponseBody作用是将标注该注解的处理方法的返回结果直接写入 HTTP Response Body**(Response 对象的 body 数据区)中。一般情况下,@ResponseBody 都会在异步获取数据时使用**,被其标注的处理方法返回的数据都将输出到响应流中,客户端获取并显示数据。
- 早期 JSON 的组装和解析都是通过手动编写代码来实现的。这种方式容易出错
- 后面有许多的关于组装和解析 JSON 格式信息的工具类出现,如 json-lib、Jackson、Gson 和 FastJson 等,可以解决 JSON 交互的开发效率。
- jackson是springboot自带解析器
- json-lib 最早也是应用广泛的 JSON 解析工具,缺点是依赖很多的第三方包,如 commons-beanutils.jar、commons-collections-3.2.jar、commons-lang-2.6.jar、commons-logging-1.1.1.jar、ezmorph-1.0.6.jar 等。对于复杂类型的转换,json-lib 在将 JSON 转换成 Bean 时还有缺陷,比如一个类里包含另一个类的 List 或者 Map 集合,json-lib 从 JSON 到 Bean 的转换就会出现问题。 json-lib 在功能和性能上面都不能满足现在互联网化的需求
- 开源的 Jackson 是 Spring MVC 内置的 JSON 转换工具。相比 json-lib 框架,Jackson 所依赖 jar 文件较少,简单易用并且性能也要相对高些。并且 Jackson 社区相对比较活跃,更新速度也比较快。但是 Jackson同样会出现上面这种方式的问题,转换的 JSON 格式不是标准的 JSON 格式。
- **Google的Gson:**是目前功能最全的 JSON 解析工具类,Gson 主要提供了 toJson 与 fromJson 两个转换函数,不需要依赖其它的 jar 文件,就能直接在 JDK 上运行。在使用这两个函数转换之前,需要先创建好对象的类型以及其成员才能成功的将 JSON 字符串转换为相对应的对象。类里面只要有 get 和 set 方法,Gson 完全可以将复杂类型的 JSON 到 Bean 或 Bean 到 JSON 的转换,是 JSON 解析的神器。Gson 在功能上面无可挑剔,但性能比 FastJson 有所差距。
- 阿里巴巴的FastJson:是用 Java 语言编写的高性能 JSON 处理器。不需要依赖其它的 jar 文件,就能直接在 JDK 上运行。同样FastJson 在复杂类型的 Bean 转换 JSON 上会出现一些问题,可能会出现引用的类型,导致 JSON 转换出错,需要制定引用。FastJson 采用独创的算法,将 parse 的速度提升到极致,超过所有 JSON 库。FastJson2已经出来了,原作者重新写了,与原来的底层都变了,速度提升134%
实际开发时可以将Gson和FastJson混合使用,如果只是功能要求,没有性能要求,可以使用 Gson。如果有性能上面的要求可以使用 Gson 将 Bean 转换 JSON 确保数据的正确,使用 FastJson 将 JSON 转换 Bean。
工具类的使用
导入依赖
<dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.13.3</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>2.0.5</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.9.0</version> </dependency>
- 实体类
@Data @AllArgsConstructor @NoArgsConstructor public class User { String username; int age; LocalDate birthday; //jackson对复杂对象支持不够 }
- 控制器类测试,单个实体类转换后是json字符串(对象形式),一个集合或数组转换后是数组格式的json字符串
@Controller @RequestMapping("/user") public class UserController { @RequestMapping(value = "/gj01",produces = "application/json;charset=utf-8") @ResponseBody public String getjson01() throws JsonProcessingException { //com.fasterxml.jackson.databind.ObjectMapper; ObjectMapper objectMapper = new ObjectMapper(); User user = new User("张三", 18, LocalDate.now()); return objectMapper.writeValueAsString(user); //`java.time.LocalDate` not supported by default: add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310" to enable handling //将LocalDate.now()换成new java.util.Date() {"username":"张三","age":18,"birthday":1656857490891} //转换为时间戳 } @RequestMapping(value = "/gj02",produces = "application/json;charset=utf-8") @ResponseBody public String getjson02() throws JsonProcessingException { User user = new User("张三", 18, LocalDate.now()); return JSON.toJSONString(user); //com.alibaba.fastjson2.JSON; //{"age":18,"birthday":"2022-07-03","username":"张三"} } @RequestMapping(value = "/gj03",produces = "application/json;charset=UTF-8") @ResponseBody public String getjson03() throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); User user = new User("张三", 18, LocalDate.now()); Gson gson = new Gson(); gson.toJson(user); return gson.toJson(user); //{"username":"张三","age":18,"birthday":{"year":2022,"month":7,"day":3}} } }
7.5 jackson对日期类的转换
jackson日期类型直接转为json,显示的是时间戳
所以需要jackson对日期类型转换格式进行设置
方式1:传统方式SimpleDateFormat
@RequestMapping(value = "/gj04") @ResponseBody public String getjson04() throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return objectMapper.writeValueAsString(sdf.format(new Date())); }
- 方式2:jackson设置
@RequestMapping(value = "/gj05") @ResponseBody public String getjson05() throws JsonProcessingException { ObjectMapper objectMapper = new ObjectMapper(); /*关闭使用时间戳的方式*/ objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //指定日期格式 objectMapper.setDateFormat(sdf); return objectMapper.writeValueAsString(new Date()); }
7.6 fastjson使用
JSONObject代表json对象,实现了map接口,通过各种形式的get()方法获取json对象中的数据,也可利用size(),isEmpty()方法获取”键值对“个数和判断是否空。本质是实现map结果并调佣接口方法完成的。对应js对象
JSONArray代表json对象数组,内部是List接口的方法完成操作
JSON代表JSONObject和JSONArray的转换
分析源码,JSON的这些方法主要是实现json对象,json对象数组,json字符串,javabean对象的相互转换
主要方法
public static String toJSONString(Object object) //java对象转JSON字符串 public static <T> T parseObject(String text, Class<T> clazz) //JSON字符串转java对象 public static Object toJSON(Object javaObject) //java对象转json对象,返回Object再强转JSONObject public static <T> T toJavaObject(JSON json, Class<T> clazz)//json对象转java对象
- fastjson的运行速度快比jacjson快一倍
- 如果返回JSON字符串太长会导致截断的问题
下一篇:SpringMVC-15-乱码问题处理
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/123888.html