본문으로 바로가기

이전 게시글에서 페이징 처리에는 성공했으나, 후 작업이 더 필요해서 게시글을 분리했다. 페이징 원칙 중에 특정 페이지의 한 게시글을 조회하거나 수정, 삭제 처리가 된 후에 다시 목록으로 리다이렉트할 경우, 그 특정 페이지로 이동해야 한다는 원칙이 있다. 그 원칙에도 만족하도록 페이징 개선 작업을 할 것이다.

 

예를 들어 5페이지에 있는 30번 게시글을 조회하거나 수정한 뒤, 목록으로 돌아가는 버튼을 눌렀다고 해보자. 그러면 이전 글의 게시판일 경우에는 1페이지로 돌아갈 것이다. 그렇게 되면 한 페이지의 여러 게시글들을 읽고 싶다면 매우 불편할 것이다. 그래서 우리는 첫 페이지로 가는게 아니라, 특성 페이지로 이동하도록 작업을 해야한다. 삭제 처리 또한 특정 페이지로 리다이렉트하도록 작업을 할 것이다.

 

현재 페이지 번호 page
페이지당 보여줄 게시글의 갯수 perPageNum

특정 페이지의 게시글 목록을 보기 위해서는 위의 정보들이 필요하다. 위의 정보들은 이전 게시글의 Criteria 클래스에서 정의했다. 조회, 수정, 삭제 작업들이 이루어질 때, 목록 페이지의 정보를 유지하기 위해 해당 정보들도 함께 넘어가도록 작업을 할 것이다.

 

1. UriComponents Class

이 클래스는 URI를 생성할 때 도움이 되는 Spring에서 제공해주는 클래스이다. 쿼리 문자열을 추가해줘서 원하는 URI를 만들 수 있다. 쿼리 문자열은 /board/boardList?IDX=77&page=3&perPageNum=10 주소 URI을 보면 ?(물음표) 뒤에 오는 것들을 말한다. uriComponents를 사용하게 되면 /board/boardDetail${pageMaker.makeQueryPage(page)} 이런식으로 사용이 가능하다.

 

PageMaker

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class PageMaker {
    
    /* 생략 */
    
    public String makeQueryPage(int page) {
        UriComponents uri = UriComponentsBuilder.newInstance()
                .queryParam("page", page)
                .queryParam("perPageNum", cri.getPerPageNum())
                .build();
        return uri.toUriString();
    }
    
    public String makeQueryPage(int idx, int page) {
        UriComponents uri = UriComponentsBuilder.newInstance()
                .queryParam("idx", idx)
                .queryParam("page", page)
                .queryParam("perPageNum", cri.getPerPageNum())
                .build();
        return uri.toUriString();
    }
 
}
cs

2개의 메소드를 생성했다. idx가 필요한 uri도 있어서 추가해줬는데, 둘 중에서 첫번째의 메소드만 사용해도 된다. 그렇게 한다면, idx도 필요한 uri는 /board/boardDetail${pageMaker.makeQueryPage(page)}&idx=23 이렇게 뒤에 문자열을 추가해서 보내주면 된다. 나는 idx 포함된 uri 주소를 만들었기 때문에 idx가 필요없으면 page 정보만, idx가 필요하면 idx, page 정보를 넘겨주면 된다.

 

 

게시글에 들어가고 나올 때마다 현재 페이지 번호와 페이지당 보여줄 게시글의 갯수를 가지고 있어야 한다. 생성한  makeQueryPage() 메소드를 이용해 URI에 정보를 담아갈 수 있게 Controller 및 JSP를 수정해야 한다. 하나씩 수정해보도록 하자. 변경된 부분만 설명을 달았다.

 

2. BoardController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
    @RequestMapping("/board/boardDetail")
    public ModelAndView boardDetail(CommandMap commandMap, Criteria cri) throws Exception {
        
        ModelAndView mv = new ModelAndView("/board/boardDetail");
        Map<String, Object> detail = boardService.viewBoardDetail(commandMap.getMap());
        mv.addObject("detail",detail);
        
        PageMaker pageMaker = new PageMaker();
        pageMaker.setCri(cri);
        mv.addObject("page",cri.getPage());
        mv.addObject("pageMaker", pageMaker);
        
        return mv;
    }
 
    @RequestMapping(value="/board/boardUpdate")
    public ModelAndView boardUpdate(CommandMap commandMap, Criteria cri) throws Exception {
        
        ModelAndView mv = new ModelAndView("/board/boardUpdate");
        Map<String, Object> detail = boardService.selectBoardDetail(commandMap.getMap());
        mv.addObject("detail",detail);
        
        PageMaker pageMaker = new PageMaker();
        pageMaker.setCri(cri);
        mv.addObject("page",cri.getPage());
        mv.addObject("pageMaker", pageMaker);
        
        return mv;
    }
 
    @RequestMapping(value="/board/boardUpdate", method=RequestMethod.POST)
    public ModelAndView boardUpdatePOST(CommandMap commandMap, Criteria cri, RedirectAttributes redAttr) throws Exception {
        
        ModelAndView mv = new ModelAndView("redirect:/board/boardDetail");
        mv.addObject("idx", commandMap.get("idx"));
        boardService.updateBoard(commandMap.getMap());
        
        redAttr.addAttribute("page", cri.getPage());
        redAttr.addAttribute("perPagNum", cri.getPerPageNum());
        
        return mv;
    }
    
    @RequestMapping(value="/board/boardDelete")
    public ModelAndView boardDelete(CommandMap commandMap, Criteria cri, RedirectAttributes redAttr) throws Exception {
        ModelAndView mv = new ModelAndView("redirect:/board/boardList");
        boardService.deleteBoard(commandMap.getMap());
        
        redAttr.addAttribute("page", cri.getPage());
        redAttr.addAttribute("perPagNum", cri.getPerPageNum());
        
        return mv;
    }
cs

- 02, 17행: 이전 목록에 대한 정보를 Criteria 클래스에 담는다.

- 08~11, 23~26행: PageMaker 인스턴트를 생성하고 현재 페이지와 함께  view로 던진다.

- 32, 45행: 이전 목록에 대한 정보를 Criteria 클래스에 담고, 리다이렉트를 위해 RedirectAttributes 를 사용한다.

- 38~39, 49~50행: 페이지 정보를 리다이렉트해준다.

 

 

3. boardList.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<td><a href='<c:url value='/board/boardDetail${pageMaker.makeQueryPage(bList.IDX, pageMaker.cri.page) }'/>'>${bList.TITLE }</a></td>
 
<ul class="pagination">
  <c:if test="${pageMaker.prev }">
  <li>
      <a href='<c:url value="/board/boardList${pageMaker.makeQueryPage(pageMaker.startPage-1) }"/>'><i class="fa fa-chevron-left"><</i></a>
  </li>
  </c:if>
  <c:forEach begin="${pageMaker.startPage }" end="${pageMaker.endPage }" var="pageNum">
  <li>
      <a href='<c:url value="/board/boardList${pageMaker.makeQueryPage(pageNum) }"/>'>${pageNum }</a>
  </li>
  </c:forEach>
  <c:if test="${pageMaker.next && pageMaker.endPage >0 }">
  <li>
      <a href='<c:url value="/board/boardList${pageMaker.makeQueryPage(pageMaker.endPage+1) }"/>'><i class="fa fa-chevron-right">></i></a>
  </li>
  </c:if>
</ul>
cs

- 01행: 게시글의 상세페이지로 가는 부분에 추가했다.

- 06, 11, 16행: 페이징 버튼 부분에 추가했다.

 

 

4. boardDetail.jsp

1
2
3
<a href='<c:url value='/board/boardUpdate${pageMaker.makeQueryPage(detail.IDX, page) }'/>'>수정</a>
<a href='<c:url value='/board/boardDelete${pageMaker.makeQueryPage(detail.IDX, page) }'/>'>삭제</a>
<a href='<c:url value='/board/boardList${pageMaker.makeQueryPage(page) }'/>'>목록으로</a>
cs

수정, 삭제의 경우는 게시글의 idx도 넘어가야하기 때문에 idx 정보도 포함해서 넘겨준다.

 

 

5. boardUpdate.jsp

1
2
3
4
5
6
<form action='<c:url value='/board/boardUpdate${pageMaker.makeQueryPage(page) }'/>' method="post">
    <!-- 생략 -->
    <input type="hidden" name="idx" value="${detail.IDX }">
    <button type="submit" class="btn btn-default">수정하기</button>
    <a href='<c:url value='/board/boardDetail${pageMaker.makeQueryPage(detail.IDX, page) }'/>'>이전으로</a>
</form>
cs

- 01행: idx도 넘어가야 하는데, input hidden 으로 보내주고 있기 때문에 uri에는 포함시키지 않았다.

- 08행: 이전 상세페이지로 돌아가는 부분에 추가했다.

 

 

6. 확인

이제 상세 페이지에 들어가보고 수정, 삭제, 목록으로, 이전으로 버튼을 눌러서 되는 지 테스트해보면 된다. 수정, 삭제가 되는 걸 보여주는 건 의미없어 보이고, uri이 잘 생성 되었는 지 확인하려고 한다. 개발자 모드(F12)를 켜서 uri를 확인해보자.

상세페이지에 들어가는 uri
페이징 버튼 부분 uri
상세페이지의 수정,삭제,목록 uri

이처럼 uri들이 적용되어 있는 것을 확인할 수 있다. idx가 포함되어 있는 uri도 있고, 페이지 정보만 담겨있는 uri도 확인할 수 있다. uriComponents 클래스의 경우는 다른 곳에서도 쓰일 수 있을 거 같아서 더 연구해보면 좋을 거 같다.

 


댓글을 달아 주세요

  1. 익셉셔너 2020.03.15 16:09

    안녕하세요. 작성해주신 글 보면서 페이징 구현 하고 있습니다.
    그런데 뭐가 문제인지 모르겠지만 글대로 따라 하는데 화면에 자꾸 0이 나오네요...
    데이터는 총 14건이고 페이지당 10건씩 보여주도록 했는데 자꾸 0만 덜렁 나오고 말아요 ㅜㅜ
    이거 왜 그런지 알수 있을까요?

    • BlogIcon #에게 2020.03.16 10:37 신고

      안녕하세요! 이런 경우는 제가 직접 코드를 보지않는 이상 이유를 알 수가 없답니다ㅠㅠ 혹시 이전 글의 페이징처리는 잘 되는데, 해당 글의 페이징처리를 하게 되면 0으로 나오는 건가요?

  2. 궁굼 2020.08.09 13:14

    안녕하세요 페이징 처리2 의 방법을 해보고있는데
    ~~주소?page=4&perPageNum=6 이런식으로 페이징 된곳에서 상세보기 들어가지고
    뒤로가기 버튼으로 목록으로 돌아갈때 그 버튼의 개발자도구 주소를 보면
    page=1&perPageNum=6 이 고정이던데 어디서 문제가있는지 의심가는 곳이 있으실까요?

    • BlogIcon #에게 2020.09.27 12:03 신고

      모든 게시글의 '목록으로' 가는 부분이page=1&perPageNum=6 으로 고정되어 있으시다는 건가요??

      목록으로 버튼은 게시글이 있던 페이지와 보여줄 목록의 갯수 로 이루어져 있어요. 그래서 첫 페이지의 모든 게시글은 page=1&perPageNum=6 이렇게 되어 있고, 두번째 페이지의 게시글들은 page=2&perPageNum=6 이렇게 되어 있는 게 맞아요.

      혹시 이 답변이 맞으실까요?

  3. 해결 2021.11.23 11:31

    목록으로 돌아갈때 ${pageMaker.makeQueryPage(page) }으로 하니까 잘 넘어가 지네요