1.9.2. ブックマーク可能な検索結果ページ
このブログサンプルには各ページの右上に小さなフォームがあり、ユーザーはブログ記事を検索することが可能です。
menu.xhtml に定義され、Facelet テンプレートの template.xhtml で含まれます。
<div id="search">
<h:form>
<h:inputText value="#{searchAction.searchPattern}"/>
<h:commandButton value="Search" action="/search.xhtml"/>
</h:form>
</div>
ブックマーク可能な検索結果ページを実装するには、 検索フォームのサブミットを処理した後に、 ブラウザのリダイレクトを実行する必要があります。 アクションの結果として JSF ビュー ID を使用しているので、 Seam はフォームがサブミットされると自動的に ビュー ID にリダイレクトします。 別の方法として、 以下のようなナビゲーションルールを定義することも可能です。
<navigation-rule>
<navigation-case>
<from-outcome>searchResults</from-outcome>
<to-view-id>/search.xhtml</to-view-id>
<redirect/>
</navigation-case>
</navigation-rule>
この場合、 フォームは以下と似たようなものになるでしょう。
<div id="search">
<h:form>
<h:inputText value="#{searchAction.searchPattern}"/>
<h:commandButton value="Search" action="searchResults"/>
</h:form>
</div>
ただし、
http://localhost:8080/seam-blog/search/ のようなブックマーク可能な URL を取得するには、フォームでサブミットされる値をその URL に含ませる必要があります。 JSF でこれを行うのは簡単ではありませんが、 Seam なら ページパラメータ と URL の書き換え の 2 つの機能があれば行うことができます。 いずれも WEB-INF/pages.xml で定義します。
<pages>
<page view-id="/search.xhtml">
<rewrite pattern="/search/{searchPattern}"/>
<rewrite pattern="/search"/>
<param name="searchPattern" value="#{searchService.searchPattern}"/>
</page>
...
</pages>
検索ページが求められたり、 検索ページへのリンクが生成されたりする場合は必ず、
searchPattern 要求パラメータを #{searchService.searchPattern} が保持する値にリンクするようページパラメータが Seam に指示します。 Seam は URL の状態ととアプリケーションの状態を結ぶリンクを管理する役割を担います。
用語
book の検索 URL は、通常 http://localhost:8080/seam-blog/seam/search.xhtml?searchPattern=book です。Seam は書き換えのルールを使ってこの URL を簡略化することが可能です。/search/{searchPattern} パターンの最初の書き換えルールには、search.xhtml の URL が searchPattern 要求パラメータを含む場合は常にその URL は簡略化された URL に圧縮されることが可能であると記述しています。このため、前述した URL (http://localhost:8080/seam-blog/seam/search.xhtml?searchPattern= book) は、http://localhost:8080/seam-blog/search/book と記述することが可能です。
ページパラメータと同様に、 URL の書き換えは両方向です。 Seam は簡略化した URL の要求を適切なビューに転送し自動的に簡略化ビューを生成するため、 ユーザーは URL を構成する必要がありません。全プロセスは透過的に処理されます。 URL の書き換えに必要なのは
components.xml で書き換えフィルタを有効にすることだけです。
<web:rewrite-filter view-mapping="/seam/*" />
リダイレクトによって
search.xhtml ページに移動します。
<h:dataTable value="#{searchResults}" var="blogEntry">
<h:column>
<div>
<s:link view="/entry.xhtml" propagation="none"
value="#{blogEntry.title}">
<f:param name="blogEntryId" value="#{blogEntry.id}"/>
</s:link>
posted on
<h:outputText value="#{blogEntry.date}">
<f:convertDateTime timeZone="#{blog.timeZone}"
locale="#{blog.locale}" type="both"/>
</h:outputText>
</div>
</h:column>
</h:dataTable>
これもまた Hibernate Search を使用し実際の検索結果を取得するために「プル」型 MVC を使用します。
@Name("searchService")
public class SearchService {
@In
private FullTextEntityManager entityManager;
private String searchPattern;
@Factory("searchResults")
public List<BlogEntry> getSearchResults() {
if (searchPattern==null || "".equals(searchPattern) )
{
searchPattern = null;
return entityManager.createQuery(
"select be from BlogEntry be order by date desc"
).getResultList();
}
else
{
Map<String,Float> boostPerField = new HashMap<String,Float>();
boostPerField.put( "title", 4f );
boostPerField.put( "body", 1f );
String[] productFields = {"title", "body"};
QueryParser parser = new MultiFieldQueryParser(productFields,
new StandardAnalyzer(), boostPerField);
parser.setAllowLeadingWildcard(true);
org.apache.lucene.search.Query luceneQuery;
try
{
luceneQuery = parser.parse(searchPattern);
}
catch (ParseException e)
{
return null;
}
return entityManager
.createFullTextQuery(luceneQuery, BlogEntry.class)
.setMaxResults(100)
.getResultList();
}
}
public String getSearchPattern()
{
return searchPattern;
}
public void setSearchPattern(String searchPattern)
{
this.searchPattern = searchPattern;
}
}