3

我在 Spring MVC 中使用自定义编辑器将字符串值映射到我的域对象。简单案例:用户对象指的是公司(User.company -> Company)。在用户表单中,我注册了数据绑定器:

protected void initBinder(WebDataBinder binder) throws Exception {
    binder.registerCustomEditor(Company.class, new CompanyEditor(appService));
}

编辑器定义如下:

class CompanyEditor extends PropertyEditorSupport {

    private AppService appService;  

    public CompanyEditor(AppService appService) {
        this.appService = appService;
    }

    public void setAsText(String text) {
        Company company = appService.getCompany(text);
        setValue(company);
    }

    public String getAsText() {
        Company company = (Company) this.getValue();
        if (company != null)
            return company.getId();
        return null;
    }    
}

当我在表单中使用下拉菜单时

<form:select path="company">
    <form:options items="${companies}" itemLabel="name" itemValue="id"/>
</form:select>

我遇到了严重的性能问题,因为(我想检查是否选择了公司)为每个选项触发 setAsText 和 getAsText,这使得它为每个公司运行 SQL 查询。

我认为当我提交表单时使用 setAsText 以使应用程序知道如何将公司 ID 转换为公司(持久)对象。为什么要在下拉菜单中触发它。任何想法如何解决它?

4

1 回答 1

2

如果您的表单支持对象存储为会话属性(即您@SessionAttributes("command")的控制器中有类似的东西),那么您可以尝试修改您的setAsText(String text)方法

public void setAsText(String text) {
        Company currentCompany = (Company) this.getValue();
        if ((currentCompany != null) && (currentCompany.getId().equals(text)))
          return;

        Company company = appService.getCompany(text);
        setValue(company);
    }

但我认为Spring 3.1 @Cacheable 抽象正是为此类事物引入的,并且更可取

请参阅文档中的示例

@Cacheable("books")
public Book findBook(ISBN isbn) {...}

PS 考虑使用新的转换器 SPI而不是属性编辑器。

通常,可以为您的查找实体实现通用转换器,因此如果实体具有某些特定属性,它将使用 id 自动从文本转换实体,例如,在我的一个项目中,所有@Entity类型都使用全局ConditionalGenericConverter实现,因此我既没有在绑定期间注册自定义属性编辑器,也没有为带有注释主键的简单@Entity类的类型实现特定转换器。@Id

@RequestParam此外,当 Spring 将文本对象 id 指定为带注释的控制器方法参数时,它们会自动将它们转换为实际实体,这也非常方便。

于 2012-08-10T09:59:38.963 回答