Searching
게시판에서 검색하는데
기준을 가지고 있어야 한다. 제목, 내용, 글쓴이 ...등등
원래는 검색은 따로 솔루션업체들이 따로 개발하게 되지만
1. bootstrap에서 사용할 form가져오기
게시판 리스트 화면에 검색 기능을 만들어 줄것이기 때문에 list.jsp에서 검색을 구현하는 UI를 Bootstrap을 통해 만들어준다.
<h1>상품 목록</h1>
<div class='float-right form-group'>
<form action="/product/list" class="form-inline">
<input type="hidden" name="pageNum" value="1">
<input type="hidden" name="amount" value="${pgvo.cri.amount }">
<div class="input-group">
<div class="input-group-prepend">
<select class="form-control" id="stype" name="type">
<option value="twc">선택</option>
<option value="t">상품명</option>
<option value="w">작성자</option>
<option value="c">상세내용</option>
<option value="tw">상품명+상세내용</option>
<option value="tc">상품명+상세내용</option>
<option value="wc">작성자+상세내용</option>
</select>
</div>
<input type="text" name="keyword" class="form-control" placeholder="키워드를 입력하세요">
<div class="input-group-append">
<button class="btn btn-success" type="submit">검색</button>
</div>
</div>
</form>
</div>
2.
Criterion.java 클래스에 가서 기존에 있던 내용 외에 type과 keyword를 cri로 받을 수 있게
변수로 선언하고 getter setter를 만들어준다.
public class Criterion {
private String keyword;
private String type;
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
3.
productCtrl에서 list부분의 cri가 db까지 가고 mapper가서 sql문을 수정한다.
내가 검색한 내용을 기반으로 paging이 되어야한다.
즉 이제는 Search + Paging이 시작되는 것이다.
따라서 Search시스템이 먼저 돌아간 후에 Paging시스템이 돌아가도록 해야하는 것!!!
예를 들어 이렇게 sql문을 작성하면
SELECT pno, title
FROM (SELECT /*+INDEX_DESC(tbl_product pk_product)*/
rownum AS rn, pno, title
FROM TBL_PRODUCT
WHERE pno > 0
AND (title LIKE '%4번%' OR writer LIKE '%4번%')
AND rownum <= 2*10)
WHERE rn > (2-1)*10;
이런결과값이 나온다.
이 방법을 이용할 것이다.

<sql>이 안에서는 $ # % 이런걸 쓸 수 없기 때문에 칸켓 연산자 '||' 를 쓴다</sql>
<sql id="search">
<if test="type != null">
<trim prefix=" and (" suffix=") ">
<choose>
<when test="type =='twc'.toString()">
title like '%'||#{keyword}||'%'or
writer like '%'||#{keyword}||'%'or
content like '%'||#{keyword}||'%'
</when>
<when test="type=='tw'.toString()">
title like '%'||#{keyword}||'%'or
writer like '%'||#{keyword}||'%'
</when>
<when test="type=='tc'.toString()">
title like '%'||#{keyword}||'%'or
content like '%'||#{keyword}||'%'
</when>
<when test="type=='wc'.toString()">
writer like '%'||#{keyword}||'%'or
content like '%'||#{keyword}||'%'
</when>
<when test="type=='t'.toString()">
title like '%'||#{keyword}||'%'
</when>
<when test="type=='w'.toString()">
writer like '%'||#{keyword}||'%'
</when>
<when test="type=='c'.toString()">
content like '%'||#{keyword}||'%'
</when>
</choose>
</trim>
</if>
</sql>
<select id="list" parameterType="Criterion" resultType="ProductVO">
<![CDATA[
select pno,title,writer,readcount,modd8,imgfile
from(select /*+INDEX_DESC(tbl_product pk_product)*/
rownum as rn,pno,title,writer,readcount,modd8,imgfile
from tbl_product
where pno > 0
]]>
<include refid="search"/>
<![CDATA[
and rownum <= #{pageNum}*#{amount})
where rn > (#{pageNum}-1) * #{amount}
]]>
<select id="totalCount" parameterType="Criterion" resultType="java.lang.Integer">
<![CDATA[
select count(pno) from tbl_product where pno > 0
]]>
<include refid="search"/>
</select>
5.
검색했을 때 searching의 endPagingNum과 Paging의 endPagingNum이 달라서 일어나는
다음과 같은 현상(검색하여 나온 내용은 한개이나 밑에 페이징은 전체 게시판글게수를 따라 생기는)

이런 일을 해결하기 위해 아래와 같이 빌드한다.
- Mapper의 totalCount에 받을 cri parameter로 생성.
그럼 cri객체에 추가한 keyword와 type을 받아 올 수 있게되므로
검색사항을 고려하여 Paging되게 할 수 있다???
<select id="totalCount" parameterType="Criterion" resultType="java.lang.Integer">
<![CDATA[
select count(pno) from tbl_product where pno > 0
]]>
<include refid="search"/>
</select>
Mapper에서 받는것 역순으로 cri쭉쭉 던저주기
ProductCtrl --> ProductService/ ProductServieImpl --> ProductDAO/ProductDAOImpl
- ProductCtrl
@GetMapping("/list")
public void list(Model model, Criterion cri) {
model.addAttribute("pList", psv.getList(cri));
}
- ProductService/ ProductServieImpl
//ProductService
public int getTotalCount(Criterion cri);
//ProductServiceImpl
@Override
public int getTotalCount(Criterion cri) {
return pdao.selectTotalCount(cri);
}
- ProductDAO/ProductDAOImpl
//ProductDAO
public int selectTotalCount(Criterion cri);
//ProductDAOImlp
@Override
public int selectTotalCount(Criterion cri) {
return sql.selectOne(ns+"totalCount", cri);
}
6.
또 다른 문제!!
이제 제대로 서칭에 따른 페이징이 된다. 한개든 두개든.
근데 문제는 이렇게 페이징 된것을 누르고 들어갔을때는 서치한 것에 대한 리스트가 아니라
전체 게시판을 조회한 리스트가 뜨게 된다.
해결해보쟈!
포인트는 내가 cri로 움직이는 곳곳마다 type과 keyword를 같이 뿌려주는것!!
목록에 관한 것.
-먼저 리스트 list.jsp에서 목록,Prev,Next를 눌렀을때 검색에 해당하는 리스트가 보여지도록 하기 위해서
cri에서 변수로 만든 type과 keyword를 모두 뿌려주면
클릭하면서 이동시에 cri에 있는 모든 변수(pageNum, amount, type, keyword)를 데리고 이동한게 된다.
//list.jsp
<ul class="pagination">
<c:if test="${pgvo.prev }">
<li class="page-item"><a class="page-link"
href="/product/list?pageNum=${pgvo.beginPagingNum - 1 }&amount=${pgvo.cri.amount }
&type=${pgvo.cri.type}&keyword=${pgvo.cri.keyword}">Prev</a></li>
</c:if>
<c:forEach begin="${pgvo.beginPagingNum }" end="${pgvo.endPagingNum }" var="i">
<li class="page-item ${pgvo.cri.pageNum ==i? 'active':'' }">
<a class="page-link"
href="/product/list?pageNum=${i }&amount=${pgvo.cri.amount}
&type=${pgvo.cri.type}&keyword=${pgvo.cri.keyword}">${i }</a></li>
</c:forEach>
<c:if test="${pgvo.next }">
<li class="page-item"><a class="page-link"
href="/product/list?pageNum=${pgvo.endPagingNum + 1 }&amount=${pgvo.cri.amount }
&type=${pgvo.cri.type}&keyword=${pgvo.cri.keyword}">Next</a></li>
</c:if>
</ul>
그리고 list.jsp에서 title을 클릭하여 detail.jsp로 넘어갈때도 함께 실어보낸다.
그래야 detail.jsp에서 나올때에도 데리고 나올 수 있다.
//list.jsp
<td>
<a href="/product/detail?
pno=${pvo.pno }&pSign=0&pageNum=${pgvo.cri.pageNum}&amount=${pgvo.cri.amount}
&type=${pgvo.cri.type}&keyword={pgvo.cri.keyword}">${pvo.title }</a>
</td>
-detail.jsp로 이동했다고 보면
여기서 수정, 삭제, 목록 부분에서도 같은 부분이 적용되어야 하므로 cri의 type과 keyword를 또 던져준다.
<tr>
<th colspan="2">
<a href="/product/list?pageNum=${cri.pageNum }&amount=${cri.amount}
&type=${pgvo.cri.type}&keyword={pgvo.cri.keyword}" class="btn btn-success">목록</a>
<c:if test="${sesInfo.email eq pvo.writer || sesInfo.email eq 'admin@admin.com'}">
<a href="/product/modify?pno=${pvo.pno }&pSign=0&pageNum=${cri.pageNum }&amount=${cri.amount}
&type=${cri.type}&keyword=${cri.keyword}" class="btn btn-warning">수정</a>
<a href="#" class="btn btn-outline-danger" id="delBtn">삭제</a>
</c:if>
</th>
</tr>
delForm에 아래 내용 추가한다.
<form action="/product/remove" id="delForm" method="post">
<input type="hidden" name="type" value="${cri.type}">
<input type="hidden" name="type" value="${cri.keyword}">
</form>
그다음 수정에 관한 부분을 modify.jsp에서 받을 수 있게 빌드한다.
-modify.jsp
<input type="hidden" name="type" value="${cri.type}">
<input type="hidden" name="type" value="${cri.keyword}">
jsp파일에서 빌드한 모든 부분들은 이제 설정한페이지이름.jsp를 찾아 ProductCtrl로 이동할 것이다.
-ProductCtrl
각자의 요청한 페이지의 이름대로
cri의 type과 keyword가 없는 부분을 추가적으로 받아준다.
("/list")와({"/delete","/modify"})에서는 cri 객체 자체로 받기때문에 따로 추가해 줄 필요가 없다.
@PostMapping("/modify")
public String modify(MultipartHttpServletRequest multiReq, Criterion cri) {
int isUp = psv.modify(fp.fileModify(multiReq));
reAttr.addAttribute("keyword", cri.getKeyword());
return "redirect:/product/detail?pSign=" + isUp
+ "&pno=" + multiReq.getParameter("pno")
+ "&pageNum="+cri.getPageNum()
+ "&amount="+cri.getAmount()
+ "&type="+cri.getType()
}
@PostMapping("/remove")
public String remove(@RequestParam("pno") int pno, @RequestParam("imgfile")String imgfile ,
RedirectAttributes reAttr, Criterion cri){
int isRm = fp.removeFile(imgfile);
isRm = psv.remove(pno);
if (isRm > 0) {
reAttr.addFlashAttribute("pSign", "삭제가 완료되었습니다");
}
reAttr.addFlashAttribute("keyword", cri.getKeyword());
return "redirect:/product/list?pageNum="+cri.getPageNum()
+ "&amount="+cri.getAmount()
+ "&type="+cri.getType()
}
------------------------------------------------------------------------------------------------------------------
이로써 검색기능도 구현해봤다
하면서 든 생각은 머리속에 Spring에 대한 작동순서만 가지고 있다면 어렵지 않게 구현해 낼 수 있겠다는 것이다.
그러므로 기본적인 그림을 머릿속에 그리고 빌드를 해야한다.
'_Programming > Spring' 카테고리의 다른 글
Spring.AOP(Aspect-Oriented Programming) (0) | 2020.07.06 |
---|---|
Spring.Comment (0) | 2020.07.02 |
Spring.페이징(Paging) (0) | 2020.07.01 |
Spring.파일첨부(file) (0) | 2020.06.30 |
Spring.classpath (0) | 2020.06.29 |