검색기능
게시판의 검색기능-폼으로 사용한다.
동적쿼리
-하나의 sql문이 검색키워드에 따라 바꿔서 실행됨.
동적쿼리란?
마이바티스의 태그로써 조건문을 써서 쿼리의 실행을 제어하는 방법.
jstl구문과 사용방법이 유사.
마이바티스의 test=""구문 안에 작성되는 값은 VO의 getter나, map의 key값이 쓰인다. #{}나 ${}를 사용안하고 바로 사용할 수 있다.
대표적 태그의 종류
- if
- choose(when, otherwise)
- foreach
- include
등등
ex)foreach로 값이 여러개 들어오면 반복해서 넣는다. 구글링으로 사용방법 찾기
ex)if문에서 ""안에 문자열을 사용할 땐 ''로.
title like concat('%',#{searchName},'%')
=>'%'문자열 합치기 #{ } 합치기 '%'.
%%안에 바로 #{}를 사용할 수 없다.
동적쿼리문을 만들 때
오류가 날 경우를 모두 고려해줘야 한다.
정말 방법이 없으면, 조건에 1=1처럼 true조건을 넣어서 오류를 피한다.
ex)1=1처럼.
즉 sql문이 여러 if 중에서
select * from trip where 1=1 order by tno desc limit 0,10;처럼 처리되어서 오류가 발생하지 않게 하는 것
검색버튼을 눌렀을 때, 페이지네이션 번호를 눌렀을 때
검색해서 검색된 결과가 페이지네이션을 눌렀을 때도 유지되어야 한다.
똑같은 매개값을 컨트롤러에 넘긴다.
- 검색키워드(제목 or 내용 등등)
- 검색값
- 페이지번호
- amount값
이 4개는 반드시 줘야 한다.
페이지네이션 번호로 이동할 때도, 똑같이 4개를 줘야 한다!
검색버튼은 form형식으로, a링크 get방식으로.
이 4개를 가지고, 동적쿼리 sql문 사용.
전체게시글 수도 동적쿼리로 변경.
넘어오는 값은 criteria에 넣기. 새로 vo를 생성해도 된다.
Criteria.java
package com.cordhistroy.myweb.util;
import lombok.Data;
//sql문에 페이지번호, 데이터개수 전달해줄 클래스
@Data
public class Criteria {
private int page; //페이지번호
private int amount; //데이터개수
private String searchType; //검색타입
private String searchName; //검색값
public Criteria() {
this.page=1;
this.amount=10;
}
public Criteria (int page, int amount) {
this.page=page;
this.amount=amount;
}
//limit함수의 페이지시작 부분에 들어갈 getter
public int getPageStart() {
return (page-1)*amount;
}
}
검색할 때, amount를 넘겨야 유지된다. 100개의 amount를 보다가 검색을 통해 이동하면 amount가 초기화되어버린다.
->hidden태그로 넘김
Controller
//목록
@RequestMapping("/notice_list")
public String notice_list(Criteria cri, Model model) {
//데이터
//ArrayList<TripVO> list = tripService.getList(cri);
//페이지네이션
//int total=tripService.getTotal();
//PageVO pageVO=new PageVO(cri, total);
//System.out.println(pageVO.toString());
//페이지 검색처리
/*
* 1. 화면에서는 page, amount, searchType, searchName을 넘긴다.
* 2. criteria에서 검색값을 받는다.
* 3. sql문을 바꾼다. (동적쿼리)
* 4. total sql문도 바꾼다.
* 5. 페이지 a태그 클릭시 searchType과 searchName을 쿼리스트링으로 넘긴다.
* 6. 검색키워드의 유지
*/
//System.out.println(cri.toString());
ArrayList<TripVO> list = tripService.getList(cri);
int total=tripService.getTotal(cri);
PageVO pageVO=new PageVO(cri, total);
//값 넘기기
model.addAttribute("list",list);
model.addAttribute(pageVO);
return "trip/notice_list";
}
인터페이스와 TripServiceImpl.java
인터페이스(TripService.java, TripMapper.java)
//public ArrayList<TripVO> getList();//조회
public ArrayList<TripVO> getList(Criteria cri);//페이지
//public int getTotal();//전체게시글수 조회
public int getTotal(Criteria cri);//검색한 게시글수 조회
TripServiceImpl.java
@Override
public ArrayList<TripVO> getList(Criteria cri) {
return tripMapper.getList(cri);
}
@Override
public int getTotal(Criteria cri) {
return tripMapper.getTotal(cri);
}
mapper.xml
<!-- 동적쿼리구문의 test에는 vo의 getter, map의 키값이 들어갑니다. -->
<select id="getList" resultType="TripVO" >
select * from trip
<if test="searchType == 'title' ">where title like concat('%',#{searchName},'%')</if>
<if test="searchType == 'content' ">where content like concat('%',#{searchName},'%')</if>
<if test="searchType == 'writer' ">where writer like concat('%',#{searchName},'%')</if>
<if test="searchType == 'titcont' ">where title or content like concat('%',#{searchName},'%')</if>
<if test="searchType == null or searchType == '' ">where 1=1 </if>
<!--<choose>
<when test="searchType == 'title'">where title like concat('%',#{searchName},'%')</when>
<when test="searchType == 'content'">where content like concat('%',#{searchName},'%')</when>
<when test="searchType == 'writer'">where writer like concat('%',#{searchName},'%')</when>
<when test="searchType == null or searchType == ''">where title like concat('%',#{searchName},'%')
or content like concat('%',#{searchName}, '%')</when>
<otherwise>where 1=1</otherwise>
</choose>-->
order by tno desc limit #{pageStart}, #{amount}
</select>
<select id="getTotal" resultType="int">
select count(*) as total from trip
<if test="searchType == 'title' ">where title like concat('%',#{searchName},'%')</if>
<if test="searchType == 'content' ">where content like concat('%',#{searchName},'%')</if>
<if test="searchType == 'writer' ">where writer like concat('%',#{searchName},'%')</if>
<if test="searchType == 'titcont' ">where title or content like concat('%',#{searchName},'%')</if>
<if test="searchType == null or searchType == '' ">where 1=1 </if>
</select>
마이바티스의 test=""구문 안에 작성되는 값은 VO의 getter나 map의 key값이 사용됨. #{}나 ${}를 사용하지 않음
->만약 매개변수가 2개면 @Param에 사용한 이름.getter명 or 이름.key값
동적쿼리(마이바티스 태그)안에서 문자열을 쓰려면 ''로 사용
문자열합치기를 하기 위해 concat 사용.
오류가 날 경우를 막기 위해 <if test="searchType == null or searchType == '' ">where 1=1 </if> 사용.
->null이거나 공백일 경우를 고려.
->where true면 기능없이 정상동작한다.
notice_list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<div id="container">
<!-- location_area -->
<div class="location_area customer">
<div class="box_inner">
<h2 class="tit_page">
TOURIST <span class="in">in</span> TOUR
</h2>
<p class="location">
고객센터 <span class="path">/</span> 공지사항
</p>
<ul class="page_menu clear">
<li><a href="#" class="on">공지사항</a></li>
<li><a href="#">문의하기</a></li>
</ul>
</div>
</div>
<!-- //location_area -->
<!-- bodytext_area -->
<div class="bodytext_area box_inner">
<h3>게시글 수 : ${pageVO.total}</h3>
<form action="notice_list" class="minisrch_form" name="actionForm">
<fieldset>
<select id="handleAmount" style="height: 35px;">
<option value="10" ${pageVO.amount==10?'selected':'' }>10개씩 보기</option>
<option value="20" ${pageVO.amount==20?'selected':'' }>20개씩 보기</option>
<option value="50" ${pageVO.amount==50?'selected':'' }>50개씩 보기</option>
<option value="100" ${pageVO.amount==100?'selected':'' }>100개씩 보기</option>
</select>
<select name="searchType" style="height: 35px;">
<option value="title" ${pageVO.cri.searchType == 'title'?'selected':'' }>제목</option>
<option value="content" ${pageVO.cri.searchType == 'content'?'selected':'' }>내용</option>
<option value="writer" ${pageVO.cri.searchType == 'writer'?'selected':'' }>작성자</option>
<option value="titcont" ${pageVO.cri.searchType == 'titcont'?'selected':'' }>제목+내용</option>
</select>
<legend>검색</legend>
<input type="hidden" name="page" value="1"/>
<input type="hidden" name="amount" value="${pageVO.amount }"/>
<input type="text" name="searchName" class="tbox" title="검색어를 입력해주세요" placeholder="검색어를 입력해주세요" value="${pageVO.cri.searchName}">
<input type="submit" class="btn_srch"value="검색" style="line-height:30px;">
<!-- <a href="javascript:;" class="btn_srch">검색</a> -->
</fieldset>
</form>
<table class="bbsListTbl" summary="번호,제목,조회수,작성일 등을 제공하는 표">
<caption class="hdd">공지사항 목록</caption>
<thead>
<tr>
<th scope="col">번호</th>
<th scope="col">제목</th>
<th scope="col">조회수</th>
<th scope="col">작성일</th>
</tr>
</thead>
<tbody>
<c:forEach var="colList" items="${list}" varStatus="num">
<tr>
<td>${pageVO.total-((pageVO.page-1)*pageVO.amount)-num.count+1}</td>
<td class="tit_notice"><a
href="notice_view?tno=${colList.tno}">${colList.title}</a></td>
<td>${colList.hit}</td>
<td><fmt:formatDate value="${colList.regdate}"
pattern="yyyy-MM-dd" /></td>
</tr>
</c:forEach>
</tbody>
</table>
<%--
<!-- pagination -->
<div class="pagination">
<!-- 5.맨처음으로 -->
<a href="notice_list?page=1&amount=${pageVO.amount}" class="firstpage pbtn"><img src="${pageContext.request.contextPath}/resources/img/btn_firstpage.png" alt="첫 페이지로 이동"></a>
<!-- 3.이전페이지네이션 -->
<c:if test="${pageVO.prev }">
<a href="notice_list?page=${pageVO.start-1}&amount=${pageVO.amount}" class="prevpage pbtn"><img src="${pageContext.request.contextPath}/resources/img/btn_prevpage.png" alt="이전 페이지로 이동"></a>
</c:if>
<!-- 1.페이지네이션 -->
<c:forEach var="num" begin="${pageVO.start}" end="${pageVO.end}">
<a href="notice_list?page=${num}&amount=${pageVO.amount}"><span class="pagenum ${pageVO.page==num?'currentpage':''}">${num}</span></a>
</c:forEach>
<!-- 2.다음페이지네이션 -->
<c:if test="${pageVO.next }">
<a href="notice_list?page=${pageVO.end+1}&amount=${pageVO.amount}" class="nextpage pbtn"><img src="${pageContext.request.contextPath}/resources/img/btn_nextpage.png" alt="다음 페이지로 이동"></a>
</c:if>
<!-- 4.맨마지막으로 -->
<a href="notice_list?page=${pageVO.realEnd}&amount=${pageVO.amount}" class="lastpage pbtn"><img src="${pageContext.request.contextPath}/resources/img/btn_lastpage.png" alt="마지막 페이지로 이동"></a>
</div>
--%>
<%--
컨트롤러에서 사용자 클래스를 매개변수로 지정을 하면 이름이
클래스명소문자로 지정되서 자동으로 다음화면으로 전달됩니다.
${criteria }
--%>
<div class="pagination">
<!-- 5.맨처음으로 -->
<a href="notice_list?page=1&amount=${pageVO.amount}&searchType=${pageVO.cri.searchType}&searchName=${pageVO.cri.searchName}" class="firstpage pbtn"><img src="${pageContext.request.contextPath}/resources/img/btn_firstpage.png" alt="첫 페이지로 이동"></a>
<!-- 3.이전페이지네이션 -->
<c:if test="${pageVO.prev }">
<a href="notice_list?page=${pageVO.start-1}&amount=${pageVO.amount}&searchType=${pageVO.cri.searchType}&searchName=${pageVO.cri.searchName}" class="prevpage pbtn"><img src="${pageContext.request.contextPath}/resources/img/btn_prevpage.png" alt="이전 페이지로 이동"></a>
</c:if>
<!-- 1.페이지네이션 -->
<c:forEach var="num" begin="${pageVO.start}" end="${pageVO.end}">
<a href="notice_list?page=${num}&amount=${pageVO.amount}&searchType=${pageVO.cri.searchType}&searchName=${pageVO.cri.searchName}"><span class="pagenum ${pageVO.page==num?'currentpage':''}">${num}</span></a>
</c:forEach>
<!-- 2.다음페이지네이션 -->
<c:if test="${pageVO.next }">
<a href="notice_list?page=${pageVO.end+1}&amount=${pageVO.amount}&searchType=${pageVO.cri.searchType}&searchName=${pageVO.cri.searchName}" class="nextpage pbtn"><img src="${pageContext.request.contextPath}/resources/img/btn_nextpage.png" alt="다음 페이지로 이동"></a>
</c:if>
<!-- 4.맨마지막으로 -->
<a href="notice_list?page=${pageVO.realEnd}&amount=${pageVO.amount}&searchType=${pageVO.cri.searchType}&searchName=${pageVO.cri.searchName}" class="lastpage pbtn"><img src="${pageContext.request.contextPath}/resources/img/btn_lastpage.png" alt="마지막 페이지로 이동"></a>
</div>
<!-- //pagination -->
</div>
<!-- //bodytext_area -->
</div>
<!-- //container -->
<script>
var msg = '${msg}';
if (msg !== '') {
alert(msg);
}
</script>
<script>
var handleAmount=document.getElementById("handleAmount")
handleAmount.onchange=function(){
document.actionForm.amount.value=event.target.value;
document.actionForm.submit();
}
</script>
에서,
<select id="handleAmount" style="height: 35px;">
<option value="10" ${pageVO.amount==10?'selected':'' }>10개씩 보기</option>
<option value="20" ${pageVO.amount==20?'selected':'' }>20개씩 보기</option>
<option value="50" ${pageVO.amount==50?'selected':'' }>50개씩 보기</option>
<option value="100" ${pageVO.amount==100?'selected':'' }>100개씩 보기</option>
</select>
는 스크립트의
<script>
var handleAmount=document.getElementById("handleAmount")
handleAmount.onchange=function(){
document.actionForm.amount.value=event.target.value;
document.actionForm.submit();
}
</script>
를 통해 이벤트를 주고, submit으로 amount값을 넘긴다.
<form action="notice_list" class="minisrch_form" name="actionForm">
<fieldset>
<select id="handleAmount" style="height: 35px;">
<option value="10" ${pageVO.amount==10?'selected':'' }>10개씩 보기</option>
<option value="20" ${pageVO.amount==20?'selected':'' }>20개씩 보기</option>
<option value="50" ${pageVO.amount==50?'selected':'' }>50개씩 보기</option>
<option value="100" ${pageVO.amount==100?'selected':'' }>100개씩 보기</option>
</select>
<select name="searchType" style="height: 35px;">
<option value="title" ${pageVO.cri.searchType == 'title'?'selected':'' }>제목</option>
<option value="content" ${pageVO.cri.searchType == 'content'?'selected':'' }>내용</option>
<option value="writer" ${pageVO.cri.searchType == 'writer'?'selected':'' }>작성자</option>
<option value="titcont" ${pageVO.cri.searchType == 'titcont'?'selected':'' }>제목+내용</option>
</select>
<legend>검색</legend>
<input type="hidden" name="page" value="1"/>
<input type="hidden" name="amount" value="${pageVO.amount }"/>
<input type="text" name="searchName" class="tbox" title="검색어를 입력해주세요" placeholder="검색어를 입력해주세요" value="${pageVO.cri.searchName}">
<input type="submit" class="btn_srch"value="검색" style="line-height:30px;">
<!-- <a href="javascript:;" class="btn_srch">검색</a> -->
</fieldset>
</form>
에서,
hidden으로 page와 amount를,
검색타입은 select태그에 searchType을 name으로,
겁색값은 input태그에 searchName을 name으로 줘서
form-action과 submit으로 값을 넘긴다.
select태그는 삼항연산자와 selected속성을 이용해서 페이지를 이동해도 값이 남아있도록 한다.
검색내용을 적는 input에서는 value로 넘어온 searchName을 줘서 페이지를 이동해도 검색값이 남아있게 한다.
<div class="pagination">
<!-- 5.맨처음으로 -->
<a href="notice_list?page=1&amount=${pageVO.amount}&searchType=${pageVO.cri.searchType}&searchName=${pageVO.cri.searchName}" class="firstpage pbtn"><img src="${pageContext.request.contextPath}/resources/img/btn_firstpage.png" alt="첫 페이지로 이동"></a>
<!-- 3.이전페이지네이션 -->
<c:if test="${pageVO.prev }">
<a href="notice_list?page=${pageVO.start-1}&amount=${pageVO.amount}&searchType=${pageVO.cri.searchType}&searchName=${pageVO.cri.searchName}" class="prevpage pbtn"><img src="${pageContext.request.contextPath}/resources/img/btn_prevpage.png" alt="이전 페이지로 이동"></a>
</c:if>
<!-- 1.페이지네이션 -->
<c:forEach var="num" begin="${pageVO.start}" end="${pageVO.end}">
<a href="notice_list?page=${num}&amount=${pageVO.amount}&searchType=${pageVO.cri.searchType}&searchName=${pageVO.cri.searchName}"><span class="pagenum ${pageVO.page==num?'currentpage':''}">${num}</span></a>
</c:forEach>
<!-- 2.다음페이지네이션 -->
<c:if test="${pageVO.next }">
<a href="notice_list?page=${pageVO.end+1}&amount=${pageVO.amount}&searchType=${pageVO.cri.searchType}&searchName=${pageVO.cri.searchName}" class="nextpage pbtn"><img src="${pageContext.request.contextPath}/resources/img/btn_nextpage.png" alt="다음 페이지로 이동"></a>
</c:if>
<!-- 4.맨마지막으로 -->
<a href="notice_list?page=${pageVO.realEnd}&amount=${pageVO.amount}&searchType=${pageVO.cri.searchType}&searchName=${pageVO.cri.searchName}" class="lastpage pbtn"><img src="${pageContext.request.contextPath}/resources/img/btn_lastpage.png" alt="마지막 페이지로 이동"></a>
</div>
에서,
a태그에 쿼리스트링으로 값을 넘긴다.
+a
Spring 특징
${pageVO.cri}로 사용해야 하는데,
컨트롤러에서 사용자 클래스와 매개변수
매개변수에서 @ModelAttribute("cri") Criteria cri로 한다는 건 cri란 이름으로 화면에서 사용하겠다는 뜻.
그런데, 매개변수에 Criteria cri만 줘도 화면에서
${criteria}로 사용할 수 있다! forward방식이기 때문에 가능
'Spring' 카테고리의 다른 글
230209 Spring 검색과 페이징 +a (0) | 2023.02.09 |
---|---|
230208 Spring 페이징, MySQL limit함수 (1) | 2023.02.08 |
230208 Spring myweb 기능구현 다음글-이전글 (0) | 2023.02.08 |
230208 Spring myweb 기능구현-등록-목록-상세, 수정, 삭제 (0) | 2023.02.08 |
230207 Spring 타일즈 뷰 템플릿 (0) | 2023.02.07 |