在将字符串转换为一组对象的情况下,最好的 Spring 转换器策略是什么?
我的视图之一具有以下(简化的)形式:
<form:form commandName="entry" method="POST">
<form:input type="text" path="name"/>
<form:input type="text" path="tags" />
<input type="submit" value="Submit"/>
</form:form>
它将绑定到以下 JavaBean:
public class Entry {
private String name;
private List<Tag> tags = new LinkedList<Tag>();
// setters and getters omitted
}
因为我想使用 Spring 3 的所有新奇特性,所以我使用注释驱动控制器来接收POST 请求:
@Controller
@RequestMapping("/entry")
public class EntryController {
@RequestMapping(method = RequestMethod.GET)
public ModelAndView show() {
ModelAndView mav = new ModelAndView("entry");
mav.addObject(new Entry());
return mav;
}
@RequestMapping(method = RequestMethod.POST)
public String add(@ModelAttribute("entry") @Valid Entry entry,
BindingResult result) {
// check validation from Binding result
// execute method on business beans: adding this entry to the system
// return a view if correct
}
}
如您所见,我需要将输入文本(看起来像 tag1, tag2, tag3
)转换为 Tag 列表,定义如下:
public class Tag {
private String name;
// setter and getter omitted
}
有几种策略可以使用Spring 3.0:(
抱歉,帖子很长,问题以粗体显示)
最简单的
编程新属性 tagsAsText
以将 getter/setter 作为字符串:
public class Entry {
// ...
public void setTagsAsText(String tags) {
// convert the text as a list of tags
}
public String getTagsAsText() {
// convert list of tags to a text
}
}
这种方法有两个缺点:
- < b>我将转换逻辑包含在我的域对象中,这是一个问题吗?
- 如果字符串出现错误,我可以在哪里访问
BindingResult
? >
使用 BeanInfo
我还可以为我的 bean 使用 BeanInfo:
public class EntryBeanInfo extends SimpleBeanInfo {
public PropertyDescriptor[] getPropertyDescriptors() {
try {
@Override
PropertyDescriptor tagsDescriptor = new PropertyDescriptor("tags", Entry.class) {
@Override
public PropertyEditor createPropertyEditor(Object bean) {
return new EntryTagListEditor(Integer.class, true);
};
};
// omitting others PropertyDescriptor for this object (for instance name)
return new PropertyDescriptor[] { tagListDescriptor };
}
catch (IntrospectionException ex) {
throw new Error(ex.toString());
}
}
}
并声明一个转换器
public class EntryTagListEditor extends PropertyEditorSupport {
public void setAsText(String text) {
// convert the text to a list of Tag
}
public String getAsText() {
// convert the list of Tag to a String
}
}
这种方法也有两个缺点:
- 每次添加/更改 Entry 类时,我都需要编辑 BeanInfo。或者有什么方法可以有一个简单的方法来定义我的 BeanInfo (例如“对于此属性,使用它,否则就像平常一样”)
- 我可以在哪里访问
BindingResult
在字符串错误的情况下?
使用转换器
转换器使用 Java 5 的通用机制:
final class StringToTagList implements Converter<String, List<Tag>> {
public List<Tag> convert(String source) {
// convert my source to a list of Tag
}
}
这种方法看起来更优雅,但仍然有两个缺点:
- 似乎我重新定义了所有默认转换器如果我在
ConversionServiceFactoryBean
的属性中配置此转换器,有什么方法可以保留默认转换器? - (再次)我在哪里可以访问
BindingResult
如果字符串出现错误?
I have the following (simplified) form in one of my view:
<form:form commandName="entry" method="POST">
<form:input type="text" path="name"/>
<form:input type="text" path="tags" />
<input type="submit" value="Submit"/>
</form:form>
Which is going to be bind to the following JavaBean:
public class Entry {
private String name;
private List<Tag> tags = new LinkedList<Tag>();
// setters and getters omitted
}
because I want to take use all new fancy features of Spring 3, I'm using annotation-driven controller to receive the POST request:
@Controller
@RequestMapping("/entry")
public class EntryController {
@RequestMapping(method = RequestMethod.GET)
public ModelAndView show() {
ModelAndView mav = new ModelAndView("entry");
mav.addObject(new Entry());
return mav;
}
@RequestMapping(method = RequestMethod.POST)
public String add(@ModelAttribute("entry") @Valid Entry entry,
BindingResult result) {
// check validation from Binding result
// execute method on business beans: adding this entry to the system
// return a view if correct
}
}
As you can see, I need to convert my input text (which look like tag1, tag2, tag3
) as a list of Tag, define like this:
public class Tag {
private String name;
// setter and getter omitted
}
There is several strategies to do this with Spring 3.0:
(Sorry long post, questions are in bold)
The simplest
Programming a new property tagsAsText
to have a getter/setter as String:
public class Entry {
// ...
public void setTagsAsText(String tags) {
// convert the text as a list of tags
}
public String getTagsAsText() {
// convert list of tags to a text
}
}
This approach has two drawbacks:
- I include the conversion logic in my domain object, is it a problem ?
- Where can i access to the
BindingResult
in the case of error in the string ?
Using BeanInfo
I can also use a BeanInfo for my bean:
public class EntryBeanInfo extends SimpleBeanInfo {
public PropertyDescriptor[] getPropertyDescriptors() {
try {
@Override
PropertyDescriptor tagsDescriptor = new PropertyDescriptor("tags", Entry.class) {
@Override
public PropertyEditor createPropertyEditor(Object bean) {
return new EntryTagListEditor(Integer.class, true);
};
};
// omitting others PropertyDescriptor for this object (for instance name)
return new PropertyDescriptor[] { tagListDescriptor };
}
catch (IntrospectionException ex) {
throw new Error(ex.toString());
}
}
}
And declare one converter
public class EntryTagListEditor extends PropertyEditorSupport {
public void setAsText(String text) {
// convert the text to a list of Tag
}
public String getAsText() {
// convert the list of Tag to a String
}
}
This approach has also two drawbacks:
- I need to edit my BeanInfo every time I add / change my Entry class. or is there any way to have a simple way to define my BeanInfo (like "for this property, use this, else just do as usual")
- Where can i access to the
BindingResult
in the case of error in the string ?
Using Converter
Converter uses the generic mechanism of Java 5:
final class StringToTagList implements Converter<String, List<Tag>> {
public List<Tag> convert(String source) {
// convert my source to a list of Tag
}
}
This approach looks more elegant but still two drawbacks:
- It seems I redefine all default Converters if I configure this converter in the Property of
ConversionServiceFactoryBean
, is there any way to keep the default Converters ? - (again) Where can i access to the
BindingResult
in the case of error in the string ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
这是一个经过深思熟虑的问题,即使它会吓跑大多数人:)
无论如何,我认为选项(2)是最接近实际解决方案的。我的第一个建议是将标签列表封装到它自己的模型类中。这将为数据绑定框架提供一个具体的注册类型,而
List
和String
则过于笼统。因此,您将拥有模型类:
然后您将拥有一个知道如何与
TagList
相互转换的PropertyEditor
:最后,您需要告诉控制器使用Converter:
我相当确定新的 Spring 3 Converter 框架会产生更优雅的解决方案,但我还没有弄清楚:)但是,我知道这种方法是有效的。
A well-considered question, even it'll scare most people off :)
Anyway, I think option (2) is the closest to a practical solution. My first suggestion is that you encapsulate the list of tags into its own model class. This will give the data binding framework a concrete type to register against, whereas
List
andString
are much too general.So you would have the model classes:
You then have a
PropertyEditor
that knows how to convert to and from aTagList
:And finally, you need to tell the controller to use the converter:
I'm fairly sure the new Spring 3 Converter framework would produce a more elegant solution, but I haven't figured it out yet :) This approach, however, I know works.