网站建设完成后如何备案,ppt要怎么做网站,电商怎么做营销推广,云主机做网站永久保留网站去年10月份以来由于公司和家里的事情太多#xff0c;所以一直没有学习#xff0c;最近缓过来了#xff0c;学习的脚步不能停滞啊。回归正题#xff0c;其实前年在学习springMvc的时候也学习过Jackson【Spring MVC学习笔记 五】SpringMVC框架整合Jackson工具#xff0c;但是…去年10月份以来由于公司和家里的事情太多所以一直没有学习最近缓过来了学习的脚步不能停滞啊。回归正题其实前年在学习springMvc的时候也学习过Jackson【Spring MVC学习笔记 五】SpringMVC框架整合Jackson工具但是呢只是局限于基本用法当时也刚进入新项目工作没多久体会也没有那么深刻。现如今工作中深度用到了Jackson但是对于Jackson的详细情况心里却没有十分的底大多数时候都是用到的时候从网上找相关的方法实现copy一份没有全局的认识所以这篇博客详细的学习和实践一下Jackson。当然市面上的序列化框架有很多例如谷歌的Gson阿里的FastJson但是因为综合考虑性能Jackson比较强、稳定性Jackson和Gson都比较强再加上SpringBoot默认集成的就是Jackson所以对于Jackson掌握清楚后就足以应对大多数工作场景了。
回顾Json格式规则
从结构上看所有的Json格式数据最终都可以分成三种类型
第一种类型是scalar标量也就是一个单独的string字符串或数字numbers比如北京这个单独的词第二种类型是sequence序列也就是若干个相关的数据按照一定顺序并列在一起又叫做array数组或List(列表)比如[北京天津]第三种类型是mapping映射也就是一个名/值对Name/value即数据有一个名称还有一个与之相对应的值这又称作hash散列或dictionary字典比如{城市名称北京}
Json格式规则有如下几种
并列的数据之间用逗号分隔映射用冒号表示并列数据的集合数组用方括号[]表示映射的集合对象用大括号{}表示
大多时候我们会用到对象和Json的序列化与反序列化操作。
SpringBoot集成Jackson
当然第一步就是在Maven中进行Jackson包的引入了还是从Maven的中央仓库引入最新版本的JacksonJackson的Maven仓库地址我们就使用截止目前Jackson更新的最新版本 pom文件如下
!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind --
dependencygroupIdcom.fasterxml.jackson.core/groupIdartifactIdjackson-databind/artifactIdversion2.14.2/version
/dependencyJackson核心包概览
Jackson包含三部分的核心包jackson-core、jackson-annotations、jackson-databind
jackson-core核心包提供基于流模式解析的相关 API它包括 JsonPaser和 JsonGenerator。 Jackson 内部实现正是通过高性能的流模式 API 的 JsonGenerator 和 JsonParser 来生成和解析 json。jackson-annotations注解包提供标准注解功能jackson-databind 数据绑定包 提供基于对象绑定解析的相关 API ObjectMapper 和树模型 解析的相关 API JsonNode基于对象绑定 解析的 API 和树模型解析的 API 依赖基于流模式解析的 API。 当然因为jackson-databind 依赖 jackson-core 和 jackson-annotations所以当添加 jackson-databind 之后 jackson-core 和 jackson-annotations 也随之添加到 Java 项目工程中。 由于我们大多数场景都是处理对象和Json之间的映射关系所以我们把重点放到对象绑定上来。
核心对象ObjectMapper
大多数的ObjectMapper对象都会被配置到Feature对象。 这篇文章ObjectMapper的一些配置提到的一些默认配置在最新的jackson版本里已经更新了例如序列化时默认的时间戳格式被取消序列化时默认的空对象异常也不会抛出了
Jackson基本用法实践
关于Jackson的基本用法如下直接上代码清单
目标Person对象
我们用来测试的对象
package com.example.springboot.jackson;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;import java.time.LocalDate;
import java.util.List;/*** The type Person.** author tianmaolin004* date 2023 /3/18*/
Data
Builder
AllArgsConstructor
NoArgsConstructor
public class Person {private String name;private Integer age;private ListString interests;private LocalDate birthday;
}
JsonUtils类
包括ObjectMapper对象的初始化以及相关的一些配置还有转换方法
package com.example.springboot.jackson;import com.alibaba.druid.util.StringUtils;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;/*** The type Json operator.** author tianmaolin004* date 2023 /3/18*/
Slf4j
public class JsonUtils {private static final ObjectMapper objectMapper new ObjectMapper();private static final String LOCAL_DATE_TIME_PATTERN yyyy-MM-dd HH:mm:ss;static {// 1 序列化及反序列化的时间配置JavaTimeModule timeModule new JavaTimeModule();timeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ISO_LOCAL_DATE));timeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ISO_LOCAL_DATE));timeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ISO_LOCAL_TIME));timeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ISO_LOCAL_TIME));timeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(LOCAL_DATE_TIME_PATTERN)));timeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(LOCAL_DATE_TIME_PATTERN)));objectMapper.registerModule(timeModule);objectMapper.setDateFormat(new SimpleDateFormat(LOCAL_DATE_TIME_PATTERN));//2 忽略反序列化时对象不存在对应属性的错误,如果不存在该属性则设置值为nullobjectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);//3 忽略序列化时值为Null元素不存在该元素则字符串中无该元素而不是展示为nullobjectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);}/*** 对象转字符串** param T the type parameter* param obj the obj* return the string*/public static T String obj2Str(T obj) {if (obj null) {return null;}try {return obj instanceof String ? (String) obj : objectMapper.writeValueAsString(obj);} catch (Exception e) {log.error(obj2Str fail);return null;}}/*** 字符串转对象** param T the type parameter* param str the str* param clazz the clazz* return the t*/public static T T str2Obj(String str, ClassT clazz) {if (StringUtils.isEmpty(str) || clazz null) {return null;}try {return clazz.equals(String.class) ? (T) str : objectMapper.readValue(str, clazz);} catch (Exception e) {log.error(str2Obj fail);return null;}}/*** 字符串转对象泛型模式一般用于集合** param T the type parameter* param str the str* param typeReference the type reference* return the t*/public static T T str2Obj(String str, TypeReferenceT typeReference) {if (StringUtils.isEmpty(str) || typeReference null) {return null;}try {return (T) (typeReference.getType().equals(String.class) ? str : objectMapper.readValue(str, typeReference));} catch (Exception e) {log.error(str2Obj fail);return null;}}/*** 字符串转JsonNode** param str the str* return the json node*/public static JsonNode str2JsonNode(String str) {if (StringUtils.isEmpty(str)) {return null;}try {return objectMapper.readTree(str);} catch (Exception e) {log.error(str2Obj fail);return null;}}/*** 对象互转** param T the type parameter* param fromValue the from value* param toValueType the to value type* return the t*/public static T T convertValue(NonNull Object fromValue, NonNull ClassT toValueType) {try {return objectMapper.convertValue(fromValue, toValueType);} catch (Exception e) {log.error(str2Obj fail);return null;}}/*** 对象互转泛型模式** param T the type parameter* param fromValue the from value* param toValueTypeRef the to value type ref* return the t*/public static T T convertValue(NonNull Object fromValue, NonNull TypeReferenceT toValueTypeRef) {try {return objectMapper.convertValue(fromValue, toValueTypeRef);} catch (Exception e) {log.error(str2Obj fail);return null;}}
}
测试Json转换
测试类及测试结果
package com.example.springboot.jackson;import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;/*** author tianmaolin004* date 2023/3/18*/
public class JsonTest {public static void main(String[] args) {// 序列化操作ListString interests new ArrayList();interests.add(跑步);interests.add(游泳);Person person Person.builder().name(tml).age(24).interests(interests).birthday(LocalDate.now()).build();System.out.println(obj2Str,序列化对象);System.out.println(JsonUtils.obj2Str(person));Person personLoseAttr Person.builder().name(tml).interests(interests).birthday(LocalDate.now()).build();System.out.println(obj2Str,序列化缺失元素对象);System.out.println(JsonUtils.obj2Str(personLoseAttr));Person emptyPerson new Person();System.out.println(obj2Str,序列化空对象);System.out.println(JsonUtils.obj2Str(emptyPerson));// 反序列化操作String personStr {\name\:\wc\,\age\:99,\interests\:[\跑步\,\游泳\,\唱跳\,\rapper\,\打游戏\],\birthday\:\2023-03-05\};System.out.println(str2Obj,反序列化对象);System.out.println(JsonUtils.str2Obj(personStr, Person.class));System.out.println(str2Obj,反序列化对象由于字符串不符合Json的mapping格式所以需要特殊判断);System.out.println(JsonUtils.str2Obj(北京, String.class));System.out.println(str2Obj,反序列化对象由于集合不能指定元素类型所以使用泛型方式);System.out.println(JsonUtils.str2Obj([\跑步\,\游泳\,\唱跳\,\rapper\,\打游戏\], new TypeReferenceListString() {}));String personLoseAttrStr {\age\:99,\interests\:[\跑步\,\游泳\,\唱跳\,\rapper\,\打游戏\]};System.out.println(str2Obj,反序列化缺失元素的对象);System.out.println(JsonUtils.str2Obj(personLoseAttrStr, Person.class));String personBadAttrStr {\ag\:99,\interests\:[\跑步\,\游泳\,\唱跳\,\rapper\,\打游戏\]};System.out.println(str2Obj,反序列化包含不存在元素的对象);System.out.println(JsonUtils.str2Obj(personBadAttrStr, Person.class));// 反序列化为jsonNode对象获取属性值并将属性值转为目标类型对象场景,目标JSON结构复杂不想映射创建一个对象只想使用其中部分数据则先将JSON转为JsonNode对象获取其部分属性值再转为我们需要的确定性对象System.out.println(str2JsonNode,反序列化JsonNode对象);JsonNode jsonNode JsonUtils.str2JsonNode(personStr);System.out.println(jsonNode);System.out.println(jsonNode.findValues(age));System.out.println(JsonUtils.convertValue(jsonNode.get(interests), new TypeReferenceListString() {}));System.out.println(JsonUtils.convertValue(jsonNode.get(name), String.class));}
}
打印结果如下
应用场景深拷贝
对于List中存在对象的情况下除了循环遍历对每个元素重建外通过序列化的方式也能轻松的实现集合的深拷贝 ListFeeRateDiscount resultPlatDiscount BeanCopyUtils.deepCopy(platDiscountFeeRates, new TypeReferenceListFeeRateDiscount() {});public static T T deepCopy(Object src, TypeReferenceT dstClazz) {if (null src) {return null;}return JsonUtils.str2Obj(JsonUtils.obj2Str(src), dstClazz);}总结一下
在不知所以然的时候很容易用错一些最基础的知识越是基础的知识其发生错误的情况所导致的影响范围也越大只有踏踏实实的自己尝试过才知道框架怎么用最好所以对于新知识最好不要抱有模糊的侥幸心理这样其实自己心里也不踏实不敢实践。Jackson是个好的开始接下来则是Jooq以及Gradle。