Spring Legacy · STS · OracleDB · SQLDeveloper
페이징 처리와 검색 기능 구현 화면
1. 게시글 데이터 늘리기
페이징을 만드려면,일단 테이블 안에 데이터 양을 늘려야 한다.
SQL로 기존의 내용을 복붙해 내용을 늘려보자.
insert into tbl_board
select seq_board.nextval,title,content,writer,regdate,viewcnt
from tbl_board;
--seq_board.nextval은 새롭게 넣음
commit;
INSERT INTO SELECT 구문
INSERT INTO 구문은 원본과 대상테이블이 모두 있을 경우 사용합니다.
TABLE A에서 모든 데이터를 가져와 B라는 테이블에 INSERT 합니다
한 테이블의 모든 열을 다른 테이블로 복사
INSERT INTO B SELECT * FROM A
위에서 TABLE A와 TABLE B는 스키마가 동일해야 합니다.
만일 A보다 컬럼수가 적을 경우에는 아래와 같이 사용합니다
한 테이블의 일부 열만 다른 테이블로 복사
INSERT INTO B SELECT COL1,COL2,COL3 FROM A
정리출처 : https://aspdotnet.tistory.com/172
테이블의 내용이 늘어나는 것을 확인할 수 있습니다.
2. 페이징 만드는 쿼리 생성하기
쿼리를 이용해서 어떻게 뽑아내야 하는가?
- 마지막페이지 → 전체데이터개수를 알아야한다
- 특정페이지 → 전체데이터개수와 한페이지에 몇개씩데이터를 보여줘야하는지 알아야한다.
① 우선 늘려놓은 테이블을 순서대로 정렬해서 확인해보자.
--01 내용 전체 내림차순으로 출력
select tbl_board.*
from tbl_board
where 1=1
order by bno desc;
--where 1=1 : 참을 의미
--oder by 기준으로 정렬 / desc 내림차순 / asc 오름차순
WHERE 1=1
where은 조회하는데이터들의 조건을 거는 문법
1=1 은 참이므로, 말그대로 참을 의미한다.
이것을 사용하는 이유 :
검색할 것을 제한을 둘 때
WHER 1=1 and X and X...이런식으로 추가해서 사용할수있다.
where 1=1 설명 링크: https://hyjykelly.tistory.com/5
② 번호를 매겨주어 실제데이터로 뽑아내려면 rownum을 사용해야함
--02 번호를 매겨주어 실제데이터로 뽑아내야한다 = rownum 사용
select rownum, tbl_board.*
from tbl_board;
--순서대로 나온다.
ROWNUM
시스템에 내장된 컬럼으로 ROWNUM은 SELECT 해온 데이터에 일련번호를 붙이는 것이다.
테이블이나 특정 집합에서 원하는 만큼의 행만 가져오고싶을대 , 행의 개수를 제한하는 용도로 사용한다.
자세한 예 ↓
- 고객들의 정보가 담겨있는 CUSTOMER 테이블이 있을때 여기서 20살 이상인 사람만 뽑고싶을때
굳이 모든 데이터를 검색하지 않고, 특정개수만큼 원하는 데이터를 추출할때 사용,
- 1,2,3,4,5,6... 식으로 순번을 매기고 싶을때도 사용
③ rownum의 문제에 대해서 알아보자
--03 rownum의 문제
select rownum, tbl_board.*
from tbl_board
where rownum <10;
--rownum<10은 정상동작
select rownum, tbl_board.*
from tbl_board
where rownum >10;
--rownum>10은 나오지않는다
rownum>10이 결과가 나오지않는이유
첫번째 데이터를 가져온다. 1번데이터는 1은 10보다 크지않다
다음데이터가들어온다 rownum은 여전히 1이고 1은 10보다 크지않고
계속해서 1로 들어온 데이터는 10 보다 계속 작기 때문에 결과가 나오지않는다.
④위와 같은 문제때문에 rownum을 시스템이아닌 DB로 만들어서 사용해야 한다.
즉 한번 정한 값이 바뀌지않게 테이블로 고정해야 한다.
고정하는 방법은 rownum에 컬럼명을 주면 된다.
--04 rownum 고정
--검색했던 시점의 데이터로 고정시키기
select *
from (select rownum rn, tbl_board.*
from tbl_board
where 1=1
order by bno desc);
이런 경우 rn이라는 컬럼이 where절과 orderby절에 영향을 받지만,
이렇게 할경우 rownum과 나머지데이터들은 완전히 짝이되어 새로운데이터로 넣어진 컬럼이되는것이다.
⑤ 특정 페이지를 보여주는 쿼리를 작성해보자
--05
--page 2, perPageNum 5
select rownum rn, a.*
from (select tbl_board.*
from tbl_board
where 1=1
order by bno desc) a
where rownum <= 2*5;
위 예제의 문제는 a테이블로 1~10까지 묶여있고 아래와 같이 이것을 잘라야한다.
⑥ 두번째 페이지이고, 한페이지에 5개씩 보여주게끔 만들어보자
--06
--page 2, perPageNum 5
--두번째페이지이고, 한페이지에 5개씩보여줌
select b.*
from (select rownum rn, a.*
from (select tbl_board.*
from tbl_board
where 1=1
order by bno desc) a
where rownum <= 2*5) b
where rn > 5;
--06 위예제와 동일
--page 2, perPageNum 5
select b.*
from (select rownum rn, a.*
from (select tbl_board.*
from tbl_board
where 1=1
order by bno desc) a
where rownum <= 2*5) b
where rn > (2-1)*5;
--page 와 perPage 라는 두개의정보로 구성해야되므로
--2와 5 사용한것임.
--현재보여주고싶은 페이지보다 1작은 페이지
전체를 b로 묶어주어야 한다.
두번째 페이지이고, 한페이지에 5개씩 잘 선택해 출력되고 있다.
⑦ 원하는 조건의 데이터 검색하기
--07 원하는 조건의 데이터 검색
select b.*
from (select rownum rn, a.*
from (select tbl_board.*
from tbl_board
where 1=1 and title like '%'||'입력'||'%'
order by bno desc) a
where rownum <= 2*5) b
where rn > (2-1)*5;
% = 이스케이프시퀀스
'%'||'입력'||'%'
문자열에 입력이 있는 모든데이터
rownum 이해설명 링크: https://turing0809.tistory.com/48
3. 쿼리를 이용해 페이징 구현하기
boardMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.human.dao.BoardDAO">
<insert id="create">
insert into tbl_board(bno,title,content,writer)
values (seq_board.nextval,#{title},#{content},#{writer})
</insert>
<select id="read" resultType="BoardDTO">
select * from tbl_board where bno=#{bno}
</select>
<update id="update">
update tbl_board set title=#{title},content=#{content}
where bno=#{bno}
</update>
<delete id="delete">
delete from tbl_board where bno=#{bno}
</delete>
<sql id='search'>
<if test="searchType!=null">
<if test="searchType == 't'.toString()"> and title like '%'|| #{keyword}||'%' </if>
<if test="searchType == 'c'.toString()"> and content like '%'|| #{keyword}||'%' </if>
<if test="searchType == 'w'.toString()"> and writer like '%'|| #{keyword}||'%' </if>
<if test="searchType == 'tc'.toString()"> and ( title like '%'|| #{keyword}||'%' OR content like '%'|| #{keyword}||'%') </if>
<if test="searchType == 'cw'.toString()"> and ( content like '%'|| #{keyword}||'%' OR writer like '%'|| #{keyword}||'%') </if>
<if test="searchType == 'tcw'.toString()"> and ( title like '%'|| #{keyword}||'%' OR content like '%'|| #{keyword}||'%' OR writer like '%'|| #{keyword}||'%') </if>
</if>
</sql>
<select id="listSearch" resultType="com.human.dto.BoardDTO">
<![CDATA[select bno, title, content, writer, viewcnt, regdate from (select rownum rn,a.*
from (
select tbl_board.*
from tbl_board
where 1=1 ]]>
<include refid="search"/>
<![CDATA[ order by bno desc) a where rownum<=#{page} * #{perPageNum}) b
where rn>(#{page} -1) * #{perPageNum}]]>
</select>
<select id="listSearchCount" resultType="int">
<![CDATA[ select count(bno) from tbl_board where 1=1 ]]>
<include refid="search"/>
<![CDATA[ and bno > 0 ]]>
</select>
</mapper>
CDATA
마이바티스에서 CDATA는 Character DATA 문자형 데이터를 의미한다.
<![CDATA[ ]]>에서 [ ] 안에 있는 문자열은 있는 본모습 그대로 문자열로 출력된다.
PageMaker.java
package com.human.vo;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
public class PageMaker {
private int page=1;//현재 페이지
private int perPageNum=10;//페이지당 데이터 개수
private String searchType;//검색할 컬럼
private String keyword;//검색 내용
//PageMaker
private int totalCount;//전체데이터개수
private int totalStartPage=1;//총시작페이지의미
private int totalEndPage;//총마지막페이지의미
private int startPage;//pageMake에서 시작 페이지 번호
private int endPage;//pageMaker에서 마지막 페이지 번호
private boolean prev;//이전 페이지 번호 목록 이동 (이전으로이동할수있으면 true false)
private boolean next;//다음 페이지 목록 이동 (다음으로이동할수있으면 true false)
//pageMaker에서 사용자에게 제공하는 한 화면에서 보여줄 페이지 개수
private int displayPageNum = 10;
public int getTotalStartPage() {
return totalStartPage;
}
public void setTotalStartPage(int totalStartPage) {
this.totalStartPage = totalStartPage;
}
public int getTotalEndPage() {
return totalEndPage;
}
public void setTotalEndPage(int totalEndPage) {
this.totalEndPage = totalEndPage;
}
public int getPage() {
return page;
}
public void setPage(int page) {
if(page<=0) {
page=1;
}
this.page = page;
}
public int getPerPageNum() {
return perPageNum;
}
public void setPerPageNum(int perPageNum) {
if(perPageNum<=0||perPageNum>100) {
perPageNum=10;
}
this.perPageNum = perPageNum;
}
public String getSearchType() {
return searchType;
}
public void setSearchType(String searchType) {
this.searchType = searchType;
}
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
//전체 개수를 설정한다음 페이징에 필요한 데이터 값을 생성
//할 수 있다.
calcData();
}
private void calcData() {
totalStartPage=1;
totalEndPage=(int)Math.ceil(totalCount/(double)perPageNum);
// private int endPage;//pageMaker에서 마지막 페이지 번호
endPage = (int) (//ceil 올림 floor 내림 round 반올림
Math.ceil(page /(double) displayPageNum)
* displayPageNum);
// private int startPage;//pageMake에서 시작 페이지 번호
startPage=endPage-displayPageNum+1;
if(totalEndPage < endPage) {
endPage=totalEndPage;
}
if(startPage<1) {
startPage=1;
}
if(startPage==1) {
prev=false;
}else {
prev=true;
}
if(endPage==totalEndPage) {
next=false;
}else {
next=true;
}
// private boolean prev;//이전 페이지 번호 목록 이동
// private boolean next;//다음 페이지 목록 이동
}
public int getStartPage() {
return startPage;
}
public void setStartPage(int startPage) {
this.startPage = startPage;
}
public int getEndPage() {
return endPage;
}
public void setEndPage(int endPage) {
this.endPage = endPage;
}
public boolean isPrev() {
return prev;
}
public void setPrev(boolean prev) {
this.prev = prev;
}
public boolean isNext() {
return next;
}
public void setNext(boolean next) {
this.next = next;
}
@Override
public String toString() {
return "PageMaker [page=" + page + ", perPageNum=" + perPageNum + ", searchType=" + searchType + ", keyword="
+ keyword + ", totalCount=" + totalCount + ", startPage=" + startPage + ", endPage=" + endPage
+ ", prev=" + prev + ", next=" + next + "]";
}
public String makeSearch() {
UriComponents u=UriComponentsBuilder.newInstance()
.queryParam("page", page)
.queryParam("perPageNum", perPageNum)
.queryParam("searchType", searchType)
.queryParam("keyword", keyword)
.build();
return u.toUriString();
}
public String makeSearch(int page) {
UriComponents u=UriComponentsBuilder.newInstance()
.queryParam("page", page)
.queryParam("perPageNum", perPageNum)
.queryParam("searchType", searchType)
.queryParam("keyword", keyword)
.build();
return u.toUriString();
}
public String makePage(int page) {
UriComponents u=UriComponentsBuilder.newInstance()
.queryParam("page", page)
.queryParam("perPageNum", perPageNum)
.build();
return u.toUriString();
}
}
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 prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@include file="../include/header.jsp"%>
<script>
var result = '${msg}';
if (result == 'success') {
alert("처리가 완료되었습니다.");
}
$(document).ready(function(){
$('#searchBtn').on("click",function(event){
alert("list"+'${pageMaker.makePage(1)}'
+'&searchType='+$("select option:selected").val()
+"&keyword="+$('#keywordInput').val());
self.location="list"+'${pageMaker.makePage(1)}'
+'&searchType='+$("select option:selected").val()
+"&keyword="+$('#keywordInput').val();
})
/* writeBtn을 클릭하면 이곳주소로 이동해라 */
$('.writeBtn').on("click",function(event){
location.href="/ex/sboard/write";
});
$('#newBtn').on("click",function(event){
self.location="write";
});
});
</script>
<div class="main">
<h2>게시판 board</h2>
<h5>목록화면</h5>
<div>
<!-- 검색창옆 검색선택부분 -->
<select name="searchType">
<option value="n" <c:out value="${pageMaker.searchType==null?'selected':'' }"/>>----</option>
<!-- <option value="n" selected>----</option>
<option value="n">----</option> -->
<option value="t" <c:out value="${pageMaker.searchType eq 't'?'selected':'' }"/>>title</option>
<option value="c" <c:out value="${pageMaker.searchType eq 'c'?'selected':'' }"/>>content</option>
<option value="w" <c:out value="${pageMaker.searchType eq 'w'?'selected':'' }"/>>writer</option>
<option value="tc" <c:out value="${pageMaker.searchType eq 'tc'?'selected':'' }"/>>title or content</option>
<option value="cw" <c:out value="${pageMaker.searchType eq 'cw'?'selected':'' }"/>>c w</option>
<option value="tcw" <c:out value="${pageMaker.searchType eq 'tcw'?'selected':'' }"/>>t c w</option>
</select>
<!-- 검색창 -->
<input type="text" name="keyword"
id="keywordInput" value="${pageMaker.keyword}">
<button id="searchBtn"> 검색하기</button>
<button id="newBtn"> 새글</button>
</div>
<table class='customers' width=100% border="1">
<tr>
<th style="width: 10px">BNO</th>
<th>TITLE1</th>
<th style="width: 100px">WRITER</th>
<th style="width: 200px">REGDATE</th>
<th style="width: 40px">VIEWCNT</th>
</tr>
<c:forEach items="${list}" var="dto">
<tr>
<td style="width: 10px">${dto.bno }</td>
<td><a href="/ex/sboard/read${pageMaker.makeSearch()}&bno=${dto.bno}">${dto.title }</a></td>
<td style="width: 100px">${dto.writer }</td>
<td style="width: 200px">
<fmt:formatDate pattern="yyyy-MM-dd HH:mm" value= "${dto.regdate }"/></td>
<td style="width: 40px">${dto.viewcnt }</td>
</tr>
</c:forEach>
</table>
<button class='writeBtn'>글쓰기</button>
<div class="pagination">
<c:if test="${pageMaker.page !=1}">
<a href='list${pageMaker.makeSearch(1)}'>«</a>
</c:if>
<c:if test="${pageMaker.prev }">
<a href='list${pageMaker.makeSearch(pageMaker.startPage-1)}'><</a>
</c:if>
<c:forEach begin="${pageMaker.startPage }" end="${ pageMaker.endPage}" var="idx">
<a href='list${pageMaker.makeSearch(idx)}'
<c:out value="${pageMaker.page==idx?' class=active ':'' }"/> >
${idx}</a>
</c:forEach>
<%--<a href='#'>1</a>
<a href='list${pageMaker.makeSearch(2)}'>2</a>
<a href='#' class="active">3</a> --%>
<c:if test="${pageMaker.next }">
<a href='list${pageMaker.makeSearch(pageMaker.endPage+1)}'>></a>
</c:if>
<c:if test="${pageMaker.page != pageMaker.totalEndPage}">
<a href='list${pageMaker.makeSearch(pageMaker.totalEndPage)}'>»</a>
</c:if>
</div>
</div>
<%@include file="../include/footer.jsp"%>
'STUDY > SpringLegacy' 카테고리의 다른 글
[JSP] import · JSP태그 · taglib · Include · c:url (0) | 2022.12.20 |
---|---|
[Spring] 답변형 게시판 만드는 방법 (2) | 2022.09.22 |
[Spring] JOIN table 생성과 설명 이미지 (0) | 2022.09.21 |
[JSP] 예외처리 연습 / JSP include 태그 (1) | 2022.09.19 |
[Spring] 게시판 만들기 총정리 (게시글 등록·확인·삭제·수정) (0) | 2022.09.19 |