03 July 2018

做分页查询的时候,发现外键关联的数据查询不出来,而且比较诡异的时候一个列表中,前面记录关联的记录可以正常出来,后面记录的关联数据出不来,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;
    }

}





blog comments powered by Disqus
Fork me on GitHub