Hibernate雙向關聯導致Java對象轉換為JSON字符串時死循環問題的分析與解決方案
引言:
本文描述了在SSH框架中,多個持久層對象相互引用,從而引發分頁查詢中,查詢所得的持久化對象轉換為JSON字符串報錯的原因及解決方案
使用EasyUI框架的小伙伴們都知道,在使用datagrid(數據表格)時,會傳入如一個URL,用于請求數據表格中的所顯示的數據:
<!--創建一個空表格-->
<table id="mytable"></table>
<script type="text/javascript">
$(function() {
//頁面加載完成后,創建數據表格datagrid
$("#mytable").datagrid(
{
//定義標題行所有的列,注意這是一個二維數組
columns : [ [ {
title : '編號',
field : 'id',
checkbox : true
}....... ] ],
//指定數據表格發送ajax請求的地址
url : '${pageContext.request.contextPath }/subareaAction_pageQuery'
});
});
</script>
而后臺相應的是一個JSON字符串,具體datagrid的使用方法,博主在另一篇文章中詳細介紹了:
既然后端需要響應的是一個JSON字符串自然需要用到JSON的轉換工具,JSON轉換工具有多種,我們這里使用Jsonlib。通過這個工具我們將在web層中將Service層返回的持久層對象轉換成JSON格式的字符串,然后響應給客戶端。那么在轉換成JSON字符串過程中會出現一個問題,需要我們注意!
問題描述:
我們這里給出兩個持久層對象:
Region對象代表區域對象,一個區域中有多個分區;但一個分區只對應一個區域。
Subarea對象(省略Get和Set方法):
public class Subarea implements java.io.Serializable {
// Fields
private String id;
private Decidedzone decidedzone;
private Region region;
private String addresskey;
private String startnum;
private String endnum;
private String single;
private String position;
}
Region對象:
public class Region implements java.io.Serializable {
// Fields
private String id;
private String province;
private String city;
private String district;
private String postcode;
private String shortcode;
private String citycode;
private Set subareas = new HashSet();
}
如果我們客戶端需要需要獲得所有Subarea的數據,此時我們會將所有Subarea對象查詢出來并返回給web層,在web層中我們會將LIst<Subarea>對象通過Jsonlib工具轉換成JSON字符串。但如果試圖直接用 JSONArray.fromObject(list) 方法將查詢出來的List對象轉換成JSON字符串會報錯。
問題分析與解決:
之所以出現上述問題,是因為在每個Subarea對象中有一個Region對象,而Region對象中又會包含Subarea本身,所以在這里會出現Java對象轉JSON的異常。
那我們如何將解決這個問題呢?這里我么需要分兩種情況
情況一:前端頁面不需要Subarea中Region對象的數據
這個情況很好解決,我們只需要在生成JSON對象時排除Region對象所對應的屬性即可。
public class SubareaAction extends BaseAction<Subarea>{
public String pageQuery() {
subareeaService.pageQuery(pageBean);
JsonConfig config = new JsonConfig();
config.setExcludes(new String[] {"currentPage","pageSize","detachedCriteria","region"});
JSONObject json = JSONObject.fromObject(obj, config);
ServletActionContext.getResponse().setContentType("text/json;charset=utf-8");
try {
ServletActionContext.getResponse().getWriter()
.write(json.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
情況二:前端頁面需要Region中的數據
有些小伙伴可能就會說了,直接排除Region對象的subareas屬性不就行了。但這樣做還不夠,因為Hibernate默認配置中,關聯對象采用延遲加載策略。Subarea對象中的Region實際上是一個代理對象。如果Jsonlib嘗試將這個代理對象轉換成字符串時,同樣會報錯!
解決步驟:
第一步:在將List<Subarea>轉換成JSON字符串時,需要將List中每個Subarea中Region對象的subareas屬性排除。
public class SubareaAction extends BaseAction<Subarea>{
public String pageQuery() {
subareeaService.pageQuery(pageBean);
JsonConfig config = new JsonConfig();
config.setExcludes(new String[] {"currentPage","pageSize","detachedCriteria","subareas"});
JSONObject json = JSONObject.fromObject(obj, config);
ServletActionContext.getResponse().setContentType("text/json;charset=utf-8");
try {
ServletActionContext.getResponse().getWriter()
.write(json.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
第二步:在配置文件中關閉關聯對象的延遲加載
<hibernate-mapping>
<class name="com.tjd.bos.domain.Subarea" table="bc_subarea" >
<id name="id" type="java.lang.String">
<column name="id" length="32" />
<generator class="uuid" />
</id>
<many-to-one name="decidedzone" class="com.tjd.bos.domain.Decidedzone" fetch="select">
<column name="decidedzone_id" length="32" />
</many-to-one>
//重點就是在這里添加 lazy="false"
<many-to-one lazy="false" name="region" class="com.tjd.bos.domain.Region" fetch="select">
<column name="region_id" length="32" />
</many-to-one>
<property name="addresskey" type="java.lang.String">
<column name="addresskey" length="100" />
</property>
<property name="startnum" type="java.lang.String">
<column name="startnum" length="30" />
</property>
<property name="endnum" type="java.lang.String">
<column name="endnum" length="30" />
</property>
<property name="single" type="java.lang.String">
<column name="single" length="1" />
</property>
<property name="position" type="java.lang.String">
<column name="position" />
</property>
</class>
</hibernate-mapping>

浙公網安備 33010602011771號