Grails应用开发:视图、控制器与审计日志实践
立即解锁
发布时间: 2025-08-15 02:33:25 阅读量: 37 订阅数: 43 AIGC 


Groovy与Grails:敏捷Web开发入门
### Grails应用开发:视图、控制器与审计日志实践
#### 1. 回顾与应用增强
在限制用户信息修改的过程中,我们学到了很多重要知识。比如,在编辑、更新和删除操作中引入逻辑,防止用户修改他人信息,只有用户本人才能进行修改。我们还研究了请求参数和Grails URL,明白了为何这种检查必须在控制器操作中进行。在查看`UserController`时,了解了信息如何以模型的形式返回给视图,以及如何通过数据绑定将参数设置到领域对象中。同时,也对领域对象验证有了初步了解,当验证失败时,视图可以从领域对象获取错误消息。
现在,我们可以利用这些知识进一步增强应用,控制显示的类别和待办事项信息。
#### 2. 控制类别显示
当用户导航到类别列表视图时,会显示所有类别,包括其他用户的类别。这对于用户维护自己的类别来说是一种干扰,没有实际价值。我们的目标是将所学的控制器操作知识应用到`Category`控制器上。
操作步骤如下:
1. **生成视图和控制器**:执行以下命令生成类别视图和控制器:
```plaintext
grails generate-views Category
grails generate-controller Category
```
2. **限制列表视图显示的类别**:在增强之前,`list`操作的代码如下:
```groovy
def list = {
if(!params.max)params.max = 10
[ categoryList: Category.list( params ) ]
}
```
第2行检查`params`映射中是否包含`max`键,如果没有,则创建一个键值对,`max`的值为10。动态方法`list`使用`max`参数限制返回的类别数量。第3行调用类别领域对象的动态方法`list`,并将结果返回给列表视图。
为了将类别限制为当前登录用户,需要进行如下修改:
```groovy
def list = {
if(!params.max)params.max = 10
def user = User.get(session.user.id)
[ categoryList: Category.findAllByUser(user, params) ]
}
```
第3行根据会话中的用户信息获取当前用户。第4行查找第3行获取的用户的所有类别,这是使用动态查找器方法的一个示例。运行应用后,列表视图将只显示当前登录用户的类别。
#### 3. 移除冗余信息
由于类别视图已经限制为当前登录用户,在任何视图中显示用户信息就显得多余了。移除用户选择组件分两步进行:
1. 从视图(`grails-app/views/category/*.gsp`)中移除用户选择组件,并在保存和更新操作调用时将用户默认设置为当前登录用户。
2. 在保存和更新操作中默认设置用户。以下是增强后的`save`和`update`操作代码:
```groovy
def update = {
def category = Category.get( params.id )
if(session.user.id != category.user.id) {
flash.message = "You can only delete your own categories"
redirect(action:list)
return
}
def user = User.get(session.user.id);
if(category) {
category.properties = params
category.user = user
if(category.save()) {
flash.message = "Category ${params.id} updated."
redirect(action:show,id:category.id)
}
}
}
def save = {
def category = new Category()
category.properties = params
def user = User.get(session.user.id);
category.user = user
if(category.save()) {
flash.message = "Category ${category.id} created."
redirect(action:show,id:category.id)
}
else {
render(view:'create',model:[category:category])
}
}
```
这里的`flash.message`是Groovy字符串(GString),`${}`允许在字符串中插入表达式,例如将`category.id`的值插入到字符串中。
#### 4. 移除类别ID
类别ID在列表和显示视图中没有实际价值,可以将其移除。移除后,视图中没有类别ID和用户名的字段,用户体验将得到显著改善。
**注意**:在列表视图中,ID字段有一个链接用于显示特定类别,要确保将链接移到类别名称上,否则将无法导航到显示视图。
同时,应将添加到`UserController`的编辑、更新和删除操作中的用户检查应用到`CategoryController`的相应操作中。并且,将对类别控制器和视图的增强应用到待办事项控制器和视图中。
#### 5. 创建审计日志
有时候,应用可能会出现问题,了解操作的输入和结果非常有用。我们可以在操作执行前显示输入,在操作结果返回前显示结果。但如果为每个操作都添加这样的打印语句,工作量大且难以维护。
Grails提供了动作拦截器机制来实现这一功能,这类似于面向切面编程(AOP),对于熟悉Servlet过滤器拦截器的开发者来说也很容易理解。Grails的实现更加简单。
Grails提供了前置和后置拦截器,我们可以使用它们来实现审计日志功能。
操作步骤如下:
1. **添加前置拦截器**:在`TodoController`中添加`beforeInterceptor`闭包,示例代码如下:
```groovy
def beforeInterceptor = {
log.trace("${session?.user?.userName} Start action ${controllerName} Controller.${actionName}() : parameters $params")
}
```
如果定义了`beforeInterceptor`,并且没有其他指示,它将在操作调用前被调用。它可以访问所有控制器属性和请求参数,使用日志记录审计信息。这里使用了`?.`安全解引用运算符,避免了`NullPointerException`。
2. **添加后置拦截器**:在`TodoController`中添加`afterInterceptor`闭包,示例代码如下:
```groovy
def afterInterceptor = { model ->
log.trace("${session?.user?.userName} End action ${controllerName}Controller.${actionName}() : returns $model")
}
```
后置拦截器与前置拦截器类似,不同的是它接收模型对象作为参数,以便将其输出到
0
0
复制全文
相关推荐









