当前位置:  开发笔记 > 编程语言 > 正文

Spring MVC,从请求生成表单支持对象?

如何解决《SpringMVC,从请求生成表单支持对象?》经验,为你挑选了2个好方法。

我正在使用Spring MVC 2.5,我正在尝试从GET请求加载JSTL表单对象.我有Hibernate POJO作为我的支持对象.

有一个页面指向请求中具有类ID(行主键)的另一个页面.该请求看起来像"newpage.htm?name = RowId".这是一个带有表单支持对象的页面,

上面的新页面将对象的字段加载到可编辑字段中,并使用行的现有值填充.我们的想法是,您应该能够编辑这些字段,然后将它们保存回数据库.

此页面的视图看起来像这样


    Name:
    
    
Scheme:
Url:
Enabled:

控制器有这个,

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

Justin.. 6

使用Spring MVC + hibernate的一个主要缺点是,自然的方法是使用hibernate域对象作为表单的后备对象.Spring将根据DEFAULT的名称绑定请求中的任何内容.这无意中包括ID或名称(通常是主键)或其他正在设置的hibernate托管属性.这也使您容易形成注射.

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

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

并且明确地将ALLOWED字段设置为仅包含表单中的字段,并排除主键,否则最终会出现问题!



1> Justin..:

使用Spring MVC + hibernate的一个主要缺点是,自然的方法是使用hibernate域对象作为表单的后备对象.Spring将根据DEFAULT的名称绑定请求中的任何内容.这无意中包括ID或名称(通常是主键)或其他正在设置的hibernate托管属性.这也使您容易形成注射.

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

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

并且明确地将ALLOWED字段设置为仅包含表单中的字段,并排除主键,否则最终会出现问题!



2> William Bren..:

要回答您的直接问题,您使用Hibernate时遇到的问题与以下事件序列有关:

    一个Hibernate会话打开(让我们称之为会话A) formBackingObject

    使用会话A,您可以加载Thingie对象 formBackingObject

    你返回Thingie对象的结果 formBackingObject

    当你返回Thingie对象时,会话A被关闭,但Thingie仍然与它相关联

    doSubmitAction被调用时,的同一实例Thingie背衬对象被作为命令传递

    打开一个新的Hibernate会话(称为会话B)

    您尝试使用会话B保存Thingie对象(最初使用会话A打开)

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
}

然后使用以下代码定义表单:


  Name:
  
Scheme:
Url:
Enabled:

现在定义表单控制器,它将填充表单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);
  }
}

推荐阅读
pan2502851807
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有