对于spring-web项目,在数据库设计时,当我们想增加一个字段时,并不希望修改表结构,希望设计一个专用的扩展字段,将增加的扩展字段以一个JSON字符串形式保存在这个专用字段中。
spring对JSON的序列化和反序列化是依赖jackson来完成的。
数据发送给前端的时候,我们希望jackson在序列化一个数据库记录对象时以JSON的形式返回这个JSON扩展字段的内容,而不是一个String,
同时前端也能以一个JSON的形式定义这个JSON扩展字段,服务端在收到请求jackson在反序列化时能自动将这个JSON字段反序列化为String.这样省去了手工写代码转换的过程才是最方便的。
举例说明一下吧,以下是一个数据库记录对象,props
字段为一个JSON扩展字段可以存储任意字段数据
public static class JsonTestUser{
private Integer id;
private String name;
/** (JSON格式)扩展字段 */
private String props;
......//
}
我们希望它序列化时,将props
字段以原始内容输出,也就是一个JSON对象,而不这种带转义符的字符串:{\"phone\":\"13088927898\","email":\"hello@qq.com\"}
{
"id":0,
"name":"tom",
"props":{
"phone":"13088927898",
"email":"hello@qq.com"
}
}
将上面的JsonTestUser#props
以原始内容输出,并不复杂,利用jackson的注解@JsonRawValue
注解就可以完美支持,
如下在props
字段定义上增加@JsonRawValue
注解,在序列化props字段就会不加转义符直接原内容输出。
@JsonRawValue
private String props;
如果希望将JSON对象反序列化保存到String字段,就需要自己实现一个JsonDeserializer
代码如下:
import java.io.IOException;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
/**
* Deserializing JSON property as String with Jackson<br>
* 实现将有{@link com.fasterxml.jackson.annotation.JsonRawValue}注解的
* 内容为JSON的String类型字段反序列化为String的反序列化器实现
* copy from <a ref="https://cassiomolin.com/2017/01/24/deserializing-json-property-as-string-with-jackson/">《Deserializing JSON property as String with Jackson》</a>
*
*/
public class RawJsonDeserializer extends JsonDeserializer<String> {
@Override
public String deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
/**
* 如果希望保存原始字符串内容,空格,tab,换行,则采用如下方式,不解析为JSON对象直接将原字符串返回
*/
long begin = jp.getCurrentLocation().getCharOffset();
jp.skipChildren();
long end = jp.getCurrentLocation().getCharOffset();
String json = jp.getCurrentLocation().getSourceRef().toString();
return json.substring((int) begin - 1, (int) end);
}
}
然后再使用@JsonDeserialize
注解指定props字段使用我们定义的反序列化器
如下,就可以完美实现JSON字段的自动序列化和反序列化
@JsonRawValue
@JsonDeserialize(using = RawJsonDeserializer.class)
private String props;