前回までで、「日報へのリアクション(いいね!)機能」「リアクションした人の一覧表示機能」をなんとか実装してきた日報管理システム。今回のお題は、「特定のユーザーのフォロー機能」の実装。
1. モデル作成
誰(follower)が誰(followee)をフォローしているかという情報を管理しておく必要があるが、followerもfolloweeも同じemployeesのオブジェクトになるし、一人が複数人をフォローしたり、複数人にフォローされたりする「多:多」の関係になるので、ここは新たにフォロー情報をまとめるテーブルを作るしかない。
ということで、followsテーブルを作る。follower_idもfollowee_idもemployeesテーブル依存。
2. コントローラの作成
新しく用意するコントローラは、誰かをフォローするためのcreate機能と、フォローを解除するdestroy機能だけでとりあえず事足りるはず。
今回は、ある日報の詳細ページを開いた時に、その日報の作成者のことをフォローする、もしくはフォロー解除するボタンを設置するようにしたい。
上のイメージでいうと、followerはログイン中の管理太郎さん、followeeは表示している日報作成者の一般花子さん。ということで、そのようにFollowCreateServletをコーディング。
followerにはログイン中のユーザー情報を、followeeには表示中のreportオブジェクトに紐づいているEmployeeをスコープから持ってきて入れる。作成日時の情報と合わせて、さっき作ったfollowsテーブルへデータ登録する。
次にフォロー解除の機能も書いておく。followsテーブルからフォロー情報を削除してフォロー解除ということにするので、削除するfollowsオブジェクト(f)を指定しなきゃならない。つまり、上の例で言えば、followerが管理太郎でfolloweeが一般花子になってるオブジェクトをfololowsテーブルから抽出して、それを削除する指示をする。このデータ抽出用に”getAnExistingFollow”というクエリをFollowモデル上に作ることにした。
@NamedQuery( name = "getAnExistingFollow", query = "SELECT f FROM Follow AS f WHERE f.follower =:follower AND f.followee =:followee" ),
上記のクエリで、followerの変数にログイン中のユーザー、followeeの変数には表示中のreport情報に紐づいたEmployeeを代入してやれば、削除するべきfollowオブジェクトが特定できる。
3. ビューの修正
これでフォローとフォロー解除の機能自体はできたので、あとは実際に画面上からその操作ができるようにビューファイルを修正していく。フォローボタン/フォロー解除ボタンは日報詳細ページにつけるので、該当するreport/show.jspのHTMLをいじっていくわけだが・・・その前に必要な準備がある。まず、ログイン中のユーザーが自分の日報を見てる時にはフォローボタンは表示させない。これはあまり問題ない。次、フォローボタンかフォロー解除ボタンのどちらを表示させるかは、当たり前だが、ログインユーザーが表示中の日報作成者を既にフォローしているかしていないかで判断する必要がある。そのジャッジをするためのコードを予め用意しておく。
まず、Followモデル上に”getExistingFollowCount”という名前でクエリを作る。followerとfolloweeを指定すれば、該当するfollowオブジェクトの数を数えてくれるクエリ。
@NamedQuery( name = "getAnExistingFollow", query = "SELECT f FROM Follow AS f WHERE f.follower =:follower AND f.followee =:followee" ),
そんでもって、このクエリを使って、ログイン中のユーザーが日報の作成者を既にフォローしているかどうかをチェックする文をReportShowServlet上に作って、その結果をfollow_countという変数としてreport/show.jspに渡すようにする。
long follow_count = em.createNamedQuery("getExistingFollowsCount", Long.class) .setParameter("follower", e) .setParameter("followee", r.getEmployee()) .getSingleResult();
follow_countが0であれば、まだフォローしてないということなので、「フォローする」ボタンを表示させる。それ以外なら「フォロー解除」のボタンを表示。(理論上、アプリが正しく機能すれば、follow_countは0か1のどちらかしかありえないが)
実際のreport/show.jsp上のコードは下のような感じ。これでボタンが表示されて、先述のFollowCreateServletもしくはFollowDestroyServletへ必要な情報を飛ばせる。
<c:if test="${sessionScope.login_employee.id != report.employee.id}"> <c:choose> <c:when test="${follow_count == 0 || follow_count == null}"> <form method="POST" action="<c:url value='/follows/create'/>"> <p> <input type="hidden" name="_token" value="${_token}" /> <input type="hidden" name="report_id" value="${report.id}"> <input type="submit" value="${report.employee.name}さんをフォローする"> </p> </form> </c:when> <c:otherwise> <form method="POST" action="<c:url value='/follows/destroy'/>"> <p> <input type="hidden" name="_token" value="${_token}" /> <input type="hidden" name="report_id" value="${report.id}"> <input type="submit" value="${report.employee.name}さんのフォローを解除"> </p> </form> </c:otherwise> </c:choose> </c:if>
実際に画面の表示はこんな感じ。
ひとまずこれで、誰かをフォローする機能は実装完了。ここから、「フォローしている人の日報だけを表示する」機能をつけて初めてこれが活きてくるわけだが、長くなるので、そっちの実装については別記事でまとめることにする。