Spring中的ConversionService

时间:2010-12-03 15:57:16

标签: java spring data-binding spring-mvc converter

我在Spring应用程序中遵循此方案。

  1. 请求被发送到服务器,其中包含对象的id以及要在此对象中填充的其他一些参数
  2. 具有此ID的对象从数据库
  3. 加载
  4. 在此对象中调用getter和setter来填充值
  5. 然后存储对象
  6. 我在this other question中询问了在填充请求的参数之前准备对象的最佳方法是什么。答案是最好的方法是使用conversion service而不是在@ModelAtribute注释方法中或在initBinder中使用编辑器。

    所以我尝试使用转换器,但我没有找到类似的例子,我有点卡住了。我编写了如下代码:在init binder中我注册了转换服务。因此,在填充User对象上的值之前,会调用convert()方法从数据库加载对象。问题是这个配置不起作用,因为它将对象用户的id(用户名字段)转换为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 个答案:

答案 0 :(得分:39)

您正在尝试实现ConversionService来执行字符串和用户对象之间的转换。但是,执行此部分的Converter实现。你想要做的是:

  1. 编写转换器
  2. 使用ConversionService注册该转换器
  3. 使用ConversionService。
  4. 您的转换器将类似于:

    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和那个factorybean定义将处理其余的事情。

    但是,如果您已在上下文中使用<mvc:annotation-driven>标记,则可以使用其conversion-service属性来引用您的ConversionServiceFactoryBean。然后,您根本不需要在类中使用InitBinder或ConversionService:只需让@RequestMapping的参数具有您的目标类型User,就可以在不必进行干预的情况下进行转换。

答案 1 :(得分:4)

我完全按照上面的说法做了,并且它有效:

我想在解决方案中添加更多信息。根据Spring文档here,使用Converter / ConversionService将URI模板变量转换为目标对象。我尝试使用@RequestParam("id") @ModelAttribute("contact") Contact contact,但由于我的视图edit.jsp中没有模型对象IllegalStateException: Neither BindingResult nor plain target object for bean name 'contact' available as request attribute,因此我得到contact。通过声明Model modelmodel.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'的转换器到id'1'转换的Contact,并将这个联系对象带到视图中。 不需要@InitBinder,因为Converter注册了ConversionService,我可以在任何我想要的地方使用 - 隐式或明确地