Eclipse+JSF+JPAで作るアプリ(17)―Primefaces Autocompleteを使う。
今回は、映画の検索画面を作成します。
技術的な内容は、以下の通りです。
これらを組み合わせて使っているので、実装自体はすっきりとします。
実装すると次のような画面が表示されます。
なお、MovieクラスのCRUD操作は、前回までのUserクラスのCRUD操作と同様なので割愛しています。
いつものように画面のxhtml(searchMovie.xhtml)→ManagedBean(SearchMovieView.java)→DBアクセス(MovieManager.java)という順で実装します。
eclipseを使っていると、仮のメソッドシグニチャを書く→プロポーザルからメソッドの実装という流れになりやすいです。
p:autocompleteタグの使用方法
autocompleteは以下のように記述します。
<p:autoComplete id="title" value="#{searchMovieView.title}" completeMethod="#{searchMovieView.completeTitle}"/> <p:autoComplete id="category" value="#{searchMovieView.category}" completeMethod="#{searchMovieView.completeCategory}" dropdown="true"/>
- completeMethodで、フィルタするためのメソッドを呼び出します。
- dropdown="true"にすると、テキストボックスの横に、ドロップダウンボタンが表示されます。
検索画面は、上記の画像の通り、タイトル、カテゴリ、あらすじの3つのフィールドを持つため、
以下のようなxhtmlになります。
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html" xmlns:f="http://java.sun.com/jsf/core" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:p="http://primefaces.org/ui" > <h2>映画の検索</h2> <p:growl id="growl" showDetail="true" autoUpdate="true"/> <h:form id="searchMovieForm"> <p:panelGrid columns="2" > <p:outputLabel value="タイトル:" /> <p:autoComplete id="title" value="#{searchMovieView.title}" completeMethod="#{searchMovieView.completeTitle}"/> <p:outputLabel value="カテゴリ:" /> <p:autoComplete id="category" value="#{searchMovieView.category}" completeMethod="#{searchMovieView.completeCategory}" dropdown="true"/> <p:outputLabel value="あらすじ:" /> <p:autoComplete id="outline" value="#{searchMovieView.outline}" completeMethod="#{searchMovieView.completeOutline}"/> </p:panelGrid> <p:messages /> <p:commandButton value="映画の検索" actionListener="#{searchMovieView.searchMovie}" update=":movieListForm:movieList" /> </h:form> …
ManagedBeanでのcompleteMethodの実装
ManagedBeanのcompleteXxxメソッドの実装です。
SearchMovieView.java
private List<String> enteredTitles; … @PostConstruct public void init() { movies = new ArrayList<Movie>(); movieModel = new IdEntityListDataModel<Movie>(movies); enteredTitles = MovieManager.getEnteredTitles(); … } … public List<String> completeTitle(String input) { return enteredTitles .stream() .filter(e -> e.contains(input)) .collect(Collectors.toList()); } public List<String> completeCategory(String input) … public List<String> completeOutline(String input) …
- List<String> enteredTitlesでDBに入力されている映画のタイトルを定義しています。
- @PostConstructのinit()メソッドでdistinctした値をMovieManagerから取得しています。(後述)
- completeTitleで、入力された値(input)をフィルタしたList<String>を返します。
- Java SDK 8.0から導入されたLambda式を使用しています。
Lambda式の利用
ラムダ式については、こちらの説明が全体像の把握には、分かりやすかったです。
http://www.ne.jp/asahi/hishidama/home/tech/java/lambda.html
上記処理では
- stream()でストリームAPIを取得し、
- 中間操作 filter()で、要素eがinputを含むものを取り出し、
- 終端操作 collect() でリストにして返しています。
フィルタ処理もラムダ式では1行で書けるのですっきりします。
DBアクセスクラス MovieManager.javaの実装
public static List<String> getEnteredTitles() { EntityManager em = getEm(); TypedQuery<String> q = em.createQuery("select distinct m.title from Movie m order by m.title asc", String.class); List<String> result = q.getResultList(); em.close(); return result; }
- select distinctで、Movie.titleを一意なリストとして取得しています。
以上です。
JPAのdistinct、Lambda式を使えば、簡単にautocompleteを実装できます。