Как сделать преобразование параметров запроса spring

В приложении с веб-интерфейсом (портлет) Spring 3 у меня есть контроллер с таким способом:

@RenderMapping
public ModelAndView handleRenderRequest(...,@RequestParam MyClass myObject)
{
    ...
}

Теперь я задаюсь вопросом: как сообщить Spring, как преобразовать параметр запроса в MyClass. Я нашел информацию об редакторах свойств и об интерфейсе конвертера, и, похоже, некоторые из них говорят о том, что конвертер является преемником редактора свойств, но, похоже, ему не нравится быть явным.

Я реализовал интерфейс конвертера для преобразования String в MyClass. Но как мне сказать Spring об этом? Я использую настройку на основе аннотаций, где это возможно, поэтому я проверил, будет ли Spring автоматически обнаруживать конвертер из моего пути к классам, но это не так.

Поэтому подумал, что часть Настройка службы конверсии из руководства хочет сказать мне, что мне нужно добавить следующее к моему applicationContext.xml, который я сделал:

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <list>
            <bean class="some.package.MyConverter"/>
        </list>
    </property>
</bean>

Бит еще:

org.springframework.beans.ConversionNotSupportedException: не удалось выполнить преобразовать значение [...]

Так что мне не хватает? И есть ли способ, просто настроить пакет и позволить Spring отсканировать этот пакет для конвертеров и зарегистрировать их автоматически? И скажите, что в одном определенном методе я хочу использовать другой конвертер, чем во всех других методах. Например, я хочу, чтобы целое число, в котором проверено Luhn-Checksum, и контрольная сумма удалена, как я могу это сделать? Что-то вроде @RequestParam (converter = some.package.MyConverter.class) было бы здорово.

ИЗМЕНИТЬ

Хорошо, я просто попал в документацию:

Используйте SPI Formatter, когда вы работаете в среде клиента, таких как веб-приложение, и необходимо проанализировать и распечатать локализованное поле Значения

Итак, я предполагаю, что это означает, что я должен использовать SPI Formatter, но есть еще одна возможность рядом с редакторами и преобразователями свойств (я думаю, что мог бы реально сопоставить таблицу сравнения и т.п.). Я также реализовал интерфейс Parser и попытался зарегистрировать конвертер, используя:

<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="converters">
        <set>
            <bean class="some.package.SortOrderEnumConverterSpring"/>
        </set>
    </property>
</bean> 

Как вы можете видеть, я использовал "set" вместо "list" для указания преобразователей. Я установил точку останова отладки в методе FormattingConversionServiceFactoryBean.setConverters, который не срабатывал при использовании списка, но он срабатывал при использовании set.

Кроме того, я добавил

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

И пространство имен для mvc-префикса для моего приложенияContext. Но все же я получаю исключение, не поддерживаемое преобразованием.

Я также попытался вернуться к подходу конвертера и изменил в своем файле applicationContext.xml список параметров для преобразователей из списка в набор, но это ничего не изменило.

EDIT2

Как отмечалось в Digitaljoel, можно установить разные преобразователи на контроллер с помощью метода initBinder. Я применил это к моему контроллеру:

@Autowired
private ConversionService conversionService;

@InitBinder
public void initBinder(WebDataBinder binder)
{
    binder.setConversionService(conversionService);
}

И в моем приложенииContext.xml:

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <set>
            <bean class="some.package.with.MyConverter"/>
        </set>
    </property>
</bean>

И все вдруг конверсия работает просто отлично:-). Но я не очень доволен необходимостью применять это к каждому из моих контроллеров. Должен быть способ просто установить его в моем приложении для всех, не так ли? Хорошо знать, что я могу переопределить значение по умолчанию, если мне нужно (в конце концов, я просил об этом), но я все еще хочу установить значения по умолчанию.

А как насчет материала Formatter. Должен ли я использовать это вместо конвертера?

Ответы

Ответ 1

Spring Портлет MVC 3.0 не поддерживает

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

Посетите https://jira.springsource.org/browse/SPR-6817 для получения дополнительной информации об этом.

Однако вы можете добавить это в свой обычный applicationContext

<bean
    class="org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="webBindingInitializer">
        <bean
            class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
            <property name="conversionService">
                <list>
                    <ref bean="conversionService" />
                </list>
            </property>
        </bean>
    </property>
</bean>

Таким образом вам не нужно добавлять @InitBinder к каждому контроллеру

и, конечно,

<bean id="conversionService"
    class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <property name="converters">
        <list>
            <!-- converter implementations here -->
        </list>
    </property>
</bean>

Ответ 2

Вы правы, что Converter (и ConverterFactory) являются наследниками редакторов свойств. Ваша проблема может заключаться в том, что вы не принимаете соответствующий тип в качестве параметра для вашего конвертера, но это трудно сказать, не видя код конвертера. Если вы ожидаете Long или Integer, вы можете получить строку из Spring и сначала выполнить преобразование ключа.

Что касается конфигурации, я считаю, что вам нужно перечислить все ваши конвертеры в конфигурации bean в вашем xml. Если вы комментируете свою реализацию конвертера с помощью @Component, вы можете ссылаться на нее по имени bean вместо полного пути, но я только пробовал это для ConverterFactory, а не для конвертера.

Наконец, на конкретных конвертерах похоже, что вы можете настроить службу преобразования на уровне контроллера (см. ответ Javi на Настройка смешанной конфигурации для аннотаций Spring MVC-контроллеры), а затем вы можете просто поместить этот метод (и другие, которые требуют этого контроллера) в контроллер, который использует вторичную услугу преобразования, которую вы должны иметь возможность вводить по имени с помощью аннотации @Resource.

Ответ 3

Внедрение WebArgumentResolver:

public class MyArgumentResolver implements WebArgumentResolver
{
    @Override
    public Object resolveArgument(MethodParameter methodParameter,
            NativeWebRequest webRequest) throws Exception
    {
        Class<?> paramType = methodParameter.getParameterType();
        if (paramType == MyClass.class)
        {
            String parameterName = methodParameter.getParameterName();
            String stringParameter = webRequest.getParameter(parameterName);
            return convert(stringParameter);
        }
        return UNRESOLVED;
    }
}

И зарегистрируйте его в своем приложенииContext.xml:

<bean class="org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter">
    <property name="customArgumentResolver">
        <bean class="com.dshs.eakte.util.MyArgumentResolver" />
    </property>
</bean>

Это работает и даже имеет преимущество разрешить преобразование параметров, основанное на нескольких параметрах метода.

Ответ 5

Я думаю, вам нужно использовать что-то вроде

public ModelAndView handleRenderRequest(...,@ModelAttribute("myObject") MyClass myObject)