我在Spring MVC中使用自定义编辑器将字符串valuest映射到我的域对象。简单案例:用户对象是指公司(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使应用程序知道如何将compnany id转换为Company(持久化)对象。为什么要在下拉列表中触发它。任何想法如何解决它?
答案 0 :(得分: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 abstraction完全是针对这类事情而引入的,并且更可取
参见文档中的示例
@Cacheable("books")
public Book findBook(ISBN isbn) {...}
P.S。考虑使用新的Converter SPI而不是属性编辑器。
通常,可以为查找实体实现通用转换器,因此如果它们具有某些特定属性,它将使用id自动从文本转换实体,例如,在我的一个项目中{{1}使用全局ConditionalGenericConverter实现自动转换类型,因此我既不在绑定期间注册自定义属性编辑器,也不为具有@Entity
注释主键的简单@Entity
类的类型实现特定转换器。
当Spring将文本对象ID指定为@Id
带注释的控制器方法参数时,它会自动将文本对象ID转换为实际实体。