做分页查询的时候,发现外键关联的数据查询不出来,而且比较诡异的时候一个列表中,前面记录关联的记录可以正常出来,后面记录的关联数据出不来,debug发现返回的数据后面的出现:{“$ref”:”$.rows[2]”} 的情况
问题复现:
实体类做关联的时候使用了延迟加载,例如:
@Data
@Table(name = "t_test")
@Entity
public class TestBean implements Serializable {
@Id
private Long id;
@Column(name = "id_org", columnDefinition = "bigint COMMENT '机构id'")
private Long idOrg;
@JoinColumn(name="id_org",referencedColumnName = "id",columnDefinition = "bigint COMMENT '机构id'",insertable = false,updatable = false)
@ManyToOne(fetch = FetchType.LAZY)
private Org org;
@Column(name = "amount", columnDefinition = "varchar(20) COMMENT '总金额'")
private String amount;
}
查询TestBean列表的时候页面通过org.name 获取机构名称
假如有两条记录的idOrg相同,那么第一条记录的org可以正常获取,而第二条记录的org返回为:”org”:{“$ref”:”$.rows[2].org”}
完整json数据记录如下:
{
"amount":"500",
"id":"1",
"idOrg":"1",
"org":{
"id":"1",
"name":"XX教育公司",
}
},
{
"amount":"111",
"id":"5",
"idOrg":"1",
"org":{"$ref":"$.rows[2].org"},
}
出现上述问题的原因在于: 后台处理hibernate 延迟加载(lazy)的数据的时候时,它交给了Javassist处理,这时fastjson.会把它当对象处理,而不会解析它。
处理办法有两种,一种是不使用延迟加载,采用EAGER方式:
@JoinColumn(name="id_org",referencedColumnName = "id",columnDefinition = "bigint COMMENT '机构id'",insertable = false,updatable = false)
@ManyToOne(fetch = FetchType.EAGER)
private Org org;
当然上述方法是下策。更好的方式是关闭fastjson的循环引用检测功能: JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect)
我们在项目中做了fastjson的全局配置,具体更改如下:
@Configuration("defaultFastjsonConfig")
@ConditionalOnClass(com.alibaba.fastjson.JSON.class)
@ConditionalOnMissingBean(FastJsonHttpMessageConverter.class)
@ConditionalOnWebApplication
public class DefaultFastjsonConfig {
@Bean
public FastJsonHttpMessageConverter fastJsonHttpMessageConverter() {
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
converter.setFastJsonConfig(fastjsonConfig());
converter.setSupportedMediaTypes(getSupportedMediaType());
return converter;
}
/**
* fastjson的配置
*/
public FastJsonConfig fastjsonConfig() {
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(
SerializerFeature.PrettyFormat,
SerializerFeature.WriteMapNullValue,
SerializerFeature.WriteEnumUsingToString,
//关闭循环应用检测
SerializerFeature.DisableCircularReferenceDetect
);
fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss");
ValueFilter valueFilter = new ValueFilter() {
public Object process(Object o, String s, Object o1) {
if (null == o1) {
o1 = "";
}
return o1;
}
};
fastJsonConfig.setCharset(Charset.forName("utf-8"));
fastJsonConfig.setSerializeFilters(valueFilter);
//解决Long转json精度丢失的问题
SerializeConfig serializeConfig = SerializeConfig.globalInstance;
serializeConfig.put(BigInteger.class, ToStringSerializer.instance);
serializeConfig.put(Long.class, ToStringSerializer.instance);
serializeConfig.put(Long.TYPE, ToStringSerializer.instance);
fastJsonConfig.setSerializeConfig(serializeConfig);
return fastJsonConfig;
}
/**
* 支持的mediaType类型
*/
public List<MediaType> getSupportedMediaType() {
ArrayList<MediaType> mediaTypes = new ArrayList<>();
mediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
return mediaTypes;
}
}