본문 바로가기
스프링

[Spring MVC] Ajax로 게시판 만들기

by 이페코장인 2024. 4. 10.

일반적인 스프링 게시판은 @GetMapping 그리고 ModelAttribute로 리스트와 페이징을 처리한다. 그래서 게시글을 검색하거나 목록 페이징를 넘기면 웹페이지가 새로 로딩된다. 하지만 Ajax방식으로 페이징을 처리하면 새 로딩 없이 게시글 목록을 갱신할 수 있다.

 

 

View에서 Ajax 넘겨주는 function 작성

우선 Controller에서 게시판 리스트를 처음 출력해주는 부분은 기존과 동일하게 Get방식으로 만든다.

	@Autowired
	private NoticeService service;

	@GetMapping("/notice/list")
	public String viewList(Model model, 
			@SessionAttribute(name = "loginMember", required = false) Member loginMember) {
		NoticeParam param = new NoticeParam(1, 10, 0);
		int count = service.selectCountNotice();
		List<Notice> list = service.selectAllNotice(param);
		PageInfo pageInfo = new PageInfo(1, 5, count, 10);
		model.addAttribute("list", list);
		model.addAttribute("count", count);
		model.addAttribute("param", param);
		model.addAttribute("pageInfo", pageInfo);
		model.addAttribute("loginMember", loginMember);
		
		return "notice/list";
	}

 

하지만 JSP파일에서 페이징 부분에서, 클릭 시 movePage라는 함수를 호출하도록 하고, 해당 함수가 Ajax방식으로 데이터를 송수신하게 설계한다. JS에서 $('#noticearea').replaceWith(result); 부분으로 송수신 성공 시, 기존의 게시글 목록+페이징 부분의 코드를 다른 코드로 교체하게 되어 있다. 

    <main>
        <!-- Hero -->
        <section class="">
            <div class="container">
                <div class="row justify-content-center">
                    <div class="col-12 col-md-8 text-center">
                        <h1 class="display-2 mb-3">공지사항</h1>
                        <c:if test="${loginMember.role == 'ADMIN'}">
                       	<div class="btn mb-2 mr-2 btn-outline-primary">
                      		<a href="${path}/notice/write">
                       		글쓰기
                      		</a>
                       	</div>
                        </c:if>
                        
                        <div id="noticearea">
	                        <div id="tablearea">
	                        	<table class="table table-hover">
								    <thead>
								        <tr>
								            <th scope="col">#</th>
								            <th scope="col">제목</th>
								            <th scope="col">좋아요 수</th>
								            <th scope="col">검색결과: ${count}</th>
								        </tr>
								    </thead>
								    <tbody>
								    	<c:if test="${empty list}">
											<tr>
												<td colspan="4">조회된 글이 없습니다.</td>
											</tr>
										</c:if>
								    
								    	<c:forEach var="item" items="${list}" varStatus="status">
									        <tr>
									            <th scope="row">${status.count}</th>
									            <td>
									                <div class="d-flex align-items-center">
									                	<a href="${path}/notice/view?nno=${item.nno}">
									                    ${item.title}
									                	</a>
									                </div>
									            </td>
									            <td>${item.likeCount}</td>
									            <td>
									                <div class="d-flex">
									                    <i class="fas fa-edit mr-3" data-toggle="tooltip" data-placement="top" title="Edit item"></i>
									                    <i class="fas fa-trash text-danger mr-2" data-toggle="tooltip" data-placement="top" title="Delete item"></i>
									                </div>
									            </td>
									        </tr>
								    	</c:forEach>
								    </tbody>
								</table>
	                        </div>
                        
                        <nav aria-label="Page navigation example">
						    <ul class="pagination">
						        <li class="page-item">
						            <div class="page-link" onclick="movePage(${pageInfo.prevPage});"><i class="fas fa-angle-double-left"></i></div>
						        </li>
	                        	
	                        	<c:forEach begin="${pageInfo.startPage}" end="${pageInfo.endPage}" varStatus="status" step="1">
	                        		<c:if test="${status.current != pageInfo.currentPage}">
							        <li class="page-item">
							            <div class="page-link" onclick="movePage(${status.current});">${status.current}</div>
							        </li>
	                        		</c:if>
	                        		<c:if test="${status.current == pageInfo.currentPage}">
							        <li class="page-item active">
							            <div class="page-link">${status.current}</div>
							        </li>
	                        		</c:if>
	                        	</c:forEach>
						        <li class="page-item">
						            <div class="page-link" onclick="movePage(${pageInfo.nextPage});"><i class="fas fa-angle-double-right"></i></div>
						        </li>
						    </ul>
						</nav>
                        </div>
                        
                    </div>
                </div>
            </div>
        </section>
    </main>
    <script type="text/javascript">
    	function movePage(page){
    		
    		$.ajax({
    			type: 'post',
    			url: '${path}/notice/page',
    			data:{
    				page : page
    			},
    			dataType: "text"
    		})
    		.done((result)=>{
    			$('#noticearea').replaceWith(result);
    		})
    		.fail((jqXHR)=>{
    			console.log(jqXHR);
    		})
    	}
    
    </script>

 

 

Controller에서 Ajax 처리

앞서 JS코드에서 type: 'post', url: '${path}/notice/page'로 지정했으므로 @PostMapping("/notice/page")의 함수가 Ajax를 처리한다.

반환하는 notice/alist 가 기존의 게시글+페이징을 교체한다.

	@PostMapping("/notice/page")
	public String noticepage(Model model, int page) {
		NoticeParam param = new NoticeParam();
		int count = service.selectCountNotice();
		param.setPage(page);
		PageInfo pageInfo = new PageInfo(param.getPage(), 5, count, 10);
		param.setLimit(pageInfo.getListLimit());
		param.setOffset(pageInfo.getStartList() - 1);
		List<Notice> list = service.selectAllNotice(param);
		model.addAttribute("count", count);
		model.addAttribute("list", list);
		model.addAttribute("pageInfo", pageInfo);
		
		return "notice/alist";
	}

 

 

교체해주는 JSP파일 작성

기존의 게시글 코드의 <div id="noticearea">내용만들 담아 줄 JSP파일(notice/alist)을 만든다.

이 파일에서도 <div id="noticearea">라고 id값을 동일하게 맞춰야 계속해서 Ajax로 페이징이 작동하여 또 새 데이터를 받은 게시글 목록으로 교체된다.

<div id="noticearea">
    <div id="tablearea">
        <table class="table table-hover">
            <thead>
                <tr>
                    <th scope="col">#</th>
                    <th scope="col">제목</th>
                    <th scope="col">좋아요 수</th>
                    <th scope="col">검색결과: ${count}</th>
                </tr>
            </thead>
            <tbody>
                <c:if test="${empty list}">
                    <tr>
                        <td colspan="4">조회된 글이 없습니다.</td>
                    </tr>
                </c:if>

                <c:forEach var="item" items="${list}" varStatus="status">
                    <tr>
                        <th scope="row">${status.count}</th>
                        <td>
                            <div class="d-flex align-items-center">
                                <a href="${path}/notice/view?nno=${item.nno}">
                                ${item.title}
                                </a>
                            </div>
                        </td>
                        <td>${item.likeCount}</td>
                        <td>
                            <div class="d-flex">
                                <i class="fas fa-edit mr-3" data-toggle="tooltip" data-placement="top" title="Edit item"></i>
                                <i class="fas fa-trash text-danger mr-2" data-toggle="tooltip" data-placement="top" title="Delete item"></i>
                            </div>
                        </td>
                    </tr>
                </c:forEach>
            </tbody>
        </table>
    </div>

<nav aria-label="Page navigation example">
    <ul class="pagination">
        <li class="page-item">
            <div class="page-link" onclick="movePage(${pageInfo.prevPage});"><i class="fas fa-angle-double-left"></i></div>
        </li>

        <c:forEach begin="${pageInfo.startPage}" end="${pageInfo.endPage}" varStatus="status" step="1">
            <c:if test="${status.current != pageInfo.currentPage}">
            <li class="page-item">
                <div class="page-link" onclick="movePage(${status.current});">${status.current}</div>
            </li>
            </c:if>
            <c:if test="${status.current == pageInfo.currentPage}">
            <li class="page-item active">
                <div class="page-link">${status.current}</div>
            </li>
            </c:if>
        </c:forEach>
        <li class="page-item">
            <div class="page-link" onclick="movePage(${pageInfo.nextPage});"><i class="fas fa-angle-double-right"></i></div>
        </li>
    </ul>
</nav>
</div>