技术开发 频道

精通 Grails:用定制URI和codec优化Grails中的URI

  按作者显示条目

  我们的最终目的就是支持像 http://localhost:9090/blogito/entry/list/jdoe 这样的 URI。注意到,User.login 出现在此 URI 内,而不是主键。在这个过程中,还需要对分页(pagination)做稍许调整。

  EntryController.list 的搭建(scaffolded)行为不允许按 User 过滤。清单 5 显示了 list 闭包的默认实现:

  清单 5. 默认的 list 实现

def list = {
    
if(!params.max) params.max = 10
    [ entryInstanceList: Entry.list( params ) ]
}

  若要支持在路径的末尾允许出现一个可选的用户名,还需要对之进行扩展。编辑 grails-app/controllers/EntryController.groovy 并添加一个新的 list 闭包,如清单 6 所示:

  清单 6. 按作者限制此列表

class EntryController {
  def scaffold
= Entry
  
  def list
= {
      
if(!params.max) params.max = 10
      flash.id
= params.id
      
if(!params.id) params.id = "No User Supplied"

      def entryList
      def entryCount
      def author
= User.findByLogin(params.id)
      
if(author){
        def query
= { eq('author', author) }
        entryList = Entry.createCriteria().list(params, query)        
        entryCount
= Entry.createCriteria().count(query)
      }
else{
        entryList
= Entry.list( params )
        entryCount
= Entry.count()
      }
      
      [ entryInstanceList:entryList, entryCount:entryCount  ]
  }  
}

  您应该注意到的第一件事情是,若终端用户没有提供 params.max 和 params.id 二者的值,就用默认值填充。现在,先不要担心 flash.id — 我稍后在探讨有关分页问题的时候还会对之进行详细讨论。

  params.id 值通常是一个整型 — 确切的说是主键。我们一般习惯于 /entry/show/1 和 entry/edit/2 这样的 URI。我本可以在 grails-app/conf/UrlMappings.groovy 内设置一个映射以便返回一个描述性更好的名称,比如 params.name 或 params.login,但现有的映射已经获取了操作名称后的路径元素并将其存储在 params.id 内。我只是充分利用了现有的行为。在 URLMapper.groovy 内,如清单 7 所示,可以看到返回 params.id 的默认映射:

  清单 7. UrlMappings.groovy 内的默认映射

class UrlMappings {
    static mappings
= {
      
"/$controller/$action?/$id?"{
          constraints {}
      }
    
//snip
    }
}

  由于这不是 User 的主键,所以不能像往常那样使用 User.get(params.id)。相反,必须使用 User.findByLogin(params.id)。

  如果找到了一个匹配的 User,就需要创建一个查询块。这就需要用到 Hibernate Criteria Builder(参见 参考资料)。在本例中,我们限制了列表只包含匹配某特定作者的那些条目。同样地,我们注意到 GORM 也允许您从对象而不是主键或外键的角度来思考。

  如果没有匹配 params.id 的作者,就会返回全部条目的完整列表: entryList = Entry.list( params )。

  注意,entryCount 值是被显式计算出来的。Scaffolded GroovyServer Pages (GSP) 代码通常会在 标记内调用 Entry.count()。由于会传递回一个过滤了的列表,所以需要在此控制器的一个变量内处理这一点。

  在 flash.id 内存储 params.id 值将允许应用程序将此查询条件传递回 标记。调整 grails-app/views/entry/list.gsp 内的 以便利用新的 entryCount 变量以及存储在 flash 范围内的参数,如清单 8 所示:

  清单 8. 针对定制分页调整 list.gsp 页面

<div class="paginateButtons">
  
<g:paginate total="${entryCount}" params="${flash}"/>
</div>

  重启 Grails 并在 Web 浏览器内访问 http://localhost:9090/blogito/entry/list/jsmith。屏幕应该类似图 2:

  图 2. 按作者列出条目  

  为了确保分页仍能工作,键入 http://localhost:9090/blogito/entry/list/jsmith?max=1。单击 Previous 和 Next 按钮以确保只有 Jane 的 blog 条目才会出现,如图 3 所示:

  图 3. 测试定制分页  

  按作者过滤的功能就绪后,就可以更进一步,创建一个更为友好的定制 URI。

0
相关文章