将搜索更深入地并入到 Blogito下面教您如何添加对 Entries 的搜索。首先,在一个文本编辑器内打开 grails-app/controllers/EntryController.groovy。添加一个简单的 search 动作,如清单 13 所示。(别忘了要允许未经身份验证的用户通过向 beforeInterceptor 添加 search 动作来进行博客条目的搜索。)
清单 13. 添加 search 动作1
2
3
4
5
6
7
8
9
10
11
| class EntryController {
def beforeInterceptor =
[action:this.&auth, except:["index", "list", "show", "atom", "search"]]
def search = {
render Entry.search(params.q, params)
}
//snip
}
|
正如在前一章节所展示的那样,SearchableService 非常适合用来进行跨所有域类的站点级别的搜索。但 Searchable 插件也可以在您个人的域类上做一些元编程。正像 Grails 可以动态地添加 list()、get() 和 findBy() 方法一样,Searchable 插件可以添加一个 search() 方法。
通过在 Web 浏览器中键入 http://localhost:9090/blogito/entry/search?q=groovy 来测试新的 search 动作。应该会看到一个搜索结果的 hashmap 图,类似于图 4:
图 4. 显示原始的搜索结果 知道了 search() 方法的工作原理后,下一步是要让用户界面更为友好一点。在 grails-app/views/layouts 中创建一个名为 _search.gsp 的局部模板。加入清单 14 中的代码:
清单 14. 局部模板1
2
3
4
5
6
7
8
9
| <div id="search">
<g:form url='[controller: "entry", action: "search"]'
id="searchableForm"
name="searchableForm"
method="get">
<g:textField name="q" value="${params.q}" />
<input type="submit" value="Search" />
</g:form>
</div>
|
请注意,在上述代码中,控制器被设为 entry,动作被设为 search。
接下来,该显示这个局部模板了。在一个文本编辑器内打开 grails-app/views/layouts/_header.gsp 并添加一个 render 标签,如清单 15 所示:
清单 15. 为 header 添加这个搜索模板1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| <g:render template="/layouts/search" />
<div id="header">
<p><g:link class="header-main" controller="entry">Blogito</g:link></p>
<p class="header-sub">
<g:link controller="entry" action="atom">
<img src="${createLinkTo(dir:'images',file:'feed-icon-28x28.png')}"
alt="Subscribe" title="Subscribe"/>
</g:link>
A tiny little blog
</p>
<div id="loginHeader">
<g:loginControl />
</div>
</div>
|
给 web-app/css/main.css 添加一些 Cascading Style Sheets (CSS) 以确保 search <div> 可以浮在屏幕的右上角,如清单 16 所示:
清单 16. 添加 CSS 来调整搜索表单的位置1
2
3
4
| #search {
float: right;
margin: 2em 1em;
}
|
所有视图变化均完成后,请刷新浏览器。屏幕看上去应该如图 5 所示:
图 5. 给 header 添加搜索表单 需要做的最后一件事情就是以 HTML 格式提交 search 结果,而不是简单的调试输出。调整 EntryController 内的 search 动作,如清单 17 所示:
清单 17. 一个更健壮的搜索动作1
2
3
4
5
6
7
| def search = {
//render Entry.search(params.q, params)
def searchResults = Entry.search(params.q, params)
flash.message = "${searchResults.total} results found for search: ${params.q}"
flash.q = params.q
return [searchResults:searchResults.results, resultCount:searchResults.total]
}
|
由于该动作被命名为 search,因此需要在 grails-app/views/entry 中创建对应的 search.gsp 文件,如清单 18 所示:
清单 18. Search.gsp1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
| <html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="layout" content="main" />
<title>Blogito</title>
</head>
<body>
<g:if test="${flash.message}">
<div class="message">${flash.message}</div>
</g:if>
<div class="body">
<div class="list">
<g:each in="${searchResults}" status="i" var="entry">
<div class="entry">
<h2>
<g:link action="show"
id="${entry.id}">${entry.title}</g:link>
</h2>
<p>${entry.summary}</p>
</div>
</g:each>
</div>
</div>
<div class="paginateButtons">
<g:paginate total="${resultCount}" params="${flash}"/>
</div>
</body>
</html>
|
在 Web 浏览器中最后做一次 grails 搜索。搜索结果应该如图 6 所示:
图 6. HTML 格式的搜索结果 |