ConversionService в Spring
Я следую этой схеме в приложении Spring.
- Запрос отправляется на сервер с идентификатором объекта и некоторыми другими параметрами, которые будут заполнены в этом объекте
- Объект с этим идентификатором загружается из базы данных
- getters и seters вызывается в этом объекте для заполнения значений
- объект затем сохраняется
Я спросил в этом другом вопросе, что было лучшим способом подготовить объект перед заполнением параметров запроса. Ответ заключался в том, что лучшим способом было использовать службу преобразования вместо того, чтобы делать это в аннотированном методе @ModelAtribute или с редактором в initBinder,
Итак, я попытался использовать конвертер, но я не нашел подобного примера, и я немного застрял. Я написал код, подобный приведенному ниже: В связывании init я регистрирую службу преобразования. Поэтому перед заполнением значений метода User object convert() вызывается для загрузки объекта из базы данных. Проблема заключается в том, что эта конфигурация не работает, потому что она преобразует идентификатор (имя пользователя) объекта Object в пользователя Object, но затем он пытается создать setUsername() с объектом, поэтому я получаю "java.lang.IllegalArgumentException: несоответствие типа аргументов".
Может ли кто-нибудь дать мне подсказку или пример способа использования ConversionService для получения желаемого поведения?
Спасибо.
@Autowired
private ConversionService conversionService;
@InitBinder("user")
public void initBinder(@RequestParam("username")String username, WebDataBinder binder){
binder.setConversionService(conversionService);
}
@RequestMapping(value="/user/save", method=RequestMethod.POST)
public String save(@ModelAttribute("user") User user, Model model) {
...
}
с чем-то вроде:
@Component
public class UserConversionService implements ConversionService{
...
@Override
public Object convert(Object name, TypeDescriptor arg1, TypeDescriptor arg2) {
return userService.find((String)name);
}
}
Ответы
Ответ 1
Вы пытаетесь реализовать ConversionService
для преобразования между объектами Strings и User. Тем не менее, это Converter
реализации, которые выполняют эту роль. Что вы хотите сделать:
- Записать конвертер
- Зарегистрируйте этот конвертер с помощью ConversionService
- Используйте ConversionService.
Ваш конвертер будет примерно таким:
final class UserConverter implements Converter<String, User> {
...
public User convert(String username) {
return userService.find(username);
}
}
Затем вам необходимо зарегистрировать этот конвертер. Вы можете либо написать свой собственный ConversionServiceFactoryBean, либо переопределить значение по умолчанию:
<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<list>
<bean class="example.UserConverter"/>
</list>
</property>
</bean>
Если вы хотите явно использовать ConversionService, как и у вас, просто оставьте его как что-то, что можно сделать autwired. Spring, и это определение фабрики позаботится об остальном.
Если, однако, вы уже используете тег <mvc:annotation-driven>
в своем контексте, вы можете использовать его атрибут conversion-service
для ссылки на свой ConversionServiceFactoryBean. Вам тогда не нужно иметь InitBinder или ConversionService в вашем классе вообще: просто имея параметр @RequestMapping, ваш целевой тип, Пользователь, преобразование будет выполнено без вмешательства.
Ответ 2
Я сделал то, что Гэри говорит выше, и это сработало:
Я хочу добавить дополнительную информацию в решение. В соответствии с Spring документацией здесь переменная шаблона URI переходит к целевому объекту с помощью программы Converter/ConversionService. Я попытался использовать @RequestParam("id") @ModelAttribute("contact") Contact contact
, но я получил IllegalStateException: Neither BindingResult nor plain target object for bean name 'contact' available as request attribute
для того, чтобы не иметь объект модели contact
в моем представлении edit.jsp. Это можно легко решить, объявив a Model model
и model.addAttribute(contact);
. Однако есть еще лучший способ; используя переменную шаблона URI. Странно, почему @RequestParam
не работает.
НЕ РАБОТАЕТ
@RequestMapping("edit") //Passing id as .. edit?id=1
public String editWithConverter(@RequestParam("id") @ModelAttribute("contact") Contact contact){
logger.info("edit with converter");
return "contact/edit";
}
ЧТО РАБОТАЕТ
@RequestMapping("edit/{contact}") //Passing id as .. edit/1
public String editWithConverter(@PathVariable("contact") @ModelAttribute("contact") Contact contact){ // STS gave a warning for using {contact} without @PathVariable
logger.info("edit with converter");
return "contact/edit";
}
Итак, что делает эта вещь.. ссылка вроде ...edit/1
неявно вызывает преобразователь для преобразования String '1' в Contact id '1' и приносит этот контактный объект в представление.
Нет необходимости в @InitBinder
, и поскольку его a Converter
, зарегистрированный с помощью ConversionService
, я могу использовать эту везде, где хочу - неявно или явно.