관리자단 화면에서 회원관리, 게시물관리 모두 공통적으로 필요한 기능은 페이징처리이다.
회원 수, 게시물 수가 많아지면 한 화면에 제한된 개수를 보여줘야 한다.
먼저, PageVO 클래스를 생성한다. 이 클래스는 회원, 게시물 관리 공통으로 사용한다.
페이징 처리에 필요한 변수를 생성하고, 계산식, getter/setter 또한 추가한다.
package org.edu.vo;
public class PageVO {
private int perPageNum;
private int queryPerPageNum;
private Integer page;
private int queryStartNo;
private boolean prev;
private boolean next;
private int totalCount;
private int startPage;
private int endPage;
//검색에 필요한 변수 2개도 포함
private String search_type; //검색조건(분류)
private String search_keyword; //검색어
}
// 계산식 4개로 반환되는 값 : startPage, endPage, prev, next
private void calcPage() {
int tempEnd = (int)(Math.ceil
(page/(double)this.perPageNum)*this.perPageNum
);
if( tempEnd*this.queryPerPageNum > this.totalCount ) { //ex. 200>195
this.endPage = (int)Math.ceil(
this.totalCount/(double)this.queryPerPageNum
);
} else {
this.endPage = tempEnd;
}
//==============(위)startPage, endPage구하는 계산식==================
this.prev = this.startPage != 1;
this.next = (this.endPage*this.queryPerPageNum < this.totalCount);
//=======================(위)prev, next 계산식=========================
}
public int getPerPageNum() {
return perPageNum;
}
public void setPerPageNum(int perPageNum) {
this.perPageNum = perPageNum;
}
public int getQueryPerPageNum() {
return queryPerPageNum;
}
public void setQueryPerPageNum(int queryPerPageNum) {
this.queryPerPageNum = queryPerPageNum;
}
public Integer getPage() {
return page;
}
public void setPage(Integer page) {
this.page = page;
}
public int getQueryStartNo() {
queryStartNo = queryPerPageNum*(this.page-1); //개발자가 추가한 계산식
return queryStartNo;
}
public void setQueryStartNo(int queryStartNo) {
this.queryStartNo = queryStartNo;
}
public boolean getPrev() {
return prev;
}
public void setPrev(boolean prev) {
this.prev = prev;
}
public boolean getNext() {
return next;
}
public void setNext(boolean next) {
this.next = next;
}
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
calcPage();
}
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 String getSearch_type() {
return search_type;
}
public void setSearch_type(String search_type) {
this.search_type = search_type;
}
public String getSearch_keyword() {
return search_keyword;
}
public void setSearch_keyword(String search_keyword) {
this.search_keyword = search_keyword;
}
AdminController에서 member_llist() 수정한다.
* 페이지 정보 입력 전, 고전적인 방식의 검색
public String member_list( @RequestParam (value="search_type", required=false) String search_type,
@RequestParam(value="search_keyword", required=false) String search_keyword) {
...
}
* 페이지 정보 입력 후, 검색
- PageVO에 search_type, search_keyword 변수 포함.
public String member_list(@ModelAttribute("pageVO") PageVO pageVO, Model model) throws Exception {
...
}
* @ModelAttribute의 기능?
수행한 pageVO 결과를 "pageVO"라는 이름으로 jsp에 정보를 보낸다.
@ModelAttribute를 사용하면,
model.addAttribute("pageVO", pageVO); 없어도 된다.
AdminController에서 member_view() 수정한다.
- 회원 상세보기에도 페이지 정보가 필요하기 때문에 @ModelAttribute("pageVO") PageVO pageVO를 추가해준다.
member_list.jsp에서 페이지 정보를 받을 수 있도록 쿼리스트링을 수정한다.
1. 회원 검색 결과가 없을 때, "조회된 데이터가 없습니다." 라는 텍스트가 화면에 출력되도록 한다.
<c:if test="${empty memberss}">
<tr><td colspan="6" class="text-center">조회된 데이터가 없습니다.</td></tr>
</c:if>
2. 회원리스트의 user_id를 클릭했을 때, user_id의 값과 user_id가 존재하는 해당 페이지 값을 page변수에 저장해 member_view로 보내준다.
<td><a href="/admin/member/member_view?page=${pageVO.page}&user_id=${member.user_id}">${member.user_id}</a></td>
3. 이전(다음) 버튼 실행 조건 설정
<c:if test="${pageVO.prev}"><!-- if문 true 일 때 아래 실행 -->
<li class="paginate_button page-item previous" id="example1_previous">
<a href="/admin/member/member_list?page=${pageVO.startPage-1}&search_type=${pageVO.search_type}&search_keyword=${pageVO.search_keyword}"
aria-controls="example1" data-dt-idx="0" tabindex="0" class="page-link">«</a></li>
</c:if>
- pageVO.prev ( this.prev = this.startPage != 1 / 시작페이지가 1이 아닐 때)가 참일 때 실행
- 이전 버튼을 클릭했을 때, page변수에 (현재 페이지리스트의 시작페이지-1) 값을 저장한다.
ex. < 6 7 8 9 10 > 일 때, 이전버튼 클릭 -> 5페이지(현재 페이지리스트의 시작페이지6 - 1)로 이동
- pageVO.next ( this.next = this.endPage * this.queryPerPageNum < this.totalCouunt)가 참일 때 실행
- 다음 버튼을 클릭했을 때, page변수에 (현재 페이지리스트의 끝페이지+1) 값을 저장한다.
4. 페이지 번호를 눌렀을 때, 활성화되도록 한다.
<!-- jstl의 for문이고, 향상된 for문이 아닌 고전 for문으로 시작값, 종료값 필요, var변수 idx는 인덱스값이 저장되어 있다.(jstl 제공)-->
<c:forEach begin="${pageVO.startPage}" end="${pageVO.endPage}" var="idx">
<li class='paginate_button page-item <c:out value="${idx == pageVO.page?'active':''}" />'>
<a href="/admin/member/member_list?page=${idx}&search_type=${pageVO.search_type}&search_keyword=${pageVO.search_keyword}"
aria-controls="example1" data-dt-idx="1" tabindex="0" class="page-link">${idx}</a></li>
</c:forEach>
- 고전 반복문으로 pageVO.startPage(시작값)부터 pageVO.endPage(종료값)까지 idx를 출력한다.
*idx는 인덱스 값이 저장되어있다.
- idx는 링크인데, 내가 클릭한 idx(버튼)과 이동한 페이지의 페이지값(쿼리스트링으로 idx값을 page변수에 저장하여 전달)이 같다면 그 버튼을 활성화한다.
* 삼항연산자
<c:out value="${idx == pageVO.page?'active':''}" />
if(idx==pageVO.page) {'active';}
else {'';}
스프링 작업 순서 : 쿼리 > DAO > Service > Controller > jsp
먼저 워크벤치에서 쿼리를 구현해보자.
(지금은 회원 리스트의 페이징 처리이지만, 데이터가 부족한 관계로 tbl_board의 데이터로 쿼리 구현)
SELECT * FROM tbl_board
ORDER BY reg_date DESC
LIMIT 0, 10;
-> 게시물을 등록일 내림차순으로 인덱스 0번부터 10개 보여줘라.
MemberMapper의 selectMember 쿼리를 수정한다.
<select id="selectMember" resultType="org.edu.vo.MemberVO">
select * from tbl_member
<if test="search_type != '' and search_type != null">
where
<if test="search_type == 'all'.toString()">
user_id LIKE concat('%', #{search_keyword}, '%')
or
user_name LIKE concat('%', #{search_keyword}, '%')
</if>
<if test="search_type == 'user_id'.toString()">
user_id LIKE concat('%', #{search_keyword}, '%')
</if>
<if test="search_type == 'user_name'.toString()">
user_name LIKE concat('%', #{search_keyword}, '%')
</if>
</if>
order by reg_date desc
limit #{queryStartNo}, #{queryPerPageNum}
</select>
-> 쿼리의 limit부분을 #{queryStartNo}, #{queryPerPageNum} 변수로 대체한다.
selectMember에 대한 부분을 수정해준다.
IF_MemberDAO, MemberDAOImpl
public List<MemberVO> selectMember(PageVO pageVO) throws Exception;
@Override
public List<MemberVO> selectMember(PageVO pageVO) throws Exception {
// mapper.xml에 접근하는 방법(아래)
// 매개변수(파라미터) 한 개로 만들어서, 값을 두 개 집어넣는 방식 - 해시데이터타입 만들어서 구현
/*
* Map<String,Object> paramMap = new HashMap<String, Object>();
* paramMap.put("search_type", search_type); paramMap.put("search_keyword",
* search_keyword);
*/
return sqlSession.selectList("memberMapper.selectMember", pageVO);
//sqlSession템플릿의 selectList메소드를 실행하면,
//memberMapper.selectMember 쿼리
}
- 원래는 검색 분류인 search_type과 검색어인 search_keyword 두가지를 해시데이터타입을 만들어서 selectMember에 매개변수로 전달했지만, 두가지 모두 PageVO에 변수로 저장되어있고 페이지정보또한 전달해야하기 때문에, pageVO로 전달한다.
IF_MemberService, MemberServiceImpl
public List<MemberVO> selectMember(PageVO pageVO) throws Exception;
@Override
public List<MemberVO> selectMember(PageVO pageVO) throws Exception {
//회원정보조회 DAO클래스의 메소드 호출(아래)
return memberDAO.selectMember(pageVO);
}
'JAVA 기반 웹&앱 콘텐츠 융합 디지털 컨버전스 개발자 과정' 카테고리의 다른 글
[31일차]- 삭제 & 삭제 메세지 JQuery 구현 (0) | 2020.12.27 |
---|---|
[33일차] ERD 생성, AOP기능 (0) | 2020.12.23 |
[28일차] (0) | 2020.12.17 |
[27일차] Service클래스 생성 및 CRUD 테스트 (0) | 2020.12.15 |
[26일차] (0) | 2020.12.14 |