如果将String转换为一组对象,最好的Spring转换策略是什么? [英] What are the best Spring converter strategies in the case of a String to convert to a set of object?
问题描述
在我的一种视图中,我具有以下(简化的)形式:
< 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:
公共类条目{
private字符串名称;
私人列表< Tag>标签=新的LinkedList< Tag>();
//省略了setter和getters
}
要使用Spring 3的所有新功能,我正在使用注释驱动的控制器来接收POST请求:
@Controller
@RequestMapping( / entry)
公共类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){
//从绑定结果中检查验证
//在bean上执行方法:将此条目添加到系统中
//返回正确的视图
}
}
如您所见,我需要转换输入文本(看起来像 tag1,tag2,tag3
)作为Tag列表,定义如下:
公共类标记{
专用字串名称;
//省略了setter和getter
}
有在Spring 3.0中,有几种策略可以做到这一点:
(很长的帖子,问题都用粗体显示)
b $ b最简单的
对新属性 tagsAsText
进行编程以使getter / setter作为String:
公共类条目{
// ...
public void setTagsAsText(String标签){
//将文本转换为标签列表
}
public String getTagsAsText(){
//将标签列表转换为文本
}
}
此方法有两个缺点:
- 我在域对象中包含了转换逻辑,这是一个问题吗?
- < b>如果字符串错误,我在哪里可以访问
BindingResult
?
使用BeanInfo
我也可以将BeanInfo用于bean:
公共类EntryBeanInfo扩展了SimpleBeanInfo {
public PropertyDescriptor [] getPropertyDescriptors(){
试试{
@Override
PropertyDescriptor tagsDescriptor = new PropertyDescriptor( tags,Entry.class){
@Override
public PropertyEditor createPropertyEditor(Object bean){
返回新的EntryTagListEditor(Integer.class,true);
};
};
//为此对象省略其他PropertyDescriptor(例如名称)
返回new PropertyDescriptor [] {tagListDescriptor};
}
catch(IntrospectionException ex){
throw new Error(ex.toString());
}
}
}
并声明一个转换器
公共类EntryTagListEditor扩展PropertyEditorSupport {
public void setAsText(String text){
//将文本转换为标签
的列表}
public String getAsText(){
//将标签列表转换为字符串
}
}
此方法也有两个缺点:
- 每次添加/更改Entry类时,我都需要编辑BeanInfo。或者有什么方法可以定义我的BeanInfo(例如为此属性使用此属性,否则只需照常操作 )
- 如果字符串出错,我在哪里可以访问
BindingResult
?
使用转换器
转换器使用Java 5的通用机制:
最终类StringToTagList实现Converter< String,List< Tag>>。 {
public List< Tag> convert(String source){
//将我的源代码转换为标签
的列表}
}
这种方法看起来更优雅,但仍然存在两个缺点:
- 似乎我重新定义了所有默认值转换器,如果我在
ConversionServiceFactoryBean
的属性中配置此转换器,是否可以保留默认转换器? - (再次)如果字符串中有错误,我在哪里可以访问
BindingResult
?
一个经过深思熟虑的问题,即使这样也会吓到大多数人:)
无论如何,我认为选项(2)最接近实际解决方案。我的第一个建议是将标签列表封装到其自己的模型类中。这将为数据绑定框架提供一个要注册的具体类型,而 List
和 String
太笼统了。 / p>
因此您将拥有模型类:
公共类条目{
私有字符串名称;
private TagList tagList;
}
公共类TagList {
private final List< Tag>标签;
public TagList(List< Tag>标签){
this.tags =标签;
}
公共列表< Tag> getTags(){
返回标签;
}
}
然后您有一个 PropertyEditor
知道如何与 TagList进行转换:
公共类TagListEditor扩展PropertyEditorSupport {
@Override
public void setAsText(String text)throws IllegalArgumentException {
TagList tagList = //从文本值解析
setValue(tagList);
}
@Override
public String getAsText(){
TagList tagList =(TagList)getValue();
return tagList.toString(); //或其他
}
}
最后,您需要告诉控制器以使用转换器:
@Controller
公共类EntryController {
@ InitBinder
public void initBinder(WebDataBinder粘结剂){
inder.registerCustomEditor(TagList.class,new TagListEditor());
}
//在此处请求映射
}
我相当确定新的Spring 3 Converter框架会产生一个更优雅的解决方案,但我还没有弄清楚:)但是,这种方法我知道有效。
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 ?
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
and String
are much too general.
So you would have the model classes:
public class Entry {
private String name;
private TagList tagList;
}
public class TagList {
private final List<Tag> tags;
public TagList(List<Tag> tags) {
this.tags = tags;
}
public List<Tag> getTags() {
return tags;
}
}
You then have a PropertyEditor
that knows how to convert to and from a TagList
:
public class TagListEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
TagList tagList = // parse from the text value
setValue(tagList);
}
@Override
public String getAsText() {
TagList tagList = (TagList) getValue();
return tagList.toString(); // or whatever
}
}
And finally, you need to tell the controller to use the converter:
@Controller
public class EntryController {
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(TagList.class, new TagListEditor());
}
// request mappings here
}
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.
这篇关于如果将String转换为一组对象,最好的Spring转换策略是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!