在我们使用json-lib和hibernate开发的时候,一开始的时候会遇到转换json数组的是出现死循环问题,下面就把我的经历记录一下,可能帮助到大家。
我的实体是这样的,用户和群两个实体(他们之间的关系是多对多,一个用户可在多个群中,一个群中有多个用户),对象模型如下:(即:实现的时候是双向的,用户可以取到群的信息,群里可以去到用户信息)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public
class
User{
private
int
id;
private
String name;
private
Set<Group> groups =
new
HashSet<Group>();
//getter or setter ....
}
public
class
Group{
private
int
id;
private
String name;
private
Set<User> users =
new
HashSet<User>();
// getter or setter ....
}
|
关系模型:
三张表:l_user(id,name)
l_group(id,name)
l_user_group(user_id,group_id);
配置的时候都设置为fetch 为懒加载的方式,现我有如下需求:
1.取出用户的时候,取出用户所在的群的所有信息,即,取一个用户,我还能够得到用户的所在所有群的名字
针对这个需求我是这样的写的dao的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
@Override
public
User findByExample(User user) {
// TODO Auto-generated method stub
User rs =
null
;
Session session = getSession();
try
{
session.beginTransaction().begin();
Query hql = session.createQuery(
"from User u where u.id=:id and u.password=:psd"
);
hql.setParameter(
"id"
,user.getId());
hql.setParameter(
"psd"
, user.getPassword());
rs = (User)hql.uniqueResult();
//加载群信息,因为使用的lazy的,所以需要加载
Iterator<Group> iterator = rs.getGroups().iterator();
while
(iterator.hasNext()){
Group g = iterator.next();
Hibernate.initialize(g);
}
session.beginTransaction().commit();
}
catch
(Exception e){
e.printStackTrace();
session.getTransaction().rollback();
}
finally
{
if
(session !=
null
&&session.isOpen())
{
session.close();
}
}
return
rs;
}
|
在action中的调用如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
public
String list(){
User u = userDAO.findByExample(
new
User(
1
,
null
,
"123456"
,
null
));
if
(u!=
null
){
//下面代码为测试
System.out.println(u.getName());
Iterator<Group> it = u.getGroups().iterator();
while
(it.hasNext()){
System.out.println(it.next().getName());
}
//打印结束
JsonConfig jsonConfig =
new
JsonConfig();
jsonConfig.setJsonPropertyFilter(
new
PropertyFilter() {
@Override
public
boolean
apply(Object arg0, String arg1, Object arg2) {
// TODO Auto-generated method stub
//问题在此处,如何过滤group中的users集合,只是去到名字,不取里面的成员信息
return
(arg0
instanceof
Group &&arg1.equals(
"users"
) && arg2==
null
);
}
});
//jsonrs字符串包含的是用户的信息
rsobj = JSONObject.fromObject(u,jsonConfig);
}
else
{
//不存在这样的用户,用户的为null,json结果为null
rsobj =
null
;
}
return
"list"
;
}
|
运行结果:
aaaaa
group1
2013-12-10 19:12:50 freemarker.log.JDK14LoggerFactory$JDK14Logger error
严重: Template processing error: "Method public java.lang.String org.apache.commons.lang.exception.NestableRuntimeException.getMessage(int) threw an exception when invoked on net.sf.json.JSONException: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.model.Group.users, no session or session was closed"
Method public java.lang.String org.apache.commons.lang.exception.NestableRuntimeException.getMessage(int) threw an exception when invoked on net.sf.json.JSONException: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.model.Group.users, no session or session was closed
The problematic instruction:
----------
==> ${msg[0]} [on line 68, column 29 in org/apache/struts2/dispatcher/error.ftl]
----------
哎,这里是我自己傻逼了,上面我的解题思路是对的,就是中间的一句代码写错了
1
2
3
4
5
6
7
8
|
jsonConfig.setJsonPropertyFilter(
new
PropertyFilter() {
@Override
public
boolean
apply(Object arg0, String arg1, Object arg2) {
// TODO Auto-generated method stub
//问题在此处,如何过滤group中的users集合,只是去到名字,不取里面的成员信息
return (arg0 instanceof Group &&arg1.equals( "users" ) && arg2== null
);
}
});
|
红色的部分用法出错了,不该使用&&,要使用||,改为
1
2
3
4
5
6
7
8
|
jsonConfig.setJsonPropertyFilter(
new
PropertyFilter() {
@Override
public
boolean
apply(Object arg0, String arg1, Object arg2) {
// TODO Auto-generated method stub
//问题在此处,如何过滤group中的users集合,只是去到名字,不取里面的成员信息
return ((arg0 instanceof Group &&arg1.equals( "users" )) || arg2== null );
}
});
|
问题就解决了,哎,自己真是S B啦。。。。
也就是说,如果我们在开发的时候有类似我们上面的需求的时候,可以把加载方式设置为lazy ,之后再DAO里按需,再在转换json的时候使用过滤器,当然设为lzay,转换json的时候使用过滤也行,但是既然不要他,为何去加载他呢,不是浪费么,是吧。所以这里可以自己灵活的使用,根据自己的需求选择加载方式,而处理死循环或者session关闭(lzay是才会出现的问题)问题时,使用JsonConfig的PorpertyFilter过滤一下就行。
关于PorpertyFliter 里面的三个参数,其实网上可以看到,这里也顺便说一下,arg0-->要过滤的属性的所有者(如:我的例子里面的users这个集合属性属于Group),arg1为需要过滤的属性名,arg2为属性的值();最终返回值为true表示过滤,否则不过滤
------------------------------------------分割线----------------------------------------------------------------
这是当初在使用struts2的时候没有了解struts2的json返回的特点,struts2和springMVC的返回json的效果其实可以一样的,直接返回查询的结果集 如:List<User>等,但是只要使用了hibernate的地方,出现了双对引用的时候就必然会出现这种问题。解决方式还是要使用json过滤。
https://github.com/FunHuan/hehe 此链接是本人总结的解决springMVC整合hibernate的时候出现的该错误的解决办法。
另外,MyBatis这个数据层框架还是不错,可以考虑用这个代替hibernate。有兴趣的同学可以研究下。
希望能够帮助到大家,谢谢