Spring

12.07.(수) MVC패턴(3)

콜라든포비 2022. 12. 8. 00:32

MVC패턴

글 선택 삭제

이제 게시판 목록에서 다중 선택을 해서 하나 이상의 글을 삭제하는 기능을 추가할 것이다.

boardList.jsp에서 checkbox를 모든 글 맨 왼쪽에 생성해주자.

<!-- jQuery 사용 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<script>
	$(function(){
		// 전체선택을 클릭하면 목록의 체크박스 모두를 선택 또는 해제하기
		$("#checkAll").click(function(){
			// $("h1").attr("title","연습");
			// 값 바꾸기 -> $("#bb").prop("checked", true);	// 값 구하기 -> $("#bb").prop("checked"); 
			// $(this) : 이벤트가 발생한 객체			this.checked	
			$(".board-list input[type=checkbox]").prop("checked", $(this).prop("checked"));
		});
	});
</script>
<style>
	.board-list>li:nth-child(6n+3){
		width:56%;
	}
	.board-list>li:nth-child(6n+1){
		width:4%;
	}
</style>
<c:forEach var="vo" items="${ list }">
    <li>
        <c:if test="${ logUsername==vo.username }">
            <input type="checkbox" name="postno" value="${ vo.postno }">
        </c:if>
        <c:if test="${ logUsername!=vo.username }">
            <input type="checkbox" disabled>
        </c:if>
    </li>
    <li>${ vo.postno }</li>
    <li class="word-cut"><a href="<%= request.getContextPath() %>/board/boardView.do?postno=${ vo.postno }">${ vo.subject }</a></li>
    <li>${ vo.username }</li>
    <li>${ vo.hitcount }</li>
    <li>${ vo.regdate }</li>
</c:forEach>

이렇게 체크박스를 추가해줬다.

이제 맨 위에 체크박스를 누르면 전체선택/해제가 되고, 로그인 정보에 따라서 나의 글이 아니면 체크박스를 비활성화시켰다.

이제 체크박스를 이용해서 여러개의 글을 삭제하는 기능을 추가해보자.

글 선택 삭제

삭제명령을 실행할 버튼을 생성하고 url매핑을 해주자.

<script>
		// 선택삭제 버튼 클릭 시
		$("#selectDel").on('click',function(){
			// 최소 1개 이상 선택되어야 이동
			// <input type="checkbox" name="postno" value="15">
			// each() 객체에 대한 반복문
			// obj에 담긴 input태그의 체크여부를 구하여 개수를 구한다
			var checkCount = 0;
			$("input[name=postno]").each(function(i, obj){
				if(obj.checked){
					checkCount++;
				}
			});
			if(checkCount>0){
				if(confirm(checkCount+"개의 글을 삭제하시겠습니까?")){
					$("#delForm").submit();
				}
			}else{
				alert("최소 1개 이상의 글을 선택하세요.");
			}
		});
	});
</script>
<input type="button" value="삭제" id="selectDel">

/board/boardMultiDel.do=com.multi.home.board.CommandBoardMultiDel

체크박스에 들어있는 고유번호 vo.postno값이 몇 개가 체크되었는지 개수를 이용해서 confirm메시지를 날린 후,

확인을 누르면 form으로 감싼 글 목록을 get방식으로 넘겨준다.

<form method="get" action="<%= request.getContextPath() %>/board/boardMultiDel.do" id="delForm">
    <ul class="board-list">
        <li><input type="checkbox" id="checkAll"></li>
        <li>No.</li>
        <li>제목</li>
        <li>작성자</li>
        <li>조회수</li>
        <li>등록일</li>

        <c:forEach var="vo" items="${ list }">
            <li>
                <c:if test="${ logUsername==vo.username }">
                    <input type="checkbox" name="postno" value="${ vo.postno }">
                </c:if>
                <c:if test="${ logUsername!=vo.username }">
                    <input type="checkbox" disabled>
                </c:if>
            </li>
            <li>${ vo.postno }</li>
            <li class="word-cut"><a href="<%= request.getContextPath() %>/board/boardView.do?postno=${ vo.postno }">${ vo.subject }</a></li>
            <li>${ vo.username }</li>
            <li>${ vo.hitcount }</li>
            <li>${ vo.regdate }</li>
        </c:forEach>
    </ul>
</form>

CommandBoardMultiDel.java에서 DAO로 DELETE쿼리문을 날려서 글을 삭제하자.

parameter는 postno라는 동일한 변수명으로 선택한 글의 개수만큼 고유번호가 전달되었다.

이때 request.getParameterValues("postno")를 통해서 parameter를 배열로 받을 수 있다.

package com.multi.home.board;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.multi.home.CommandService;

public class CommandBoardMultiDel implements CommandService {

	@Override
	public String process(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		BoardDAO dao = BoardDAO.getInstance();
		HttpSession session = req.getSession();
		
		// 삭제하기 위해 선택한 postno를 가져오기
		String[] postnoStr = req.getParameterValues("postno");
		int[] postno = new int[postnoStr.length];
		
		for(int i=0; i<postnoStr.length; i++) {
			postno[i] = Integer.parseInt(postnoStr[i]);
		}
		
		int result = dao.boardMultiDel(postno, (String)session.getAttribute("logUsername"));
		
		req.setAttribute("result", result);
		
		return "/board/boardMultiDel.jsp";
	}

}

이때 기존에 없는 boardMultiDel()메소드를 DAO인터페이스에 추가 후, DAO에서 오버라이딩해준 후 로직을 짜면 된다.

// 글 선택 삭제
@Override
public int boardMultiDel(int[] postno, String username) {
    int result = 0;

    try {
        dbConn();

        sql = "DELETE FROM board_tbl WHERE username=? and postno IN (?";
        for(int i=1; i<postno.length; i++) {
            sql += ",?";
        }
        sql += ")";
        pstmt = conn.prepareStatement(sql);

        pstmt.setString(1, username);
        for(int i=0; i<postno.length; i++) {
            pstmt.setInt(i+2, postno[i]);
        }

        result = pstmt.executeUpdate();
    }catch(Exception e) {
        System.out.println("글 선택 삭제 예외");
        e.printStackTrace();
    }finally {
        dbClose();
    }

    return result;
}

마찬가지로 반환값은 실행횟수인 result이다. 실행결과페이지는 이제 간단하게 느껴질 정도이다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!-- CommandBoardMultiDel에서 넘어온 attribute : result -->
<c:if test="${ result==0 }">
	<!-- 글 삭제 실패 -->
	<script>
		alert("글 선택 삭제 실패");
		history.back();
	</script>
</c:if>
<c:if test="${ result>0 }">
	<!-- 글 삭제 성공 location, sendRedirect -->
	<script>
		location.href = "/webMVC/board/boardList.do";
	</script>
</c:if>

액션태그 include로 상단/하단 메뉴바 만들기

이전에 .jspf파일을 액션태그 include로 텍스트를 갖다붙인적이 있다. 이 방식을 이용해서 모든 페이지에서 사용 가능한 기능을 넣은 상단 메뉴바를 만들어보자.

menu.jspf파일을 새로운 include폴더 안에 생성하자.

그리고 해당 .jspf파일을 web.xml에서 jsp-config를 설정해준다.

  <jsp-config>
  	<jsp-property-group>
  		<url-pattern>*.jsp</url-pattern>	<!-- 모든 .jsp파일에 대해서 -->
  		<include-prelude>/include/menu.jspf</include-prelude>	<!-- 페이지 상단에 include -->
        <!-- <include-coda></include-coda> 페이지 하단에 지정한 파일이 include됨 -->
  	</jsp-property-group>
  </jsp-config>

이제 menu.jspf파일을 구성하자.

우리가 홈 화면에서 쓰던 로그인/로그아웃, 게시판 링크를 그대로 가져오면 된다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Menu</title>
<link rel="stylesheet" href="/webMVC/css/style.css" type="text/css">
<style>
	.topMenu{
		height:50px;
		background:lightblue;
	}
	
	.topMenu>ul>li{
		float:left;
		height:50px;
		line-height:50px;
		width:100px;
		text-align:center;
	}
	
	.topMenu>ul>li:last-child{
		width:auto;
	}
</style>
</head>
<body>
	<div class="container">
		<div class="topMenu">
			<ul>
				<li><a href="/webMVC/index.do">홈</a></li>
				<li><a href="/webMVC/board/boardList.do">게시판</a></li>
				<li>
					<c:if test="${ logUsername==null || logUsername=='' }">
						<a href="/webMVC/member/login.do">로그인</a>
					</c:if>
					<c:if test="${ logUsername!=null && logUsername!='' }">
						${ logName }님 반갑습니다! <a href="/webMVC/member/logout.do">로그아웃</a>
					</c:if>
				</li>
			</ul>
		</div>
	</div>
</body>
</html>

빨간 부분의 상단 메뉴바를 모든 페이지에서 볼 수 있다.

페이지 소스를 확인해보면 <!DOCTYPE html>부터 </html>부분이 두번 적혀있는걸 확인할 수 있다.

이렇게 적혀있어도 문제는 전혀 없지만, 간결하게 보이기 위해서 겹치는 부분을 지워줄 수 있다.