最近在做项目的时候使用的框架结构是springMVC+hibernate+easyui。
但在实际开发过程中遇到了一个问题就是:由于hibernate为了提高读取效率,使用了懒加载的机制,但是在实际前台读取JSON的时候确报错:No serializer found for class org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer and no properties discovered to create BeanSerialize……原因是启用了懒加载机制,但是JSON回去读全部的内容,读不到而导致出错。
一开始想既然JSON读不到,而我做的只是给一个工厂用的小的库房管理系统,如果不考虑懒加载呢?于是我把所有的model的关联关系中的懒加载都取消,问题又来了:这次用火狐的debug看控制台,发现传到前台的JSON数据无线循环,eclipse后台也报错了。然后上网找了一堆这样的问题,发现基本有两种解决方案:
1.使用vo+do,前后台分层的机制,do对象是从数据库里查出来的持久化对象,vo是为了给页面展示,直接new的视图对象。
这种方案也是我最初想到的一种方案,但是有个缺点就是需要写一堆的重复代码。因为vo和do的区别就是vo之间的关系没有do紧密,只需要把do中需要展示的属性赋予do即可。比如:现在我有一个user对象和一个role对象。二者是多对一的关系,在用户列表中需要展示用户的角色信息(用户角色名)。vo和do我是这么设计的:
UserVO:
package com.app.permission.model.vo; import java.util.Date; public class UserVO { private Integer id; private String username; private String password = "123456"; private String realName; private String roleName; // 角色名 private Integer roleId; // 角色ID private String departmentName; private Integer departmentId; private String departmentCode; private String sex; private Integer activeFlag = 1;// 是否有效:1有效,0无效 private String tel; private String email; private String description; private Date createDate = new Date(); private String idcard; private Date loginTime;// private String userSecurity;// 用户密级 private String address;// 现住址 private String mobileTel;// 手机号 private String homeTel;// 家庭电话 //。。。。省略get和set }
UserDO:
package com.app.permission.model; import java.util.Date; import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import org.hibernate.annotations.Cache; import org.hibernate.annotations.CacheConcurrencyStrategy; /** * 用户 * * @author gefangshuai * @email [email protected] * @createdate 2012-11-3下午12:11:46 */ @Entity @Cache(usage = CacheConcurrencyStrategy.READ_WRITE) public class User { private Integer id; private String username; private String password = "123456"; private String realName; private String sex; private Integer activeFlag = 1;// 是否有效:1有效,0无效 private String tel; private String email; private String description; private Date createDate = new Date(); private Role role; private Department department; private String idcard; private Date loginTime;// private String userSecurity;// 用户密级 private String address;// 现住址 private String mobileTel;// 手机号 private String homeTel;// 家庭电话 public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getMobileTel() { return mobileTel; } public void setMobileTel(String mobileTel) { this.mobileTel = mobileTel; } public String getHomeTel() { return homeTel; } public void setHomeTel(String homeTel) { this.homeTel = homeTel; } /** * 流水号 * * @return */ @Id @GeneratedValue(strategy = GenerationType.AUTO) public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } /** * 用户名 * * @return */ public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } /** * 密码 * * @return */ public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } /** * 真实姓名 * * @return */ public String getRealName() { return realName; } public void setRealName(String realName) { this.realName = realName; } /** * 是否有效 1有效 0无效 * * @return */ public Integer getActiveFlag() { return activeFlag; } public void setActiveFlag(Integer activeFlag) { this.activeFlag = activeFlag; } /** * 联系电话 * * @return */ public String getTel() { return tel; } public void setTel(String tel) { this.tel = tel; } /** * 邮箱 * * @return */ public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } /** * 备注描述 * * @return */ public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } /** * 创建日期 * * @return */ public Date getCreateDate() { return createDate; } public void setCreateDate(Date createDate) { this.createDate = createDate; } /** * 用户拥有的角色 * * @return */ @ManyToOne() @JoinColumn(name = "roleId") public Role getRole() { return role; } public void setRole(Role role) { this.role = role; } /** * 用户所在部门 * * @return */ @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "departmentId") public Department getDepartment() { return department; } public void setDepartment(Department department) { this.department = department; } /** * 身份证号码 * * @return */ public String getIdcard() { return idcard; } public void setIdcard(String idcard) { this.idcard = idcard; } /** * 上次登录时间 * * @return */ public Date getLoginTime() { return loginTime; } public void setLoginTime(Date loginTime) { this.loginTime = loginTime; } /** * 用户密级 * * @return */ public String getUserSecurity() { return userSecurity; } public void setUserSecurity(String userSecurity) { this.userSecurity = userSecurity; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } }
二者之间的区别就是DO中是完整的和Role的关联关系,VO提供供展示的属性,比如我在用户列表中只需要将对应用的角色名字展示,那么我在设计VO的时候,只需要一个String类型的roleName即可,当然为了前台关联方便,我将roleId也传到前台当隐藏表单。
这种设计思路是比较清晰容易的一种思路,但是如果我的DO中有100个属性呢?是不是在进行DO和VO转化的时候进行100次get和set呢?这样无用的工作量太大了,幸好apache有现成的工具类给我们用:org.apache.commons.beanutils.BeanUtil这个类有copyProperties(Object dest, Object orig),这个方法可以将两个相似的对象只要属性名相同可以进行属性值的拷贝。省了我们很多的功夫。
2.使用@JsonIgnoreProperties(value={"hibernateLazyInitializer"})注解。
当然我最先想如果这种方案能解决问题,就一个注解搞定,但是试了好多次这种方法都没成功,大牛是否能提供一下完整的解决思路呢?
以下是没成功的代码:
/** * 用户拥有的角色 * * @return */ @ManyToOne() @JoinColumn(name = "roleId") @JsonIgnoreProperties(value={"hibernateLazyInitializer"}) public Role getRole() { return role; }
是不是除了加一个注解还需要配置什么东西?