2012-12-08 23 views
7

Trước hết ... Im tương đối mới trong mùa xuân, tôi sử dụng mùa xuân 3.x và tôi KHÔNG THÍCH SPRING'S XML CONFIGURATION FILES ... Tôi không muốn cho mỗi lần tái cấu trúc, để chạy vào tệp XML để cập nhật ...Đăng ký chuyển đổi và converterFactories với chú thích trong mùa xuân 3

Tôi đang cố gắng định cấu hình lò xo theo cách cho bất kỳ yêu cầu nào, nếu tôi có một số @ RequestParam/@ RequestBody/@ PathVariable v.v ... với loại khác ngoài Chuỗi trong trình quản lý của tôi , spring sẽ chuyển đổi các giá trị thành kiểu đó một cách chính xác hoặc đặt null thành arg của trình xử lý (tôi không bao giờ sử dụng các kiểu nguyên thủy trong các đối số trình xử lý). Cho đến nay rất tốt ...

Cho đến bây giờ tôi đã đăng ký tất cả các chuyển đổi/classes converterFactory như thế này:

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"> 
    <property name="converters"> 
     <list> 
      <!-- converters is a set of both converters and converterfactories --> 
      <bean class="controller.converters.enumConverter" /> 
      <bean class="controller.converters.integerConverter" /> 
      <bean class="controller.converters.objects.FooConverter" /> 
      ... 
     </list> 
    </property> 
</bean> 

Có cách nào để đăng ký chuyển đổi với các chú thích?

Có thể làm bất cứ điều gì (hoặc chỉ những thứ cơ bản) về Spring XML chỉ với chú thích và loại bỏ cấu hình XML một lần và cho tất cả? ... và làm thế nào?

Trả lời

9

Mùa xuân không có hỗ trợ chú thích cho Người chuyển đổi, nhưng bạn có thể tự xây dựng.

Tất cả bạn cần là một chú thích tùy chỉnh vòng loại (cho phép gọi nó là @AutoRegistered) và một số loại chuyển đổi/Formatter đăng ký (cụ FormatterRegistrar) mà đăng ký tất cả các Đậu mùa xuân với @AutoRegistered chú thích này (và một số xml để đăng ký dịch vụ đăng ký này) .

Sau đó, bạn cần ghi chú chú thích của bạn với chú thích này (và một số chú thích khác để biến nó thành đậu mùa xuân) và đó là tất cả.

@AutoRegistered chú thích:

@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE }) 
@Retention(RetentionPolicy.RUNTIME) 
@Qualifier 
public @interface AutoRegistered {} 

dịch vụ đăng ký:

import java.util.List; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.core.convert.converter.Converter; 
import org.springframework.format.FormatterRegistrar; 
import org.springframework.format.FormatterRegistry; 

public class AutoregisterFormatterRegistrar implements FormatterRegistrar { 

    /** 
    * All {@link Converter} Beans with {@link AutoRegistered} annotation. 
    * If spring does not find any matching bean, then the List is {@code null}!. 
    */ 
    @Autowired(required = false) 
    @AutoRegistered 
    private List<Converter<?, ?>> autoRegisteredConverters; 


    @Override 
    public void registerFormatters(final FormatterRegistry registry) { 
     if (this.autoRegisteredConverters != null) { 
      for (Converter<?, ?> converter : this.autoRegisteredConverters) { 
       registry.addConverter(converter); 
      } 
     } 
    } 
} 

cấu hình XML cho các công ty đăng ký:

<bean id="applicationConversionService" 
    class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> 
    <property name="formatterRegistrars"> 
     <set> 
      <bean 
       class="AutoregisterFormatterRegistrar" 
       autowire="byType" /> 
     </set> 
    </property> 
</bean> 

BTW cho chuyển đổi enum của bạn, bạn không cần một ConversionFactory - một chuyển đổi đơn giản là đủ:

@AutoRegistered 
@Component 
public class EnumConverter implements Converter<Enum<?>, String> { 

    /** Use the same immutable value instead of creating an new array every time. */ 
    private static final Object[] NO_PARAM = new Object[0]; 

    /** The prefix of all message codes. */ 
    private static final String PREFIX = "label_"; 

    /** The separator in the message code, between different packages 
     as well as between package can class. */ 
    private static final String PACKAGE_SEPARATOR = "_"; 

    /** The separator in the message code, between the class name 
     and the enum case name. */ 
    private static final String ENUM_CASE_SEPARATOR = "_"; 

    /** The message source. */ 
    private MessageSource messageSource; 

    @Autowired 
    public EnumConverter(final MessageSource messageSource) { 
     if (messageSource == null) { 
      throw new RuntimeException("messageSource must not be null"); 
     } 

     this.messageSource = messageSource; 
    } 

    @Override 
    public String convert(final Enum<?> source) { 
     if (source != null) { 
      String enumValueName = source.name(); 
      String code = PREFIX + source.getClass().getName().toLowerCase(). 
        replace(".", PACKAGE_SEPARATOR) 
      + ENUM_CASE_SEPARATOR + enumValueName.toLowerCase(); 

      String message = messageSource.getMessage(code, NO_PARAM, enumValueName, 
                LocaleContextHolder.getLocale()); 

      return message; 
     } else { 
      return ""; 
     } 
    } 
} 
+0

FormatterRegistrar? Tôi đoán bạn có nghĩa là FormatterRegistry ... Danh sách > autoRegisteredConverters tự động điền? ps. Các giải pháp ConverterFactory cho enums là nhỏ gọn hơn ... kiểm tra này [thực hiện] (http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/validation.html#core-convert -ConverterFactory-SPI) – ApollonDigital

+0

Đây là FormatterRegistrar (tính năng Spring 3.1) http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/format/FormatterRegistrar.html – Ralph

5

Cách tiếp cận được vạch ra bởi @Ralph là gọn gàng, tôi đã +1 câu trả lời của anh ấy. Hãy để tôi cũng đề xuất một phương pháp thay thế đang sử dụng @Configurationsupport - về cơ bản là một cách để định cấu hình Spring bean bằng cách sử dụng Java thay vì xml. Với phương pháp này, các bộ chuyển đổi thông điệp có thể được đăng ký theo cách này:

@Configuration 
@EnableWebMvc 
@ComponentScan(...) 
public class CustomConfig extends WebMvcConfigurerAdapter { 


    @Override 
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { 
     converters.add(new EnumConverter()); 
       converters.add(new FooConverter()); 
       ... 
    } 

} 
+0

Cảm ơn phản ứng. Tôi không nghĩ rằng cách giải quyết vấn đề. Mặc dù bạn thoát khỏi xml, bạn vẫn cần cập nhật khi refactories. – ApollonDigital

+0

+1 Điều này làm việc như một sự quyến rũ đối với tôi và tôi hoàn toàn thoát khỏi cấu hình XML với điều này. –

6

Trước tiên, bạn phải xác định một chú thích: TypeConverter

@Target({ElementType.TYPE}) 
@Retention(RetentionPolicy.RUNTIME) 
@Documented 
@Component 
public @interface TypeConverter { 
} 

Sau đó, bạn phải đăng ký dịch vụ chuyển đổi và thêm tất cả các hạt cà phê mà có chú thích.Điều này sẽ được thực hiện với các bài xử lý như sau:

public class ConverterRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor { 

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { 
    registry.registerBeanDefinition("conversionService", BeanDefinitionBuilder.rootBeanDefinition(ConversionServiceFactoryBean.class).getBeanDefinition()); 
} 

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { 
    Map<String, Object> beansWithAnnotation = beanFactory.getBeansWithAnnotation(TypeConverter.class); 
    Collection converters = beansWithAnnotation.values(); 
    DefaultConversionService conversionService = (DefaultConversionService) beanFactory.getBean("conversionService"); 
    for (Object converter : converters) { 
     conversionService.addConverter((Converter<?, ?>) converter); 
    } 
} 
} 

Nếu bạn cần biết thêm chi tiết kiểm tra này blog entry

+1

Chào mừng bạn đến với Stack Overflow! Cảm ơn bạn đã đăng câu trả lời! Vui lòng đảm bảo đọc kỹ [FAQ on Self-Promotion] (http://stackoverflow.com/faq#promotion). Cũng lưu ý rằng nó là * bắt buộc * mà bạn đăng tuyên bố từ chối trách nhiệm mỗi lần bạn liên kết đến trang web/sản phẩm của riêng bạn. –

1

Với Spring MVC 3.2, bạn có thể tạo ra một lớp dịch vụ chuyển đổi mở rộng DefaultFormattingConversionService ví dụ

ApplicationConversionService.java

import org.springframework.format.support.DefaultFormattingConversionService; 
import org.springframework.stereotype.Component; 

@Component("conversionService") 
public class ApplicationConversionService extends DefaultFormattingConversionService { 

    public ApplicationConversionService(){ 
     //DefaultFormattingConversionService's default constructor 
     //creates default formatters and converters 
     super(); //no need for explicit super()? 

     //add custom formatters and converters 
     addConverter(new MyConverter()); 
    } 

} 

và xác định nó trong cấu hình mùa xuân ví dụ

phối-servlet.xml

<mvc:annotation-driven conversion-service="conversionService"/> 
6

đăng ký tự động đậu Chuyển đổi cũng được cung cấp bởi Spring Boot khi @EnableAutoConfiguration được bật - xem Spring Boot features. Có vẻ như không có chú thích bổ sung nào (ngoài việc đánh dấu mỗi bean chuyển đổi là @Component) là bắt buộc đối với điều này.

+0

Gợi ý hữu ích. bạn có biết cách bật tính năng này trong thử nghiệm junit không? – Heri

+0

Sory @ Heri, tôi bắt gặp điều này khi nhìn vào mã nguồn cho một dự án khác nhưng Spring Boot không được sử dụng trong dự án mà tôi đang làm và tôi đã kết thúc giải pháp gần với câu trả lời được chấp nhận. Vì vậy, không thể tư vấn về các bài kiểm tra jUnit (giả sử ở đây bạn có nghĩa là các bài kiểm tra tích hợp sử dụng jUnit?) –

+0

Vâng, chính xác. Tôi đã không thành công để có các Converters tự động đăng ký. Và vì tôi đã không thành công, tôi đã không thử nó trong bootrun bình thường của ứng dụng bởi vì tôi đã hoàn nguyên các thay đổi mã (tôi có một giải pháp tương tự như gmateo với chú thích tùy chỉnh được thêm vào SpringService được tạo ra (truy xuất trong getConverters()) :. – Heri

0

Tôi không chắc chắn nếu điều này làm việc trong mùa xuân 3 nhưng đây là giải pháp cho mùa xuân 4:

@Configuration 
@EnableWebMvc 
class WebMvcContext extends WebMvcConfigurerAdapter { 

    @Override 
    public void addFormatters(FormatterRegistry registry) { 
     registry.addConverter(new DateConverter("yyyy-MM-dd HH:mm:ss")); 
     //registry.addConverter(anotherConverter); 
    } 
} 

DateConverter là một bộ chuyển đổi tùy chỉnh:

public class DateConverter implements Converter<String, Date>{ 
    private static final Logger LOGGER = LoggerFactory.getLogger(DateConverter.class); 
    private final String dateFormat; 
    private final SimpleDateFormat formatter; 
    public DateConverter(String dateFormatPattern) { 
     this.dateFormat = dateFormatPattern; 
     this.formatter = new SimpleDateFormat(dateFormatPattern); 
    } 

    @Override 
    public Date convert(String source) { 
     Date date = null; 
     try { 
      date = formatter.parse(source); 
     } catch (ParseException e) { 
      e.printStackTrace(); 
     } 
     return date; 
    } 
} 
Các vấn đề liên quan