Как сделать преобразование параметров запроса 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>
Это работает и даже имеет преимущество разрешить преобразование параметров, основанное на нескольких параметрах метода.
Ответ 4
Чтобы достичь чего-то похожего на то, что вы делаете, я нашел эту запись в блоге.
Ответ 5
Я думаю, вам нужно использовать что-то вроде
public ModelAndView handleRenderRequest(...,@ModelAttribute("myObject") MyClass myObject)