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>

控制器里面有这个

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);
    }
}

从注释代码中可以看到,我尝试从请求中手动设置对象ID(这种情况下为名称)。但是,当我尝试将数据持久保存在表单中时,Hibernate抱怨该对象被取消同步。

org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)

该错误似乎对整个会话都起作用,从而使整个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;
}

问题答案:

使用Spring MVC +
hibernate的主要缺陷之一是自然的方法是使用hibernate域对象作为表单的后备对象。Spring将根据名称通过DEFAULT绑定请求中的任何内容。这无意间包括了诸如ID或名称(通常是主键)或其他hibernate管理属性的设置。这也使您很容易进行表单注入。

为了在这种情况下保持安全,您必须使用类似以下内容的方法:

protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) 
throws Exception {
 String[] allowedFields = {"name", "birthday"}
 binder.setAllowedFields(allowedFields);
}

并明确地将“允许”字段设置为仅表单中的那些字段,并排除主键,否则您将陷入混乱!!!