Szukam najłatwiejszego i najprostszego sposobu na powiązanie i konwersję danych w Spring MVC. Jeśli to możliwe, bez wykonywania jakiejkolwiek konfiguracji XML.
Do tej pory korzystałem z PropertyEditors w następujący sposób:
public class CategoryEditor extends PropertyEditorSupport {
// Converts a String to a Category (when submitting form)
@Override
public void setAsText(String text) {
Category c = new Category(text);
this.setValue(c);
}
// Converts a Category to a String (when displaying form)
@Override
public String getAsText() {
Category c = (Category) this.getValue();
return c.getName();
}
}
i
...
public class MyController {
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Category.class, new CategoryEditor());
}
...
}
To proste: obie konwersje są zdefiniowane w tej samej klasie, a powiązanie jest proste. Gdybym chciał wykonać ogólne powiązanie na wszystkich moich kontrolerach, nadal mógłbym dodać 3 wiersze w mojej konfiguracji xml .
Ale Spring 3.x wprowadził nowy sposób, aby to zrobić, używając konwerterów :
W kontenerze Spring ten system może być używany jako alternatywa dla PropertyEditors
Powiedzmy, że chcę używać konwerterów, ponieważ jest to „najnowsza alternatywa”. Musiałbym stworzyć dwa konwertery:
public class StringToCategory implements Converter<String, Category> {
@Override
public Category convert(String source) {
Category c = new Category(source);
return c;
}
}
public class CategoryToString implements Converter<Category, String> {
@Override
public String convert(Category source) {
return source.getName();
}
}
Pierwsza wada: muszę zrobić dwie klasy. Zaleta: nie ma potrzeby rzucania dzięki hojności.
Jak więc po prostu powiązać konwertery z danymi?
Druga wada: nie znalazłem prostego sposobu (adnotacje lub inne funkcje programistyczne), aby to zrobić w kontrolerze: nic podobnego someSpringObject.registerCustomConverter(...);
.
Jedyne sposoby, które znalazłem, byłyby żmudne, nie proste i dotyczyłyby tylko ogólnego powiązania między kontrolerami:
-
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="somepackage.StringToCategory"/> <bean class="somepackage.CategoryToString"/> </set> </property> </bean>
Konfiguracja Java ( tylko w Spring 3.1+ ):
@EnableWebMvc @Configuration public class WebConfig extends WebMvcConfigurerAdapter { @Override protected void addFormatters(FormatterRegistry registry) { registry.addConverter(new StringToCategory()); registry.addConverter(new CategoryToString()); } }
Biorąc pod uwagę wszystkie te wady, po co używać konwerterów? Czy coś mi brakuje? Czy są inne sztuczki, których nie jestem świadomy?
Kusi mnie, aby dalej używać PropertyEditors ... Wiązanie jest znacznie łatwiejsze i szybsze.
źródło
Odpowiedzi:
Nie, myślę, że bardzo szczegółowo opisałeś zarówno PropertyEditor, jak i Converter, jak każdy z nich jest deklarowany i rejestrowany.
Moim zdaniem, PropertyEditors mają ograniczony zakres - pomagają przekonwertować String na typ, a ten ciąg zwykle pochodzi z interfejsu użytkownika, więc rejestracja PropertyEditor za pomocą @InitBinder i WebDataBinder ma sens.
Z drugiej strony konwerter jest bardziej ogólny, jest przeznaczony do KAŻDEJ konwersji w systemie - nie tylko do konwersji związanych z interfejsem użytkownika (ciąg na typ docelowy). Na przykład Spring Integration szeroko używa konwertera do konwersji ładunku wiadomości na żądany typ.
Myślę, że w przypadku przepływów związanych z interfejsem użytkownika PropertyEditors są nadal odpowiednie, szczególnie w przypadku, gdy trzeba zrobić coś niestandardowego dla określonej właściwości polecenia. W innych przypadkach skorzystałbym z zalecenia Springa i zamiast tego napisałbym konwerter (np. W celu konwersji z Long id na jednostkę, powiedzmy, jako próbkę).
źródło
źródło
Najprostszym (zakładając, że używasz struktury trwałości), ale nie idealnym sposobem jest zaimplementowanie ogólnego konwertera jednostek za pośrednictwem
ConditionalGenericConverter
interfejsu, który skonwertuje jednostki przy użyciu ich metadanych.Na przykład, jeśli używasz JPA, ten konwerter może sprawdzić, czy określona klasa ma
@Entity
adnotację, i użyć@Id
pola z adnotacją, aby wyodrębnić informacje i przeprowadzić wyszukiwanie automatycznie, używając podanej wartości String jako identyfikatora do wyszukiwania.public interface ConditionalGenericConverter extends GenericConverter { boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType); }
ConditionalGenericConverter
jest "ostateczną bronią" interfejsu Spring Convertion API, ale zostanie wdrożona, gdy będzie w stanie przetworzyć większość konwersji jednostek, oszczędzając czas programisty - to wielka ulga, gdy po prostu określisz klasy jednostek jako parametry kontrolera i nigdy nie myśl o implementacji nowy konwerter (oczywiście z wyjątkiem typów niestandardowych i innych niż encje).źródło
Możesz obejść potrzebę posiadania dwóch oddzielnych klas Converter, implementując dwie Converters jako statyczne klasy wewnętrzne.
public class FooConverter { public static class BarToBaz implements Converter<Bar, Baz> { @Override public Baz convert(Bar bar) { ... } } public static class BazToBar implements Converter<Baz, Bar> { @Override public Bar convert(Baz baz) { ... } } }
Nadal musiałbyś zarejestrować oba z nich osobno, ale przynajmniej zmniejsza to liczbę plików, które musisz zmodyfikować, jeśli wprowadzisz jakiekolwiek zmiany.
źródło