Java SpringRoo或SpringWebMVC中的只读字段

Java SpringRoo或SpringWebMVC中的只读字段,java,spring-mvc,spring-roo,Java,Spring Mvc,Spring Roo,我在SpringMVC中遇到了一个常见的问题。我的一些域对象具有不可更新的字段,因此在我看来,我没有绑定这些字段。 出于竞争考虑,从视图中排除这些对象的方法是编辑spring roo脚手架视图,将参数上的“渲染”属性设置为false 当SpringMVC创建对象的新实例而不是更新现有对象时,这些字段为空。然而,这意味着在控件到达控制器之前,对象的验证失败 我的很多实体都会有额外的字段,这些字段在视图中是不可更新的,因此我希望能够提出一个通用的解决方案,而不是不断地重复同样的工作 如果视图中省略了

我在SpringMVC中遇到了一个常见的问题。我的一些域对象具有不可更新的字段,因此在我看来,我没有绑定这些字段。 出于竞争考虑,从视图中排除这些对象的方法是编辑spring roo脚手架视图,将参数上的“渲染”属性设置为false

当SpringMVC创建对象的新实例而不是更新现有对象时,这些字段为空。然而,这意味着在控件到达控制器之前,对象的验证失败

我的很多实体都会有额外的字段,这些字段在视图中是不可更新的,因此我希望能够提出一个通用的解决方案,而不是不断地重复同样的工作

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

可能的解决办法:

从控制器中省略@Valid注释。 专业人士

易于实现。 容易理解。 缺点

意味着更改每个对象上每次更新的控制器方法。 验证不会与应用程序的所有其余部分发生在同一位置。 没有简单的方法将绑定错误返回到视图中,需要在事后验证对象 为需要省略字段的方法添加自定义验证器 例如:

@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();
}
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;
    }

}
专业人士

清流。 缺点

饱受干燥问题之苦。这意味着,如果域对象以任何方式被更改,我需要重新验证。 保存时,字段验证与Hibernate验证不同。 忽略验证和手动验证没有明显的好处。

是否考虑?

自定义验证器可以委托给标准JSR-303验证器,但只需省略字段。 从域对象中删除JSR-303注释 非选项这意味着在保存之前没有对对象进行验证。更糟糕的是,我认为这会影响为数据库生成的DDL,从而消除数据库本身的约束。只是为了完整起见才放在这里

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

缺点

在点击控制器之前访问数据库有点异味。 我看不出有什么办法来实现这一点。 不适用于在对象生命周期的其他阶段需要忽略的字段。例如,如果在创建期间添加时间戳。 我想知道如何实现委托给标准JSR-303验证器的验证器,或者如何在修改对象之前查找对象。或者有没有其他可能的解决方案

这两种解决方案中的任何一种都允许对多个对象进行一致的处理

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

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

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

干杯

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

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


干杯

最后一个选项可以通过@modeldattribute注释实现

创建一个返回域对象的方法,并向其添加@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();
}
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;
    }

}

最后一个选项可以通过@modeldattribute注释实现

创建一个返回域对象的方法,并向其添加@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();
}
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;
    }

}

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

还有另一种解决方案:将域对象包装成只公开要验证的字段的特殊形式对象

例如:

@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();
}
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;
    }

}

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

还有另一种解决方案:将域对象包装到特殊的 仅公开要验证的字段的窗体对象

例如:

@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();
}
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;
    }

}

您是否尝试过使用CSS或将这些字段作为隐藏字段隐藏在UI中=这将起作用,但这将意味着我需要向客户机公开与他们无关的属性,例如哈希密码。对于密码,您没有其他选择,只能在更新时从数据库中查找=您是否尝试过使用CSS或将这些字段作为隐藏字段隐藏在UI中=这将起作用,但这将意味着我需要向客户机公开与他们无关的属性,例如哈希密码。对于密码,您没有其他选择,只能在更新时从数据库中查找=