问题
工作中遇到一个问题,QueryDSL查询 pg数据库的一个表,表中一个某个字段类型是jsonb,jsonb的存取和json在java层面上没有什么区别,但是得到的数据,会多余了一个type字段。比如:
数据库存的是:
{"wubi": "tgrpss", "pinyin": "teshuzhidingjigou", "shoupin": "tszdjg"}
经过QueryDSL查出来的数据就变成了下面这样:
{
"type": "jsonb",
"value": "{\"wubi\": \"tgrpss\", \"pinyin\": \"teshuzhidingjigou\", \"shoupin\": \"tszdjg\"}"
}
这就很难受了,前端用起来极不方便。
原因
解决过程少不了看源码,经过源码分析,流程大概这样:
-
前端调用接口,接口方法中,使用的是 QueryDSL,通过pgConnection驱动进行sql查询,查看打印sql,再正常不过了。
-
pgConnection驱动从pg中查出结果,在处理过程中,通过层层映射,这里就不细说了,实际上并没有映射到相关的类型,走的default路径,最后给 QueryDSL 返回一个 org.postgresql.util.PGobject 对象。
public class PGobject implements Serializable, Cloneable {
protected String type;
protected String value;
public PGobject() {
}
...
}

-
QueryDSL 得到对象后,处理很简单,就是通过反射,讲查询的到数据,放到一个前端接口映射的一个对象中。
-
最终前端拿到这个对象,是一个PGobject 。
解决思路
首先, pgConnection驱动从pg库中取数据这个过程,我们是没有办法处理的,这个是pg驱动jar来处理的,处理这个不划算。
第二,QueryDSL 通过反射, PGobject 写到前端查询需要的对象(OBJ)中。这一步也是QueryDSL的jar来处理的,反射过程很简单,也没有重构的必要。
所以,只能冲前端拿到 OBJ 之前,做处理了。处理这个,SpringMVC早就有一套了。
Spring MVC JSON自己定义类型转换
继承 JsonSerializer 抽奖类,重写 serialize方法,如下:
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import org.postgresql.util.PGobject;
import java.io.IOException;
import java.util.Objects;
public class PgObjectJsonSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object o, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
if (Objects.isNull(o)) {
return;
}
if (o instanceof PGobject) {
PGobject pgO = (PGobject) o;
if ("jsonb".equals(pgO.getType())) {
jsonGenerator.writeObject(pgO.getValue());
}
}
}
}
在返回给前端的对象上使用即可:
public class XXX implements Serializable {
@JsonSerialize(using = PgObjectJsonSerializer.class)
private transient Object xxx;
...
}

5755

被折叠的 条评论
为什么被折叠?



