注册转换器和converterFactories与注释在Spring 3(Register conv

2019-07-04 19:15发布

首先,...林在春天相对较新的,我用的弹簧3.x和我不喜欢Spring的XML配置文件...我不想为每个重构我这样做,碰到更新XML文件...

我想要的方式配置弹簧,对于任何要求,如果我有一些@ RequestParam / @ RequestBody / @ PathVariable等与我hadlers非字符串类型,春天将值正确地转换成该类型或把空来处理的ARGS(我从来没有在处理程序的参数使用基本类型)。 到现在为止还挺好 ...

到现在为止我已经注册的所有转换器/ converterFactory类是这样的:

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

有什么办法来注册注释器?

可什么(或只是基本的东西)春天有关XML注释与只能做,并获得一劳永逸摆脱XML配置的? ... 如何?

Answer 1:

春天不具有转换器注解支持,但你可以建立自己的。

所有你需要的是一个自定义的限定注释(可以称之为@AutoRegistered )和某种转换器/格式化处长(实现FormatterRegistrar ),其注册所有与此有关的Spring Bean @AutoRegistered注释(和一些XML注册该注册服务)。

然后,你需要这个注释(和其他一些注释,使其一个Spring bean)来注释conveter,这是所有。

@AutoRegistered注释:

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

注册服务:

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

可以由注册XML配置:

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

BTW你的枚举转换器,你不需要ConversionFactory -一个简单的转换就足够了:

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


Answer 2:

首先,你必须定义一个注释:类型转换器

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

然后,你必须注册转换服务,并添加所有有注释的豆类。 这将与以下后处理器来完成:

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

如果您需要更多的细节检查这个博客条目



Answer 3:

转换豆的自动注册时,也由Spring提供引导@EnableAutoConfiguration看-被打开弹簧引导功能 。 看来,没有额外的说明(比标记每个转换器bean作为其他@Component )是必需的这一点。



Answer 4:

通过@Ralph介绍的方法是整齐的,我有+1他的答案。 让我也建议其使用的替代方法@Configuration 支持 -本质的方式使用,而不是XML的Java配置的Spring bean。 这种方法的消息转换器可以注册这种方式:

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


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

 }


Answer 5:

借助于Spring MVC 3.2,您可以创建一个扩展DefaultFormattingConversionService如转换服务类

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

}

在春天的配置如指定它

调度员servlet.xml中

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


Answer 6:

我不知道,如果这个工程在春季3但这是春季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是一个自定义转换器:

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


文章来源: Register converters and converterFactories with annotations in Spring 3