게시판의 검색 기능을 구현해 보도록 하자
개발환경 : Oracle11g, Eclipse
먼저 기존의 게시판 bbs.jsp에 검색 입력을 받는 입력창과 검색 버튼을 추가한다.
<form method="post" action="searchedBbs.jsp">
<div class="col-lg-4">
<input type="text" class="form-control pull-right" placeholder="Search" name="searchWord" />
</div>
<button class="btn btn-primary" type="submit" >
<span class="glyphicon glyphicon-search">
</span>
</button>
</form>
Post 방식으로 검색어를 입력받아 name = searchWord 로 변수명을 정해주고 type=submit 버튼을 이용해 searchedBbs.jsp로 넘긴다.
SearchedBbs.jsp는 bbs.jsp를 기반으로 만든 게시판 jsp파일이다.
searchedBbs.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.io.PrintWriter"%>
<%@ page import="bbs.BbsDAO"%>
<%@ page import="bbs.Bbs"%>
<%@ page import="java.util.ArrayList"%>
<% request.setCharacterEncoding("UTF-8"); %>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width" initial-scale="1">
<link rel="stylesheet" href="css/bootstrap.css">
<title>JSP JSW 게시판 웹사이트</title>
<style type="text/css">
a, a:hover {
color: #000000;
text-decoration: none;
}
</style>
</head>
<body>
<%
String userID = null;
if(session.getAttribute("userID") != null) {
userID = (String) session.getAttribute("userID");
}
int pageNumber =1;
if(request.getParameter("pageNumber")!=null){
pageNumber = Integer.parseInt(request.getParameter("pageNumber"));
System.out.println("pageNumber="+pageNumber);
}
String searchWord = null;
if(request.getParameter("searchWord")!=null){
searchWord = (String) request.getParameter("searchWord");
System.out.println("searchword from parameter is :" + searchWord);
}
if(session.getAttribute("searchWord")!=null){
searchWord = (String) session.getAttribute("searchWord");
System.out.println("searchword from session is :" + searchWord);
}
%>
<nav class="navbar navbar-default">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed"
data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"
aria-expanded="false">
<span class="icon-bar"></span> <span class="icon-bar"></span> <span
class="icon-bar"></span>
</button>
<a class="navbar-brand" href="main.jsp">JSP 게시판 메인</a>
</div>
<div class="collapse navbar-collapse"
id="bs-example-navbar-collapse-1">
<ui class="nav navbar-nav">
<li><a href="main.jsp">메인</a></li>
<li class="active"><a href="bbs.jsp">게시판</a></li>
</ui>
<%
if( userID ==null ) {
%>
<ui class="nav navbar-nav navbar-right">
<li class="dropdown"><a href="#" class="dropdown-toggle"
data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">접속하기<span class="caret"></</span></a>
<ul class="dropdown-menu">
<li class="active"><a href="login.jsp">로그인</a></li>
<li><a href="join.jsp">회원가입</a></li>
</ul></li>
</ui>
<%
} else {
%>
<ui class="nav navbar-nav navbar-right">
<li class="dropdown"><a href="#" class="dropdown-toggle"
data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">회원관리<span class="caret"></</span></a>
<ul class="dropdown-menu">
<li><a href="logoutAction.jsp">로그아웃</a></li>
</ul></li>
</ui>
<%
}
%>
</div>
</nav>
<div class="container">
<div class="row">
<table class="table table-striped"
style="text-align: center; border: 1px solid #dddddd">
<thead>
<div>
<div class=" col-lg-4">
<input type="text" class="form-control pull-right" placeholder="Search" id="txtSearch" />
</div>
<button class="btn btn-primary" type="submit">
<span class="glyphicon glyphicon-search"></span>
<a href="searchedBbs.jsp"></a>
</button>
</div>
<tr>
<th style="background-color: #eeeeee; text-align: center;">번호</th>
<th style="background-color: #eeeeee; text-align: center;">제목</th>
<th style="background-color: #eeeeee; text-align: center;">작성자</th>
<th style="background-color: #eeeeee; text-align: center;">작성일</th>
</tr>
</thead>
<tbody>
<%
BbsDAO bbsDAO = new BbsDAO();
//System.out.println("here before getlist");
ArrayList<Bbs> list = bbsDAO.getSearchedList(pageNumber,searchWord);
//System.out.println("here after getlist" + list.get(0).getBbsDate().substring(0,11));
for(int i=0;i<list.size();i++){
%>
<tr>
<td><%=list.get(i).getBbsID()%></td>
<td><a href="view.jsp?bbsID=<%=list.get(i).getBbsID()%>"><%=list.get(i).getBbsTitle().replaceAll(" "," ").replaceAll("<","<").replaceAll("<",">").replaceAll("\n","<br>")%></a></td>
<td><%= list.get(i).getUserID()%></td>
<td><%= list.get(i).getBbsDate().substring(0, 11) + list.get(i).getBbsDate().substring(11,13) + "시" + list.get(i).getBbsDate().substring(14,16) + "분"%></td>
</tr>
<%
}
%>
</tbody>
</table>
<tr>
<td class = "pull-left">
<%
if(pageNumber != 1) {
session.setAttribute("searchWord",searchWord);
%> <a href="searchedBbs.jsp?pageNumber=<%=pageNumber-1%>"
class="btn btn-success btn-arrow-left">이전</a> <%
} if(bbsDAO.searchedNextPage(pageNumber,searchWord)) {
session.setAttribute("searchWord",searchWord);
%> <a href="searchedBbs.jsp?pageNumber=<%=pageNumber+1%>"
class="btn btn-success btn-arrow-right">다음</a> <%
}
%>
</td>
<td><a href="write.jsp" class="btn btn-primary pull-right">글쓰기</a>
</td>
</tr>
</div>
</div>
<script src="http://code.jquery.com/jquery-3.1.1.min.js"></script>
<script src="js/bootstrap.js"></script>
</body>
</html>
검색어를 처음에 post 방식으로 넘겨 getParameter함수를 이용해 가져오고
아래에도 getAttribute가 있는 이유는 나중에 설명하도록 한다.
String searchWord = null;
if(request.getParameter("searchWord")!=null){
searchWord = (String) request.getParameter("searchWord");
System.out.println("searchword from parameter is :" + searchWord);
}
if(session.getAttribute("searchWord")!=null){
searchWord = (String) session.getAttribute("searchWord");
System.out.println("searchword from session is :" + searchWord);
}
Print 함수는 중간중간 코딩하면서 변수가 잘 넘어오는지 확인하기 위함이다.
이제 검색어를 기반으로 데이터 리스트를 불러 올 함수를 만들어야한다.
우선 DAO와 연동시키는 부분에서 getList(pageNumber) 함수를 getSearchedList(pageNumber, searchWord)로 바꾸어준다.
파라미터 중 pageNumber는 페이지당 10개의 데이터를 불러오는데 사용할 것이고, searchWord는 검색어 문자열을 Query에 이용하기 위함이다.
<%
BbsDAO bbsDAO = new BbsDAO();
//System.out.println("here before getlist");
ArrayList<Bbs> list = bbsDAO.getSearchedList(pageNumber,searchWord);
//System.out.println("here after getlist" + list.get(0).getBbsDate().substring(0,11));
for(int i=0;i<list.size();i++){
%>
다음은 bbsDAO.java 파일에 검색기능을 가진 함수를 만들어 준다.
public ArrayList<Bbs> getSearchedList(int pageNumber, String searchWord){
int no2=0;
if(getNext()>pageNumber*10) {
no2 = pageNumber*10;
} else {
no2 = getNext();
}
int no1=(pageNumber -1)*10+1;
String SQL = "select * from (select row_number() over (order by bbsDate desc) NUM, A.* from bbs A where bbsavailable=1 and bbstitle like'%"
+ searchWord
+ "%' order by bbsDate desc) where NUM between "
+ no1
+ " and "
+ no2;
ArrayList<Bbs> list = new ArrayList<Bbs>();
try {
System.out.println("sql statement : "+SQL);
Statement stmt = conn.createStatement();
rs = stmt.executeQuery(SQL);
while(rs.next()) {
Bbs bbs = new Bbs();
bbs.setBbsID(rs.getInt(2));
bbs.setBbsTitle(rs.getString(3));
bbs.setUserID(rs.getString(4));
bbs.setBbsDate(rs.getString(5));
bbs.setBbsContent(rs.getString(6));
bbs.setBbsAvailable(rs.getInt(7));
list.add(bbs);
}
}catch(Exception e) {
System.out.println("Exception:search");
e.printStackTrace();
}
System.out.println(" resultset_return list:search");
return list;
}
다른 부분은 앞서 게시판을 만들 때 사용한 getList함수와 동일하고 다른 부분인 쿼리를 보면,
"select * from (select row_number() over (order by bbsDate desc) NUM, A.* from bbs A where bbsavailable=1 and bbstitle like'%"
+ searchWord
+ "%' order by bbsDate desc) where NUM between "
+ no1
+ " and "
+ no2;
터미널을 옆에 켜두고 원하는 쿼리를 완성시키는게 좋다.
예시로 asdf 더미 데이터를 넣어둔다.
터미널에 쿼리를 열심히 구글링하며 만들어 보고 날려본다.
select * from (select row_number() over (order by bbsDate desc) NUM, A.* from bbs A where bbsavailable=1 and bbstitle like'%asdf%' order by bbsDate desc) where NUM between 11 and 20;
다음과 같은 쿼리가 완성되었다. 다른 부분은 게시판 불러오는 쿼리와 동일하고 다른 부분을 살펴보자.
Where bbsAvailable=1 and bbstitle like ‘%asdf%’
bbsAvailable 변수를 이용해 글이 삭제되지 않은 글만 불러오고, 글 제목(bbsTitle) 중 asdf라는 문자열을 포함한 데이터를 가져온다.
데이터를 불러올 시 getNext() 함수도 bbsID를 기준으로 불러오다보니 32개의 데이터 중 4개를 지웠을 시 bbsID는 32를 가리키고 있기 때문에 4페이지까지 넘어가는 걸 확인했다.
Row_number() 를 이용해 num을 부여하고 해당하는 데이터의 개수만 새로 불러오도록 getNext() 쿼리를 수정했다.
public int getNext() {
String SQL = "select NUM from (select row_number() over (order by bbsDate desc) NUM, A.* from bbs A where bbsavailable=1 order by NUM desc)";
try {
//PreparedStatement pstmt = conn.prepareStatement(SQL);
//rs = pstmt.executeQuery();
Statement stmt = conn.createStatement();
rs = stmt.executeQuery(SQL);
if(rs.next()) {
return rs.getInt(1)+1;
}
return 1;
} catch (Exception e) {
e.printStackTrace();
}
return -1;
}
마지막으로 다음 이전 페이지 넘기기 버튼 부분을 수정한다.
<%
if(pageNumber != 1) {
session.setAttribute("searchWord",searchWord);
%> <a href="searchedBbs.jsp?pageNumber=<%=pageNumber-1%>"
class="btn btn-success btn-arrow-left">이전</a> <%
} if(bbsDAO.searchedNextPage(pageNumber,searchWord)) {
session.setAttribute("searchWord",searchWord);
%> <a href="searchedBbs.jsp?pageNumber=<%=pageNumber+1%>"
class="btn btn-success btn-arrow-right">다음</a> <%
}%>
각 페이지가 넘어갈 시에 searchWord를 session에 넣어줌으로써 페이지간 변수를 주고 받을 수 있도록 한다.
if(session.getAttribute("searchWord")!=null){
searchWord = (String) session.getAttribute("searchWord");
System.out.println("searchword from session is :" + searchWord);
}
그래서 위에 getAttribute를 추가로 작성했다.
검색된 새로운 데이터를 기반으로 다음 버튼을 생성해야 하기에 searchedNextPage 함수를 새로 만들어준다.
public boolean searchedNextPage(int pageNumber,String searchWord) {
try {
if(getSearchedNext(searchWord)>(pageNumber)*10) {
return true;
} else {
return false;
}
}catch(Exception e) {
e.printStackTrace();
}
return false;
}
여기서 getNext 함수는 검색된 데이터를 이용하는 함수가 아니라 전체 데이터를 대상으로 하는 함수이므로 getSearchedNext 함수를 새로 만들어준다.
public int getSearchedNext(String searchWord) {
String SQL = "select NUM from (select row_number() over (order by bbsDate desc) NUM, A.* from bbs A where bbsavailable=1 and bbsTitle like '%"+searchWord+"%' order by NUM desc)";
try {
//PreparedStatement pstmt = conn.prepareStatement(SQL);
//rs = pstmt.executeQuery();
System.out.println("query for searched NEXT : "+SQL);
Statement stmt = conn.createStatement();
rs = stmt.executeQuery(SQL);
if(rs.next()) {
return rs.getInt(1)+1;
}
return 1;
} catch (Exception e) {
e.printStackTrace();
}
return -1;
}
다른 부분은 getNext와 동일하고 변경된 쿼리를 한번 보자
우리가 원하는 쿼리는 먼저 검색어를 포함하고있는 데이터를 불러오는 것이다.
Select * from bbs where bbsavailable=1 and bbstitle like ‘%검색어%’;
여기에 row_number()를 이용해 숫자를 매겨 불러온 데이터의 개수를 리턴하는데 도움을 주도록 한다.
select count(*) from bbs where bbsavailable=1;
이 쿼리를 이용해도 된다는 사실을 뒤늦게 알아버렸다. 효율성을 위해선 위 쿼리를 이용하는게 좋아보인다. 차후에 시간이 나면 수정해보도록 하겠다.
무튼 그래서 row_number()를 이용해 데이터에 숫자를 매겨 리턴시켜 보았다.
select NUM from (select row_number() over (order by bbsDate desc) NUM, A.* from bbs A where bbsavailable=1 and bbsTitle like '%"+searchWord+"%' order by NUM desc)
잘 넘어온다.
성공!