Spring - 绑定到对象而不是String或基元

时间:2021-11-17 20:30:13

Let's say I have the following command object:

假设我有以下命令对象:

class BreakfastSelectCommand{
    List<Breakfast> possibleBreakfasts;
    Breakfast selectedBreakfast;
}

How can I have spring populate "selectedBreakfast" with a breakfast from the list?

如何从名单中选择含早餐的“selectedBreakfast”?

I was figuring I'd do something like this in my jsp:

我在想我在jsp中做这样的事情:

<form:radiobuttons items="${possibleBreakfasts}" path="selectedBreakfast"  />

But this doesn't seem to work. Any ideas?

但这似乎不起作用。有任何想法吗?

thanks,

-Morgan

1 个解决方案

#1


The key to it all of this is the PropertyEditor.

所有这一切的关键是PropertyEditor。

You need to define a PropertyEditor for your Breakfast class and then configure the ServletDataBinder using registerCustomEditor in the initBinder method of your controller.

您需要为Breakfast类定义PropertyEditor,然后在控制器的initBinder方法中使用registerCustomEditor配置ServletDataBinder。

example:

public class BreakfastPropertyEditor extends PropertyEditorSupport{
    public void setAsText(String incomming){
        Breakfast b = yourDao.findById( Integer.parseInt(incomming));
        setValue(b);
    }
    public String getAsText(){
        return ((Breakfast)getValue()).getId();
    }
}

note you'll be needing some null checking etc, but you get the idea. In your controller:

请注意,您将需要一些空检查等,但您明白了。在你的控制器中:

public BreakfastFooBarController extends SimpleFormController {
    @Override
    protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) {
        binder.registerCustomEditor(Breakfast.class, new BreakfastPropertyEditor(yourDao));
    }
}

things to watch out for:

需要注意的事项:

  • PropertyEditor's are not thread safe
  • PropertyEditor不是线程安全的

  • if you need spring beans, either manually inject them or define them in spring as prototype scope and use method injection into your controller
  • 如果你需要spring bean,可以手动注入它们,或者在spring中定义它们作为原型范围,并使用方法注入你的控制器

  • throw IllegalArgumentException if the inbound parameter is not valid/not found, spring will convert this into a binding error correctly
  • 抛出IllegalArgumentException如果入站参数无效/未找到,spring会将此转换为绑定错误

hope this helps.

希望这可以帮助。

Edit (in response to the comment): It looks a little strange in the given example because BreakfastSelectCommand doesn't look like an entity, I'm not sure what the actual scenario you have is. Say it is an entity, for example like Person with a breakfast property then the formBackingObject() method would load the Person object from the the PersonDao and return it as the command. The binding phase would then change the breakfast property depending on the selected value, such that the command that arrives in onSubmit has the breakfast property all set up.

编辑(响应评论):在给定的例子中看起来有点奇怪,因为BreakfastSelectCommand看起来不像实体,我不确定你的实际情况是什么。假设它是一个实体,例如像带有早餐属性的Person那么formBackingObject()方法将从PersonDao加载Person对象并将其作为命令返回。然后绑定阶段将根据所选值更改早餐属性,以便到达onSubmit的命令具有所有设置的早餐属性。

Depending on the implementation of your DAO objects calling them twice or attempting to load the same entity twice doesn't actually mean that you will get two SQL statements being run. This applies particularly to Hibernate, where it guarantees that it will return the same object that is in it's session for a given identifier, thus running letting the binding attempt to load the Breakfast selection even through it hasn't changed shouldn't result in any undue overhead.

根据您的DAO对象的实现调用它们两次或尝试两次加载相同的实体并不意味着您将获得两个运行的SQL语句。这特别适用于Hibernate,它保证它将返回给定标识符在其会话中的同一对象,从而运行让绑定尝试加载Breakfast选项,即使它没有改变也不会导致任何过度开销。

#1


The key to it all of this is the PropertyEditor.

所有这一切的关键是PropertyEditor。

You need to define a PropertyEditor for your Breakfast class and then configure the ServletDataBinder using registerCustomEditor in the initBinder method of your controller.

您需要为Breakfast类定义PropertyEditor,然后在控制器的initBinder方法中使用registerCustomEditor配置ServletDataBinder。

example:

public class BreakfastPropertyEditor extends PropertyEditorSupport{
    public void setAsText(String incomming){
        Breakfast b = yourDao.findById( Integer.parseInt(incomming));
        setValue(b);
    }
    public String getAsText(){
        return ((Breakfast)getValue()).getId();
    }
}

note you'll be needing some null checking etc, but you get the idea. In your controller:

请注意,您将需要一些空检查等,但您明白了。在你的控制器中:

public BreakfastFooBarController extends SimpleFormController {
    @Override
    protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) {
        binder.registerCustomEditor(Breakfast.class, new BreakfastPropertyEditor(yourDao));
    }
}

things to watch out for:

需要注意的事项:

  • PropertyEditor's are not thread safe
  • PropertyEditor不是线程安全的

  • if you need spring beans, either manually inject them or define them in spring as prototype scope and use method injection into your controller
  • 如果你需要spring bean,可以手动注入它们,或者在spring中定义它们作为原型范围,并使用方法注入你的控制器

  • throw IllegalArgumentException if the inbound parameter is not valid/not found, spring will convert this into a binding error correctly
  • 抛出IllegalArgumentException如果入站参数无效/未找到,spring会将此转换为绑定错误

hope this helps.

希望这可以帮助。

Edit (in response to the comment): It looks a little strange in the given example because BreakfastSelectCommand doesn't look like an entity, I'm not sure what the actual scenario you have is. Say it is an entity, for example like Person with a breakfast property then the formBackingObject() method would load the Person object from the the PersonDao and return it as the command. The binding phase would then change the breakfast property depending on the selected value, such that the command that arrives in onSubmit has the breakfast property all set up.

编辑(响应评论):在给定的例子中看起来有点奇怪,因为BreakfastSelectCommand看起来不像实体,我不确定你的实际情况是什么。假设它是一个实体,例如像带有早餐属性的Person那么formBackingObject()方法将从PersonDao加载Person对象并将其作为命令返回。然后绑定阶段将根据所选值更改早餐属性,以便到达onSubmit的命令具有所有设置的早餐属性。

Depending on the implementation of your DAO objects calling them twice or attempting to load the same entity twice doesn't actually mean that you will get two SQL statements being run. This applies particularly to Hibernate, where it guarantees that it will return the same object that is in it's session for a given identifier, thus running letting the binding attempt to load the Breakfast selection even through it hasn't changed shouldn't result in any undue overhead.

根据您的DAO对象的实现调用它们两次或尝试两次加载相同的实体并不意味着您将获得两个运行的SQL语句。这特别适用于Hibernate,它保证它将返回给定标识符在其会话中的同一对象,从而运行让绑定尝试加载Breakfast选项,即使它没有改变也不会导致任何过度开销。