8

首先......我在 Spring 中相对较新,我使用 spring 3.x 并且我不喜欢 SPRING 的 XML 配置文件......我不希望每次重构都运行到 XML 文件进行更新......

我正在尝试以针对任何请求的方式配置spring,如果我的hadlers中有一些@RequestParam/@RequestBody/@PathVariable等类型不是String,spring会将值正确转换为该类型或将null放入处理程序args(我从不在处理程序参数中使用原始类型)。到目前为止,一切都很好 ...

到目前为止,我已经像这样注册了所有转换器/转换器工厂类:

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

有没有办法用注释注册转换器?

关于 Spring XML 的任何事情(或只是基本的东西)都可以只用注释来完成,并且一劳永逸地摆脱 XML 配置吗?... 如何?

4

7 回答 7

9

Spring 没有对转换器的注解支持,但您可以构建自己的。

您所需要的只是一个自定义限定符注解(让我们称之为@AutoRegistered)和某种FormatterRegistrar使用此@AutoRegistered注解注册所有 Spring Beans 的 Converter/Formatter Registrar(实现)(以及一些用于注册此注册服务的 xml)。

然后,您需要使用此注释(以及其他一些注释以使其成为 Spring bean)来注释您的转换器,仅此而已。

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

顺便说一句,对于您的枚举转换器,您不需要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 "";
         }
     }   
}
于 2012-12-08T14:41:07.330 回答
7

@EnableAutoConfiguration开启时,Spring Boot 还提供了Converter bean 的自动注册- 请参阅Spring Boot 特性。似乎不需要额外的注释(除了将每个转换器 bean 标记为 a 之外@Component)。

于 2015-04-27T10:51:07.307 回答
6

首先你必须定义一个注解:TypeConverter

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

然后您必须注册转换服务并添加所有具有注释的 bean。这将使用以下后处理器完成:

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

如果您需要更多详细信息,请查看此 博客条目

于 2013-03-15T02:17:43.633 回答
5

@Ralph 概述的方法很简洁,我已经 +1 了他的答案。让我还推荐一种使用@Configuration 支持​​的替代方法- 本质上是一种使用 Java 而不是 xml 配置 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());
                ...
    }

 }
于 2012-12-08T18:05:29.327 回答
1

使用 Spring MVC 3.2,您可以创建一个扩展 DefaultFormattingConversionService 的转换服务类,例如

应用程序转换服务.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());
    }

}

并在 spring 配置中指定它,例如

调度程序-servlet.xml

<mvc:annotation-driven conversion-service="conversionService"/>
于 2014-02-05T08:37:15.920 回答
0

我不确定这是否适用于 Spring 3,但这是 Spring 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;
    }
}
于 2017-12-15T09:53:48.750 回答
0

请执行下列操作:

@SpringBootApplication
@PropertySources({ @PropertySource("classpath:application.properties") })
public class YourApplication {

public static void main(String[] args) {
    SpringApplication.run(YourApplication.class, args);

    ConversionService conversionService = DefaultConversionService.getSharedInstance();
    ConverterRegistry converters = (ConverterRegistry) conversionService;
    converters.addConverter(new LocalDateToStringConverter());

    }

}

LocalDateToStringConverter 看起来像这样。

public class LocalDateToStringConverter implements Converter<LocalDate, String> {

@Override
public String convert(LocalDate localDate) {
    try {

        String date = localDate.format(DateTimeFormatter.ofPattern("dd-MM-yyyy"));
        return date;
    } catch(DateTimeParseException ex) {
    }
    return null;
  }
}
于 2019-11-19T11:01:20.840 回答