只读spring-roo或spring-web-mvc中的字段

时间:2012-12-03 09:33:33

标签: java spring-mvc spring-roo

我有一个似乎是spring-mvc中的常见问题。我的几个域对象都有不可更新的字段,因此在我看来,我没有绑定这些字段。 为了竞争起见从视图中排除这些的方式是编辑spring-roo scaffolded视图,将参数的render属性设置为false。

当spring-mvc创建对象的新实例而不是更新现有对象时,这些字段为空。但这意味着对象在控件到达控制器之前未通过验证

我的很多实体在视图中都会有额外的字段不可更新所以我希望能够提出一个通用的解决方案,而不是继续做同样的工作。再次(违反DRY)。

如果从视图中省略字段,如何允许以一致的方式进行验证?

    @RequestMapping(method = RequestMethod.PUT, produces = "text/html")
public String UserController.update(@Valid User user, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) {
    if (bindingResult.hasErrors()) {
        populateEditForm(uiModel, user);
        return "admin/users/update";
    }
    uiModel.asMap().clear();
    user.merge();
    return "redirect:/admin/users/" + encodeUrlPathSegment(user.getId().toString(), httpServletRequest);
}

可能的解决方案:

从控制器中省略@Valid注释。

赞成

  • 易于实施。
  • 易于理解。

缺点

  • 表示为每个对象的每次更新更改控制器方法。
  • 验证不会与应用程序的其余部分在同一位置发生。
  • 没有简单的方法将绑定错误返回给视图(之后需要验证对象)

为需要省略字段

的方法添加自定义验证器

示例:

@InitBinder
public void initBinder(WebDataBinder binder, HttpServletRequest request) {
    if (request.getMethod().equals("PUT")) {
        binder.setDisallowedFields("registrationDate", "password");
        Validator validator = binder.getValidator();
        Validator userUpdateValidator = new UserUpdateValidator();
        binder.setValidator(userUpdateValidator);
    }
}

赞成

  • 清除流程。

缺点

  • 遭受干旱问题的严重影响。这意味着如果以任何方式更改域对象,我需要重新验证。
  • 保存时,字段验证与Hibernate验证不同。
  • 没有遗漏验证和手动验证的实际好处。

会考虑是否?

  • 自定义验证程序可以委托给标准JSR-303验证程序,但只省略字段。

从域对象

中删除JSR-303注释

不是选项这意味着在保存之前对对象没有验证。更糟糕的是我认为它会影响为数据库生成的DDL,从数据库本身中删除约束。 为了完整起见,只放在这里

验证发生前查找域对象

此解决方案的想法是在更新之前查找现有域对象。将任何非空字段从请求复制到旧对象。 的优点   - 验证可以通过正常循环。   - 验证不需要根据您所暗示的方法进行更改。

缺点

  • 点击控制器之前的数据库访问有一点气味
  • 我看不出任何方法来实现这一点。
  • 不适用于在对象生命周期的其他阶段需要省略的字段。例如,如果在创建期间添加时间戳。

我想知道如何实现委托给标准JSR-303验证器的验证器,或者如何在修改它之前查找对象。或者,如果有人有任何其他可能的解决方案?

这些解决方案中的任何一种都允许治疗在多个对象上保持一致。

希望要么允许添加注释,例如。 @RooCreateOnly意味着可以对域对象进行注释,将所有验证定义留在一个位置。

3 个答案:

答案 0 :(得分:2)

使用@ModelAttribute注释可以实现最后一个选项。

创建一个返回域对象并向其添加@ModelAttribute注释的方法。然后将相同的注释添加到要使用该对象的方法的域对象参数中。 Spring将首先从ModelAttribute方法加载对象,然后将其与发布的数据合并。

示例:

@ModelAttribute("foobar")
public User fetchUser() {
    return loadUser();
}

   @RequestMapping(method = RequestMethod.PUT, produces = "text/html")
public String update(@ModelAttribute("foobar") @Valid User user, BindingResult bindingResult, Model uiModel, HttpServletRequest httpServletRequest) {
    return etc();
}

答案 1 :(得分:1)

您可以在disabled文件中使用jspx属性作为输入标记,其中包含您要标记为只读字段的表单。

另外,请确保清除与该字段相关的z属性,以便Roo在稍后对该实体进行任何更改时将忽略该标记。

干杯!

答案 2 :(得分:1)

我发布的另一个答案完全与我之前的答案无关。

还有另一种解决方案:将您的域对象包装到只显示您要验证的字段的特殊表单对象中。

示例:

public class UserForm {
    private final User user = new User();

    // User has many fields, but here we only want lastName
    @NotEmpty // Or whatever validation you want
    public String getLastName() {
        return this.user.getLastName();
    }

    public void setLastName(String lastName) {
        this.user.setLastName(lastName);
    }

    public User getUser() {
        return this.user;
    }

}