글목록 수정
현재 게시물 목록을 보면 '이름'이 찍혀야 하는데 '아이디'가 보이고 있다.
이름(name)은 게시판(board) 테이블에는 없고
회원(member) 테이블에 있다.
-- 게시판 테이블과 회원 테이블 join
select bno, title, writer, name, regdate, viewcnt
from board b, member m
where b.writer=m.userid
order by bno desc;
이 코드를 mybatis에 기존 코드를 수정해 보자 (listAll)
board/list.jsp 에서 ${row.writer} => ${row.name}
페이지 나누기
delete from board
-- 게시물 1000개 입력 (pl /sql 코드를 돌려 입력한다.)
아이디는 member 테이블에 있는 아이디로 한다.
'||'는 문자와 숫자를 더해준다.
declare
i number := 1;
begin
while i<=1000 loop
insert into board (bno,title,content,writer)
values
((select nvl(max(bno)+1,1) from board)
,'제목~'||i,'내용~~~'||i,'gksmf');
i := i+1;
end loop;
end;
/
PL/SQL 프로시저가 성공적으로 완료되었습니다.
select count(*) from board; // 1000개 확인
오라클은 페이지 나누기를 하기 위해서 아래와 같이 조금 복잡한 방식으로 한다.
select 쿼리가 3번 들어간다.
-- rownum : 출력순서
select *
from (
select rownum as rn, A.*
from (
select rownum, bno, title, regdate, viewcnt, name
from board b, member m
where b.writer=m.userid
order by bno desc
) A
) where rn between 1 and 10;
안쪽의 빨간색 구문이 중요하다 mybatis에서 바뀌는 부분이고
나머지는 바뀌지 않는다.
sql 구문 실행 순서는
from ~절이 처음
where ~ 절이 두번째
select ~
order by ~ 가 마지막으로 실행된다.
먼저 안쪽 selec~desc을 실행해보고
두번째 select rownum as rn, A.* ~ ) A 를 실행하면 아래와 같이 보인다.
마지막 select ~ 절은 두번째 select~의 결과(RN)에서 10개씩(페이지당 게시물 수) 끊어서 가져온다.
select * ~~ ) where rn between 1 and 10;
select * ~~ ) where rn between 12 and 20;
나. 페이지 나누기
- 페이지당 게시물 수 : 10개
- 전체 게시물 수 : 991개
- 몇 페이지? : 100
991 / 10 => 99.1 dhffla => 100
- 페이지의 시작번호, 끝번호 계산
where rn between 1 and 10
1페이지 => 1 ~10
2페이지 => 11 ~20
... ...
11페이지 => 101 ~110
57페이지 => 561 ~570
99페이지 => 981 ~990
100페이지 => 991 ~1000
시작번호=(현재페이지 - 1) * 페이지당 게시물수 + 1
1페이지 => (1-1) * 10 + 1 => 1
2페이지 => (2-1) * 10 + 1 => 11
7페이지 => (7-1) * 10 + 1 => 61
끝번호 = 시작번호 + 페이지당 게시물수 - 1
1페이지 => 1 + 10 - 1 = 10
2페이지 => 11 + 10 - 1 = 20
* 전체 페이지 블록수
전체페이지갯수 / 10
92 / 10 => 9.2 => 10개
1 2 3 4 5 6 7 8 9 10 [다음]
[이전]11 12 13 14 15 16 17 18 19 20 [다음]
...
[이전]41 42 43 44 45 46 47 48 49 50 [다음]
[이전]51 52 53 54 55 56 57 58 59 60 [다음]
...
[이전]91 92 ==> 끝에는 2개 블록이 남는다.
현재 페이지가 속한 블록
(현재 페이지-1)/페이지 블록단위 + 1
1페이지 => 몇번째 블록?
(1-1) / 10 + 1 => 1블록
9페이지 => 몇번째 블록?
(9-1) / 10 + 1 => 1블록
11페이지 => 몇번째 블록?
(11-1) / 10 + 1 => 2블록
20페이지 => 몇번째 블록?
(20-1) / 10 + 1 => 2블록
89페이지 => 몇번째 블록?
(89-1) / 10 + 1 => 9블록
91페이지 => 몇번째 블록?
(91-1) / 10 + 1 => 10번째 블록
* 페이지 블록의 시작 번호
(현재블록-1) * 블록단위 + 1
1블록 => (1-1) * 10 + 1 => 1
2블록 => (2-1) * 10 + 1 => 11
9블록 => (9-1) * 10 + 1 => 81
10블록 => (10-1) * 10 + 1 => 91
* 페이지 블록의 끝 번호
(현재블록-1) * 블록단위 + 1
1블록 => (1) + 10 - 1 => 10
2블록 => (11) + 10 - 1 => 20
9블록 => (81) + 10 - 1 => 90
10블록 => (91) + 10 - 1 => 100 ???
16) Pager.java
// 페이지 나누기 관련 작업 클래스
public class Pager {
public static final int PAGE_SCALE=10; //페이지당 게시물수
public static final int BLOACK_SCALE=10;//화면당 페이지 수
private int curPage; //현재 페이지
private int prevPage; //이전 페이지
private int nextPage; //다음 페이지
private int totPage; //전체 페이지 갯수
private int totBlock; //전체 페이지 블록 갯수
private int curBlock; //현재 페이지 블록
private int prevBlock; //이전 페이지 블록
private int nextBlock; //다음 페이지 블록
// where rn between #{start} and #{end}
private int pageBegin; //#{start}
private int pageEnd; //#{end}
//[이전] blockBegin 42 43 44 45 46 47 48 49 blockEnd [다음]
private int blockBegin; //현재 페이지 블록의 시작번호
private int blockEnd; //현재 페이지 블록의 끝번호
// 생성자
// Pager(레코드 갯수, 현재 페이지 번호)
public Pager(int count, int curPage) {
curBlock=1; // 현재 페이지 블록 번호
this.curPage = curPage;// 현재 페이지 설정
setTotPage(count); // 전체 페이지 갯수 계산
// between #{start} and #{end}에 입력될 값 계산
setPageRange();
setTotBlock(); // 전체 페이지 블록 갯수 계산
setBlockRange(); // 페이지 블록의 시작, 끝 번호 계산
}
public void setBlockRange() {
// 페이지 100개, PAGE_SCALE=10; BLOACK_SCALE=10
// 현재 페이지 34이면 curBlock = (34-1) / 10 + 1
// curBlock - 현재 페이지가 몇번째 페이지 블록에 속하는지 계산
curBlock = (int)Math.ceil((curPage-1)/BLOACK_SCALE -1); // 4번째 블럭
// blockBegin, blockEnd-현재 페이지 블록의 시작, 끝 번호 계산
blockBegin = (curBlock-1) * BLOACK_SCALE + 1;
blockEnd = blockBegin + BLOACK_SCALE + 1;
// 마지막 페이지 번호가 범위를 초과하지 않도록 처리
if(blockEnd > totPage) blockEnd = totPage;
// [이전]을 눌렀을 때 이동할 페이지 번호
prevPage = (curBlock == 1) ? 1 : (curBlock - 1) * BLOACK_SCALE;
// [다음]을 눌렀을 때 이동할 페이지 번호
nextBlock = (curBlock > totBlock) ?
(curBlock * BLOACK_SCALE) : curBlock * BLOACK_SCALE + 1;
// 마지막 페이지가 범위를 초과하지 않도록 처리
if(nextPage >= totPage) nextPage = totPage;
}
public void setPageRange() {
// where rn between #{start} and #{end}에 입력될 값
//시작번호=(현재페이지 - 1) * 페이지당 게시물수 + 1
//끝번호 = 시작번호 + 페이지당 게시물수 - 1
pageBegin = (curPage-1) * PAGE_SCALE + 1;
pageEnd = pageBegin + PAGE_SCALE -1;
}
// getter / setter()
...
public void setTotPage(int count) {
// Math.ceil(실수)올림 처리
this.totPage = (int)Math.ceil(count * 1.0 / PAGE_SCALE);
}
...
//페이지 블록의 갯수 계산(총 100 페이지라면 10개 블록)
public void setTotBlock() {
this.totBlock = (int)Math.ceil(totPage / PAGE_SCALE);
}
...
}
컨트롤러 수정.
@RequestMapping("list.do")
public ModelAndView list() throws Exception {..}
@RequestMapping("list.do")
public ModelAndView list(
@RequestParam(defaultValue="1") int curPage,
@RequestParam(defaultValue="all") String search_option,
@RequestParam(defaultValue="") String keyword ) throws Exception {...}
추카 코드
// 레코드 갯수 계산
int count = boardService.countArticle(search_option, keyword);
// 페이지 나누기 관련 처리
Pager pager = new Pager(count, curPage);
int start = pager.getPageBegin();
int end = pager.getPageEnd();
컨트롤러 수정.
List<BoardDTO> list = boardService.listAll(0, 0, "", ""); // 목록
List<BoardDTO> list = boardService.listAll(start, end, search_option, keyword);
// 컨트롤러 수정 후 dao에 코드를 추가로 작성해야 한다.
BoardDAOImpl 수정.
public List<BoardDTO> listAll(int start, int end,
String search_option, String keyword) throws Exception {
Map<String, Object> map = new HashMap<>();
map.put("search_option", search_option);
map.put("keyword", keyword);
map.put("start", start);
map.put("end", end);
return sqlSession.selectList("board.listAll", map);
}
추카 코드
map.put("count", count);
map.put("search_option", search_option);
map.put("keyword", keyword);
map.put("pager", pager);
boardMapper.xml
<sql>태그는 sql의 부분이다. 재활용을 할 수 있도록 되어있다.
${search_option}에서 '$'을 붙이면 따옴표가 빠진다
#{keyword}에서 '#'는 따옴표를 붙인다.
<sql id="search">
<choose>
<when test="search_option == 'all'">
where
b.writer = m.userid
and
( name like '%'||#{keyword}||'%'
or content like '%'||#{keyword}||'%'
or title like '%'||#{keyword}||'%')
</when>
<otherwise>
where b.writer=m.userid and
${search_option} like '%'||#{keyword}||'%'
</otherwise>
</choose>
</sql>
<sql id="paging_header">
select *
from (
select rownum as rn, A.*
from (
</sql>
<sql id="paging_footer">
) A
) where rn between #{start} and #{end}
</sql>
boardMapper.xml의 listAll 수정
<select id="listAll" resultType="com.example.spring02.model.board.dto.BoardDTO">
select bno, title, writer, name, regdate, viewcnt
from board b, member m
where b.writer=m.userid ( include 'search 절로 대체)
order by bno desc
</select>
아래와 같이 수정한다.
<select id="listAll" resultType="com.example.spring02.model.board.dto.BoardDTO">
<include refid="paging_header"/>
select bno, title, writer, name, regdate, viewcnt
from board b, member m
where b.writer=m.userid
<include refid="search" />
order by bno desc
<include refid="paging_footer" />
</select>
board/list.jsp 수정
<!-- 페이지 네비게이션 -->
1부터 끝(100)까지 나오고 클릭했을때 페이지 전환이 되는지 확인한다.
<c:forEach var="num" begin="1" end="${map.pager.totPage}">
<a href="javascript:list('${num}')">${num}</a>
</c:forEach>
잘 작동한다면 아래처럼 코드를 수정해 본다.
[처음][이전]페이지 블럭(blockBigin~blockEnd)[다음][끝]
<c:if test="${map.pager.curBlock > 1}">
<a href="javascript:list('1')">[처음]</a>
</c:if>
<c:if test="${map.pager.curBlock > 1}">
<a href="javascript:list('${map.pager.prevPage}')">[이전]</a>
</c:if>
<c:forEach var="num" begin="${map.pager.blockBegin}" end="${map.pager.blockEnd}">
<c:choose>
<c:when test="${num == map.pager.curPage}">
<span style="color:red">${num}</span>
</c:when>
<c:otherwise>
<a href="javascript:list('${num}')">${num}</a>
</c:otherwise>
</c:choose>
</c:forEach>
<c:if test="${map.pager.curBlock < map.pager.totBlock }">
<a href="javascript:list('${map.pager.nextPage}')">[다음]</a>
</c:if>
<c:if test="${map.pager.curPage < map.pager.totPage }">
<a href="javascript:list('${map.pager.totPage}')">[끝]</a>
</c:if>
전체게시물 갯수(count)를 구하는 로직을 구현한다.
// 레코드 갯수 계산
int count = boardService.countArticle(search_option, keyword);
BoardDAOImpl.java 수정
public int countArticle(String search_option, String keyword) throws Exception {
Map<String, Object> map = new HashMap<>();
map.put("search_option", search_option);
map.put("keyword", keyword);
return sqlSession.selectOne("board.countArticel", map);
}
boardMapper.xml 수정
<select id="countArticel" resultType="int">
select count(*)
from board b, member m
<include refid="search" />
</select>
레코드 81개를 삭제하고 게시물 수를 확인해 보자
delete from board where bno between 10 and 90;
검색기능을 구현해본다.
'프로그래밍 > JAVA & SPRING' 카테고리의 다른 글
[LifeSoft] spring 22강 게시판만들기3 (상세화면, 댓글쓰기/댓글목록/댓글갯수) (0) | 2020.06.07 |
---|---|
[LifeSoft] spring 22강 게시판만들기3 (상세화면, 댓글쓰기/댓글목록/댓글갯수) (0) | 2020.06.07 |
[LifeSoft] spring 20강 게시판 만들기1(목록, 글쓰기) (0) | 2020.06.07 |
[LifeSoft] spring 19강 Smart Editor(CKEditor, SummerNote) (2) | 2020.06.07 |
[LifeSoft] spring 18강 이메일 보내기 (0) | 2020.06.07 |