12.07.(수) MVC패턴(3)
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>부분이 두번 적혀있는걸 확인할 수 있다.
이렇게 적혀있어도 문제는 전혀 없지만, 간결하게 보이기 위해서 겹치는 부분을 지워줄 수 있다.