2010-06-22 7 views
5

Mam następujący (uproszczony) forma w jednym z moim zdaniem:Jakie są najlepsze strategie konwertera Spring w przypadku String do przekonwertowania na zestaw obiektów?

<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> 

Który będzie wiązać się z poniższym JavaBeans:

public class Entry { 
    private String name; 
    private List<Tag> tags = new LinkedList<Tag>(); 

    // setters and getters omitted 
} 

bo chcę wziąć wykorzystanie wszystkich nowych fantazyjne cechy Spring 3, używam kontroler adnotacji napędzane do otrzymania żądania 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 
    } 
} 

Jak widać, trzeba konwertować mój tekst wejściowy (co loo k jak tag1, tag2, tag3) jako lista Tag zdefiniować tak:

public class Tag { 
    private String name; 

    // setter and getter omitted 
} 

Istnieje kilka strategii, aby to zrobić z wiosny 3,0:

( Niestety długi post, pytania są pogrubioną)

Najprostszym

Programowanie nową właściwość tagsAsText mieć getter/setter jako wyrażenie:

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 
    } 
} 

Podejście to ma dwie wady:

  • I obejmuje logikę konwersji w moim obiektu domeny, jest to problem?
  • Gdzie mogę uzyskać dostęp do BindingResult w przypadku błędu w ciągu znaków?

Korzystanie BeanInfo

mogę też użyć BeanInfo dla mojego Fasola:

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()); 
    } 
    } 
} 

i zadeklarować jeden konwerter

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 
    } 
} 

Takie podejście ma również dwie wady:

  • Muszę edytować moje informacje BeanInfo za każdym razem, gdy dodaję/zmieniam moją klasę wprowadzania. czy jest jakiś sposób, aby w prosty sposób definiować moje BeanInfo (jak „dla tej nieruchomości, to wykorzystać, bo inaczej po prostu zrobić jak zwykle”)
  • Gdzie mogę uzyskać dostęp do BindingResult w przypadku błędu w ciągu?

Korzystanie Converter

Converter używa ogólnego mechanizmu Java 5:

final class StringToTagList implements Converter<String, List<Tag>> { 
    public List<Tag> convert(String source) { 
    // convert my source to a list of Tag 
    } 
} 

Podejście wygląda bardziej elegancki, ale nadal dwie wady:

  • Wydaje się przedefiniować wszystkie domyślne konwertery, jeśli skonfiguruję ten konwerter w usłudze ConversionServiceFactoryBean, to istnieje jakiś sposób na zachowanie domyślnych konwerterów?
  • (ponownie) Gdzie mogę uzyskać dostęp do BindingResult w przypadku błędu w ciągu znaków?
+0

Przepraszam, że tak długo, ale to może być interesująca dyskusja na temat konwersji na wiosnę – Kartoch

Odpowiedz

2

Dobrze rozważyć pytanie, nawet będzie to większość ludzi straszyć off :)

Zresztą, myślę, że opcja (2) znajduje się najbliżej praktycznego rozwiązania. Moją pierwszą sugestią jest enkapsulacja listy znaczników do własnej klasy modelu. Da to ramie wiążącej dane konkretny typ do zarejestrowania się, podczas gdy List i String są zbyt ogólne.

Więc trzeba klas modeli:

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; 
    } 
} 

Następnie mają PropertyEditor, który wie, jak konwertować do iz 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 
    } 
} 

i wreszcie trzeba powiedzieć kontroler do użycia konwertera:

@Controller 
public class EntryController { 

    @InitBinder 
    public void initBinder(WebDataBinder binder) { 
     binder.registerCustomEditor(TagList.class, new TagListEditor()); 
    } 

    // request mappings here 
} 

Jestem całkiem s w nowym środowisku Spring 3 Converter powstałoby bardziej eleganckie rozwiązanie, ale jeszcze tego nie odkryłem :) Takie podejście jednak działa.

Powiązane problemy