today_is

[ jsp ] 회원 + 게시판 본문

java

[ jsp ] 회원 + 게시판

ye_rang 2023. 12. 14. 20:36

오늘의 목표

회원, 게시판 생성하여 게시판 기능을 만들어보자

 


 

Member 테이블 

컬럼명 null 여부 데이터 타입  
IDX NOT NULL NUMBER primary key
USERID NOT NULL VARCHAR2(100) unique
USERPW NOT NULL VARCHAR2(500)  
USERNAME NOT NULL VARCHAR2(100)  
EMAIL NOT NULL VARCHAR2(100)  
GENDER   VARCHAR2(50)  

 

 

Board 테이블

컬럼명 null 여부 데이터 타입 참조  
IDX  NOT NULL  NUMBER   primary key
TITLE  NOT NULL  VARCHAR2(500)    
WRITER  NOT NULL VARCHAR2(100) member 테이블의 userid 참조  
CONTENT  NOT NULL VARCHAR2(4000)    
WRITEDATE   DATE    

 

 

 

 

MemberDTO & BoardDTO

: 각 필드의 getter & setter 생성

 

 

 

BoardDAO

: 게시판 기능을 처리해줄 함수들 

package board;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

public class BoardDAO {
	private Connection conn;
	private PreparedStatement pstmt;
	private ResultSet rs;
	
	private Context init;
	private DataSource ds;
	
	private static BoardDAO instance = new BoardDAO();
	public static BoardDAO getInstance() {
		return instance;
	}
	private BoardDAO() {
		try {
			init = new InitialContext();
			ds = (DataSource) init.lookup("java:comp/env/jdbc/oracle");
		} catch (NamingException e) {
			e.printStackTrace();
		}
	}
	
	private void close() {
		try {
			if(rs != null) 		rs.close();
			if(pstmt != null) 	pstmt.close();
			if(conn != null) 	conn.close();
		}catch(SQLException e) {}
	}
	
	private BoardDTO mapping(ResultSet rs) throws SQLException {
		BoardDTO dto = new BoardDTO();
		dto.setContent(rs.getString("content"));
		dto.setIdx(rs.getInt("idx"));
		dto.setTitle(rs.getString("title"));
		dto.setWriteDate(rs.getDate("writeDate"));
		dto.setWriter(rs.getString("writer"));
		return dto;
	}
	
	// 게시글 목록
	public List<BoardDTO> selectList() {
		ArrayList<BoardDTO> list = new ArrayList<>();
		String sql = "select "
				+ " (select count(*) from reply where board_idx = board.idx) as replyCount,"
				+ " board.* "
				+ " from board order by idx desc";	// 최신글이 위에 노출되도록
		try {
			conn = ds.getConnection();
			pstmt = conn.prepareStatement(sql);
			rs = pstmt.executeQuery();
			while(rs.next()) {
				BoardDTO dto = mapping(rs);				// 기본 맵핑 + 
				dto.setReplyCount(rs.getInt("replyCount")); // 댓글 개수
				list.add(dto);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally { close(); }
		return list;
	}
	
	// 게시글 조회
	public BoardDTO selectOne(int idx) {
		BoardDTO dto = null;
		String sql = "select * from board where idx = ?";
		try {
			conn = ds.getConnection();
			pstmt = conn.prepareStatement(sql);
			pstmt.setInt(1, idx);
			rs = pstmt.executeQuery();
			while(rs.next()) {
				dto = mapping(rs);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally { close(); }
		return dto;
	}
	
	// 게시글 작성
	public int insert(BoardDTO dto) {
		int row = 0;
		String sql = "insert into board (title, writer, content) "
				+ "	values (?, ?, ?)";
		try {
			conn = ds.getConnection();
			pstmt = conn.prepareStatement(sql);
			pstmt.setString(1, dto.getTitle());
			pstmt.setString(2, dto.getWriter());
			pstmt.setString(3, dto.getContent());
			row = pstmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally { close(); }
		return row;
	}	
}

 

 

header.jsp

: 모든 페이지에 적용할 태그선언과 링크를 작성함

 

다른 페이지에서는 header.jsp 의 내용을 include 를 이용하여 적용한다 !

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" import="member.*, board.*, reply.*" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<c:set var="cpath" value="${pageContext.request.contextPath }" />
<c:set var="memberDAO" value="${MemberDAO.getInstance() }" />
<c:set var="boardDAO" value="${BoardDAO.getInstance() }" />
<c:set var="replyDAO" value="${ReplyDAO.getInstance() }" />

<%	request.setCharacterEncoding("UTF-8"); %>
<%	response.setCharacterEncoding("UTF-8"); %>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>day16 - board</title>
</head>
<body>

<header>
	<h1><a href="${cpath }">day16 - board</a></h1>
	<div style="text-align: right; padding-right: 20px; height: 30px;">
		${login.userid }
	</div>
	<nav>
		<ul style="display: flex; list-style: none; justify-content: space-around;">
			<li><a href="${cpath }/login.jsp">로그인</a></li>
			<li><a href="${cpath }/logout.jsp">로그아웃</a></li>
			<li><a href="${cpath }/join.jsp">회원가입</a></li>
			<li><a href="${cpath }/board.jsp">게시판</a></li>
		</ul>
	</nav>
</header>

 

 

board.jsp 

: 게시판 

 

boardDAO 에 있는 selectLIst() 함수를 이용하여 게시판 목록을 보여줌

 

c:forEach 를 이용하여 게시글을 1개씩 보여줄 수 있도록 반복문

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ include file="header.jsp" %>

<h3>게시판</h3>

<table border="1" cellpadding="10" cellspacing="0" width="800" align="center">
	<c:set var="list" value="${boardDAO.selectList() }" />
	<c:forEach var="dto" items="${list }">
	<tr>
		<td>${dto.idx }</td>
		<td width="500">
			<a href="${cpath }/view.jsp?idx=${dto.idx}">${dto.title }</a>
			<c:if test="${dto.replyCount != 0 }">
				<span style="color: red;
				font-size: 13px;">[${dto.replyCount }]</span>
			</c:if>
		</td>
		<td>${dto.writer }</td>
		<td>${dto.writeDate }</td>
	</tr>
	</c:forEach>
</table>

<div style="display: flex; width: 800px; margin: 20px auto; justify-content: space-between;">
	<div>
	
	</div>
	<div>
		<a href="${cpath }/write.jsp"><button>작성</button></a>
	</div>
</div>

</body>
</html>

 

 

 

write.jsp

: 게시글 작성

 

만약 메서드가 GET이면서 로그인이 되어있지 않는 상태라면, 

alert 을 이용하여 '로그인 후 작성 가능' 이라는 에러 상태를 알리고

login.jsp 로 페이지 이동 시킴

 

 

form 에 method 를 POST로 걸어두고

form 을 작성하게 한다

 

 

form 을 제출하면 

boardDAO 에 있는 insert() 함수를 이용하여 게시글을 추가로 생성 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ include file="header.jsp" %>

<c:if test="${pageContext.request.method == 'GET' }">
	<c:if test="${empty login }">
		<script>
			alert("먼저 로그인 후 글을 작성할 수 있습니다")
			location.href = '${cpath}/login.jsp'
		</script>
	</c:if>
	<form method="POST">
		<p><input type="text" name="title" placeholder="제목" required autofocus></p>
		<input type="hidden" name="writer" value="${login.userid }">
		<p>
			<textarea name="content" placeholder="내용" rows="8" cols="60" required></textarea>
		</p>
		<p><input type="submit" value="작성하기"></p>
	</form>
</c:if>

<c:if test="${pageContext.request.method == 'POST' }">
	<jsp:useBean id="dto" class="board.BoardDTO" />
	<jsp:setProperty property="*" name="dto"/>
	<c:set var="row" value="${boardDAO.insert(dto) }" />
	<c:redirect url="/board.jsp" />
</c:if>

</body>
</html>

 

 

 

view.jsp

: 게시글 상세보기 (개별보기)

 

boardDAO 에 있는 selectOne() 함수를 이용하여 

1개의 게시물만 볼 수 있도록 한다

 

각 게시물 밑에는 form 을 위치시킴 (== 댓글)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ include file="header.jsp" %>

<h3>게시글 상세 보기</h3>

<fieldset>
	<c:set var="dto" value="${boardDAO.selectOne(param.idx) }" />
	<h4>${dto.title } | ${dto.writer } | ${dto.writeDate }</h4>
	<pre>${dto.content }</pre>
</fieldset>
<br>

<form method="POST" action="reply-write.jsp">
	<h3>댓글 작성</h3>
	<c:if test="${empty login }">
		<c:set var="replyComment">로그인 후에 댓글 작성 가능합니다</c:set>
	</c:if>
	<c:if test="${not empty login }">
		<c:set var="replyComment">바르고 고운 말을 사용합시다</c:set>
	</c:if>
	<div style="display: flex; align-items: center;">
		<textarea name="content" rows="5" cols="80"
				  placeholder="${replyComment }" ${empty login ? 'disabled' : '' }
				  style="resize: none;
				  		 height: 100px;
				  		 padding: 10px;
				  		 box-sizing: border-box;"></textarea>
		<input type="submit" value="댓글쓰기"
			   ${empty login ? 'disabled' : '' }
			   style="margin: 10px;
			   		  height: 100px;">
	</div>
	<input type="hidden" name="board_idx" value="${param.idx }">
	<input type="hidden" name="writer" value="${login.userid }">
</form>

<div id="reply">
	<c:forEach var="reply" items="${replyDAO.selectList(param.idx) }">
	<div class="replyItem" style="border: 1px solid grey; 
				margin: 20px;
				padding: 10px;
				box-sizing: border-box;">
		<div style="display: flex; justify-content: space-between;">
			<div>${reply.writer }</div>
			<div><fmt:formatDate value="${reply.writeDate }" pattern="yyyy-MM-dd a hh:mm" /></div>
		</div>
		<div>
			<pre>${reply.content }</pre>
			<c:if test="${reply.writer == login.userid }">
				<a href="${cpath }/reply-delete.jsp?idx=${reply.idx}&board_idx=${dto.idx}">
					<button>댓글 삭제</button>
				</a>
			</c:if>
		</div>
	</div>
	</c:forEach>
</div>



</body>
</html>

 

 

 


study_review

 

오늘은 크게 실수하는 것 없이 잘 수행했다

 

아쉬운 점이라면,

게시물 상세보기를 빠져나가는 버튼을 만들지 않은 것을 지금 발견했다 ㅋㅋㅋㅋㅋ

 

view.jsp 하단에

<a href="${cpath }/board.jsp"><button>목록으로</button></a> 를 추가하면 좋을듯하다 !