问题原型:项目中的一个小的留言板程序,大致是这样得:用户发表留言后,保存留言后并返回到留言展示页面,即用户留言与留言展示共享同一个视图页面。程序处理流程如下:
1.用户提交留言
2.struts2接受数据,并调用业务逻辑层保存数据,返回到留言展示页面
3.留言展示页面是由另一个action负责,用户添加留言与展示页面是同一个struts action类。它们的代码如下:
package com.asm.bbs.action;
//省略导入的包
/**
* 前台留言板的添加展示
*
* @author heou0709@126.com
*
*/
@Controller
public class SimpleMessageAction extends ActionSupport implements ServletRequestAware {
private static final long serialVersionUID = 1L;
@Resource
private SimpleMessageService messageService;
private HttpServletRequest request;
private Integer page = 1;
private SimpleMessage message;
/**
* 留言展示页面
*/
public String listMsg() throws Exception {
//业务逻辑处理,准备分页数据给展示页面
return "success";
}
/**
* 添加留言
*/
public String addMsg() throws Exception {
//调用业务逻辑层,持久化留言数据
return "success";
}
public Integer getPage() {
return page;
}
public void setPage(Integer page) {
this.page = page;
}
public SimpleMessage getMessage() {
return message;
}
public void setMessage(SimpleMessage message) {
this.message = message;
}
@Override
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
}
需要说明的是,当添加留言并处理后,经过redirectAction方式跳转到留言展示页面。在struts的配置如下:
<action name="goWord" class="simpleMessageAction" method="listMsg"> <result>/WEB-INF/..../leverWord.jsp</result> </action> <action name="addWord" class="simpleMessageAction" method="addMsg"> <result name="success" type="redirectAction"> <param name="actionName">goWord</param> </result> </action>
由于做了这样的配置,每次第一次添加留言都没的问题,但是如果第二次添加就会出问题,出现的异常如下:
javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: com.asm.xxxx.SimpleMessage
org.hibernate.PersistentObjectException: detached entity passed to persist: com.asm.xxxx.SimpleMessage
报这个错误的原因:struts2的强大的数据还原功能:因为第二次添加留言时,SimpleMessage类已具有一个初始化的id数据,这时我想起在hibernate官方文档说如果id是自动生成的,建议一定要把它的setter方式设为私有,如果在这里真这样做,问题仍不能解决,因为struts填充数据,并不只是依赖于字段的setter方式,它会借助于强大的反射功能和值栈技术,所以struts2的数据保存还原非常强大。要解决此问题的一个有效方式是对此action加spring实例对象作用域注解,因为受spring管理的所有类,默认的作用域singleton,即共享同一个bean实例对象。 在此处加上prototype注解: 每次请求都会创建一个实例,这样处理后问题基本解决,如果更合理的作用域,应根据具体需求来选择spring的web作用域。
总结:1.org.hibernate.PersistentObjectException: detached entity passed to persist异常原因:本该是自动生成id值被手工赋值,实体与数据库表的设计不相符
2.struts2的数据填充不只是依赖于setter方式,它会借助于反射实现数据填充。
3.spring管理的对象在使用时,一定要根据具体的需要来灵活设置作用域。