英和辞書アプリの作成を前回の続きから行う。
検索結果が多い場合には[次へ]などのナビゲーションが必要となる。そのナビゲーションの実装と、検索結果をブックマークできるようにリクエストの処理をGETで行うように変更する。
DAOへの追記
1.WordDAOにページによって取得範囲を変えるメソッドを追記する。
変更箇所:112行目以降のgetListBySearchWordメソッドを追記する
●dao.WordDAO.java
package dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.sql.DataSource; import model.Word; public class WordDAO { private Connection db; private PreparedStatement ps; private ResultSet rs; private void connect() throws NamingException, SQLException { Context context=new InitialContext(); DataSource ds=(DataSource)context.lookup("java:comp/env/ejword"); this.db=ds.getConnection(); } private void disconnect() throws SQLException { if(rs !=null) { rs.close(); } if(ps !=null) { ps.close(); } if(db != null) { db.close(); } } public List<Word> getListBySearchWord(String searchWord,String mode){ List<Word> list=new ArrayList<>(); switch(mode) { case "startsWith": searchWord=searchWord+"%"; break; case "contains": searchWord="%"+searchWord+"%"; break; case "endsWith": searchWord="%"+searchWord; } try { this.connect(); ps=db.prepareStatement("SELECT * FROM words WHERE title LIKE ?"); ps.setString(1, searchWord); //System.out.println(ps); rs=ps.executeQuery(); while(rs.next()) { String title=rs.getString("title"); String body=rs.getString("body"); Word w=new Word(title,body); list.add(w); } } catch (NamingException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); }finally { try { this.disconnect(); } catch (SQLException e) { e.printStackTrace(); } } return list; } public List<Word> getListBySearchWord(String searchWord,String mode,int limit){ List<Word> list=new ArrayList<>(); switch(mode) { case "startsWith": searchWord=searchWord+"%"; break; case "contains": searchWord="%"+searchWord+"%"; break; case "endsWith": searchWord="%"+searchWord; } try { this.connect(); ps = db.prepareStatement("SELECT * FROM words WHERE title LIKE ? LIMIT ?"); ps.setString(1, searchWord); ps.setInt(2, limit); rs = ps.executeQuery(); while (rs.next()) { int id = rs.getInt("id"); String title = rs.getString("title"); String body = rs.getString("body"); list.add(new Word(id, title, body)); } } catch (NamingException | SQLException e) { e.printStackTrace(); } finally { try { this.disconnect(); } catch (SQLException e) { // TODO 自動生成された catch ブロック e.printStackTrace(); } } return list; } public List<Word> getListBySearchWord(String searchWord,String mode,int limit,int offset){ List<Word> list=new ArrayList<>(); switch(mode) { case "startsWith": searchWord=searchWord+"%"; break; case "contains": searchWord="%"+searchWord+"%"; break; case "endsWith": searchWord="%"+searchWord; } try { this.connect(); ps = db.prepareStatement("SELECT * FROM words WHERE title LIKE ? LIMIT ? OFFSET ?"); ps.setString(1, searchWord); ps.setInt(2, limit); ps.setInt(3, offset); rs = ps.executeQuery(); while (rs.next()) { int id = rs.getInt("id"); String title = rs.getString("title"); String body = rs.getString("body"); list.add(new Word(id, title, body)); } } catch (NamingException | SQLException e) { e.printStackTrace(); } finally { try { this.disconnect(); } catch (SQLException e) { // TODO 自動生成された catch ブロック e.printStackTrace(); } } return list; } //一致件数を求めるメソッド public int getCount(String searchWord,String mode){ switch(mode) { case "startsWith": searchWord=searchWord+"%"; break; case "contains": searchWord="%"+searchWord+"%"; break; case "endsWith": searchWord="%"+searchWord; } int total=0; try { this.connect(); ps = db.prepareStatement("SELECT count(*) AS total FROM words WHERE title LIKE ?"); ps.setString(1, searchWord); rs = ps.executeQuery(); if (rs.next()) { total = rs.getInt("total"); } } catch (NamingException | SQLException e) { e.printStackTrace(); } finally { try { this.disconnect(); } catch (SQLException e) { e.printStackTrace(); } } return total; } }
controllerの変更
2.Main.javaを以下のように変更する。すべてdoGetで処理をするようにする。(doPostはコメントアウトまたは削除)
●controller.Main.java
package controller; import java.io.IOException; import java.util.List; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import dao.WordDAO; import model.Word; @WebServlet("/main") public class Main extends HttpServlet { private static final long serialVersionUID = 1L; private static final int LIMIT = 20; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("UTF-8"); String searchWord = request.getParameter("searchWord"); if (searchWord != null) { String mode = request.getParameter("mode"); if(mode ==null){ mode="startsWith"; } String page=request.getParameter("page"); int pageNo=page==null? 1:Integer.parseInt(page); WordDAO dao = new WordDAO(); int total = dao.getCount(searchWord, mode); List<Word> list = dao.getListBySearchWord(searchWord, mode, LIMIT,(pageNo-1)*LIMIT); request.setAttribute("total", total); request.setAttribute("limit", LIMIT); request.setAttribute("searchWord", searchWord); request.setAttribute("mode", mode); request.setAttribute("list", list); request.setAttribute("pageNo",pageNo); } RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/view/main.jsp"); rd.forward(request, response); } }
viewの変更
3.main.jspを以下のように変更する。
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" import="model.*,java.util.*"%> <% String searchWord=(String)request.getAttribute("searchWord"); searchWord=searchWord ==null? "":searchWord; String mode=(String)request.getAttribute("mode"); mode=mode == null? "":mode; List<Word> list=(List<Word>)request.getAttribute("list"); Integer total=(Integer)request.getAttribute("total"); Integer limit=(Integer)request.getAttribute("limit"); Integer pageNo=(Integer)request.getAttribute("pageNo"); %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>EJWord</title> </head> <body> <form action="/ejword/main" method="get"> <input type="text" name="searchWord" value="<%=searchWord%>"> <select name="mode"> <option value="startsWith"<%if(mode.equals("statsWith")) out.print(" selected"); %>>で始まる</option> <option value="contains"<%if(mode.equals("contains")) out.print(" selected"); %>>含む</option> <option value="endsWith"<%if(mode.equals("endsWith")) out.print(" selected"); %>>で終わる</option> <option value="match"<%if(mode.equals("match")) out.print(" selected"); %>>一致する</option> </select> <button type="submit">検索</button> </form> <% if(list !=null && list.size() > 0){ %> <%-- 件数表示部分作成 --%> <% if(total <= limit){ %> <p>全<%=total %>件</p> <%}else{ %> <%--ページ番号を利用して何件から何件を表示しているのかを表示する --%> <p>全<%=total %>件中 <%=(pageNo-1)*limit+1 %>~<%=pageNo*limit > total? total:pageNo*limit %>件を表示</p> <%--ページ番号が1より大きかったら前へのリンクを表示 --%> <ul> <%if(pageNo > 1) {%> <li><a href="/ejword/main?searchWord=<%=searchWord %>&mode=<%=mode %>&page=<%=pageNo-1%>"><span aria-hidden="true">←</span>前へ</a></li> <%} %> <%--件数が全件数に届かないときは次へのリンクを表示 --%> <%if(pageNo*limit < total) {%> <li><a href="/ejword/main?searchWord=<%=searchWord %>&mode=<%=mode %>&page=<%=pageNo+1%>">次へ<span aria-hidden="true">→</span></a></li> <%} %> </ul> <%} %> <table border="1"> <% for(Word w:list){ %> <tr><th><%=w.getTitle() %></th><td><%=w.getBody() %></td></tr> <%} %> </table> <%} %> </body> </html>
動作確認
4.実行し以下のように動作すれば成功だ。
●次があるときは次へのリンクが表示されている。
●次も前もある時は両方表示されている。
●最後のページ
URLの確認
5.GET通信でリクエストを処理するとデータがクエリパラメーターとなってURLに付与される。
localhost:8080/ejword/main?searchWord=book&mode=contains&page=1
このURLをブックマークすることによっていつでも同じ検索結果を見ることができる。このように検索結果をブックマークしたいアプリには今回のようにGET通信用いることがポイントだ。
JSP & Servlet-18日目(英和辞書アプリの作成5)
英和辞書アプリの作成を前回の続きから行う。基本的な仕組みが出来上がったので見た目を少し整えよう。こういったときには最短労力でそれなりのがすぐにできるBootstrapを使うと効率がよい。Bootstarpの設定1.まずは以下にアクセスする(...
コメント