英和辞書アプリの作成を前回の続きから行う。
検索結果が多い場合には[次へ]などのナビゲーションが必要となる。そのナビゲーションの実装と、検索結果をブックマークできるようにリクエストの処理を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.まずは以下にアクセスする(...
コメント