1. SpringCloud使用FastjsonHttpMessageConverter遇到的坑
1.序列化到前台时时间变成时间戳,没有时间格式,SpringBoot自带的配置时间序列化格式因为已经被替换了实现类所以不在生效,需要使用fastJson的时间设置方式@JSONField(format ="yyyy-MM-dd HH:mm:ss")在实体类上加上次注解即可。
2.在序列话到前台时候fastjson遍历集合会存纤帆在对象被返回的情况,以及所有请求被拦截,但是处理不是很理想的情况,贴出配置供参考
当作一个Bean注册掘竖渗
public class FastJsonHttpMessageConverter {
private static SetsupportedMediaTypes;
public () {
supportedMediaTypes =new HashSet<>();
supportedMediaTypes.add(MediaType.APPLICATION_JSON);
判脊 supportedMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
}
@Override
public boolean canRead(Type type, Class contextClass, MediaType mediaType) {
return this.supports(contextClass) &&supportedMediaTypes.contains(mediaType);
}
@Override
public boolean canWrite(Type type, Class clazz, MediaType mediaType) {
return super.supports(clazz) &&supportedMediaTypes.contains(mediaType);
}
@Override
protected void writeInternal(Object object, HttpOutputMessage outputMessage)throws IOException, {
OutputStream out = outputMessage.getBody();
String text = JSON.toJSONString(object, SerializerFeature.);
byte[] bytes = text.getBytes("utf-8");
out.write(bytes);
}
}
2. fastJson的@JSONField和jackson的@JsonProperty使用
@JSONField
作用:在字段和方法上
1 .Field:@JSONField作用在Field时,name可以定义输入key的名字,反序列化的时 值不会赋值到属性上灶扒
2 .作用在setter和getter方法上
3 .format :用在Date类型的字段来格式化时间格式
4 .布尔类型:serialize和deserialize
在销辩亩序列化的时候就不包含这个字段了。deserialize与之相反。但是有一点需要注意,当字段为final的时候注解放在字段上是不起作用的,这时候应该放在get或set方法上。
5. serialzeFeatures 属性:fastjson默认的序列化规则是当字段的值为null的时候,是不会序列化这个字段
对象序列化下边的类,结果是:{"name":"LiSi","age":18}
6 .SerializerFeature枚举
当value的值为null的时候,依然会把它的值序列化出来: {"name":"LiSi","age":18,"address":null}
当字段类型为int类型时,会序列化成 0,需要把类型改成Integer
1 . 引入jar包
2 . jsonProperty介绍
@JsonProperty 此注解用于属性上,作用是把该属性的名称序列化为另外一个名称,如把trueName属性序列化为name,@JsonProperty(value="name")。
3 . jackson的@JsonIgnore使用
作用:在json序列化时将java bean中的一些属性忽略掉,序列化和亏森反序列化都受影响。
使用方法:一般标记在属性或者方法上,返回的json数据即不包含该属性。
3. Spring Boot使用@JsonProperty,@JsonIgnore,@JsonFormat注解
@JsonProperty, @JsonIgnore 和 @JsonFormat 注解都是 fasterxml jackson 里面的注解,现在也被 Spring Boot 集成了。
这里需要注意的是将对象转换成json字符串使用的方法是fasterxml.jackson提供的!!
如果使用fastjson
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.28</version>
</dependency>
没有生效,为啥?
因为fastjson不认识@JsonProperty注解呀!所以要使用jackson自迟埋己的序列化工具方法
我们在使用上面的注解时,不需要在 pom.xml 显示的引入 fasterxml jackson 的依赖包。只需要加入如下依赖即可。
@JsonProperty
用于属性、setter / getter 方法上,属性序列化后可重命名
生成的 json 字符串就是image_width和image_height。
@JsonIgnore
属性使用此注解后,将不被序列化。
@JsonFormat
用于格式化日期
@JsonInclude,@JsonIgnoreProperties,@JsonIgnore
真实案例
{
"rowid": "111111",
"created": "液清2018-12-27 16:15:25",
"createdby": "1111111",
"lastupd": "2018-12-27 08:25:48",
"lastupdby": "111111",
"modificationnum": 1
}
返回Json参数字段均为小写,在接收时,需要按照标准的命名规则进行映射
解决办法:
创建接收数据对象,生成Get\Set方法:,在Set方法上,加上@JsonProperty注解,
@JsonProperty 此注解用于属性上,作用是把该属性的名称序列化为另闹旦前外一个名称,如把rowId属性序列化为rowid,@JsonProperty("rowid")。
4. 当 Json 遇到 Map
了解一下日常开发中关于 Json 解析的一些非常规用法,以及使用 fastjson 的一些总结。
一般情况 Json 的使用都是非常简单的。 我们会根据上游定义的 Json 数据格式,由下游定义相应的解析模型。比如像下面这个简单的 Json 字符串。
一般会定义如下的数据类(以 Kotlin 为例)
具体使用也是非常简单了,无论是借助 fastjson 、gson 或者是原生的 JsonObject 都可以非常方便的完成数据的序列化和反序列操作,比如以 fastjson 为例。
无论原始的 Json 数据格式多么的复杂,包含原始数据类型、List、数组还是他类型, 只要需要解析的属性的 key 是确定的,那么就可以定义出相应的数据模型来解析 。 因为在定义任何一个数据模型是时,对于其中的每一个字段(或者叫做属性、类成员),唯一需要确定的就是变量的类型和变量名的名称,比如面对下面这个略显复杂的 Json :
我们依旧可以定义出如下的数据模型
但有时候我们会遇到 Json 数据中,key 值无法确定的情况。也就是说,我们需要解析的字段名是不确定的。或者说,Json 数据中字段名和字段值重合的情况。
比如上面这个 Json ,按照日期返回一个 List(至于 List 里具体是什么,我们也无需关心)或者是其他任何数据,这里就比较有意思了。
既然返回的属性名是无法确定的,那么怎么定义 Json 对应的数据类型中的变量名呢 ?
上面 ??? 这里应该怎么定义呢? 毕竟总不能穷举所有日期吧? 再说也穷举不过来呀,时间是无限的呀。
这里就需要转换一下思路了,我们从本质出发,这里整个 Json 其实是一个 Map 。既然是一个 Map ,那我们就把他当做一个 Map 去解析好了。
因此,fastjson 在解析的时候不知道具体该怎么办了,只知道这是个把原始 Json 字符串解析为一个 Map 。剩下的就该靠我们自己了. fastjson 不知道具体类型,我们自己是知道的呀。因此,就需要遍历 map 自己去处理了。
到这里,我们就可以获取到原始 Json 字符串中的数据了。可以看到,对于上游返回的 Map 这种类型的数据,由于其本身灵活的特性,我们需要按具体的类型做具体拆解,没有通用的方法。
作为常用的 Json 序列化框架 ,这里总结一下使用 fastjson 遇到一些坑和收获。
日常开发中上游给我们的 Json 数据往往是很丰富的,并且由于 json 的特性,在一大段字符串中要找到我们关系的字段是有点困难的,因此我们往往把 Json 字符串贴到各类 Json解析助手之类的网站或工具里,进行格式化。其实,不用那么麻烦,fastjson 自身提供了可以格式化打印 Json 的方法。
这里格式化打印一下刚才的 map printBeautyJson(map)
从截图可以看到,已经实现了 Json 的格式化输出。SerializerFeature 还有很多其他很多实用的功能,可以按需要进行配置。
JSONField 是一个定义在 fastjson 内的注解,其中最常用的两个值是 serialize 和 deserialize ,都是 boolean 类型,用户决定对特定字段进行序列化和反序列化。
序列化毕竟是一个 IO 操作,在优化性能的场景,我们就可以基于实际业务场景和需求出发,减少非必要的序列和反序列操作,尤其是对一些比较打的对象。需要注意的是,deserialize 这个值只有把注解打在方法上时才是有效的(这点可以从其源码看到)。
最后再说一个使用 fastjson 最最常见的问题,关于默认构造函数的问题。
我们知道一个普通的 Java 类,如果没有定义构造函数的话,编译器会帮我们自定生成一个构造函数。但是如果我们自己定义了构造函数,那么默认的构造函数就没了。
这个时候如果我们直接解析 Json 解析,会抛出异常。 com.alibaba.fastjson.JSONException: default constructor not found
至于具体原因,看一下源码也很容易理解了。这个时候,就只能把默认的构造加上了。
而在使用 Kotlin 的场景,也是存在同样的问题。
现在大家都习惯使用 data class 定义数据类。虽然这样定义的类型,从反编译的结果看似乎是存在默认构造函数的,但依旧会报错。
可以看到是有存在构造函数的,但是依旧会产生问题。对于 Kotlin 的场景,我们用两种解决办法。
这样依旧不解决问题。
to be continued ...
本文从 Json 解析常规用法出发,解读了对 Map 这种 Json 数据类型的解析。从中可以学习到,有时候我们在面临一些问题是会一筹莫展,会出现非常规的场景。这个时候,就需要我们从问题的本质出发,看透问题的根源,一层层抽丝剥缕的去解决。
问题总是会不断出现的,重要的是在我们解决完问题之后不仅要学会解决方法,更要学会解决问题的思路。
5. 阿里fastjson到底如何使用
json是一种文件传输格式,类似于以 "/t" 分割,csv文件,是一种数据标准。
json的数消庆中据格式是这样的:
大家一看就明白,类似于Map,是一种键值对的存在,其中{....} 代表对象,[..]代表拿山数组,中间以逗号分割。具体就不多说了,想要了解的随便一搜就有很多。。。
接下来看阿里fastjson的用法:
首先fastjson是目前用途最广泛,也是最好用的一种json工具。
首先你拿到json数据后可以使用parse方法将数差手据转化为json对象(底层Map)
这样你想要拿什么字段值直接 jsonObject.get("字段名")就可以了
6. FastJson和Json以及@ResponseBody
@Restcontroller是@Controller和@ResponseBody的结合体,将后台返回的Java对象转换为Json字符串传递给前台。它是springmvc通过配置实现的,spring默认带的转json包为jackson,因为fastJson比较快一般会引入fastjson来替换。
解决bean与json字段不一致问题,或者字段定义不符合前端所需岩租要的标准,需要使用@JsonProperty和@JSONField注解粗橡兆。
@jsonProperty是Jackson的包,@JSONproperty这个注解用于属性上面
而@jsonfield是如链fastjson的包,@JSONField这个注解可以用于get、set以及属性上面@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")是时间的格式化,可以用于get、set以及属性上面
FastJson是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。FastJson的API十分简洁,FastJson重要的类为JSONObject,经常调用的方法如下:
public static final Object parse(String text); // 把JSON文本parse为JSONObject或者JSONArray
public static final JSONObject parseObject(String text); // 把JSON文本parse成JSONObject
public static final T parseObject(String text, Class clazz); // 把JSON文本parse为JavaBean
public static final JSONArray parseArray(String text); // 把JSON文本parse成JSONArray
public static final List parseArray(String text, Class clazz); //把JSON文本parse成JavaBean集合
public static final String toJSONString(Object object); // 将JavaBean序列化为JSON文本public static final String toJSONString(Object object, boolean prettyFormat); // 将JavaBean序列化为带格式的JSON文本
public static final Object toJSON(Object javaObject); 将JavaBean转换为JSONObject或者JSONArray。
Jackson相对来说比较高效的Json类库,在项目中主要使用Jackson进行JSON和Java对象转换,Jackson ObjectMapper类是使用Jackson解析JSON最简单的方法。可以从字符串、流或文件解析JSON,并创建Java对象或对象图来表示已解析的JSON。将JSON解析为Java对象也称为从JSON反序列化Java对象
1.JAVA对象转JSON
ObjectMapper mapper = new ObjectMapper();
String bjectMapper = mapper.writeValueAsString(obj);
2.JSON转Java类[JSON反序列化]
ObjectMapper mapper = new ObjectMapper();
HashMap<String, Object> inMap = mapper.readValue(jsonStr, HashMap.class);
7. 阿里的Json解析包FastJson使用
maven配置:
源码地址
public static final Object parse(String text);
public static final JSONObject parseObject(String text);
public static final <T> T parseObject(String text, Class<T> clazz);
public static final JSONArray parseArray(String text);
public static final <T> List<T> parseArray(String text, Class<T> clazz);
public static final String toJSONString(Object object, boolean prettyFormat);
public static final Object toJSON(Object javaObject);
public static final String toJSONString(Object object);
8. Jackson序列化&&FastJson序列化API使用
JDK英文文档,墙裂不推荐看中文!!!
ObjectMapper的API文档
1 需要注意的是:
2 Jackson的API: `
3. Jackson提供的注解
Jackson 提供了一系列的注解,方便对 JSON 序列化和反序列化进行控制,下面介绍一些常用的注解:
1. 引入MAVEN依赖:
2. 实体类
3. 测试类:
首先注意的是 JDK1.8 中时间类,采用了一套新的API。
在这里我们采用是 LocalDate 类,若是 User 类中,没有使用注解,那么序列化结果为:
显然,这不是我们预期的 Json 串。并且,我们在反序列化过族侍裤程中,会出现异常:
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of java.time.LocalDate (no Creators, like default construct, exist):
cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (String)"{"name":"小胖","sports":["足球","游泳"],"date":{"year":2019,"month":"MARCH","chronology":{"id":"ISO","calendarType":"iso8601"},"dayOfMonth":27,"dayOfWeek":"WEDNESDAY","dayOfYear":86,"era":"CE","monthValue":3,"leapYear":false}}"; line: 1, column: 43] (through reference chain: com.JsonSerializer.User["date"])
大概意思:就是 LocalDate 的没有参数是 Object 的构造函数。不能实例化对象。
华丽的分割线 SpringBoot的处理
SpringBoot的解决方案:
Java bean的解决方案:
在 Java Bean 中使用注解,就可以进行反序列化和序列化。
执行结果:
FastJson 是性能极好的 JSON 解析器和生成器。
1. FastJson的优点:
2. FastJson的主要类:
1. FastJson的MAVEN依赖:
2. JSON准备:
ARR_JSON格式:
COMPLEX_JSON格式:
使用方式: github的使用文档
1. 通过 TypeReference 处理泛型对象
2. 使用 getType() 可以获取更好的性能。
1. TypeRefrence部分源码分析:
为什么这里的构造方法要是兆简 protected 的,即我们无法直接创建该对象,只能使用匿名类创建 子类 对象。
getGenericSuperclass()的API方法
返回 Class 对象(类,接口,基本数据类型,void)的谈闭直接父类的 Type 类型。
如果父类是 parameterized [pə'ræmɪtəraɪzd] 类型(也可以理解为 父类是泛型对象 ),那么返回的参数类型是父类的泛型类型。
基本原理:
使用 public static <T> T parseObject(String text, Class<T> clazz) 方法,边可完成JSON的反序列化。
1. 特殊JSON反序列化
2. 泛型丢失
我们可以看到,因为返回值需要泛型类型 T 所以我们采用的是 Class<T> ,防止返回Object对象,让用户强转。但需要注意: 这种方式在反序列化的时候,会丢失泛型类型。
方式一:TypeReference
方式二:使用parseArray
我们可以通过这个 API ,完成 Bean 对象转换成 String 类型。
String toJSONString(Object object, SerializerFeature... features)
若是对象的属性只是简单数据类型(基本数据类型,或者String类型)那么可以使用Class方式转化为Object对象。
若是一个对象里面的属性依旧是一个对象,那么我们就可以使用TypeRefrence进行转换。
我们在将JSON转换为对象的时候,就可以保留List<T>的泛型。即:
参考文章:
Java下利用Jackson进行JSON解析和序列化
使用FastJson处理JSON数据
fastjson如何json数组串转换为Object[]时如何指定各个数据项的数据类型