【问题标题】:Spring MVC binding parameters to backing objectSpring MVC 将参数绑定到支持对象
【发布时间】:2009-10-28 23:43:34
【问题描述】:

我正在使用 Spring MVC,并且在我的控制器中,我希望能够自动将传入参数绑定到我的 Java 对象。看起来这应该很容易做到。唯一的问题是传入的参数名称(例如“用户名”)可能与 java 对象中的字段名称(例如“名称”)不完全匹配。

来自 Spring 文档 (http://static.springsource.org/spring/docs/2.5.6/reference/mvc.html):

"Spring Web MVC 允许你使用任何 对象作为命令或表单对象.... 这一切意味着你不需要 复制您的业务对象' 属性作为简单的无类型字符串 在你的表单对象中只是为了能够 处理无效的提交,或 正确转换字符串。反而, 通常最好绑定 直接连接到您的业务对象。 "

我该怎么做呢?任何代码或链接表示赞赏。

例如,我的业务对象

public class User {
  private String username;
  private String password;

  //getters and setter
}

我的控制器正在处理的请求:

example.com/login?name=Steve&pw=1234

我想将“Steve”绑定到 User.username,将“1234”绑定到 User.password。

谢谢。

【问题讨论】:

  • 例如,如果您要在控制器中拼出您期望的所有字段,您可以使用@RequestParam 来指定调用的参数。:@RequestParam(value="accountName") String accountName 但是,我想使用支持对象而不是单独指定所有字段。

标签: java model-view-controller spring spring-mvc


【解决方案1】:

如果我没记错的话,你可以覆盖 public Object formBackingObject(HttpServletRequest request) 并手动设置你的命令 POJO。

【讨论】:

  • 请注意 - 上述方法仅适用于表单控制器层次结构 - AbstractFormController 和子级。它不适用于基本命令控制器,其中覆盖参数名称的唯一方法是实现自定义ServletRequestDataBinder,这相当复杂。
  • 没错...我通常在 SimpleFormController 中使用它。
【解决方案2】:

在这种情况下,您可以使用自定义参数解析器。

public class UserArgumentResolver implements HandlerMethodArgumentResolver {
    public Object resolveArgument(final MethodParameter parameter,
                                  final ModelAndViewContainer container,
                                  final NativeWebRequest webRequest,
                                  final WebDataBinderFactory binderFactory) {
        final User user = new User();
        user.setUsername(webRequest.getParameter("name"));
        user.setPassword(webRequest.getParameter("pw"));

        return user;
    }
}

在你的 spring 配置中:

<mvc:annotation-driven>
    <mvc:argument-resolvers>
        <bean class="your.package.UserArgumentResolver"/>
    </mvc:argument-resolvers>
</mvc:annotation-driven>

【讨论】:

    【解决方案3】:

    example.com/login?username=Steven&password=1234

    当属性名称不匹配时,您不能指望 Spring MVC 进行自动绑定。这不合逻辑。

    【讨论】:

    • 感谢您的回复。嗯,那么我在问题中粘贴的 SpringSource 的引用似乎是一种虚假广告。例如,将 java 对象中的字段名称与 html 表单中的参数名称紧密耦合也是不合逻辑的。如果你重构你的 java 类并重命名字段,你的控制器将停止工作!
    • 我宁愿将我的模型绑定到我的视图,也不愿将我的视图绑定到我的控制器,如果您在控制器中将“名称”映射到“用户名”就会出现这种情况。
    【解决方案4】:

    编辑:按照 Kaleb 说的做,覆盖 formBackingObject 更简洁。

    不过,我会留下这个便条:

    但是,如果您对双方都有任何控制权,我强烈建议使名称保持一致。约定优于配置。

    【讨论】:

    • 感谢您的回复。尽管您似乎经常希望业务逻辑中的字段名称与您公开的字段名称不完全相同。 “accountAdminContactFirstName”可能不是一个在 URL 中看到的好名字。 “名称”可能更简洁。
    • 在我看来,无论如何都不应该出现在 URL 中。要么做一个 POST 要么重写 URL 使其中没有参数。
    • 实际上,account.adminContact.firstName 会更干净 :-) Spring 也支持它。 bpapa 完全正确 - 通过使用一致的命名方案,您将使您的生活很多更轻松
    • 好吧,这是一个人为的例子。我在这里的用例是公开一个 API 调用,例如:一个 POST 到 example.com/api/user,一旦它被公开并且该 api 被其他人使用,这意味着我永远不能重命名我的用户 java 对象中的相应字段!这种耦合对我来说没有意义。谢谢。
    • Spring MVC 可能不是 API 处理的最佳方法;您可能想看看 restlets 或改用 Web 服务。也就是说,我不确定我是否理解您的论点——如果您的 java User 对象作为公共 API 的一部分公开,您也永远无法更改其字段(或者更确切地说,公共方法);那么为什么“基于网络”的 API 应该有所不同呢?
    【解决方案5】:

    如果您想将请求绑定到 POJO,您可能需要扩展 AbstractCommandController 或者如果您有一个表单 - SimpleFormController。我相信您将需要 org.springframework.web.servlet.mvc 包中的 servlet 版本。

    • 使用 setCommandClass() 在控制器构造函数中设置支持 bean 的正确类型,即 POJO:

      setCommandClass(User.class);

    • formBackingBean() 用于创建 POJO 的新实例,供控制器使用。

    • 控制器负责将请求参数映射到 POJO 字段。
    • 如果映射不适合您,请覆盖 formBackingBean() 或 onBind() 方法来读取请求参数并将值放入 POJO。

    【讨论】:

      【解决方案6】:

      您应该更改表单或对象,以使名称匹配。如果您尝试在 Spring MVC 之类的框架中使用这些功能,您可能应该遵循它们的约定。

      约定优于配置。

      【讨论】:

      • 如果您有无法遵守约定的遗留代码,那该怎么办?
      猜你喜欢
      • 2011-01-14
      • 2011-04-09
      • 1970-01-01
      • 2013-05-29
      • 1970-01-01
      • 2016-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多