Grails:命令对象、视图模式和条件表单字段?
Grails: Command objects, view patterns and conditional form fields?
我正在尝试正确使用命令对象。我有一些问题。
给定一个通用域,例如:
package com.foo
class Ticket {
Customer customer
Product product
Defect defect
Solution solution
String comment
static constraints = {
customer nullable:false
product nullable:false
defect nullable:true
solution nullable:true
comment nullable:true
}
}
然后,考虑工单表格的以下规则:
- 客户只能在创建时 selected。在编辑时,select 不得
显示,而是显示标签;
- 产品只能在创建时 selected。然而,在编辑时,select 必须显示为禁用;
- 可以在创建或编辑时 select 编辑缺陷;
- 解决方法无论如何都不能设置成这种形式。
- 评论只能由具有特定角色的用户通知(例如使用 SpringSecurity)。如果用户没有这样的角色,文本区域必须显示为禁用。
现在,我想知道的是:
使用 CommandObject 处理的最佳方法是什么
这种情况?
- 1 个 CommandObject 用于两个操作?
- 1 个特定于每个操作的 CommandObject?
- 在单个 CommandObject 的情况下,如何防止用户入侵程序,例如传递禁止的参数?
实施表单规则的最佳方法是什么?也就是说,每种情况下哪个字段是shown/enabled/disabled。
- 对于这种情况有什么模式或建议吗?
- 这样的规则应该写成实际的形式吗?
- 或者有人应该"ask"这种形式吗?也许是 CommandObject?还是域实例本身?
例如,考虑这个表单的要点:
<div class="fieldcontain ${hasErrors(bean:ticketInstance, field:'customer', 'error')} required">
<label for="customer">
<g:message code="ticket.customer.label" default="Customer" />
<span class="required-indicator">*</span>
</label>
<g:if test="${ticketInstance.id}">
<span class="label read-only">${ticketInstance.customer.name}</span>
</g:if>
<g:else>
<g:select id="customer" name="customer.id" from="${Customer.list()}" optionKey="id"
required="" disabled="" value="${ticketInstance?.customer?.id}" class="many-to-one"/>
</g:else>
</div>
这种情况下问题不大,因为检查比较简单。即:
<g:if test="${ticketInstance.id}">
...
但是,请考虑更复杂的规则。类似于:
<g:if test="${ticketInstance.id && currentUser.granted('SOME_RULE') && ticketInstance.someField != null}">
...
以此类推
现在,这种方法存在一些问题:
- 它相当冗长,因此容易出错。
- 假设这样的规则被其他领域共享。在这种情况下,我将不得不以某种方式对其进行管理(局部变量、复制代码等)。
- 此外,为此,我需要在我的 TicketCommand 中使用 属性 'Id',我不知道这是否是个好主意。
因此,我想知道是否有任何模式或建议可用于改善这些情况。也就是说,可以封装这种复杂性的东西。例如:
<g:if test="${cmd.customerAllowed}">
...
CommandObject 可能是这样的:
@Validateable
class TicketCreateCommand {
def currentUser //injected somehow..
Customer customer
Product product
Defect defect
String comment
static constraints = {
importFrom Ticket
}
boolean isNew() {
true
}
boolean isCustomerAllowed() {
this.new && currentUser.granted('SOME_RULE') && this.someField != null
//some more rules if necessary..
}
boolean isSomeFieldAllowed() {
//rules for creating
}
}
以及用于编辑的 CommandObject:
@Validateable
class TicketEditCommand {
def currentUser //injected somehow..
Customer customer
Product product
Defect defect
String comment
static constraints = {
importFrom Ticket
}
boolean isNew() {
false
}
boolean isCustomerAllowed() {
this.new && currentUser.granted('SOME_RULE') && this.someField != null
//some more rules if necessary..
}
boolean isSomeFieldAllowed() {
//rules for editing
}
}
CommndObject 可以承担这样的职责吗?如果没有,是否还有其他更好的方法来集中这些复杂性?另外,正如我之前所说,无法将 属性 客户设置为更新。如何处理?
嗯,我想差不多就是这样了。
如果有任何意见和建议,我将不胜感激。任何 link 的教程也很棒。
PS:对于那些想看的人,完整的项目可以在 github.
上找到
使用命令对象处理这种情况的最佳方法是什么?
对于查看、编辑和删除操作,需要一个简单的工单 ID。我觉得那个阶段的命令对象太过分了。
由于在更新(编辑提交操作)和保存(创建提交操作)中使用的表单背后存在逻辑,您应该尝试为每个表单创建一个命令对象。
关于命令对象的结构,我个人的偏好是让它反映表单提供的数据。然后,您可以在命令 object/controller 到 construct/get a Ticket
中使用提供的数据中的实用程序方法。
实施表单规则的最佳方法是什么?
表格的规则可以在gsp中写成一系列的条件语句。如果有大量的条件语句,或者任何在应用程序中定期重复使用的条件语句,那么您可以将方法添加到您的命令对象中以集中处理。
由于命令对象位于视图和控制器之间,我不明白为什么不能在此处存储表单逻辑。
如果应该禁用某个字段,那么您可以简单地将 disabled="disabled"
属性添加到表单字段。或者使用命令对象方法:
disabled="${cmd.isFooFieldDisabled() ? 'disabled' : ''}"
如果该字段应该隐藏,那么您可以像这样使用隐藏输入,该值对用户不可见,但会在表单提交时传递到命令对象中。
<input type="hidden" name="foo" value="${ticket.foo}"/>
我相信 are tags provided spring 安全插件根据用户的角色 show/hide gsp 元素。
为防止用户传递无效数据,您可以使用以下代码在您的控制器中对此进行验证。
def foo(FooCommand cmd)
{
if(cmd.hasErrors())
{
// Handle validation errors
}
}
方法 hasErrors
使用您定义的约束验证命令对象。从这一点开始,您可以 return 错误或从验证错误中恢复并继续操作流程。
如果用户更改隐藏表单输入,例如对象的 ID,则控制器代码应检查用户是否有权使用给定 ID 编辑对象。如果他们这样做了,那么安全策略就没有被破坏。如果不是,那么您可以 return 选择一些错误。请参阅 this post 关于隐藏字段的保护。
我正在尝试正确使用命令对象。我有一些问题。
给定一个通用域,例如:
package com.foo
class Ticket {
Customer customer
Product product
Defect defect
Solution solution
String comment
static constraints = {
customer nullable:false
product nullable:false
defect nullable:true
solution nullable:true
comment nullable:true
}
}
然后,考虑工单表格的以下规则:
- 客户只能在创建时 selected。在编辑时,select 不得 显示,而是显示标签;
- 产品只能在创建时 selected。然而,在编辑时,select 必须显示为禁用;
- 可以在创建或编辑时 select 编辑缺陷;
- 解决方法无论如何都不能设置成这种形式。
- 评论只能由具有特定角色的用户通知(例如使用 SpringSecurity)。如果用户没有这样的角色,文本区域必须显示为禁用。
现在,我想知道的是:
使用 CommandObject 处理的最佳方法是什么 这种情况?
- 1 个 CommandObject 用于两个操作?
- 1 个特定于每个操作的 CommandObject?
- 在单个 CommandObject 的情况下,如何防止用户入侵程序,例如传递禁止的参数?
实施表单规则的最佳方法是什么?也就是说,每种情况下哪个字段是shown/enabled/disabled。
- 对于这种情况有什么模式或建议吗?
- 这样的规则应该写成实际的形式吗?
- 或者有人应该"ask"这种形式吗?也许是 CommandObject?还是域实例本身?
例如,考虑这个表单的要点:
<div class="fieldcontain ${hasErrors(bean:ticketInstance, field:'customer', 'error')} required">
<label for="customer">
<g:message code="ticket.customer.label" default="Customer" />
<span class="required-indicator">*</span>
</label>
<g:if test="${ticketInstance.id}">
<span class="label read-only">${ticketInstance.customer.name}</span>
</g:if>
<g:else>
<g:select id="customer" name="customer.id" from="${Customer.list()}" optionKey="id"
required="" disabled="" value="${ticketInstance?.customer?.id}" class="many-to-one"/>
</g:else>
</div>
这种情况下问题不大,因为检查比较简单。即:
<g:if test="${ticketInstance.id}">
...
但是,请考虑更复杂的规则。类似于:
<g:if test="${ticketInstance.id && currentUser.granted('SOME_RULE') && ticketInstance.someField != null}">
...
以此类推
现在,这种方法存在一些问题:
- 它相当冗长,因此容易出错。
- 假设这样的规则被其他领域共享。在这种情况下,我将不得不以某种方式对其进行管理(局部变量、复制代码等)。
- 此外,为此,我需要在我的 TicketCommand 中使用 属性 'Id',我不知道这是否是个好主意。
因此,我想知道是否有任何模式或建议可用于改善这些情况。也就是说,可以封装这种复杂性的东西。例如:
<g:if test="${cmd.customerAllowed}">
...
CommandObject 可能是这样的:
@Validateable
class TicketCreateCommand {
def currentUser //injected somehow..
Customer customer
Product product
Defect defect
String comment
static constraints = {
importFrom Ticket
}
boolean isNew() {
true
}
boolean isCustomerAllowed() {
this.new && currentUser.granted('SOME_RULE') && this.someField != null
//some more rules if necessary..
}
boolean isSomeFieldAllowed() {
//rules for creating
}
}
以及用于编辑的 CommandObject:
@Validateable
class TicketEditCommand {
def currentUser //injected somehow..
Customer customer
Product product
Defect defect
String comment
static constraints = {
importFrom Ticket
}
boolean isNew() {
false
}
boolean isCustomerAllowed() {
this.new && currentUser.granted('SOME_RULE') && this.someField != null
//some more rules if necessary..
}
boolean isSomeFieldAllowed() {
//rules for editing
}
}
CommndObject 可以承担这样的职责吗?如果没有,是否还有其他更好的方法来集中这些复杂性?另外,正如我之前所说,无法将 属性 客户设置为更新。如何处理?
嗯,我想差不多就是这样了。
如果有任何意见和建议,我将不胜感激。任何 link 的教程也很棒。
PS:对于那些想看的人,完整的项目可以在 github.
上找到使用命令对象处理这种情况的最佳方法是什么?
对于查看、编辑和删除操作,需要一个简单的工单 ID。我觉得那个阶段的命令对象太过分了。
由于在更新(编辑提交操作)和保存(创建提交操作)中使用的表单背后存在逻辑,您应该尝试为每个表单创建一个命令对象。
关于命令对象的结构,我个人的偏好是让它反映表单提供的数据。然后,您可以在命令 object/controller 到 construct/get a Ticket
中使用提供的数据中的实用程序方法。
实施表单规则的最佳方法是什么?
表格的规则可以在gsp中写成一系列的条件语句。如果有大量的条件语句,或者任何在应用程序中定期重复使用的条件语句,那么您可以将方法添加到您的命令对象中以集中处理。
由于命令对象位于视图和控制器之间,我不明白为什么不能在此处存储表单逻辑。
如果应该禁用某个字段,那么您可以简单地将 disabled="disabled"
属性添加到表单字段。或者使用命令对象方法:
disabled="${cmd.isFooFieldDisabled() ? 'disabled' : ''}"
如果该字段应该隐藏,那么您可以像这样使用隐藏输入,该值对用户不可见,但会在表单提交时传递到命令对象中。
<input type="hidden" name="foo" value="${ticket.foo}"/>
我相信 are tags provided spring 安全插件根据用户的角色 show/hide gsp 元素。
为防止用户传递无效数据,您可以使用以下代码在您的控制器中对此进行验证。
def foo(FooCommand cmd)
{
if(cmd.hasErrors())
{
// Handle validation errors
}
}
方法 hasErrors
使用您定义的约束验证命令对象。从这一点开始,您可以 return 错误或从验证错误中恢复并继续操作流程。
如果用户更改隐藏表单输入,例如对象的 ID,则控制器代码应检查用户是否有权使用给定 ID 编辑对象。如果他们这样做了,那么安全策略就没有被破坏。如果不是,那么您可以 return 选择一些错误。请参阅 this post 关于隐藏字段的保护。