본문 바로가기
내가 공부하려고 올리는/JSP\Servlet

[JSP 게시판] Model 2 JSP/Servlet 게시판 만들기(9) - 게시글 상세보기/파일 다운로드/게시글 수정/게시글 삭제

by 결딴력 2022. 1. 18.
반응형

BoardDetailAction

BoardListForm.jsp

- BoardListForm.jsp입니다.

- 게시글 목록 구현하는 부분에 게시글 제목 부분에 <a> 태그를 삽입하여,

  클릭 시 'BoardDetailAction.bo?num=${board.boardNum}&page=${page}'로 이동할 수 있게 했습니다.

- 여기서 'num'과 'page'의 value값인 '${board.boardNum}'과 '${page}'는

  'BoardDetailAction에서 파라미터 값으로 전달됩니다.

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
package jsp.board.action;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import jsp.board.model.BoardBean;
import jsp.board.model.BoardDAO;
import jsp.common.action.Action;
import jsp.common.action.ActionForward;
 
public class BoardDetailAction implements Action{
 
    @Override
    public ActionForward execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ActionForward forward = new ActionForward();
        
        //전달받은 num 파라미터 가져오기
        int num =  Integer.parseInt(request.getParameter("num"));
        //전달받은 page 파라미터 가져오기
        String page = request.getParameter("page");
        
        BoardDAO bDAO = BoardDAO.getInstance();
        //getDetail 메서드 실행
        BoardBean board = bDAO.getDetail(num);
        //조회수 증가를 위해 viewCount 메서드 실행
        boolean result = bDAO.viewCount(num);
        
        //request 객체에 BoardBean객체와 page 값 담기
        request.setAttribute("board", board);
        request.setAttribute("page", page);
 
        if(result) {
            forward.setRedirect(false);
            forward.setPath("BoardDetailForm.bo");
        }
        
        return forward;
    }
    
}
 
cs

- BoardDetailAction.java입니다.

- 전달받은 파라미터 값을 이용해 클릭한 글의 정보를 조회하는 Action 클래스입니다.

- 'num'과 'page' 파라미터 값을 변수에 저장합니다. (17~20번째 줄)

- BoardDAO 객체를 생성하고, 파라미터로 전달받은 'num'값을 이용해

  getDetail() 메서드를 실행해 BoardBean 객체에 저장합니다. (24번째 줄)

- 파라미터로 전달받은 'num'값을 이용해 viewCount() 메서드를 실행

  결과값으로 boolean 타입을 반환합니다. (26번째 줄)

- request 객체에 BoardBean 객체와 page 값을 담습니다. (29~30번째 줄)

- viewCount() 실행 결과 반환 값이 'true'라면 'BoardDetailForm.bo'로 데이터를 'forward'합니다. (32~35번째 줄)

 

getDetail()

- BoardDAO의 getDetail() 메서드입니다.

- 전달받은 'num' 값을 이용해 게시글의 내용을 조회합니다.

- 조회한 내용의 값을 BoardBean 객체에 저장하고 반환합니다.

 

viewCount()

- BoardDAO의 viewCount() 메서드입니다.

- 전달받은 'num'값을 이용해 조회수를 증가하고, 조회수를 증가시켰다면 'true' 값을 반환합니다.

 

 

 

BoardListForm

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 
<!DOCTYPE html>
<html>
    <head>
    <meta charset="UTF-8">
    <title>${board.boardSubject}</title>
    <style type="text/css">
        .container{
            margin-top: 100px;
        }
        .input-group{
            margin-bottom: 5px;
        }
        #btn{
            margin-top: 20px;
        }
        #subject, #content{
            background-color: white;
        }
    </style>
    <script type="text/javascript">
        function detailAction(value) {
            if(value == 0)
            {
                location.href = "BoardUpdateFormAction.bo?num=${board.boardNum}&page=${page}";
            } 
            else if(value == 1
            {
                if(confirm("정말로 삭제하시겠습니까?"))
                {
                    location.href="BoardDeleteAction.bo?num=${board.boardNum}";
                    return true;
                } 
                else 
                {
                    return false;
                }
            } 
            else if(value == 2
            {
                location.href = "BoardListAction.bo?page=${page}";
            }
    }
    </script>
    </head>
    <body>
    <div class="container">
        <input type="hidden" name="boardID" value="${sessionScope.memberID}">
        <!-- 제목, 작성날짜  -->
        <div class="input-group">
            <input id="subject" name="boardSubject" type="text" class="form-control" aria-label="Sizing example input" aria-describedby="inputGroup-sizing-default" value="${board.boardSubject}" readonly/>
            <span class="input-group-text" id="basic-addon2">${board.boardDate}</span>            
        </div>
        <!-- 첨부파일 -->
        <div class="input-group mb-3">
            <span type="text" class="form-control" placeholder="Recipient's username" aria-label="Recipient's username" aria-describedby="basic-addon2">
                <a href="BoardDownloadAction.bo?boardFile=${board.boardFile}">${board.boardFile}</a>
            </span>
            <label class="input-group-text" for="inputGroupFile02">첨부파일</label>
        </div>
        <!-- 내용 -->
        <div class="input-group">
            <textarea id="content" name="boardContent" class="form-control" aria-label="With textarea" rows="20" readonly>${board.boardContent}</textarea>
        </div>
        <!-- 로그인 정보와 boardID 값이 일치하면 수정/삭제 버튼 출력  -->
        <div id="btn" class="d-grid gap-2 d-sm-flex justify-content-sm-center">
            <c:if test="${sessionScope.memberID!=null}">
                <c:if test="${sessionScope.memberID == board.boardID}">
                    <button type="button" class="btn btn-primary btn-sm px-3 gap-3" onclick="detailAction(0)">수정</button>
                    <button type="button" class="btn btn-outline-secondary btn-sm px-3" onclick="detailAction(1)">삭제</button>
                </c:if>
            </c:if>
            <button type="button" class="btn btn-outline-secondary btn-sm px-3" onclick="detailAction(2)">목록</button>
        </div>
    </div>
    </body>
</html>
cs

- BoardListForm.jsp입니다.

- 글 상세보기 화면에서는 글 제목, 글 작성 날짜, 첨부 파일, 글 내용을 출력합니다.

- session에 저장된 memberID의 값이 있고, session에 저장된 memberID와

  BoardListAction 클래스에서 전달한 BoardBean 객체의  boardID 값을 가져와 값이 같다면

  '수정', '삭제' 버튼을 출력합니다. (70~75번째 줄)

- session에 저장된 memberID 값과 상관없이 '목록' 버튼을 출력합니다. (76번째 줄)

- '수정' 버튼을 클릭하는 경우 BoardUpdateFormAction.bo로 이동하며,

  파라미터 값으로 글 번호와 페이지 번호를 전달합니다. (26~29번째 줄)

- '삭제' 버튼을 클릭하는 경우 정말로 내용을 삭제할 것인지 확인창을 출력한 후

  '확인' 버튼을 누르면 BoardDeleteAction.bo로 이동하면 파라미터 값으로 글 번호를 전달합니다. (32~36번째 줄)

- '목록' 버튼을 누를 경우 파라미터 값으로 페이지 번호를 전달하며 BoardListAction.bo로 이동합니다. (44번째 줄)

- 'boardFile'을 출력하는 곳에 <a> 태그를 삽입해 'BoardDownloadAction'을 수행할 수 있게 합니다.(60번째 줄)

 

 

 

 

BoardUpdateFormAction

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
package jsp.board.action;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import jsp.board.model.BoardBean;
import jsp.board.model.BoardDAO;
import jsp.common.action.Action;
import jsp.common.action.ActionForward;
 
public class BoardUpdateFormAction implements Action {
 
    @Override
    public ActionForward execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ActionForward forward = new ActionForward();
        
        String page = request.getParameter("page");
        int num = Integer.parseInt(request.getParameter("num"));
        
        BoardDAO bDAO = BoardDAO.getInstance();
        BoardBean board = bDAO.getDetail(num);
        
        request.setAttribute("board", board);
        request.setAttribute("page", page);
        
        forward.setRedirect(false);
        forward.setPath("BoardUpdateForm.bo");
        
        return forward;
    }
 
}
 
cs

- BoardUpdateFormAction.java 클래스입니다.

- 파라미터로 전달받은 페이지 값과 글 번호를 변수에 저장합니다. (17~18번째 줄)

- BoardDAO 객체의 getDetail() 메서드를 실행합니다. (20~21번째 줄)

- 실행결과를 BoardBean 객체에 저장하여 request 객체에 저장하고,

  전달받은 글 번호(page)도 request 객체에 저장합니다. (23~24번째 줄)

- 'BoardUpdateForm.bo'로 'forward'합니다.

 

 

 

 

BoardUpdateForm

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
    <meta charset="UTF-8">
    <title>수정페이지</title>
    <style type="text/css">
        .container{
            margin-top: 100px;
        }
        .input-group{
            margin-bottom: 5px;
        }
        #btn{
            margin-top: 20px;
        }
    </style>
    
    <script type="text/javascript">
        function checkValue() {
            /* form 태그 가져오기 */
            const form = document.boardForm;
            /* form 태그의 boardSubject, boardContent의 value 가져오기 */
            const subject = form.boardSubject.value;
            const content = form.boardContent.value;
            
            /* 입력이 되지 않았다면 */
            if(!subject) {
                alert("제목을 입력해주세요.");
                return false;
            } else if(!content) {
                alert("내용을 입력해주세요.");
                return false;
            }
        }
        
        function goToList() {
            location.href = "BoardListAction.bo?page=${page}";
        }
    </script>
    </head>
    <body>
        <div class="container">
            <form method="post" action="BoardUpdateAction.bo?page=${page}" name="boardForm" enctype="multipart/form-data" onsubmit="return checkValue()">
                <!-- 파라미터로 전달할 hidden 요소 값 -->
                <input type="hidden" name="boardID" value="${sessionScope.memberID}">
                <input type="hidden" name="boardFile" value="${board.boardFile}">
                <input type="hidden" name="boardNum" value="${board.boardNum}">
                <!-- 제목  -->
                <div class="input-group">
                    <span class="input-group-text" id="inputGroup-sizing-default">제목</span>
                    <input name="boardSubject" type="text" class="form-control" aria-label="Sizing example input" aria-describedby="inputGroup-sizing-default" value="${board.boardSubject}"/>
                </div>
                <!-- 첨부파일 -->
                <div class="input-group mb-3">
                    <input name="newBoardFile" type="file" class="form-control" id="inputGroupFile02">
                    <label class="input-group-text" for="inputGroupFile02">Upload</label>
                </div>
                <!-- 내용 -->
                <div class="input-group">
                    <span class="input-group-text">내용</span>
                    <textarea name="boardContent" class="form-control" aria-label="With textarea" rows="20">${board.boardContent}</textarea>
                </div>
                <!-- 등록/취소 버튼 -->
                <div id="btn" class="d-grid gap-2 d-sm-flex justify-content-sm-center">
                    <input type="submit" class="btn btn-primary btn-sm px-3 gap-3" value="등록"></button>
                    <input type="button" class="btn btn-outline-secondary btn-sm px-3" value="취소" onclick="goToList()"></input>
                </div>
            </form>
        </div>
    </body>
</html>
cs

- BoardUpdateForm.jsp입니다.

- hidden 타입으로 memberID와 파일명, 글 번호를 전달합니다. (47~49번째 줄)

- '취소' 버튼을 누를 경우 페이지 번호를 파라미터 값으로 전달하며 게시판 목록 화면으로 이동합니다.

- '수정' 버튼을 누를 경우 제목과 내용이 모두 입력됐는지 확인합니다. (21~35번째 줄)

 

수정 화면 (1)

- 게시글 상세 보기에서 수정 버튼을 누르면 위와 같은 화면이 출력됩니다.

 

수정 화면 (2)

- 제목이나 내용을 입력하지 않고 등록 버튼을 누르면 위와 같이 경고창이 출력됩니다.

 

수정 화면 (3)

- 첨부 파일이 없던 글에 첨부 파일을 추가하고 등록 버튼을 눌러보겠습니다.

 

수정 화면 (4)

- 위와 같이 첨부파일이 추가된 것을 확인할 수 있습니다.

- 이 상황에서 로그아웃을 해보겠습니다.

 

로그아웃 후 게시글 상세보기

- 로그아웃을 하면 세션에 저장된 회원의 아이디 값이 사라지기 때문에

  '수정', '삭제' 버튼이 사라지고 '목록' 버튼만 출력됩니다.

 

 

 

 

 

BoardDownloadAction

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package jsp.board.action;
 
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
 
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
 
import jsp.common.action.Action;
import jsp.common.action.ActionForward;
 
public class BoardDownloadAction implements Action {
 
    @Override
    public ActionForward execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 다운로드할 파일명을 가져온다.
        String fileName = request.getParameter("boardFile");
 
        // 파일이 있는 절대경로를 가져온다.
        // 현재 업로드된 파일은 UploadFolder 폴더에 있다.
        String folder = request.getServletContext().getRealPath("UploadFolder");
        // 파일의 절대경로를 만든다.
        String filePath = folder + "/" + fileName;
 
        try {
            File file = new File(filePath);
            byte b[] = new byte[(int) file.length()];
            
            // page의 ContentType등을 동적으로 바꾸기 위해 초기화
            response.reset();
            
            // 한글 인코딩
            String encoding = new String(fileName.getBytes("utf-8"),"iso-8859-1");
            
            // 파일 링크를 클릭했을 때 다운로드 저장 화면이 출력되게 처리하는 부분
            response.setHeader("Content-Disposition""attachment;filename="+ encoding);
            response.setHeader("Content-Type""application/octet-stream; charset=utf-8");
            response.setHeader("Content-Length"String.valueOf(file.length()));
 
            if (file.isFile()) // 파일이 있을경우
            {
                FileInputStream fileInputStream = new FileInputStream(file);
                ServletOutputStream servletOutputStream = response.getOutputStream();
                
                //  파일을 읽어서 클라이언트쪽으로 저장한다.
                int readNum = 0;
                // byte 배열의 모든 바이트를 읽어들이기
                while ( (readNum = fileInputStream.read(b)) != -1) {
                    //다 읽어들이면 버퍼를 0부터 byte의 길이만큼 출력
                    servletOutputStream.write(b, 0, readNum);
                }
                
                //stream 객체 닫기
                servletOutputStream.close();
                fileInputStream.close();
            }
            
        } catch (Exception e) {
            System.out.println("Download Exception : " + e.getMessage());
        }
 
        return null;
    }
}
 
cs

- BoardDownloadAction.java 클래스입니다.

- 우선 파일의 절대경로를 얻어옵니다. (20~26번째 줄)

- 파일명을 이용해 파일 객체를 생성하고 Byte 배열을 파일의 길이만큼 생성합니다. (29~30번째 줄)

- response 객체를 초기화합니다.(33번째 줄)

- 다운로드 시 파일 헤더 처리를 어떻게 할 것인지 설정합니다.(39~41번째 줄)

- 파일이 존재하는 경우 'FileInputStream' 객체를 이용해 byte 배열의 모든 byte를 읽어 들이고,

  'ServletOutputStream' 객체를 이용해 버퍼를 0부터 byte 배열의 길이만큼 출력합니다. (50~54번째 줄)

- 출력 후 Stream 객체를 닫습니다. (57~58번째 줄)

다운로드 화면

- 다운로드 시 아래와 같이 파일이 다운로드됩니다. (파일을 두 번 다운로드하여서 위와 같이 출력)

 

 

 

 

BoardDeleteAction

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
54
55
56
57
package jsp.board.action;
 
import java.io.File;
import java.io.FileInputStream;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
 
import jsp.board.model.BoardDAO;
import jsp.common.action.Action;
import jsp.common.action.ActionForward;
 
public class BoardDeleteAction implements Action {
 
    @Override
    public ActionForward execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
        ActionForward forward = new ActionForward();
        BoardDAO bDAO = BoardDAO.getInstance();
        
        //파라미터로 전달받은 페이지 값 저장
        int num = Integer.parseInt(request.getParameter("num"));
        
        //파일 가져오기
        String file = bDAO.getFile(num);
        //파일 삭제하기
        boolean result = bDAO.deleteBoard(num);
        
        //파일이 존재한다면
        if(file != null) {
            //절대 경로 가져오기
            String folderPath = request.getServletContext().getRealPath("UploadFolder");
            
            String filePath = folderPath + "/" +file;
            
            //폴더+파일 네임으로 파일 찾기
            File fileName = new File(filePath);
            //파일이 존재한다면 파일 삭제
            if(fileName.exists()) {
                fileName.delete();
            }
        }
        
        //삭제가 진행되었다면
        if(result) {
            //redirect
            forward.setRedirect(true);
            forward.setPath("BoardListAction.bo");
        } else {
            return null;
        }
        
        return forward;
    }
 
}
 
cs

- BoardDeleteAction.java 클래스입니다.

- 파라미터로 전달받은 페이지 번호를 변수에 저장합니다. (22번째 줄)

- BoardDAO 객체를 생성하고 getFile() 메서드를 실행합니다 (25번째 줄)

- 전달받은 페이지 번호를 이용해 deleteBoard() 메서드를 실행합니다. (27번째 줄)

- getFile() 결과 파일명이 존재한다면 폴더의 절대 경로와 파일명을 더해 파일 삭제를 진행합니다. (30~42번째 줄)

- deleteBoard() 메서드가 성공적으로 실행되면 'true'값이 반환되고,

  'BoardListAction.bo'로 페이지가 'redirect'됩니다. (45~48번째 줄)

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
54
55
56
57
58
59
60
61
62
63
    // 삭제할 파일명을 가져오기 위한 메서드
    public String getFile(int num) {
        String file = null;
        
        DBConnection dbConnection = null;
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        
        try {
            dbConnection = DBConnection.getInstance();
            conn = dbConnection.getConnection();
            
            StringBuffer sql = new StringBuffer();
            sql.append("SELECT BOARD_FILE FROM BOARD WHERE BOARD_NUM = ?");
            
            pstmt = conn.prepareStatement(sql.toString());
            pstmt.setInt(1, num);
            
            rs = pstmt.executeQuery();
            
            if(rs.next()) {
                file = rs.getString("BOARD_FILE");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            dbConnection.freeConnection(conn, pstmt, rs);
        }
        
        return file;
    }
    
    // 글을 삭제하기 위한 메서드
    public boolean deleteBoard(int num) {
        boolean result = false;
        
        DBConnection dbConnection = null;
        Connection conn = null;
        PreparedStatement pstmt = null;
        
        try {
            dbConnection = DBConnection.getInstance();
            conn = dbConnection.getConnection();
            
            StringBuffer sql = new StringBuffer();
            sql.append("DELETE FROM BOARD WHERE BOARD_NUM = ? ");
            
            pstmt = conn.prepareStatement(sql.toString());
            pstmt.setInt(1, num);
            
            int updateCount = pstmt.executeUpdate();
            if(updateCount > 0) {
                result = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            dbConnection.freeConnection(conn, pstmt);
        }
        
        return result;
    }
cs

- getFile(), deleteBoard() 메서드입니다.

- 두 메서드 모두 전달받은 페이지 번호를 파라미터로 사용합니다.

- getFile() 메서드는 file명을, deleteBoard() 메서드는 boolean 값을 리턴합니다.

 

글 삭제 버튼

- 글 삭제 버튼을 누르면 위와 같은 화면이 출력됩니다.

 

글 삭제 후 화면

- 삭제 버튼을 누르면 위와 같이 게시판에 글이 삭제된 것을 확인할 수 있습니다.

 

 

 


오늘은 게시글 상세보기, 게시글 수정, 게시글 삭제, 파일 다운로드를 구현하는 방법을 살펴봤습니다.

 

해당 프로젝트는 여기까지 구현하려고 합니다.

 

이후에는 스프링을 이용해

웹페이지의 확실한 컨셉을 선정한 이후에

다중 첨부파일 구현이나

댓글 및 추천 기능 구현, 아이디 중복 검사 구현,

가입시 작성한 이메일로 아이디나 비번 찾기 기능 구현 등

다양한 API를 활용해 프로젝트를 확장해 볼 예정입니다.

 

스프링으로 웹 프로젝트를 진행하게 되면

블로그글도 바로 업데이트 하겠습니다.

 

다음 글은 해당 프로젝트 마지막 글로

프로젝트 배포를 할 예정입니다.

 

여기까지 긴 글 읽어주셔서 감사하고

이해가 안가는 내용은 댓글 부탁드립니다!

감사합니다!

반응형

댓글