Spring 中的转换服务

发布于 2024-10-06 01:45:56 字数 1506 浏览 0 评论 0原文

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

  1. 请求被发送到服务器,其中包含对象的 id 和要填充到此对象中的一些其他参数。
  2. 数据库加载具有此 id 的对象,
  3. 在此对象中调用 getter 和 setter 来填充
  4. 对象然后存储的

从 值在这个其他问题中提出,在填充参数之前准备对象的最佳方法是什么要求。答案是最好的方法是使用 转换服务,而不是在 @ModelAtribute 注解的方法中或使用 initBinder 中的编辑器来完成。

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

I'm following this scheme in a Spring application.

  1. Request is sent to the server with the id of the object and some other params to be populated in this object
  2. The object with this id is loaded from the database
  3. getters and setters are invoked in this object to populate the values
  4. the object is then stored

I asked in this other question what was the best way to prepare the object before populate the params of the request. The answer was that the best way was to use a conversion service instead of doing it in a @ModelAtribute annotated method or with an editor in the initBinder.

So I have tried to use a converter, but I haven't found a similar example and I'm a little stuck. I have written a code like the one below: In the init binder I register the conversion service. So before populating the values on the User object convert() method is invoked to load the object from the database. The problem is that this configuration doen't work because it is converting the id (username field) of the Object User into an Object user, but then it tries to make a setUsername() with the object so I get a "java.lang.IllegalArgumentException: argument type mismatch".

Can anyone give me a clue or an example of the way of using the ConversionService to get the desired behaviour?

Thanks.

@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) {        
    ...
}

with something like:

@Component
public class UserConversionService implements ConversionService{
    ...        
    @Override
    public Object convert(Object name, TypeDescriptor arg1, TypeDescriptor arg2) {
        return userService.find((String)name); 
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

洛阳烟雨空心柳 2024-10-13 01:45:56

您正在尝试实现 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 和factorybean 定义将处理剩下的事情。

但是,如果您已在上下文中使用 标记,则可以使用其 conversion-service 属性来引用 ConversionServiceFactoryBean。然后,您根本不需要在类中包含 InitBinder 或 ConversionService:只需让 @RequestMapping 的参数具有您的目标类型 User,转换就会发生,而无需您干预。

You're trying to implement a ConversionService to do the conversion between Strings and User objects. However, it's Converter implementations that do this part. What you want to do is:

  1. Write a Converter
  2. Register that converter with a ConversionService
  3. Make use of the ConversionService.

Your converter would be something like:

final class UserConverter implements Converter<String, User> {
    ...
    public User convert(String username) {
        return userService.find(username);
    }

}

You then need to register that converter. You can either write your own ConversionServiceFactoryBean or override the default:

<bean id="conversionService"
      class="org.springframework.context.support.ConversionServiceFactoryBean">
    <property name="converters">
        <list>
            <bean class="example.UserConverter"/>
        </list>
    </property>
</bean>

If you want to use the ConversionService explicitly, as you have, just leave it as something that can be autowired. Spring and that factorybean definition will take care of the rest.

If, however, you're already using the <mvc:annotation-driven> tag in your context, you can use its conversion-service attribute to reference your ConversionServiceFactoryBean. You then don't need to have InitBinder or ConversionService in your class at all: by simply having a parameter of a @RequestMapping have your target type, User, the conversion will take place without you having to intervene.

傲世九天 2024-10-13 01:45:56

我完全按照加里上面所说的做了,它起作用了:

我想在解决方案中添加更多信息。根据 Spring 文档此处 使用 Converter/ConversionService 将 URI 模板变量转换为目标对象。我尝试使用 @RequestParam("id") @ModelAttribute("contact") Contact contact,但我得到了一个 IllegalStateException: 既没有 BindingResult 也没有 bean name 'contact 的普通目标对象' 可用作请求属性,因为我的视图 edit.jsp 中没有模型对象 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' 的联系人,并带来这个将对象与视图联系起来。
不需要@InitBinder,因为它是一个向ConversionService注册的Converter,我可以在任何我想要的地方使用它 - 隐式或显式< /强>。

I did exactly what Gary is saying above and it worked:

I want to add some more information to the solution. As per the Spring documentation here a URI template variable gets translated to the target object using the Converter/ConversionService. I tried to use a @RequestParam("id") @ModelAttribute("contact") Contact contact, but I was getting an IllegalStateException: Neither BindingResult nor plain target object for bean name 'contact' available as request attribute for not having the model object contact in my view edit.jsp. This can be easily resolved by declaring a Model model and model.addAttribute(contact);. However, there is an even better way; using the URI template variable. It's strange why @RequestParam did not work.

DID NOT WORK

@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";
}

WHAT WORKED

@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";
}

So what does this thing do .. a link like ...edit/1 implicitly invokes the converter for String '1' to Contact of id '1' conversion, and brings this contact object to the view.
No need for @InitBinder and since its a Converter registered with the ConversionService I can use this anywhere I want - implicitly or explicitly.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文