Jam*_*hon 5 java hibernate spring-mvc
我正在使用Spring MVC 2.5,我正在尝试从GET请求加载JSTL表单对象.我有Hibernate POJO作为我的支持对象.
有一个页面指向请求中具有类ID(行主键)的另一个页面.该请求看起来像"newpage.htm?name = RowId".这是一个带有表单支持对象的页面,
上面的新页面将对象的字段加载到可编辑字段中,并使用行的现有值填充.我们的想法是,您应该能够编辑这些字段,然后将它们保存回数据库.
此页面的视图看起来像这样
<form:form commandName="thingie">
<span>Name:</span>
<span><form:input path="name" /></span>
<br/>
<span>Scheme:</span>
<span><form:input path="scheme" /></span>
<br/>
<span>Url:</span>
<span><form:input path="url" /></span>
<br/>
<span>Enabled:</span>
<span><form:checkbox path="enabled"/></span>
<br/>
<input type="submit" value="Save Changes" />
</form:form>
Run Code Online (Sandbox Code Playgroud)
控制器有这个,
public class thingieDetailController extends SimpleFormController {
public thingieDetailController() {
setCommandClass(Thingie.class);
setCommandName("thingie");
}
@Override
protected Object formBackingObject(HttpServletRequest request) throws Exception {
Thingie thingieForm = (Thingie) super.formBackingObject(request);
//This output is always null, as the ID is not being set properly
logger.debug("thingieForm.getName(): [" + thingieForm.getName() + "]");
//thingieForm.setName(request.getParameter("name"));
SimpleDAO.loadThingie(thingieForm);
return thingieForm;
}
@Override
protected void doSubmitAction(Object command) throws Exception {
Thingie thingie = (Thingie) command;
SimpleDAO.saveThingie(thingie);
}
}
Run Code Online (Sandbox Code Playgroud)
从注释代码中可以看出,我尝试从请求中手动设置对象ID(名称就是这种情况).但是,当我尝试在表单中保存数据时,Hibernate会抱怨对象被取消同步.
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)
Run Code Online (Sandbox Code Playgroud)
这个错误似乎对整个会话起了作用,它停止了我的整个Web应用程序的工作,不断抛出上面所见的Stale Object State Exception.
如果熟悉Spring MVC的人可以帮助我或建议一个解决方法,我会非常感激.
编辑:
会话工厂代码.
private static final SessionFactory sessionFactory;
private static final Configuration configuration = new Configuration().configure();
static {
try {
// Create the SessionFactory from standard (hibernate.cfg.xml)
// config file.
sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
} catch (Throwable ex) {
// Log the exception.
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
Run Code Online (Sandbox Code Playgroud)
使用Spring MVC + hibernate的一个主要缺点是,自然的方法是使用hibernate域对象作为表单的后备对象.Spring将根据DEFAULT的名称绑定请求中的任何内容.这无意中包括ID或名称(通常是主键)或其他正在设置的hibernate托管属性.这也使您容易形成注射.
为了在这种情况下保持安全,您必须使用以下内容:
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder)
throws Exception {
String[] allowedFields = {"name", "birthday"}
binder.setAllowedFields(allowedFields);
}
Run Code Online (Sandbox Code Playgroud)
并且明确地将ALLOWED字段设置为仅包含表单中的字段,并排除主键,否则最终会出现问题!
要回答您的直接问题,您使用Hibernate时遇到的问题与以下事件序列有关:
formBackingObjectformBackingObjectformBackingObjectdoSubmitAction被调用时,的同一实例Thingie背衬对象被作为命令传递Hibernate此时对会话A一无所知,因为它已关闭,因此您会收到错误.好消息是你不应该这样做,正确的方法将完全绕过这个错误.
该formBackingObject方法用于在显示表单之前使用数据填充表单的命令对象.根据您更新的问题,听起来您只是尝试显示填充了给定数据库行信息的表单,并在提交表单时更新该数据库行.
看起来你已经有了一个模型类供你的记录使用; 我会Record在这个答案中称之为班级.你也有Record课程的DAO ,我会打电话给你RecordDao.最后,您需要一个UpdateRecordCommand将成为您的支持对象的类.在UpdateRecordCommand应与以下字段和setter /吸气剂来定义:
public class UpdateRecordCommand {
// Row ID of the record we want to update
private int rowId;
// New name
private int String name;
// New scheme
private int String scheme;
// New URL
private int String url;
// New enabled flag
private int boolean enabled;
// Getters and setters left out for brevity
}
Run Code Online (Sandbox Code Playgroud)
然后使用以下代码定义表单:
<form:form commandName="update">
<span>Name:</span>
<span><form:input path="name" /></span><br/>
<span>Scheme:</span>
<span><form:input path="scheme" /></span><br/>
<span>Url:</span>
<span><form:input path="url" /></span><br/>
<span>Enabled:</span>
<span><form:checkbox path="enabled"/></span><br/>
<form:hidden path="rowId"/>
<input type="submit" value="Save Changes" />
</form:form>
Run Code Online (Sandbox Code Playgroud)
现在定义表单控制器,它将填充表单formBackingObject并处理更新请求doSubmitAction.
public class UpdateRecordController extends SimpleFormController {
private RecordDao recordDao;
// Setter and getter for recordDao left out for brevity
public UpdateRecordController() {
setCommandClass(UpdateRecordCommand.class);
setCommandName("update");
}
@Override
protected Object formBackingObject(HttpServletRequest request)
throws Exception {
// Use one of Spring's utility classes to cleanly fetch the rowId
int rowId = ServletRequestUtils.getIntParameter(request, "rowId");
// Load the record based on the rowId paramrter, using your DAO
Record record = recordDao.load(rowId);
// Populate the update command with information from the record
UpdateRecordCommand command = new UpdateRecordCommand();
command.setRowId(rowId);
command.setName(record.getName());
command.setScheme(record.getScheme());
command.setUrl(record.getUrl());
command.setEnabled(record.getEnabled());
// Returning this will pre-populate the form fields
return command;
}
@Override
protected void doSubmitAction(Object command) throws Exception {
// Load the record based on the rowId in the update command
UpdateRecordCommand update = (UpdateRecordCommand) command;
Record record = recordDao.load(update.getRowId());
// Update the object we loaded from the data store
record.setName(update.getName());
record.setScheme(update.getScheme());
record.setUrl(update.getUrl());
record.setEnabled(update.setEnaled());
// Finally, persist the data using the DAO
recordDao.save(record);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
31664 次 |
| 最近记录: |