ConversionService весной - PullRequest
       23

ConversionService весной

25 голосов
/ 03 декабря 2010

Я придерживаюсь этой схемы в приложении Spring.

  1. На сервер отправляется запрос с идентификатором объекта и некоторыми другими параметрами, которые нужно заполнить в этом объекте
  2. Объект с этим идентификатором загружается из базы данных
  3. В этом объекте вызываются геттеры и сеттеры для заполнения значений
  4. затем объект сохраняется

Iспросил в этот другой вопрос , как лучше всего подготовить объект перед заполнением параметров запроса.Ответ был таков: лучше всего использовать сервис преобразования вместо того, чтобы делать это с помощью аннотированного метода @ModelAtribute или с редактором в initBinder.

Итак, я попытался использовать конвертер, но я не нашел подобного примера, и я немного застрял.Я написал код, подобный приведенному ниже: в привязке init я регистрирую службу преобразования.Поэтому перед заполнением значений в пользовательском объекте вызывается метод convert () для загрузки объекта из базы данных.Проблема в том, что эта конфигурация не работает, потому что она конвертирует id (поле имени пользователя) пользователя 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); 
    }
}

Ответы [ 2 ]

40 голосов
/ 03 декабря 2010

Вы пытаетесь реализовать ConversionService для преобразования между строками и объектами пользователя.Однако, это Converter реализации, которые делают эту часть.Что вы хотите сделать:

  1. Написать конвертер
  2. Зарегистрировать этот конвертер с помощью ConversionService
  3. Использовать 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, просто оставьте его как что-то, что может быть автоматически подключено.Spring и это определение фабрики позаботятся обо всем остальном.

Если, однако, вы уже используете тег <mvc:annotation-driven> в своем контексте, вы можете использовать его атрибут conversion-service для ссылки на ваш ConversionServiceFactoryBean.Тогда вам вообще не нужно иметь InitBinder или ConversionService в вашем классе: просто если у параметра @RequestMapping есть целевой тип, пользователь, преобразование будет происходить без вмешательства.

4 голосов
/ 15 августа 2012

Я сделал именно то, что Гари говорит выше, и это сработало:

Я хочу добавить больше информации к решению. Согласно документации 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. Это можно легко решить, объявив 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 неявно вызывает конвертер для преобразования строки «1» в контакт с идентификатором «1» и выводит этот объект контакта в представление. Нет необходимости в @InitBinder, и, поскольку он Converter зарегистрирован в ConversionService, я могу использовать где угодно - неявно или явно .

...