quilt code

[전자정부프레임워크] 게시판 만들기 (1) 본문

weekly/게시판 만들기

[전자정부프레임워크] 게시판 만들기 (1)

김뱅쇼 2023. 12. 21. 17:39

ojt 기간에 했던 crud 게시판 만들기 정리글

빠르고 간략하게 정리해봐야겠다!

 

DB연결, 게시판 crud

 

 

0. DB연결

 

1) pom.xml

: pom에 설정 추가

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
<!-- mysql이나 oracle DB 사용시 아래 설정 추가 -->
        <dependency>
            <groupId>com.googlecode.log4jdbc</groupId>
            <artifactId>log4jdbc</artifactId>
            <version>1.2</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-api</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>
 
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
        </dependency>
 
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.31</version>
        </dependency>
 
        <dependency>
            <groupId>ojdbc</groupId>
            <artifactId>ojdbc</artifactId>
            <version>6</version>
            <scope>system</scope>
            <systemPath>${basedir}/src/main/webapp/WEB-INF/lib/ojdbc6-11.2.0.4.jar</systemPath>
        </dependency>
cs

 

oracle db 사용시

1
2
3
4
5
6
<!-- oracle db -->
        <dependency>
            <groupId>com.oracle.database.jdbc</groupId>
            <artifactId>ojdbc6</artifactId>
            <version>11.2.0.4</version>
        </dependency>
cs

 

 

2) context-datasource.xml

: url, username, password 입력

 

참고) https://ss-o.tistory.com/157

 

 

 

* 파일목록 *

 

 

 

1. 게시판 create

 

1) BoardMapper.xml

create 쿼리

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!-- 게시글 작성 -->
    <insert id="insertTest" parameterType="egovframework.example.board.vo.BoardVo">
        <selectKey resultType="int" order="BEFORE" keyProperty="boardNo">
            SELECT AUTONUM.NEXTVAL FROM DUAL
        </selectKey>
        INSERT INTO BOARD (
                        boardNo
                        ,title
                        ,content
                        ,memId
                        ,regDate
                        ,boardDelYn
                        
                    ) VALUES (
                        #{boardNo}
                        ,#{title}
                        ,#{content}
                        ,#{memId}
                        ,SYSDATE
                        ,'n'
                    )
    </insert>
cs

boardDelYn : delete 처리 하지 않고 DB에 삭제 여부로 판단. 기본값 n으로 설정 후 삭제 update 처리 시 y로 변경

 

 

2) BoardController.java



1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 게시글 작성 페이지 이동
    @RequestMapping(value = "/register.do")
    public String testRegister() {
        return "board/register";
    }
 
    // 게시글 등록
    @RequestMapping(value = "/insertTest.do")
    public String write(@ModelAttribute("boardVo") BoardVo boardVo, HttpSession session) throws Exception {
//        System.out.println("내용:"+ boardVo.getContent());
 
        boardService.insertTest(boardVo);
        return "redirect:list.do";
    }
cs




게시글 작성 페이지로 이동하는 메소드, 게시글 등록(insert) 메소드 따로 존재

 

 

3)  register.jsp


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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
<%@ 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 PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>게시글 작성</title>
 
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<script type="text/javascript" src="<c:url value='/js/egovframework/com/cmm/fms/EgovMultiFile.js'/>" ></script>
<%@ include file="/WEB-INF/jsp/member/menu.jsp" %>
<style type="text/css">
a{
 text-decoration: auto;
}
</style>
</head>
<body>
<String memId = (String)session.getAttribute("memId"); %>
<c:set var="memId" value="<%=memId%>" />
 
<br/>
    <h1 class="text-center">게시글 작성</h1>
<br/>
<br/>
<div class="container">
        <form id="form_test" action="insertTest.do" method="post" encType="multipart/form-data">
            <input type="hidden" id="memId" name="memId" value="<%=memId%>" />
            <table class="table table-bordered">
                <tbody>
                    <tr> 
                        <th>제목</th>
                        <td><input type="text" placeholder="제목을 입력하세요."
                            name="title" class="form-control" /></td>
                    </tr>
                    <tr>
                        <th>내용</th>
                        <td><textarea placeholder="내용을 입력하세요." name="content"
                                class="form-control" style="height: 200px;"></textarea></td>
                    </tr>
                    <tr>
                        <th>첨부파일</th>
                        <div class="divFile"> 
                            <td><input type="file" class="files form-control form-control-sm" id="fileUpload" name="fileUpload" multiple ></td> 
                        </div>
                        <div id="uploadedList"></div>
                      </tr>
                    <tr>
                        <td colspan="2" style="text-align: right;">
                            <button id="btn_register" type="button" class="btn btn-success me-1 mb-1">등록</button>
<!--                             <button id="btn_file" type="button" class="btn btn-success me-1 mb-1">파일확인용</button> -->
                            <button id="btn_previous" type="button" class="btn btn-danger me-1 mb-1">취소</button>
                    </tr>
                </tbody>
            </table>
        </form>
        
        
</div>
 
 
 
</body>
<script type="text/javascript">
 
    //글쓰기
    $(document).on('click''#btn_register'function(e) {
        var title = document.getElementsByName("title")[0].value;
        var content = document.getElementsByName("content")[0].value;
        var memId = document.getElementsByName("memId")[0].value;
        
//         console.log("title:",title);
//         console.log("content:",content);
//         console.log("memId:",memId);
        
        if(title == "" || title == null){
            alert("제목을 작성해주세요!");
            document.getElementById("title").focus();
            return;
        }
        
        if(content == "" || content == null){
            alert("내용을 작성해주세요!");
            document.getElementById("content").focus();
            return;
        }
        
        
        //form태그 방식
        $("#form_test").submit();
//         console.log('gogo');
       /*
       //ajax 방식
       var formData = new FormData(document.getElementById("form_test"));
       
        $.ajax({
            type: "POST",
            url: "/insertTest.do",
            data: formData,
            processData: false,
            contentType: false,
            success: function(data) {
                // 성공 시 처리 (필요하면)
                console.log("성공:", data);
            },
            error: function(error) {
                // 오류 시 처리 (필요하면)
                console.log("오류:", error);
            }
        });
        */
       
       
       
    });
 
    //이전 클릭 시 testList로 이동
    $("#btn_previous").click(function previous() {
        $(location).attr('href''list.do');
 
    });
    
    
    
    //파일업로드
    /*
    $(document).
    
    
    var formData = new FormData(document.getElementById('myForm'));    
    
    $.ajax({
       type:"POST",
       enctype: 'multipart/form-data',
       processData:false,
       contentType:false,
       url:"/test",
       data:formData,
       success:function(data){
       console.log("success") 
       
       }
    
    }); 
    
    
    $(document).ready(function(){
        
        $("#btn_file").on("click",function(e){
            var formData = new FormData();
            var inputFile = $("input[name='uploadFile']");
            
            
            
            var files = inputFile[0].files;
            console.log(files);
            
            //add File Data to formData
            for(var i = 0; i < files.length; i++){
                formData.append("uploadFile", files[i]);
            }
            
            $.ajax({
                   url:"/uploadAjax.do",
                   processData:false,
                   contentType:false,
                   data:formData,
                   type:"POST",
//                    enctype: 'multipart/form-data',
                   success:function(data){
//                        console.log("success"); 
                       alert("업로드 성공!!");
                   }
            }); //ajax
        });
    });    
            */
            
    
    
    
    
</script>
</html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cs
form 태그 방식으로 db전송

 

 

 

 

2. 게시판 update

 

1) BoardMapper.xml


1
2
3
4
5
6
7
8
9
10
11
    <!-- 게시글 수정 -->
        <update id="updateTest" parameterType="egovframework.example.board.vo.BoardVo">
               UPDATE BOARD
            SET
                title = #{title}
                ,content = #{content}
            
            WHERE
                boardNo = #{boardNo}
        </update>    
        
cs


boardNo을 PK로 잡아서 update 처리

 

 

2) BoardController.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 게시글 수정 페이지로 이동
    @RequestMapping(value = "/update.do", method = RequestMethod.GET)
    public String updateTest(int boardNo, Model model) throws Exception {
        BoardVo boardVo = this.boardService.selectDetail(boardNo);
        model.addAttribute("vo", boardVo);
        return "board/update";
    }
    
    // 게시글 수정
    @RequestMapping(value = "/updateTest.do", method = RequestMethod.POST)
    public String updateTest(BoardVo boardVo) throws Exception {
        boardService.updateTest(boardVo);
        return "redirect:list.do";
    }
cs

update 페이지로 이동 메소드, update 수정 처리 메소드 

 

 

3) update.jsp





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
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>게시글 수정하기</title>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<%@ include file="/WEB-INF/jsp/member/menu.jsp" %>
<style type="text/css">
a{
 text-decoration: auto;
}
</style>
</head>
<body>
    <br />
    <h1 class="text-center">게시글 수정하기</h1>
    <br />
    <br />
    <div class="container">
        <form action="updateTest.do" id="viewForm" method="post"
            encType="multiplart/form-data">
            <table class="table table-bordered">
                <tbody>
                    <tr>
                        <th>글번호</th>
                        <td><input name="boardNo" type="text" value="${vo.boardNo}"
                            class="form-control" readonly /></td>
                    </tr>
                    <tr>
                        <th>제목</th>
                        <td><input type="text" value="${vo.title}"
                            name="title" class="form-control" /></td>
                    </tr>
                    <tr>
                        <th>내용</th>
                        <td><textarea name="content" class="form-control"
                                style="height: 200px;">${vo.content}</textarea></td>
                    </tr>
                    <tr>
                        <th>첨부파일</th>
                        <td><input type="file" name="uploadFile" class="files form-control form-control-sm"></td> 
                      </tr>
                    <tr>
                        <td colspan="2" style="text-align: right;">
                            <button id="btn_modify" type="button" class="btn btn-primary me-1 mb-1">수정</button>
                            <button id="btn_previous" type="button" class="btn btn-secondary me-1 mb-1">취소</button>
                        </td>
                    </tr>
                </tbody>
            </table>
        </form>
    </div>
</body>
<script type="text/javascript">
    $(document).on('click''#btn_modify'function(e) {
        if (confirm("정말 수정하시겠습니까?"== true) {
            $("#viewForm").submit();
        } else {
            return
        }
    });
 
    //목록 클릭 시 list로 이동
    $("#btn_previous").click(function previous() {
        $(location).attr('href''list.do');
 
    });
</script>
</html>
 
cs
form

 

 

3. 게시판 delete

: 실제 db는 사라지지 않음

 

1) BoardMapper.xml


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    <!-- 게시글 삭제 -->
    <!-- 실제 db까지 삭제하는 경우의 쿼리 (boardNo를 pk로 잡아서 삭제)     
        <delete id="deleteTest" parameterType="Integer">
            DELETE FROM BOARD
            WHERE boardNo = #{boardNo}
        </delete>
      -->   
        <update id="deleteTest" parameterType="egovframework.example.board.vo.BoardVo" >
            UPDATE BOARD 
            SET
                boardDelYn = 'y' 
            WHERE 
                boardNo = #{boardNo}
        
        
        </update>
cs
insert할 때 boardDelYn의 기본값을 n으로 줌 -> delete처리할 때 y로 update시켜서 처리함 : 화면단에서는 삭제된걸로 보이지만 DB 상에는 존재

 

 

2) BoardController.java


1
2
3
4
5
6
7
// 게시글 삭제
    @RequestMapping(value = "/deleteTest.do")
    public String deleteTest(HttpServletRequest request) throws Exception {
        int boardNo = Integer.parseInt(request.getParameter("boardNo"));
        boardService.deleteTest(boardNo);
        return "redirect:list.do";
    }
cs


삭제처리 후 list로 redirect

 

 

 

4. 게시판 목록

 

1) BoardMapper.xml

 


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
<!-- 게시글 목록 -->
    <select id="selectTest" parameterType="egovframework.example.board.vo.Pagination" resultType="egovframework.example.board.vo.BoardVo">
        SELECT *
            FROM(
                SELECT ROWNUM as RNUM, t.*
                FROM
                (
                    SELECT *
                    FROM BOARD
                    <where>
                        <if test="searchType=='title' and keyword != null and keyword !=''">
                            AND title like CONCAT('%',#{keyword},'%')
                        </if>
                        <if test="searchType=='content' and keyword != null and keyword !=''">
                            AND content like CONCAT('%',#{keyword},'%')
                        </if>
                        <if test="searchType=='memId' and keyword != null and keyword !=''">
                            AND memId like CNCAT('%',#{keyword},'%')
                        </if>
                    </where>
                    ORDER BY boardNo DESC
                ) t
                WHERE ROWNUM <![CDATA[<=]]> #{startList}+#{listSize}
                    AND boardDelYn = 'n'    
            )
        WHERE RNUM <![CDATA[>=]]> #{startList} 
            
        
    </select>
cs
10개씩/5페이지씩 페이징 처리

 

 

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
// 글목록페이지,페이징,검색
    @RequestMapping(value = "/list.do")
    public String testListDo(Model model, @RequestParam(required = false, defaultValue = "1"int page,
            @RequestParam(required = false, defaultValue = "1"int range,
            @RequestParam(required = false, defaultValue = "title"String searchType,
            @RequestParam(required = falseString keyword, @ModelAttribute("search") Search search) throws Exception {
 
        // 검색
        model.addAttribute("search", search);
        search.setSearchType(searchType);
        search.setKeyword(keyword);
 
        // 전체 게시글 개수
        int listCnt = boardService.getBoardListCnt(search);
        
        System.out.println("전체 게시글 개수 : " + listCnt);
        
        // 검색 후 페이지
        search.pageInfo(page, range, listCnt);
        // 페이징
        model.addAttribute("pagination", search);
        // 게시글 화면 출력
        model.addAttribute("list", boardService.selectTest(search));
        
        return "board/list";
    }
cs


페이징 처리 메소드 포함

 

 

3) list.jsp





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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
<%@ 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 PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>게시판</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.4.1.js"></script>
<style type="text/css">
a{
 text-decoration: auto;
}
.row>*{
    width:auto;
}
</style>
</head>
<body>
<%@ include file="/WEB-INF/jsp/member/menu.jsp" %>
    <br/>
    <h1 class="text-center">게시판</h1>
    <br/>
    <br/>
    <div class="container">
        <table class="table table-hover text-center" >
            <colgroup>
                <col width="10%" />
                <col width="50%" />
                <col width="20%" />
                <col width="20%" />
            </colgroup>
            <thead>
                <tr>
                    <th>번호</th>
                    <th>제목</th>
                    <th>작성자</th>
                    <th>등록일자</th>
                </tr>
            </thead>
 
            <tbody>
            <c:forEach items="${list}" var="result">
                <tr>
                    <td>${result.boardNo}</td>
                    <td><a href="detail.do?boardNo=${result.boardNo}">${result.title}
                        <c:if test="${result.cmntCnt ne 0}">
                            <small><b>[&nbsp;<c:out value="${result.cmntCnt}"/>&nbsp;]</b></small>
                        </c:if>
                    </a></td>
                    <td>${result.memId}</td>
                    <td>${result.regDate}</td>
                    
                </tr>
            </c:forEach>
            </tbody>
        </table>
        <!-- pagination start -->
        <div id="paginationBox" class="pagination1">
            <ul class="pagination" style="justify-content: center;">
 
                <c:if test="${pagination.prev}">
                    <li class="page-item"><a class="page-link" href="#"
                        onClick="fn_prev('${pagination.page}', '${pagination.range}', '${pagination.rangeSize}', '${pagination.listSize}'
                    ,'${search.searchType}', '${search.keyword}')">이전</a></li>
                </c:if>
 
                <c:forEach begin="${pagination.startPage}" end="${pagination.endPage}" var="boardNo">
                    <li class="page-item <c:out value="${pagination.page == boardNo ? 'active' : ''}"/> ">
                    <a class="page-link" href="#"
                        onClick="fn_pagination('${boardNo}', '${pagination.range}', '${pagination.rangeSize}', '${pagination.listSize}'
                     ,'${search.searchType}', '${search.keyword}')">
                            ${boardNo} </a></li>
                </c:forEach>
 
                <c:if test="${pagination.next}">
                    <li class="page-item"><a class="page-link" href="#"
                        onClick="fn_next('${pagination.range}', '${pagination.range}', '${pagination.rangeSize}', '${pagination.listSize}'
                    ,'${search.searchType}', '${search.keyword}')">다음</a></li>
                </c:if>
            </ul>
        </div>
        <!-- pagination end -->
        <hr />
        
        <a class="btn btn-primary me-1 mb-1" style="float: right" href="register.do">글쓰기</a>
 
        <!-- search start -->
        <!--  
        <div class="form-group row">
 
            <div class="w100" style="padding-right: 10px">
                <select class="form-control form-control-sm" name="searchType" id="searchType">
                    <option value="title">제목</option>
                    <option value="content">내용</option>
                    <option value="name">작성자</option>
                </select>
            </div>
 
            <div class="w300" style="padding-right: 10px">
                <input type="text" class="form-control form-control-sm" name="keyword" id="keyword">
            </div>
 
            <div>
                <button class="btn btn-sm btn-primary" name="btnSearch" id="btnSearch">검색</button>
            </div>
 
        </div>
        -->
        <!-- search end -->
    
    </div>
    <br>
    <script
        src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-ygbV9kiqUc6oa4msXn9868pTtWMgiQaeYH7/t7LECLbyPA2x65Kgf80OJFdroafW"
        crossorigin="anonymous"></script>
 
    <script
        src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.5.4/dist/umd/popper.min.js"
        integrity="sha384-q2kxQ16AaE6UbzuKqyBE9/u/KzioAlnx2maXQHiDX9d4/zp8Ok3f+M7DPm+Ib6IU"
        crossorigin="anonymous"></script>
    <script
        src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.min.js"
        integrity="sha384-pQQkAEnwaBkjpqZ8RU1fF1AKtTcHJwFl3pblpTlHXybJjHpMYo79HY3hIi4NKxyj"
        crossorigin="anonymous"></script>
</body>
    <script type="text/javascript">
    //이전 버튼 이벤트
    //5개의 인자값을 가지고 이동 testList.do
    //무조건 이전페이지 범위의 가장 앞 페이지로 이동
    function fn_prev(page, range, rangeSize, listSize, searchType, keyword) {
            
        var page = ((range - 2* rangeSize) + 1;
        var range = range - 1;
            
        var url = "/list.do";
        url += "?page=" + page;
        url += "&range=" + range;
        url += "&listSize=" + listSize;
        url += "&searchType=" + searchType;
        url += "&keyword=" + keyword;
        location.href = url;
        }
 
 
    //페이지 번호 클릭
    function fn_pagination(page, range, rangeSize, listSize, searchType, keyword) {
 
        var url = "/list.do";
            url += "?page=" + page;
            url += "&range=" + range;
            url += "&listSize=" + listSize;
            url += "&searchType=" + searchType;
            url += "&keyword=" + keyword; 
 
            location.href = url;    
        }
 
    //다음 버튼 이벤트
    //다음 페이지 범위의 가장 앞 페이지로 이동
    function fn_next(page, range, rangeSize, listSize, searchType, keyword) {
        var page = parseInt((range * rangeSize)) + 1;
        var range = parseInt(range) + 1;            
        var url = "/list.do";
            url += "?page=" + page;
            url += "&range=" + range;
            url += "&listSize=" + listSize;
            url += "&searchType=" + searchType;
            url += "&keyword=" + keyword;
            location.href = url;
        }
        
    // 검색
    $(document).on('click''#btnSearch'function(e){
        e.preventDefault();
        var url = "/list.do";
        url += "?searchType=" + $('#searchType').val();
        url += "&keyword=" + $('#keyword').val();
        location.href = url;
        console.log(url);
 
    });    
 
    </script>
</html>
 
cs

 

 

5. 게시글 상세보기

 

1) BoardMapper.xml


1
2
3
4
5
6
7
    <!--게시글 상세보기 -->
        <select id="selectDetail" parameterType="Integer" resultType="egovframework.example.board.vo.BoardVo">
            SELECT * FROM BOARD
            WHERE boardNo = #{boardNo}
                AND boardDelYn = 'n'
        </select>    
        
cs


pk: boardNo

 

 

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
// 게시글 상세보기
    @RequestMapping(value = "/detail.do")
    public String viewForm(Model model, CmntVo cmntVo, HttpServletRequest request) throws Exception {
        int boardNo = Integer.parseInt(request.getParameter("boardNo"));
        
        //게시글 상세보기
        BoardVo boardVo = boardService.selectDetail(boardNo);
        model.addAttribute("vo", boardVo);
        
        //댓글 목록
//        List<CmntVo> comment = boardService.listCmnt(boardNo);
//        model.addAttribute("comment",comment);
        
        //대댓글 목록
        List<CmntVo> reply = boardService.listReply(boardNo);
        model.addAttribute("comment",reply);
        
        //댓글 갯수
        int cmntCnt = boardService.updateReplyCount(boardNo);
        model.addAttribute("cmntCnt",cmntCnt);
 
        return "board/detail";
    }
cs
댓글 대댓글 기능 추후 서술

 

 

3) detail.jsp




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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
<%@page import="egovframework.example.board.vo.CmntVo"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>게시판 상세보기</title>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/js/bootstrap.bundle.min.js" integrity="sha384-..." crossorigin="anonymous"></script>
<style type="text/css">
a{
 text-decoration: auto;
}
 
</style>
 
<%@ include file="/WEB-INF/jsp/member/menu.jsp" %>
 
</head>
 
<body>
<
 
    String memId = (String)session.getAttribute("memId"); 
    CmntVo cmntVo = (CmntVo)request.getAttribute("cmntVo");
    
%>
    <br />
    <h1 class="text-center">게시글 상세보기</h1>
    <br />
    <br />
    <div class="container" id="boardArea">
        <form action="updateTest.do" id="viewForm" method="post" encType="multiplart/form-data">
            <table class="table table-bordered">
                <tbody>
                    <input type="hidden" name="memId" id="memId" value="<%=memId %>" />
                    <tr>
                        <th>글번호</th>
                        <td><input name="boardNo" type="text" value="${vo.boardNo}"
                            class="form-control" readonly /></td>
                    </tr>
                    <tr>
                        <th>제목</th>
                        <td><input type="text" value="${vo.title}"
                            name="title" class="form-control" readonly /></td>
                    </tr>
                    <tr>
                        <th>작성자</th>
                        <td><input type="text" value="${vo.memId}"
                            name="title" class="form-control" readonly /></td>
                    </tr>
                    <tr>
                        <th>내용</th>
                        <td><textarea readonly name="content" class="form-control"
                                style="height: 200px;">${vo.content}</textarea></td>
                    </tr>
<!--                     <tr> -->
<%--                         <c:if test="${vo.fileName ne null}"> --%>
<!--                             <tr> -->
<!--                                 <th>다운로드</th> -->
<%--                                 <td><a href="fileDownload.do?fileName=${vo.fileName}"> --%>
<%--                                     <input type="text" id="filename" value="${vo.fileName}" name="fileName" class="form-control" readonly="readonly" /></a> --%>
<!--                             </tr> -->
<%--                         </c:if> --%>
<!--                     </tr> -->
                    <tr>
                        <td colspan="2" style="text-align: right;">
                            <button id="btn_previous" type="button" class="btn btn-secondary me-1 mb-1">목록</button>
                            <button id="btn_modify" type="button" class="btn btn-success me-1 mb-1">수정</button>
<%--                             <a href="/update?no=${vo.boardNo}" role="button" class="btn btn-success me-1 mb-1">수정2</a> --%>
                            <button id="btn_delete" type="button" class="btn btn-danger me-1 mb-1">삭제</button>
                        </td>
                    </tr>
                </tbody>
            </table>
        </form>
    </div>
 
    
    
<!-- ///////////// 댓글 시작 /////////////-->
 
<!-- 댓글 출력 시작 -->
    <div class="container" id="cmcmArea">
        <h5>[댓글 목록]</h5>
        <div id="commentArea" class="list-group">
            <c:forEach items="${comment}" var="result" varStatus="stat" >
                <hr/>
<%--                    <c:if test="${result.cmntDelYn == 'n'}"> --%>
                    <!-- 댓글 목록 -->    
                    <c:if test="${result.cmntDepth == 0}">
                        <div id="comment_${result.cmntNo}">
                            <input type="hidden" id="boardNo" value="${result.cmntNo}" />
                            <p></p>
                            <p>댓글 내용: </p>
                            <name="cmtCnt">${result.cmntContent}</p>
                            <p>작성자: ${result.memId}</p>
                            <p>작성일시: <fmt:formatDate value="${result.cmntDate}" pattern="yyyy-MM-dd HH:mm:ss"/>
                            <p></p>
<%--                             <button type="button" id="replyOpen" data-id="replyWrite${stat.count}" class="btn btn-outline-secondary btn-sm hiddenContent">답글 달기</button> --%>
                            <button type="button" id="replyOpen" data-id="comment_${result.cmntNo}" class="btn btn-outline-secondary btn-sm hiddenContent">답글 달기</button>
                            <button type="button" class="btn btn-outline-primary btn-sm cmntBtnMod" 
                                    data-bs-toggle="modal" 
                                    data-bs-target="#myModal"
                                    onclick="showCommentContents(${result.cmntNo})"
                                    >
                                    수정</button>
                            <button type="button" class="btn btn-outline-danger btn-sm cmntBtnDel" id="deleteComment-${result.cmntNo}" onclick="deleteComment(${result.cmntNo})">삭제</button>
                        </div>
                    <!-- 대댓글 작성 -->
                        <div class="container" id="hiddenContent_${result.cmntNo}" >
                            <form class="modifyViews" method="post" name="id123" id="replyWrite${stat.count}" action="/insertReply.do">
                                <div style="margin-top: 30px;" >
                                    <div class="mb-3 d-flex align-items-center">
                                        <input type="hidden" id="replyWriter"  value="<%=memId%>" /> 
                                        <input type="hidden" id="boardNo1" value="${vo.boardNo}" />
<%--                                         <input type="hidden" id="parentCmntNo" value="${result.cmntNo}" /> --%>
                                        <input type="hidden" id="replyNo_${result.cmntNo}" name="cmntNo2" value="${result.cmntNo}" /> 
                                        <input id="reContent" name="reContent" class="form-control me-1" type="text" placeholder="댓글을 입력해 주세요" aria-label="default input example" style="width: 95%;"></ipnut>
                                      <button type="button" onclick="replyGogo(${result.cmntNo})" class="btn btn-primary btn-sm">등록</button>
                                    </div>
                                </div>
                            </form>
                        </div>
                    </c:if>
                    <!-- 대댓글 목록 -->
                    <c:if test="${result.cmntDepth == 1}">
                        <div id="comment1_${result.cmntNo}" style="margin-left: 5%;">
                            <input type="hidden" id="boardNo" value="${result.cmntNo}" />
                            <p>↳댓글 내용: </p>
                            <name="cmtCnt">${result.cmntContent}</p>
                            <p>작성자: ${result.memId}</p>
                            <p>작성일시: <fmt:formatDate value="${result.cmntDate}" pattern="yyyy-MM-dd HH:mm:ss"/>
                            <p></p>
                            <button type="button" class="btn btn-outline-primary btn-sm cmntBtnMod" 
                                    data-bs-toggle="modal" 
                                    data-bs-target="#myModal"
                                    onclick="showCommentContents(${result.cmntNo})"
                                    >
                                    수정</button>
                            <button type="button" class="btn btn-outline-danger btn-sm cmntBtnDel" id="deleteComment1-${result.cmntNo}" onclick="deleteComment(${result.cmntNo})">삭제</button>
                        </div>
                    </c:if>
                    
<%--                    </c:if> --%>
                </c:forEach>
                        <!-- 대댓글 끝 -->
                <!-- 삭제된 댓글 출력 -->
                   <c:if test="${result.cmntDelYn == 'y'}">
                       <div class="col-md-7 py-2" id="comment" data-cmntno="${result.cmntNo}">삭제된 댓글 입니다</div>
                       <hr/>
                   </c:if>
        </div>
    </div>
 
<!-- 댓글 출력 끝 -->
 
<!-- 댓글 작성 시작-->
    <div class="container">
        <form method="post" id="cmntWrite" action="/insertCmnt.do">
            <div id="commentDiv" style="margin-top: 30px;" >
                <div class="mb-3 d-flex align-items-center">
                    <input type="hidden" id="cmntWriter" value="<%=memId%>" />
                    <input type="hidden" id="boardNo" value="${vo.boardNo}" />
<%--                     <input type="hidden" id="cmntNo" value="${cmnt.cmntNo}" />  --%>
                    <textarea id="cmntContent" class="form-control me-1" type="text" placeholder="댓글을 입력해 주세요" aria-label="default input example" style="width: 95%;" ></textarea>
                  <button type="button" id="cmntBtn" class="btn btn-primary ">등록</button>
                </div>
            </div>
        </form>
    </div>
<!-- 댓글 작성 끝-->
 
<!-- 댓글 수정 모달 시작 -->
<div class="modal fade" id="myModal" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog modal-dialog-centered" role="document" style="max-width: 500px">
        <div class="modal-content position-relative">
            <div class="modal-body p-0">
                <div class="rounded-top-lg py-3 ps-4 pe-6 bg-light">
                  <h4 class="mb-1" id="modalExampleDemoLabel">댓글 수정창</h4>
                </div>
                <div class="p-4 pb-0">
                  <form>
                    <input class="form-control" id="cmntNo1" name="cmntNo1" readonly />
                    <div class="mb-3">
                      <label class="col-form-label" for="message-text">댓글 내용</label>
                      <textarea class="form-control" id="writeModComment" name="writeModComment" type="text" placeholder="댓글 내용을 입력해주세요"></textarea>
                    </div>
                  </form>
                </div>  
            </div>
            <div class="modal-footer">
                <button class="btn btn-primary cmntModalMod" id="commentModModalConfirm" type="button" value="true">수정</button>
                <button class="btn btn-secondary modalCancle" id="commentModModalCancle" type="button" data-bs-dismiss="modal">취소</button>
            </div>
        </div>
    </div>
</div>
<!-- 댓글 수정 모달 끝 -->
 
 
<!-- //////////// 댓글 끝 /////////////// -->
</body>
 
 
<script type="text/javascript">
 
 
    
 
    // 게시글 삭제
    $(document).on('click''#btn_delete'function(e) {
        var boardNo = ${vo.boardNo};
        if (confirm("정말 삭제하시겠습니까 ?"== true) {
            $("#viewForm").attr("action""deleteTest.do?boardNo="+boardNo);
            $("#viewForm").submit();
//             console.log("삭제");
        } else {
            return;
        }
    });
    
    //수정 클릭 시 update로 이동
    $("#btn_modify").click(function() {
        window.location.href = "/update.do?boardNo=" + ${vo.boardNo};
 
    });
    
 
    //목록 클릭 시 list로 이동
    $("#btn_previous").click(function previous() {
        $(location).attr('href''list.do');
 
    });
    
    
      //댓글작성
    $("#cmntBtn").on("click"function() {
       console.log("댓글 올라가세용");
       
       var cmntContent = $("#cmntContent").val();
       console.log("댓글내용 : "+ cmntContent);
       
       
       var memId =$("#memId").val();
       console.log("작성자 : " + memId)
       
       var boardNo = $("input[name='boardNo']").val();
       console.log("글번호 : " + boardNo );
       
       var data = {
                     "cmntContent"    :    cmntContent
                     ,"memId"        :    memId
                     ,"boardNo"        :    boardNo
        //              ,"cmntNo":cmntNo
                 };
//        console.log(data);
 
//         var cmntDelYn = $("#cmntDelYn").val();
//         console.log("cmntDelYn: " + cmntDelYn);
         
       $.ajax({
           url:"<c:url value='/'/>insertCmnt.do" ,
           data:data,
           type:"POST",
             success:function(data){
                $("#cmntContent").val("");
//                 alert("댓글 작성 성공");
 
             //href + "(여기 한칸 무조건 띄워야함 무조건) #div id" : 
                $("#cmcmArea").load(window.location.href + " #cmcmArea");
             }
//              ,
//              error:function(request,status,error){
                 //alert("code:"+request.status+"\n"+"message:"+request.responseText+"\n"+"error:"+error);
//                 }
    
         });
         
       });
 
      
      
     
    //댓글삭제
    function deleteComment(cmntNo) {
//         $(".cmntBtnDel").on("click", function() {
//             console.log("댓글 사라지세용");
            
            var boardNo = $("input[name='boardNo']").val();
 
            var data = {
                            "boardNo" : boardNo
                            ,"cmntNo" : cmntNo
                        };
            console.log(data);
            
            $.ajax({
                 url:"<c:url value='/'/>deleteCmnt.do" ,
                 data:data,
                 dataType:"JSON",
                 type:"POST",
                 success:function(data){
                 $("#cmntContent").val("");
                  alert("댓글 삭제 완료");
 
                //href + "(여기 한칸 무조건 띄워야함 무조건) #div id" : 
                 $("#cmcmArea").load(window.location.href + " #cmcmArea");
                 }
//                 ,complete: function () {
//                     alert("나와라!");
//                 }    
        
          });
//      }); 
    }
 
     
    //댓글 수정 버튼(모달창)
     $(document).on("click""#updateCmntModal"function() {
            console.log("댓글 수정 버튼이에욥");
            
            var boardNo = $("input[name='boardNo']").val();
             console.log("글번호 : " + boardNo);
            
             
             var cmntNo = $(this).data("cmntNo");
             console.log("댓글번호 : " + cmntNo);
             
             var cmntContent = $(this).data("cmntContent");
             console.log("댓글내용 : " + cmntContent);
             
             //댓글 수정 모달에서 취소버튼 누르면 입력 값 비우기
              $("#commentModModalCancle").click(function(){
                  $("#writeModComment").val("");
              });
             
     }); 
    
    //모달창에 값 가져오기
     function showCommentContents(x){
         let comment_val = $('#comment_'+x).find('p[name=cmtCnt]').text();
         console.log("=======================");
         console.log("댓글번호: " + x);
         console.log("댓글내용: " + comment_val);
         
         $("#cmntNo1").val(x);
         $("#writeModComment").val(comment_val);
         
         $('#cmntNo').val(x);
         
     }
    
    //댓글 수정
            
        $('#commentModModalConfirm').on( 'click'function() {
         console.log("=====================================");
         console.log("댓글 수정!!!!!!");
         
         var writeModComment = $("#writeModComment").val();
         console.log("확인: " + writeModComment);
         
         var boardNo = $("input[name='boardNo']").val();
         console.log("글번호 : " + boardNo);
         
         var cmntNo = $("#cmntNo").val();
         console.log("댓글번호 : " + cmntNo);         
         
         
         var data = {
                       "boardNo" : boardNo
                       ,"cmntNo" : cmntNo
                       ,"cmntContent" : writeModComment
                   };
         
         console.log(data);
         
         $.ajax({
//              url:"<c:url value='/'/>updateCmnt.do" ,
             url:"<c:url value='/'/>insertCmnt.do" ,
 
             data:data,
             type:"POST",
             success:function(data){
               $("#myModal").modal('hide');
               
                //href + "(여기 한칸 무조건 띄워야함 무조건) #div id" : 
               $("#cmcmArea").load(window.location.href + " #cmcmArea");
               }   
        });
      });
            
        $(document).ready(function() {    
            // 모든 수정 창 숨김
            $(".modifyViews form").css("display""none");  
            
            
            
 
    //대댓글 입력 창 나타내기
    $(document).on("click""button[data-id]"function() {
        console.log("대댓글 입력 클릭!!!");
        
        var cmntNo = $(this).data("id");
        console.log("댓글 cmntNo:", cmntNo);  //여기까지는 됨
        
        
        //각 해당 댓글번호의 등록 폼 띄우기   
        
        
//         $("#" + cmntNo).css("display", "block");
//         document.getElementById("hiddenContent").style.display = 'block';
        
        
//         //댓글번호 출력
//         var modiReNo = $("#" + cmntNo + " input[name='cmntNo']").val();
//         console.log("댓글 번호:", modiReNo);
        
        
//         $("#" + cmntNo).css("display", "block");
        
        
        
        
        
//         if($("#replyWrite" + cmntNo).is(":visible")){    
//             $("#replyWrite" + cmntNo).slideUp();
//         }else{
//             $("#replyWrite" + cmntNo).slideDown();
//         }
 
//         var getID = document.getElementsByName(id123);
//         getID.style.display=(getID.style.display=='block') ? 'none' : 'block';
        
        });
    });
 
    
    
        //대댓글 작성
        function replyGogo(re){
                console.log("대댓글 올라가세요");
                
//                 var reContent = $("#reContent").val();
//                 console.log("대댓글내용 : "+ reContent);
                
                let reContent = $('#hiddenContent_'+re).find('input[name=reContent]').val();
                console.log("대댓글내용 : "+ reContent);
               
                var replyWriter =$("#replyWriter").val();
                console.log("대댓글작성자 : " + replyWriter)
               
                var boardNo1 = $("#boardNo1").val();
                console.log("글번호 : " + boardNo1);
                
                let replyNo = $('#hiddenContent_'+re).find('input[name=cmntNo2]').val();
                console.log("댓글번호 : " + replyNo);
                
                
                 var data = {
                         "cmntContent"    :    reContent
                         ,"memId"        :    replyWriter
                         ,"boardNo"        :    boardNo1
                         ,"cmntNo"        :    replyNo
                       };
               
               console.log("data:" + data);
                
                
                /*
                //대댓글 내용
                let reply_val = $('#hiddenContent_'+re).find('input[name=reContent]').val(); //원댓글 번호를 가져옴
                console.log("=======================");
                console.log("댓글번호: " + re);
                console.log("대댓글내용: " + reply_val);
               
                //대댓글 번호 가져오기
                $("#replyNo").val(re);    
               
                //대댓글 내용 가져오기
                $("#reContent").val(reply_val);
                
//                 $('#replyNo').val(re);
               
                var data = {
                        "cmntContent"    :    reContent
                        ,"memId"        :    replyWriter
                        ,"boardNo"        :    boardNo
                        ,"cmntNo"        :    replyNo
//                        ,"upCmntNo"        :    upCmntNo
                    };
               */
               
               
                $.ajax({
                     url:"<c:url value='/'/>insertReply.do" ,
                     data:data,
                     dataType:"JSON",
                     type:"POST",
                     success:function(data){
//                          $("#cmntContent1").val("");
//                          alert("대댓글 작성 성공");
 
                        //href + "(여기 한칸 무조건 띄워야함 무조건) #div id" : 
                         $("#cmcmArea").load(window.location.href + " #cmcmArea");
                     }
            
                  });
            
            
        }
 
    
 
 
     
    
</script>
</html>
 
 
 
 
 
 
cs