스프링 MVC 유형 변환 : PropertyEditor 또는 Converter?


129

Spring MVC에서 데이터를 바인딩하고 변환하는 가장 쉽고 간단한 방법을 찾고 있습니다. 가능한 경우 XML 구성을 수행하지 않고

지금까지 PropertyEditors를 다음 과 같이 사용했습니다 .

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

}

...
public class MyController {

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

    ...

}

간단합니다. 두 변환 모두 동일한 클래스에 정의되어 있으며 바인딩은 간단합니다. 모든 컨트롤러에서 일반 바인딩을 원한다면 여전히 xml config에 3 줄을 추가 할 수 있습니다 .


그러나 Spring 3.x는 Converters를 사용하여 새로운 방법을 도입했습니다 .

스프링 컨테이너 내에서이 시스템은 PropertyEditors의 대안으로 사용될 수 있습니다

"최신 대안"이기 때문에 변환기를 사용하고 싶다고 가정 해 봅시다. 두 개의 변환기 를 만들어야합니다 .

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

}

첫 번째 단점 : 두 가지 수업을 만들어야합니다. 이점 : 일반성 덕분에 캐스팅 할 필요가 없습니다.

그렇다면 어떻게 간단히 데이터를 변환기에 바인딩합니까?

두 번째 단점 : 컨트롤러에서 간단한 방법 (주석 또는 기타 프로그래밍 기능)을 찾지 못했습니다 someSpringObject.registerCustomConverter(...);.

내가 찾은 유일한 방법은 지루하고 단순하지 않으며 일반적인 크로스 컨트롤러 바인딩에만 관한 것입니다.

  • XML 설정 :

    <bean id="conversionService"
      class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="somepackage.StringToCategory"/>
                <bean class="somepackage.CategoryToString"/>
            </set>
        </property>
    </bean>
    
  • Java 설정 ( Spring 3.1 이상에서만 ) :

    @EnableWebMvc
    @Configuration
    public class WebConfig extends WebMvcConfigurerAdapter {
    
        @Override
        protected void addFormatters(FormatterRegistry registry) {
            registry.addConverter(new StringToCategory());
            registry.addConverter(new CategoryToString());
        }
    
    }
    

이 모든 단점을 가지고 왜 변환기를 사용 하는가? 뭔가 빠졌습니까? 내가 모르는 다른 트릭이 있습니까?

PropertyEditors를 계속 사용하고 싶습니다 ... 바인딩이 훨씬 쉽고 빠릅니다.


참고 (Spring 3.2.17을 사용하여 넘어졌습니다) : <mvc : annotation-driven />을 사용할 때 실제로이 conversionService Bean을 참조해야합니다 : <mvc : annotation-driven conversion-service = "conversionService"/>
mauhiz

addFormatters (...)는 공용이어야합니다. 또한 5.0 이후 WebMvcConfigurerAdapter는 더 이상 사용되지 않습니다.
Paco Abato

답변:


55

이 모든 단점을 가지고 왜 변환기를 사용 하는가? 뭔가 빠졌습니까? 내가 모르는 다른 트릭이 있습니까?

아니요, PropertyEditor와 Converter를 각각 매우 선언하고 등록하는 방법을 매우 포괄적으로 설명했다고 생각합니다.

내 생각에 PropertyEditors의 범위는 제한되어 있습니다. String을 형식으로 변환하는 데 도움이되며이 문자열은 일반적으로 UI에서 제공되므로 @InitBinder를 사용하여 WebDataBinder를 사용하여 PropertyEditor를 등록하는 것이 좋습니다.

반면에 변환기는 더 일반적이며 UI 관련 변환 (문자열 대 대상 유형)뿐만 아니라 시스템의 모든 변환을위한 것입니다. 예를 들어 Spring Integration은 메시지 페이로드를 원하는 유형으로 변환하기 위해 변환기를 광범위하게 사용합니다.

UI 관련 흐름에 대해서는 PropertyEditors가 여전히 특정 명령 속성에 대해 사용자 정의 작업을 수행 해야하는 경우에 적합하다고 생각합니다. 다른 경우에는 Spring 참조에서 권장 사항을 가져 와서 대신 변환기를 작성하십시오 (예 : Long id에서 엔티티로 샘플로 변환).


5
변환기가 Stateless 인 또 다른 좋은 점은 속성 편집기가 Stateful이고 여러 번 작성되어 많은 API 호출로 구현되는 반면, 이것이 성능에 큰 영향을 미칠 것이라고 생각하지 않지만 변환기는 더 깨끗하고 간단합니다.
Boris Treukhov

1
@Boris cleaner 예, 초보자에게는 특히 간단하지는 않습니다 : 2 개의 변환기 클래스를 작성하고 xml config 또는 java config에 여러 줄을 추가해야합니다. Spring MVC 양식 제출 / 표시와 일반적인 변환 (엔티티뿐만 아니라)에 대해 이야기하고 있습니다.
Jerome Dalbert

16
  1. String으로 /에서 String으로 변환 할 때는 변환기 대신 formatter (implement org.springframework.format.Formatter )를 사용하십시오. 그것은이 인쇄 (...)구문 분석을 (...) 방법, 그래서 당신은 하나의 클래스 만 대신 두 필요는 없다. 이를 등록하려면 ConversionServiceFactoryBean 대신 변환기와 포맷터를 모두 등록 할 수있는 FormattingConversionServiceFactoryBean을 사용하십시오 .
  2. 새로운 포매터에는 다음과 같은 몇 가지 추가 이점이 있습니다.
    • 포맷터 인터페이스는 locale 객체를 print (...)parse (...) 메서드로 제공하므로 문자열 변환은 로케일 구분 가능
    • 사전 등록 된 포맷터 외에도 FormattingConversionServiceFactoryBean 에는 편리한 사전 등록 된 AnnotationFormatterFactory 객체 가 함께 제공되어 주석을 통해 추가 형식 매개 변수를 지정할 수 있습니다. 예를 들면 다음과 같습니다. @RequestParam@DateTimeFormat (pattern = "MM-dd-yy")LocalDate baseDate ... 자체 AnnotationFormatterFactory 클래스 를 만드는 것은 그리 어렵지 않습니다 . 간단한 예제는 Spring의 NumberFormatAnnotationFormatterFactory 를 참조하십시오 . 컨트롤러 별 포맷터 / 에디터가 필요하지 않다고 생각합니다. 모든 컨트롤러에 하나의 ConversionService 를 사용 하고 주석을 통해 형식을 사용자 정의하십시오.
  3. 컨트롤러 특정 문자열 변환이 여전히 필요한 경우 가장 간단한 방법은 여전히 ​​사용자 정의 속성 편집기를 사용하는 것입니다. ( 내 @InitBinder 메소드 에서 ' binder.setConversionService (...) ' 를 호출하려고 시도했지만 바인더 객체에 이미 '전역'변환 서비스가 설정되어 있기 때문에 실패합니다. 컨트롤러 당 변환 클래스는 권장하지 않습니다. 봄 3).

7

가장 간단하지만 (퍼시스턴스 프레임 워크를 사용한다고 가정 할 때) 완벽한 방법은 아니지만 ConditionalGenericConverter메타 데이터를 사용하여 엔티티를 변환하는 인터페이스를 통해 일반 엔티티 변환기를 구현하는 것입니다.

예를 들어, JPA를 사용하는 경우이 변환기는 지정된 클래스에 @Entity주석 이 있는지 확인하고 @Id주석이있는 필드를 사용하여 정보를 추출하고 제공된 문자열 값을 조회 ID로 사용하여 자동으로 조회를 수행 할 수 있습니다.

public interface ConditionalGenericConverter extends GenericConverter {
    boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType);
}

ConditionalGenericConverter Spring 변환 API의 "궁극적 인 무기"이지만 일단 엔티티 변환 대부분을 처리하고 개발자 시간을 절약 할 수있게되면 구현됩니다. 엔티티 클래스를 컨트롤러의 매개 변수로 지정하고 구현에 대해 생각하지 않을 때 큰 도움이됩니다. 새로운 변환기 (물론 사용자 정의 및 비 엔티티 유형 제외).


트릭 덕분에 엔터티 변환 만 처리 할 수있는 훌륭한 솔루션입니다. 클래스를 하나 더 작성해야하기 때문에 처음에는 단순하지 않지만 장기적으로는 단순하고 시간에 정통합니다.
Jerome Dalbert

Btw와 같은 변환기는 일반적인 계약을 준수하는 모든 유형에 대해 구현 될 수 있습니다-다른 예 : 열거 형이 일반적인 역방향 조회 인터페이스를 구현하는 경우 일반 변환기를 구현할 수도 있습니다 ( stackoverflow.com 과 유사 함) / questions / 5178622 /… )
Boris Treukhov

@JeromeDalbert 예 PS 그리고 양식) 어쨌든 바인딩에 동일한 속성 편집기마다 등록 지루한 될 것입니다) 초보자는 약간의 무거운 무게의 물건을하기가 조금 어렵습니다,하지만 당신은 개발자의 팀이 있다면 그것은 간단합니다
Boris Treukhov

1

두 개의 변환기를 정적 내부 클래스로 구현하여 두 개의 개별 변환기 클래스를 사용해야 할 필요성을 해결할 수 있습니다.

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) { ... }
    }
}

여전히 두 파일을 개별적으로 등록해야하지만 최소한 변경하면 수정해야 할 파일 수가 줄어 듭니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.