반응형

게시판 구현하기


작업에 사용할 파일 미리 다운받아서 준비

images.zip

lib.zip

 


준비작업

DB설치, DB연동 라이브러리 추가 및 웹 환경설정을 해야 한다. 

이클립스에서 인코딩 관련 문제가 발생할 수 있으므로 모든 인코딩은 UTF-8로 통일한다.

이클립스 메뉴에서 [Window] – [Preferences] – [Web]에 보면 왼쪽과 같이 파일이 보인다. 

클릭하여 모두 인코딩을 맞춰준다. 그리고 DB와 연동하기 위해 라이브러리를 추가하고 context.xml 과 web.xml 파일을 수정한다. 

추가로 게시판에서 사용되는 이미지 파일을 포함한다.


1.라이브러리 추가 및 이미지 파일 추가

Connection Pool 기능을 적용시키기 위해 다음과 같이 파일을 준비한다.

위와 같이 구성 후 Build Path 설정(tomcat-dbcp, ojdbc)


2. WebContent/WEB-INF/web.xml에 추가

1
2
3
4
5
6
<resource-ref>
    <description>ConnectionPool</description>
    <res-ref-name>jdbc/myOracle</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-auth>Container</res-auth>
</resource-ref>
cs


3. WebContent/META-INF/context.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
<?xml version="1.0" encoding="UTF-8"?>
<Context>
    <Resource name="jdbc/myOracle"
           auth="Container"
           driverClassName="oracle.jdbc.driver.OracleDriver"
           type="javax.sql.DataSource"
           url="jdbc:oracle:thin:@localhost:1521:xe"
           username="데이터베이스접속계정"
           password="데이터베이스접속계정비밀번호"
           initialSize="50"
           maxTotal="20"     
           maxIdle="10"
           maxWaitMillis="10000"    />
<!-- 
    initialSize
        : 최초 시점에 getConnection() 를 통해 커넥션 풀에 채워 넣을 커넥션 개수 (default = 0)
    maxTotal (1.x에서는 maxActive): 
        : 동시에 사용할 수 있는 최대 커넥션 개수 (default = 8)
    maxIdle
        : Connection Pool에 반납할 때 최대로 유지될 수 있는 커넥션 개수 (default = 8)
    minIdle 
        : 최소한으로 유지할 커넥션 개수 (default = 0)
    maxWaitMillis (1.x에서는 maxWait) 
        : pool이 고갈되었을 경우 최대 대기 시간 (ms단위, default = -1 = 무한정)
-->
</Context>
cs

 

위의 준비가 완료되면 다음을 따라서 게시판 구현을 시작한다.


1. 게시판 테이블 만들기

게시판을 구현하기에 앞서 DB에 글을 저장할 테이블을 만든다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
create table "BOARD" (
    "NUM"        number(7,0not null,
    "WRITER"     varchar2(12not null,
    "EMAIL"      varchar2(30not null,
    "SUBJECT"    varchar2(50not null,
    "PASS"       varchar2(10not null,
    "READCOUNT"  number(5,0default 0 not null,
    "REF"        number(5,0default 0 not null,
    "STEP"       number(3,0default 0 not null,
    "DEPTH"      number(3,0default 0 not null,
    "REGDATE"    timestamp default sysdate not null,
    "CONTENT"    varchar2(4000not null,
    "IP"         varchar2(20not null,
    constraint  "BOARD_PK" primary key ("NUM")
);
cs

다음 시퀀스 생성
1
2
create sequence "BOARD_SEQ" start with 1 increment by 1 nomaxvalue nocache nocycle;
 
cs

이러서 MVC패턴에서 모델에 해당하는 부분인 DTO와 DAO를 작성한다.
src/boardone/BoardDto.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
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
package boardone;
import java.sql.Timestamp;
public class BoardDto {
    private int num;
    private String writer;
    private String email;
    private String subject;
    private String pass;
    private int readcount;
    private int ref;
    private int step;
    private int depth;
    private Timestamp regdate;
    private String content;
    private String ip;
    public BoardDto(){}
    public int getNum() {
        return num;
    }
    public void setNum(int num) {
        this.num = num;
    }
    public String getWriter() {
        return writer;
    }
    public void setWriter(String writer) {
        this.writer = writer;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public String getSubject() {
        return subject;
    }
    public void setSubject(String subject) {
        this.subject = subject;
    }
    public String getPass() {
        return pass;
    }
    public void setPass(String pass) {
        this.pass = pass;
    }
    public int getReadcount() {
        return readcount;
    }
    public void setReadcount(int readcount) {
        this.readcount = readcount;
    }
    public int getRef() {
        return ref;
    }
    public void setRef(int ref) {
        this.ref = ref;
    }
    public int getStep() {
        return step;
    }
    public void setStep(int step) {
        this.step = step;
    }
    public int getDepth() {
        return depth;
    }
    public void setDepth(int depth) {
        this.depth = depth;
    }
    public Timestamp getRegdate() {
        return regdate;
    }
    public void setRegdate(Timestamp regdate) {
        this.regdate = regdate;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    public String getIp() {
        return ip;
    }
    public void setIp(String ip) {
        this.ip = ip;
    }
}
 
cs


앞에서 회원가입 로그인을 만든 후 Singleton 개념을 적용시키자고 했었다. 
이번에는 처음부터 적용해 보자.
Singleton을 유틸리티 형태로 만들어 본다.
src/boardone/ConnUtil.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package boardone;
 
import java.sql.*;
import javax.sql.*;
import javax.naming.*;
 
public class ConnUtil {
    private static DataSource ds;
    static {
        try{
            InitialContext ctx = new InitialContext();
            ds = (DataSource)ctx.lookup("java:comp/env/jdbc/myOracle");
        } catch(NamingException e){}
    }
    public static Connection getConnection() throws SQLException{
        return ds.getConnection();
    }
}
cs

위에서 만든 ConnUtil에서 실제 데이터베이스에 쿼리작업을 해 줄 DAO를 만든다.
src/boardone/BoardDao.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package boardone;
 
public class BoardDao {
    private static BoardDao instance = null;
    private BoardDao(){}
    public static BoardDao getInstance(){
        if(instance == null){
            synchronized(BoardDao.class){
                instance = new BoardDao();
            }
        }
        return instance;
    }
    //이제부터 여기에 게시판에서 필요한 작업 기능들을 메서드로 추가하게 된다.
}
cs

디자인 요소 작성(중요하지 않음)
게시판에 적용시킬 디자인요소에 해당하는 css파일을 작성.
WebContent/boardone/css/style.css
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@CHARSET "UTF-8";
body{
    background-color:#d1d3fc;
    font-size:15px;
    color: #ce16e9;
    text-align: center;
}
a:link {
    text-decoration:nonecolor:#696969;
}
a:hover{
    text-decoration:yescolor:#66ccff;
}
a:visited {
    text-decoration:noncolor:#330066;
}
 
cs

기본적인 게시판작성 준비 완료

이제 본격적으로 게시판을 구현하도록 한다.
먼저 게시판에 글을 작성할 수 있는 글쓰기 화면을 작성한다.
WebContent/boardone/writeForm.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
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!doctype html>
<html>
<head>
<title>My Board</title>
<link href="css/style.css" rel="stylesheet" type="text/css"/>
<link href="css/writeFormstyle.css" rel="stylesheet" type="text/css"/>
<script src="script.js"></script>
</head>
 
<!-- //뒤에서 새글, 답변글 구분하는 코드를 추가할 부분<1> -->
 
<body>
<section>
<b>글쓰기</b>
<article>
    <form method="post" name="writeForm" action="writeProc.jsp" 
                                    onsubmit="return writeSave()">
    <table class="board">
        <tr>
            <td class="attr">이름</td>
            <td><input type="text" name="writer"/></td>
        </tr>
        <tr>
            <td class="attr">이메일</td>
            <td><input type="email" name="email"/></td>
    </tr>
    <tr>
        <td class="attr">제목</td>
        <td><input class="input"  type="text" name="subject"/></td>
    </tr>
    <tr>
        <td class="attr">내용</td>
        <td>
            <textarea name="content" rows="13" cols="50"></textarea>
        </td>
    </tr>
    <tr>
        <td class="attr">비밀번호</td>
        <td><input type="password" name="pass"/></td>
    </tr>
    <tr>
        <td colspan="2" class="attr">
            <input type="submit" value="글쓰기"/>
            <input type="reset" value="다시 작성"/>
            <input type="button" value="목록" 
                    onClick="window.location='list.jsp'">
        </td>
    </tr>
    </table>
</form>
</article>
</section>
<!-- 예외처리 코드가 들어갈 부분<2> -->
</body>
</html>
cs

-CSS작성
WebContent/boardone/css/writeFormstyle.css
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
@CHARSET "UTF-8";
section{
    padding-top: 30px;
    width:500px;
    margin: auto;
    left:0; top:0; right:0; bottom:0;
}
.board{
    text-align:center;
    border-collapse:collapse;
}
.board td {
    border:1px solid #333;
    text-align:left;
    width:200px;    
    height:30px;
    border:1px solid #333;
}
.board td .input{
    width:97%;
}
.board .attr{
    width: 100px;
    text-align:center;
}
cs

작성 후 실행하면 다음과 같은 페이지가 보여진다.


확인 후 writeSave() 함수를 자바스크립트로 작성해야 한다.
WebContent/boardone/script.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function writeSave(){
    if(document.writeForm.writer.value == ""){
        alert("작성자를 입력하세요.");
        document.writeForm.writer.focus();
        return false;
    }
    if(document.writeForm.subject.value == ""){
        alert("제목을 입력하세요.");
        document.writeForm.subject.focus();
        return false;
    }
    if(document.writeForm.content.value == ""){
        alert("내용을 입력하세요.");
        document.writeForm.content.focus();
        return false;
    }
    if(document.writeForm.pass.value == ""){
        alert("비밀번호를 입력하세요.");
        document.writeForm.pass.focus();
        return false;
    }
}
 
cs

작성 후 writeForm.jsp를 실행하여 글쓰기 버튼을 눌러 값을 확인하는 동작을 확인한다.

다음으로 글 작성 기능을 구현한다. 
글쓰기 버튼을 클릭 했을 때 writeProc.jsp페이지로 이동하여 글쓰기 기능을 수행할 것이다. 이 때 새글 및 답글을 구분하기 위해 writeForm.jsp파일의 주석<1> 부분에 다음 코드를 추가한다.
WebContent/boardone/writeForm.jsp 의 <1>주석 부분에 추가
1
2
3
4
5
6
7
8
9
10
11
12
13
<%
    int num = 0;
    int ref = 1;
    int step = 0;
    int depth = 0;
    try{
        if(request.getParameter("num"!= null){
            num = Integer.parseInt(request.getParameter("num"));
            ref = Integer.parseInt(request.getParameter("ref"));
            step = Integer.parseInt(request.getParameter("step"));
            depth = Integer.parseInt(request.getParameter("depth"));
        }
%>
cs

새 글일 경우는 num=0 이라는 값이 넘어가고 답글일 경우 원본 글의 num값을 받아와서 넘기도록 동작한다.
위 코드 작성 후 주석<2>부분에 예외처리 코드를 추가한다.
WebContent/boardone/writeForm.jsp 의 <2>주석 부분에 추가
1
2
3
4
<!-- 예외처리 코드가 들어갈 부분<2> -->
<% }catch(Exception e) {
    e.printStackTrace();
%>
cs

다음 추가적으로 writeProc.jsp페이지로 이동할 때 num, ref, step, depth의 값을 갖고 넘어가야 하므로 hidden형태로 넘겨주도록 한다.
writeForm.jsp파일의 <form>태그 안에 다음 코드를 추가한다.
1
2
3
4
5
<input type="hidden" name="num" value="<%= num %>"/>
<input type="hidden" name="ref" value="<%= ref %>"/>
<input type="hidden" name="step" value="<%= step %>"/>
<input type="hidden" name="depth" value="<%= depth %>"/>
 
cs

그리고 제목 부분을 구현하고 있는 input태그를 수정하여 
새 글과 답 글을 구별할 수 있도록 한다.
writeForm.jsp의 제목을 구현한 부분의 <input> 태그를 다음과 같이 수정
1
2
3
4
5
6
7
8
<td class="attr">제목</td>
    <td>
    <% if(request.getParameter("num"== null) { %>
        <input class="input" type="text" name="subject"/>
    <%else { %>
        <input class="input" type="text" name="subject" value="[답변]"/>
    <%%>
    </td>
cs

writeForm.jsp로부터 num, ref, step, level을 받아서 DB에 데이터를 넣어줄 writeProc.jsp를 작성한다.
WebContent/boardone/writeProc.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import = "boardone.BoardDao" %>
<%@ page import = "java.sql.Timestamp" %>
<% request.setCharacterEncoding("UTF-8"); %>
<jsp:useBean id="article" scope="page" class="boardone.BoardDto">
    <jsp:setProperty name="article" property="*"/>
</jsp:useBean>    
<%
    article.setRegdate( new Timestamp( System.currentTimeMillis() ) );
    article.setIp( request.getRemoteAddr() );
    BoardDao dbPro = BoardDao.getInstance();
    dbPro.insertArticle(article);
    response.sendRedirect("list.jsp");
%>
 
cs

그 다음 insertArticle(BoardDto article) 메서드가 없으므로 BoardDao에 추가한다.
src/boardone/BoardDao.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
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
    public void insertArticle(BoardDto article){
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        int num = article.getNum();
        int ref = article.getRef();
        int step = article.getStep();
        int depth = article.getDepth();
        int number = 0;
        String sql = "";
        try{
            conn = ConnUtil.getConnection();
            pstmt = conn.prepareStatement("select max(NUM) from BOARD");
            rs = pstmt.executeQuery();
            if(rs.next()){
                number = rs.getInt(1+ 1;
            }
            else{
                number = 1;
            }
            if(num != 0){ //답 글일 경우
                sql = "update BOARD set STEP=STEP+1 where REF = ? and STEP > ?";
                pstmt.close();
                pstmt = conn.prepareStatement(sql);
                pstmt.setInt(1, ref);
                pstmt.setInt(2,  step);
                pstmt.executeQuery();
                step++;
                depth++;
            }
            else{//새 글일 경우
                ref = number;
                step = 0;
                depth = 0;
            }
            //쿼리 작성
            sql = "insert into BOARD"
                    + "(NUM, WRITER, EMAIL, SUBJECT, PASS, "
                    + "REGDATE, REF, STEP, DEPTH, CONTENT, IP) "
                    + "values(BOARD_SEQ.nextval, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
            pstmt.close();
            pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, article.getWriter());
            pstmt.setString(2, article.getEmail());
            pstmt.setString(3, article.getSubject());
            pstmt.setString(4, article.getPass());
            pstmt.setTimestamp(5, article.getRegdate());
            pstmt.setInt(6, ref);
            pstmt.setInt(7, step);
            pstmt.setInt(8, depth);
            pstmt.setString(9, article.getContent());
            pstmt.setString(10, article.getIp());
            pstmt.executeQuery();
        }catch(Exception e){
            e.printStackTrace();
        }finally{
            if(rs != nulltry { rs.close(); } catch (SQLException e){}
            if(pstmt != nulltry { pstmt.close(); } catch (SQLException e){}
            if(conn != nulltry { conn.close(); } catch (SQLException e){}
        }
    }
cs

이제 실행해서 글쓰기를 입력하면 DB에 저장은 된다. 저장 후 이동하는 페이지인 list.jsp페이지가 없으므로 글쓰기 후 404에러페이지가 출력되지만 DB의 내용을 확인해보면 글 내용이 저장되는 것을 확인할 수 있다.


DB에 저장된 데이터 확인


그래서 글 목록을 확인할 수 있는 페이지를 작성한다. 
먼저 글의 개수를 가져올 메서드를 BoardDao.java에 추가한다.
BoardDao.java에 다음 메서드 추가
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public int getArticleCount(){
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    int x = 0;
    try{
        conn = ConnUtil.getConnection();
        pstmt = conn.prepareStatement("select count(*) from BOARD");
        rs = pstmt.executeQuery();
        if(rs.next()){
            x = rs.getInt(1);
        }
    } catch(Exception e){
        e.printStackTrace();
    } finally{
        if(rs != nulltry { rs.close(); } catch (SQLException e){}
        if(pstmt != nulltry { pstmt.close(); } catch (SQLException e){}
        if(conn != nulltry { conn.close(); } catch (SQLException e){}
    }
    return x;
}
cs

다음은 데이터베이스의 board table에서 데이터를 가져오는 메서드를 BoardDao.java에 추가한다.
src/boardone/BoardDao.java 파일에 추가
먼저 맨 윗줄에 import java.util.*; 추가 후 작성
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
    public List<BoardDto> getArticles(/* 수정<1> */){
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        List<BoardDto> articleList = null;
        try{
            conn = ConnUtil.getConnection();
            /* 수정<2> */
            pstmt = conn.prepareStatement(
                                        "select * from BOARD order by NUM desc"); //수정<3>
            rs = pstmt.executeQuery();
            if(rs.next()){
                articleList = new ArrayList<BoardDto>(); //수정<4>
                do {
                    BoardDto article = new BoardDto();
                    article.setNum(rs.getInt("num"));
                    article.setWriter(rs.getString("writer"));
                    article.setEmail(rs.getString("email"));
                    article.setSubject(rs.getString("subject"));
                    article.setPass(rs.getString("pass"));
                    article.setRegdate(rs.getTimestamp("regdate"));
                    article.setReadcount(rs.getInt("readcount"));
                    article.setRef(rs.getInt("ref"));
                    article.setStep(rs.getInt("step"));
                    article.setDepth(rs.getInt("depth"));
                    article.setContent(rs.getString("content"));
                    article.setIp(rs.getString("ip"));
                    articleList.add(article);
                } while(rs.next());
            }
        } catch(Exception e){
            e.printStackTrace();
        } finally{
            if(rs != nulltry { rs.close(); } catch (SQLException e){}
            if(pstmt != nulltry { pstmt.close(); } catch (SQLException e){}
            if(conn != nulltry { conn.close(); } catch (SQLException e){}
        }
        return articleList;
    }
 
cs

실제로 글목록을 보여줄 list.jsp 페이지를 작성한다.
WebContent/boardone/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
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import = "boardone.BoardDao" %>
<%@ page import = "boardone.BoardDto" %>
<%@ page import = "java.util.List" %>
<%@ page import = "java.text.SimpleDateFormat" %>
<%!
    //수정<1>
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
%>
<%
    //수정<2>
    int count = 0;
    int number = 0;
    List<BoardDto> articleList = null;
    BoardDao dbPro = BoardDao.getInstance();
    count = dbPro.getArticleCount(); //전체 글 수
    if(count > 0){
        articleList = dbPro.getArticles(); //수정<3>
    }
    number = count; //수정<4>
%>
<!doctype html>
<html>
<head>
<title>게시판</title>
<link href="css/style.css" rel="stylesheet" type="text/css">
<link href="css/liststyle.css" rel="stylesheet" type="text/css"/>
</head>
<body>
<section>
<article>
<b>글목록(전체 글:<%= count %>)</b>
<table class="listwritebutton">
    <tr>
    <td><a href="writeForm.jsp">글쓰기</a></td>
    <tr>
</table>
<%
    if(count == 0){
%>
<table class="listtable">
<tr>
    <td>게시판에 저장된 글이 없습니다.</td>
</table>
<% } else { %>
<table  class="listtable">
    <tr>
        <th id="num">번 호</th>
        <th id="title">제 목</th>
        <th id="writer">작성자</th>
        <th id="date">작성일</th>
        <th id="counter">조 회</th>
        <th id="ip">IP</th>
    </tr>
<%
    for(int i = 0; i < articleList.size(); i++){
        BoardDto article = (BoardDto)articleList.get(i);
%>
    <tr>
        <td<%= number-- %></td>
        <td class="titletd">
        <!-- 수정<5> -->
        <a href="content.jsp?num=<%= article.getNum() %>&pageNum=1"><!-- 수정<6> -->
            <%= article.getSubject() %></a>
            <% if(article.getReadcount() >= 20){ %>
            <img src="images/hot.gif"><% } %></td>
        <td>
            <a href="mailto:<%= article.getEmail() %>">
            <%= article.getWriter() %></a></td>
        <td>
            <%= sdf.format(article.getRegdate()) %></td>
        <td><%= article.getReadcount() %></td>
        <td><%= article.getIp() %></td>
    </tr>
        <% } %>
</table>
</article>
<% } %>
<!-- 수정<7> -->
</section>
</body>
</html>
cs

-CSS작성
WebContent/boardone/css/liststyle.css
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
@CHARSET "UTF-8";
section{
    padding-top: 30px;
    width: 700px; 
    margin: auto;
    left:0; top:0; right:0; bottom:0;
}
table{
    width:700px;
    border-collapse:collapse;
}
a{ 
    text-decoration:none; 
}
.listwritebutton{
    text-align:right;
}
.listtable{
    text-align:center;    
    border:1px solid #333;
}
.listtable td{
    border:1px solid #333;
}
.listtable th{
    color: #ffffff;
    border:1px solid #333;
    background-color: #4aa8b5; 
    height:30px;
}
.listtable .titletd{
    text-align:left;
}
#num{ width:50px;}
#title{ width:250px;}
#writer{ width:100px;}
#date{ width:150px;}
#counter{ width:50px;}
#ip{ width:100px;}
cs

요청결과>


위와 같이 앞에서 글을 저장했던 목록이 나오면 DB에서 직접 삭제한다.
(아직 웹 페이지에서 삭제 기능은 동작 불가)

이 후 list.jsp를 실행해서 다음과 같이 “게시판에 저장된 글이 없습니다.” 라는 내용을 확인한다.


다음으로 글 내용을 확인하는 페이지를 작성한다.
list.jsp페이지에서 글 제목을 클릭하면 글의 내용을 보여줄 수 있도록 작업할 것이다. 
클릭을 했을 때 해당 글의 num을 매개변수로 DB에서 세부정보를 가져와야 된다. 
그래서 DB에서 글 하나의 정보를 가져오는 메서드를 BoardDao.java 에 추가한다.
src/boardone/BoardDao.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
27
28
29
30
31
32
33
34
35
36
37
38
39
    public BoardDto getArticle(int num){
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        BoardDto article = null;
        try{
            conn = ConnUtil.getConnection();
            pstmt = conn.prepareStatement(
                    "update BOARD set READCOUNT=READCOUNT+1 where NUM = ?");
            pstmt.setInt(1, num);
            pstmt.executeQuery();
            pstmt.close();
            pstmt = conn.prepareStatement("select * from BOARD where NUM = ?");
            pstmt.setInt(1, num);
            rs = pstmt.executeQuery();
            if(rs.next()){
                article = new BoardDto();
                article.setNum(rs.getInt("num"));
                article.setWriter(rs.getString("writer"));
                article.setEmail(rs.getString("email"));
                article.setSubject(rs.getString("subject"));
                article.setPass(rs.getString("pass"));
                article.setRegdate(rs.getTimestamp("regdate"));
                article.setReadcount(rs.getInt("readcount"));
                article.setRef(rs.getInt("ref"));
                article.setStep(rs.getInt("step"));
                article.setDepth(rs.getInt("depth"));
                article.setContent(rs.getString("content"));
                article.setIp(rs.getString("ip"));
            }
        } catch(Exception e){
            e.printStackTrace();
        } finally{
            if(rs != nulltry { rs.close(); } catch (SQLException e){}
            if(pstmt != nulltry { pstmt.close(); } catch (SQLException e){}
            if(conn != nulltry { conn.close(); } catch (SQLException e){}
        }
        return article;
    }
cs

다음으로 글 내용을 보여줄 content.jsp를 작성한다.
WebContent/boardone/content.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
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import = "boardone.BoardDao" %>
<%@ page import = "boardone.BoardDto" %>
<%@ page import = "java.text.SimpleDateFormat" %>
<!doctype html>
<html>
<head>
<title>게시판</title>
<link href="css/style.css" rel="stylesheet" type="text/css">
<link href="css/contentstyle.css" rel="stylesheet" type="text/css">
</head>    
<%
    int num = Integer.parseInt(request.getParameter("num"));
    String pageNum = request.getParameter("pageNum");
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
    try{
        BoardDao dbPro = BoardDao.getInstance();
        BoardDto article = dbPro.getArticle(num);
        int ref = article.getRef();
        int step = article.getStep();
        int depth = article.getDepth();
%>
<body>
<section>
<article>
<b>글 내용 보기</b>
<br/><br/>
<form>
    <table class="contenttable">
        <tr>
            <th>글번호</th>
            <td><%= article.getNum() %></td>
            <th>조회수</th>
            <td><%= article.getReadcount() %></td>
        </tr>
        <tr>
            <th>작성자</th>
            <td><%= article.getWriter() %></td>
            <th>작성일</th>
            <td><%= article.getRegdate() %></td>
        </tr>
        <tr>
            <th>글제목</th>
            <td colspan="3" class="contenttitle"><%= article.getSubject() %></td>
        </tr>
        <tr>
            <th>글내용</th>
            <td colspan="3" class="content"><pre><%= article.getContent() %></pre></td>
        </tr>
        <tr>
            <td colspan="4">
                <input type="button" value="글수정" 
                onClick="document.location.href=
                'updateForm.jsp?num=<%=article.getNum()%>&pageNum=<%=pageNum%>'">
                    &nbsp;&nbsp;&nbsp;&nbsp;
                <input type="button" value="글삭제" 
                onClick="document.location.href=
                'deleteForm.jsp?num=<%=article.getNum()%>&pageNum=<%=pageNum%>'">
                    &nbsp;&nbsp;&nbsp;&nbsp;
        <!-- 수정<1> -->
                <input type="button" value="글목록" 
                    onClick="document.location.href=
                    'list.jsp?pageNum=<%=pageNum%>'">
            </td>
        </tr>
    </table>
    <%
    } catch(Exception e){}
    %>
</form>
</article>
</section>
</body>
</html>
cs

- CSS 작성
WebContent/boardone/css/contentstyle.css
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
@CHARSET "UTF-8";
section{
    padding-top: 30px;
    width:500px;
    margin: auto;
    left:0; top:0; right:0; bottom:0;
}
.contenttable{
    text-align:center;
    border-collapse:collapse;
}
.contenttable th{
    color: #ffffff;
    border:1px solid #333;
    background-color: #4aa8b5; 
    height:30px;
    width:125px;
}
.contenttable td {
    border:1px solid #333;
    text-align:center;
    width:125px;    
    height:30px;
    border:1px solid #333;
}
table .contenttitle{
    text-align:left;
}
table .content{
    text-align:left;
    height:200px;
}
cs

이제 글 작성하고 저장하고 목록확인 내용확인이 잘 동작하는지 확인한다.
<글 작성하기>


<글 목록확인>



<글 내용확인>



잘 동작하는 것을 확인하면 다음으로 글 수정, 삭제, 답변 처리를 구현한다.
[글수정]을 누를 경우 updateForm.jsp로 이동하도록 링크를 걸었으니 글 수정화면을 작성해야 한다.
글 수정 시에는 목록보기와 다르게 조회 수를 증가시킬 필요가 없기 때문에 num에 해당하는 게시물을 가져오기만 하는 메서드를 BoardDao.java 파일에 추가한다.
src/boardone/BoardDao.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
27
28
29
30
31
32
33
34
public BoardDto updateGetArticle(int num){
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    BoardDto article = null;
    try{
        conn = ConnUtil.getConnection();
        pstmt = conn.prepareStatement("select * from BOARD where NUM = ?");
        pstmt.setInt(1, num);
        rs = pstmt.executeQuery();
        if(rs.next()){
            article = new BoardDto();
            article.setNum(rs.getInt("num"));
            article.setWriter(rs.getString("writer"));
            article.setEmail(rs.getString("email"));
            article.setSubject(rs.getString("subject"));
            article.setPass(rs.getString("pass"));
            article.setRegdate(rs.getTimestamp("regdate"));
            article.setReadcount(rs.getInt("readcount"));
            article.setRef(rs.getInt("ref"));
            article.setStep(rs.getInt("step"));
            article.setDepth(rs.getInt("depth"));
            article.setContent(rs.getString("content"));
            article.setIp(rs.getString("ip"));
        }
    } catch(Exception e){
        e.printStackTrace();
    } finally{
        if(rs != nulltry { rs.close(); } catch (SQLException e){}
        if(pstmt != nulltry { pstmt.close(); } catch (SQLException e){}
        if(conn != nulltry { conn.close(); } catch (SQLException e){}
    }
    return article;
}
cs

이어서 updateForm.jsp를 작성한다.
WebContent/boardone/updateForm.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"%>
<%@ page import = "boardone.BoardDao" %>
<%@ page import = "boardone.BoardDto" %>
<%
    int num = Integer.parseInt(request.getParameter("num"));
    String pageNum = request.getParameter("pageNum");
    try{
        BoardDao dbPro = BoardDao.getInstance();
        BoardDto article = dbPro.updateGetArticle(num);
%>
<!doctype html>
<html>
<head>
<title>My Board</title>
<link href="css/style.css" rel="stylesheet" type="text/css"/>
<link href="css/writeFormstyle.css" rel="stylesheet" type="text/css"/>
<script src="script.js"></script>
</head>
 
<body>
<section>
<b>글수정</b>
<article>
    <form method="post" name="writeForm" 
        action="updateProc.jsp?num=<%=num%>&pageNum=<%=pageNum%>"
        onsubmit="return writeSave()">
    <input type="hidden" name="writer" value="<%=article.getWriter() %>">
    <table class="board">
        <tr>
            <td class="attr">이름</td>
            <td><%= article.getWriter() %></td>
        </tr>
        <tr>
            <td class="attr">이메일</td>
            <td><input type="email" name="email" 
                    value="<%=article.getEmail()%>"/></td>
    </tr>
    <tr>
        <td class="attr">제목</td>
        <td>
            <input class="input" type="text" name="subject"
                    value="<%=article.getSubject() %>"/>
        </td>
    </tr>
    <tr>
        <td class="attr">내용</td>
        <td>
        <textarea name="content" rows="13" cols="50"><%=article.getContent()%>
        </textarea>
        </td>
    </tr>
    <tr>
        <td class="attr">비밀번호</td>
        <td><input type="password" name="pass"/></td>
    </tr>
    <tr>
        <td colspan="2" class="attr">
            <input type="submit" value="글수정"/>
            <input type="reset" value="다시 작성"/>
            <input type="button" value="목록" 
                    onClick="window.location='list.jsp'">
        </td>
    </tr>
    </table>
</form>
</article>
</section>
<!-- 예외처리 코드가 들어갈 부분<2> -->
<% }catch(Exception e) {
    e.printStackTrace();
%>
</body>
</html>
cs

글 수정 눌렀을 때 화면


updateForm.jsp에서 비밀번호를 입력한 후 글 수정을 클릭하면 DB의 게시물이 수정되어야 한다. 그래서 BoardDao.java에 글 수정을 처리할 메서드를 추가한다.
src/boardone/BoardDao.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
27
28
29
30
31
32
33
34
35
36
37
38
39
public int updateArticle(BoardDto article){
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    String dbpassword = "";
    String sql = "";
    int result = -1//결과 값
    try{
        conn = ConnUtil.getConnection();
        pstmt = conn.prepareStatement("select PASS from BOARD where NUM = ?");
        pstmt.setInt(1, article.getNum());
        rs = pstmt.executeQuery();
        if(rs.next()){
            dbpassword = rs.getString("pass");//비밀번호 비교
            if(dbpassword.equals(article.getPass())){
                sql = "update BOARD set WRITER=?,EMAIL=?,"
                    + "SUBJECT=?,CONTENT=? where NUM=?";
                pstmt.close();
                pstmt = conn.prepareStatement(sql);
                pstmt.setString(1, article.getWriter());
                pstmt.setString(2, article.getEmail());
                pstmt.setString(3, article.getSubject());
                pstmt.setString(4, article.getContent());
                pstmt.setInt(5, article.getNum());
                pstmt.executeQuery();
                result = 1//수정 성공
            } else {
                result = 0//수정 실패
            }
        }
    } catch(Exception e){
        e.printStackTrace();
    } finally{
        if(rs != nulltry { rs.close(); } catch (SQLException e){}
        if(pstmt != nulltry { pstmt.close(); } catch (SQLException e){}
        if(conn != nulltry { conn.close(); } catch (SQLException e){}
    }
    return result;
}
cs

위의 메서드를 사용하여 수정처리를 해주는 updateProc.jsp페이지를 작성한다.
WebContent/boardone/updateProc.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import = "boardone.BoardDao" %>
<%@ page import = "java.sql.Timestamp" %>
<% request.setCharacterEncoding("UTF-8"); %>
<jsp:useBean id="article" scope="page" class="boardone.BoardDto">
    <jsp:setProperty name="article" property="*"/>
</jsp:useBean>
<%
    String pageNum = request.getParameter("pageNum");
    BoardDao dbProc = BoardDao.getInstance();
    int check = dbProc.updateArticle(article);
    if(check == 1){
%>
    <meta http-equiv="Refresh" content="0;url=list.jsp?pageNum=<%= pageNum %>">
<%    } else { %>
    <script>
    <!--
        alert("비밀번호가 맞지 않습니다.");
        history.go(-1);
    -->
    </script>
<%    } %>
cs

수정하는 동작에 필요한 작업을 완료했다. 수정이 정상적으로 동작하는지 테스트 한다. 입력되어 있던 내용을 수정해보자. 에러 없이 동작된다면 다음으로 글 삭제를 구현하자.
비밀번호가 다를 경우 팝업 표시


비밀번호 입력 검증

비밀번호를 제대로 입력하면 글 내용이 수정되는 것을 확인할 수 있다.


수정된 결과

글 삭제 버튼을 누르면 비밀번호를 입력 받아 DB의 비밀번호와 비교 후 일치할 경우만 삭제처리를 수행한다. 그리고 비밀번호가 맞지 않을 경우는 메시지 처리만 해준다.
글 삭제화면 작성
WebContent/boardone/deleteForm.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
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
    int num = Integer.parseInt(request.getParameter("num"));
    String pageNum = request.getParameter("pageNum");
%>
<html>
<head
<title>게시판</title>
<link href="css/style.css" rel="stylesheet" type="text/css">
<link href="css/deleteFormstyle.css" rel="stylesheet" type="text/css"/>
<script>
    function deleteSave(){
        if(document.delForm.pass.value == ""){
                alert("비밀번호를 입력하세요.");
                document.delForm.pass.focus();
                return false;
        }
    }
</script>
</head>
<body>
<section>
<b>글삭제</b>
    <form method="post" name="delForm" action=
    "deleteProc.jsp?pageNum=<%=pageNum%>" onsubmit="return deleteSave()">
        <table class="deletetable">
            <tr>
                <th><b>비밀번호를 입력 해 주세요.</b></th>
            </tr>
            <tr>
                <td>비밀번호 : 
                    <input type="password" name="pass">
                    <input type="hidden" name="num" value="<%=num%>">
                </td>
            </tr>
            <tr>
                <td>
                    <input type="submit" value="글삭제">
                    <input type="button" value="글목록" onClick=
                    "document.location.href='list.jsp?pageNum=<%=pageNum%>'">
                </td>
            </tr>
        </table>
    </form>
</section>
</body>
</html>
cs

- CSS 작성
WebContent/boardone/css/deleteFormstyle.css
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
@CHARSET "UTF-8";
section{
    padding-top: 30px;
    width:300px;
    margin: auto;
    left:0; top:0; right:0; bottom:0;
}
table{
    text-align:center;
    border-collapse:collapse;
}
th{
    color: #ffffff;
    border:1px solid #333;
    background-color: #4aa8b5; 
    height:30px;
}
td {
    border:1px solid #333;
    text-align:center;
    width:300px;    
    height:30px;
    border:1px solid #333;
}
 
cs

이제 글 삭제를 누르면 비밀번호를 입력하도록 동작한다. 
비밀번호를 입력하면 DB와 비밀번호를 비교한 후 삭제를 처리할 메서드를 작성한다.
src/boardone/BoardDao.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
27
28
29
30
31
32
33
public int deleteArticle(int num, String pass){
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    String dbpasswd = "";
    int result = -1//결과 값
    try{
        conn = ConnUtil.getConnection();
        pstmt = conn.prepareStatement(
                "select PASS from BOARD where NUM=?");
        pstmt.setInt(1, num);
        rs = pstmt.executeQuery();
        if(rs.next()){
            dbpasswd = rs.getString("pass");
            if(dbpasswd.equals(pass)){
                pstmt.close();
                pstmt = conn.prepareStatement("delete from BOARD where NUM=?");
                pstmt.setInt(1, num);
                pstmt.executeQuery();
                result = 1//글삭제 성공
            } else {
                result = 0//비밀번호 틀림
            }
        }
    }catch(Exception e){
        e.printStackTrace();
    } finally{
        if(rs != nulltry { rs.close(); } catch (SQLException e){}
        if(pstmt != nulltry { pstmt.close(); } catch (SQLException e){}
        if(conn != nulltry { conn.close(); } catch (SQLException e){}
    }
    return result;
}
cs

이어 삭제를 수행하는 deleteProc.jsp를 작성한다.
WebContent/boardone/deleteProc.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import = "boardone.BoardDao" %>
<%@ page import = "java.sql.Timestamp" %>
<% request.setCharacterEncoding("UTF-8"); %>
<%
    int num = Integer.parseInt(request.getParameter("num"));
    String pageNum = request.getParameter("pageNum");
    String pass = request.getParameter("pass");
    BoardDao dbPro = BoardDao.getInstance();
    int check = dbPro.deleteArticle(num, pass);
    if(check == 1){
%>
    <meta http-equiv="Refresh" content="0;url=list.jsp?pageNum=<%=pageNum%>">
<%    } else {%>
    <script>
        alert("비밀번호가 맞지 않습니다.");
        history.go(-1);
    </script>
<%    } %>
cs

완료되면 글 삭제가 이루어지는지 테스트 한다.


삭제 후 보여지는 목록


기본적인 게시판을 구현했다. 전체 동작과 코드들을 정리하도록 한다.
















반응형

+ Recent posts