Day 58 -[JSP]MVC2 게시판 만들기

2021. 5. 9. 16:37JSP 공부

이번에는 JSP 환경에서 MVC2 모델 방식으로 게시판을 만들어 봅시다.

 

게시판 만들기

게시판의 배경 및 form 등등은 선생님이 미리 만들어 주셨고, 컨트롤러를 같이 만들었습니다 ~

 

먼저, 게시판의 목록 화면이 있고, 글 작성을 누를 수 있습니다.

글을 작성하는 페이지로 이동한 후, 목록을 누르면, 다시 게시판 목록으로 이동되고, 작성 완료를 누르면 글이 작성 됩니다.

게시판 목록으로 이동될 때, 데이터베이스에 연결해서 테이블의 정보를 읽어 옵니다. 게시판의 제목은 링크를 걸어서 클릭하면 글 상세보기 화면으로 이동 합니다.

글 상세보기 화면에서는, 목록을 누르면 다시 게시판 목록으로 , 수정을 누르면 글 수정화면으로, 삭제를 누르면 글이 삭제가 됩니다.

 

파일명 : board_list.jsp ( 게시판 목록 )

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> 
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %> 
<%@ include file="../include/header.jsp" %>   
	<style>
        .btn {
          
            border: 0; 
            border-radius: 0; /*윤곽 0*/
            padding: 5px 10px; 
            margin: 20px 0px;
        }
	</style>

	<div class="container">
		<h3>My Web게시판</h3>

		<table class="table table-bordered">
			<thead>
				<tr>
					<th>글 번호</th>
					<th>작성자</th>
					<th>제목</th>
					<th>날짜</th>
					<th>조회수</th>
				</tr>
			</thead>
			
			<tbody>
				<c:forEach var="vo" items="${list }">
					<tr>
						<td>${vo.bno }</td>
						<td>${vo.writer}</td>
						<td><a href="getContent.board?bno=${vo.bno }">${vo.title }</a></td>
						<td><fmt:formatDate value="${vo.regdate }" pattern="yyyy년 MM월dd일 HH시 mm분 ss초" /></td>
						<td>${vo.hit }</td>
					</tr>
				</c:forEach>
			</tbody>
			
			<tbody>
				<tr>
					<td colspan="5" align="center">
	               			<ul class="pagination pagination-sm">
                        		<li><a href="#">이전</a></li>
                        		<li  class="active"><a href="#">1</a></li>
                        		<li><a href="#">2</a></li>
                        		<li><a href="#">3</a></li>
                        		<li><a href="#">4</a></li>
                        		<li><a href="#">5</a></li>
                        		<li><a href="#">다음</a></li>
                    			</ul>
					<input type="button" value="글 작성" class="btn btn-default pull-right" onclick="location.href='write.board'">
					
					</td>
				</tr>
			</tbody>
		
		</table>
	</div>

<%@ include file="../include/footer.jsp" %>

파일명 : board_write ( 글 작성 화면 )

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

<div align="center" class="div_center">
	<h3>게시판 글 작성 페이지</h3>
	<hr>
	
	<form action="regist.board" method="post">
		<table border="1" width="500">
			<tr>
				<td>작성자</td>
				<td>
					<input type="text" name="writer" size="10" required>
				</td>
			</tr>
			<tr>
				<td>글 제목</td>
				<td>
					<input type="text" name="title" required>
				</td>
			</tr>
			<tr>
				<td>글 내용</td>
				<td>
					<textarea rows="10" style="width: 95%;" name="content"></textarea>
				</td>
			</tr>
			<tr>
				<td colspan="2">
					<input type="submit" value="작성 완료" >
					<input type="button" value="목록" onclick="location.href='list.board'">         
				</td>
			</tr>
			
		</table>
	</form>
</div>

<%@ include file="../include/footer.jsp" %>

파일명 : board_content.jsp ( 글 상세보기 화면 )

<%@ 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" %>

<%@ include file="../include/header.jsp" %>

<div align="center" class="div_center">

	<h3>게시글 내용 보기</h3>
	<hr>
	<table border="1" width="500">
		<tr>
			<td width="20%">글번호</td>
			<td width="30%">${vo.bno }</td>
			
			<td width="20%">조회수</td>
			<td width="30%">${vo.hit }</td>
		</tr>
		<tr>
			<td width="20%">작성자</td>
			<td width="30%">${vo.writer }</td>
			
			<td width="20%">작성일</td>
			<td width="30%"><fmt:formatDate value="${vo.regdate }" pattern="yyyy년MM월dd일" /></td>
		</tr>
		
		<tr>
			<td width="20%">글제목</td>
			<td colspan="3" width="30%">${vo.title }</td>
		</tr>
		<tr>
			<td width="20%">글내용</td>
			<td colspan="3" width="30%" height="120px">${vo.content }</td>
		</tr>
		
		<tr>
			<td colspan="4" align="center">
				<input type="button" value="목록" onclick="location.href='list.board'">&nbsp;&nbsp;
				<input type="button" value="수정" onclick="location.href='modify.board?bno=${vo.bno}'">&nbsp;&nbsp;
				<input type="button" value="삭제" onclick="location.href='delete.board?bno=${vo.bno}'">&nbsp;&nbsp;
			</td>
		</tr>
	</table>
	
</div>

<%@ include file="../include/footer.jsp" %>

파일명 : board_modify.jsp ( 글 수정 화면 )

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

<div align="center" class="div_center">
	<h3>게시판 글 수정 페이지</h3>
	<hr>
	
	<form action="update.board" method="post">
	
		<!-- form안에서 화면에 보이지는 않지만, 반드시 넘겨줘야 되는 값을 숨겨서 보낼 때는 인풋태그의 hidden을 사용합니다. -->
		<input type="hidden" name="bno" value="${vo.bno }">
		<input type="hidden" name="writer" value="${vo.writer }">
				
		<table border="1" width="500">
			
			<tr>
				<td>글 번호</td>
				<td>${vo.bno }</td>
			</tr>
			<tr>
				<td>작성자</td>
				<td>${vo.writer }</td>
			</tr>
			<tr>
				<td>글 제목</td>
				<td>
					<input type="text" name="title" value="${vo.title }">
				</td>
			</tr>
			<tr>
				<td>글 내용</td>
				<td>
					<textarea rows="10" style="width: 95%;" name="content">${vo.content }</textarea>
				</td>
			</tr>
			<tr>
				<td colspan="2">
					<input type="submit" value="수정 하기" >&nbsp;&nbsp;
					<input type="button" value="목록" onclick="location.href='list.board'">        
				</td>
			</tr>
			
		</table>
	</form>
	
</div>

<%@ include file="../include/footer.jsp" %>

위와 같이 작성된 .jsp파일 들을 컨트롤러에서 어떤 처리를 할지 정해 주었습니다.

 

★ 컨트롤러 ☆

package com.myweb.controller;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.myweb.board.service.DeleteServiceImpl;
import com.myweb.board.service.GetContentServiceImpl;
import com.myweb.board.service.GetListServiceImpl;
import com.myweb.board.service.IBoardService;
import com.myweb.board.service.RegistServiceImpl;
import com.myweb.board.service.UpHitServiceImpl;
import com.myweb.board.service.UpdateServiceImpl;

// 1. 
@WebServlet("*.board")
public class BoardController extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    public BoardController() {
        super();
    }

    // 2. get, post요청 통일
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doAction(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doAction(request, response);
	}
	
	protected void doAction(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		// 3. 요청분기
		request.setCharacterEncoding("UTF-8");
		
//		String command = request.getRequestURI().substring(request.getContextPath().length());
		String uri = request.getRequestURI(); // URI
		String path = request.getContextPath();
		
		String command = uri.substring(path.length()); // 요청경로
		
		System.out.println(command);
		
		// MVC2 방식은 forward 이동을 기본적으로 사용합니다. Redirect는 다시 컨트롤러로 연결할 때 사용합니다.
		
		// service의 인터페이스 타입을 선언(if문 안에서 알맞은 서비스 클래스로 연결)
		IBoardService service;
		
		if(command.equals("/board/list.board")) { // 글목록 요청
			// ....조회 메서드를 실행하고, 값을 가지고 화면으로 이동
			service = new GetListServiceImpl();
			service.execute(request, response);
			
			// 화면에 전달할 값이 있으니 forward이동
			request.getRequestDispatcher("board_list.jsp").forward(request, response);
			
		} else if(command.equals("/board/write.board")) { // 글작성 화면요청
			
			request.getRequestDispatcher("board_write.jsp").forward(request, response);
		} else if(command.equals("/board/regist.board")) { // 글 등록 요청
			
			// ....
			service = new RegistServiceImpl();
			service.execute(request, response);
			
			response.sendRedirect("list.board"); // 리다이렉트는 다시 컨트롤러를 태울때 사용합니다.
		} else if (command.equals("/board/getContent.board")) { // 글 상세
			
			// 조회수 증가 (service영역)
			service = new UpHitServiceImpl();
			service.execute(request, response);
			
			// 게시글 정보 조회
			service = new GetContentServiceImpl();
			service.execute(request, response);
			
			request.getRequestDispatcher("board_content.jsp").forward(request, response);
		} else if (command.equals("/board/modify.board")) { // 글 수정요청
			
			// getContentServiceImpl 재활용
			service = new GetContentServiceImpl();
			service.execute(request, response);
			
			request.getRequestDispatcher("board_modify.jsp").forward(request, response);
		} else if (command.equals("/board/update.board")) { // 글 수정 완료
			
			// 서비스...
			/*
			 *  1. UpdateServiceImpl 클래스를 생성하고 execute()메서드 실행.
			 *  2. 서비스 영역에서 bno, title, content를 받아서 DAO의 update() 메서드 실행
			 *  3. update()는 sql문을 이용해서 해당 글 번호의 내용을 수정.
			 *  4. 컨트롤러에서는 Content화면으로 이동. (content가 필요한 값을 자바측에서 전송)
			 */
			service = new UpdateServiceImpl();
			service.execute(request, response);
			
			// forward 로 넘길 경우. 주소값이 변경되지 않아서 새로고침 하는 순간 다시 update로 넘어오게 됌
			response.sendRedirect("getContent.board?bno=" + request.getParameter("bno")); // 수정완료된 글로 이동
//			response.sendRedirect("list.board"); // 글 목록 이동
		} else if (command.equals("/board/delete.board")) { // 글 삭제 요청
			
			service = new DeleteServiceImpl();
			service.execute(request, response);
			
			response.sendRedirect("list.board");
		}
		
	}

}

 

각각의 서비스들은 Interface IBoardServcie 를 implements 해서 만듭니다.

각각의 서비스에서 필요한 처리를 오버라이딩 해서, 구현화를 해줍니다. 구현화를 할 때 데이터베이스 에 처리해줄 내용이 있다면 모델인 DAO 에 메서드를 만들고 사용합니다.

 

파일명 : BoardDAO.java

package com.myweb.board.model;

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

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

import com.myweb.util.JdbcUtil;

public class BoardDAO {

	// 1. 스스로 객체를 1개 생성합니다.
		private static BoardDAO instance = new BoardDAO();
		
		// 2. 외부에서 생성자를 호출할 수 없도록 생성자에 private제한을 붙임
		private BoardDAO() {
			try {
//				Class.forName("oracle.jdbc.driver.OracleDriver");
				
				// 커넥션풀을 얻는 방법
				InitialContext ctx = new InitialContext();
				ds = (DataSource)ctx.lookup("java:comp/env/jdbc/oracle");
				
			} catch(Exception e) {
				System.out.println("드라이버 호출 에러!");
			}
		}
		
		// 3. 외부에서 객체생성을 요구하면 getter메서드를 이용해서 1번의 객체를 반환
		public static BoardDAO getInstance() {
			return instance;
		}
		
		////////////////////////////////////////////////////
		// 멤버변수
		private DataSource ds; // 데이터베이스 연결풀을 저장해놓는 객체
		
		private Connection conn = null;
		private PreparedStatement pstmt = null;
		private ResultSet rs = null;
	
		// 글등록 메서드
		public void regist(String writer, String title, String content) {

			// insert...
			String sql = "insert into board(bno, writer, title, content) values(board_seq.nextval, ?, ?, ?)";
			
			try {
				conn = ds.getConnection();
				
				pstmt = conn.prepareStatement(sql);
				pstmt.setString(1, writer);
				pstmt.setString(2, title);
				pstmt.setString(3, content);
				
				pstmt.executeUpdate(); // 등록후에 끝.
				
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				JdbcUtil.close(conn, pstmt, rs);
			}
		}

		// 글목록 조회
		public List<BoardVO> getList(){
			
			List<BoardVO> list = new ArrayList<>();
			
			String sql = "select * from board order by bno desc";
			
			try {
				conn = ds.getConnection(); // 연결
				
				pstmt = conn.prepareStatement(sql); // sql준비
				
				rs = pstmt.executeQuery(); // sql문 실행
				
				while(rs.next()) {
					// 한바퀴 회전당 VO를 하나씩 생성
					BoardVO vo = new BoardVO();
					
					vo.setBno(rs.getInt("bno"));
					vo.setWriter(rs.getString("writer"));
					vo.setTitle(rs.getString("title"));
					vo.setContent(rs.getString("content"));
					vo.setRegdate(rs.getTimestamp("regdate")); // 날짜형은 Timestamp() or Date()
					vo.setHit(rs.getInt("hit"));
					
					list.add(vo);
				}
				
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				JdbcUtil.close(conn, pstmt, rs);
			}
			
			return list;
		}

		// 글 상세정보 메서드
		public BoardVO getContent(String bno) {
			BoardVO vo = null;
			
			String sql = "select * from board where bno = ?";
			
			try {
				conn = ds.getConnection();
				
				pstmt = conn.prepareStatement(sql);
				pstmt.setString(1, bno);
				
				rs = pstmt.executeQuery();
				
				if(rs.next()) {
					String writer = rs.getString("writer");
					String title = rs.getString("title");
					String content = rs.getString("content");
					Timestamp regdate = rs.getTimestamp("regdate");
					int hit = rs.getInt("hit");
					
					vo = new BoardVO(Integer.parseInt(bno), writer, title, content, regdate, hit);
				}
				
				
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				JdbcUtil.close(conn, pstmt, rs);
			}
			
			return vo;
		}

		// 글 수정하는 메서드
		public void update(String bno, String title, String content) {
			
			String sql ="update board set title = ?, content = ?, regdate = sysdate where bno = ?";
			
			try {
				conn = ds.getConnection();
				
				pstmt = conn.prepareStatement(sql);
				pstmt.setString(1, title);
				pstmt.setString(2, content);
				pstmt.setString(3, bno);
				
				pstmt.executeUpdate();
				
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				JdbcUtil.close(conn, pstmt, rs);
			}
			
		}
		
		// 글 삭제하는 메서드
		public void delete(String bno) {
			
			String sql="delete from board where bno = ?";
			
			try {
				conn = ds.getConnection();
				
				pstmt = conn.prepareStatement(sql);
				pstmt.setString(1, bno);
				
				pstmt.executeUpdate(); // sql문 실행
				
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				JdbcUtil.close(conn, pstmt, rs);
			}
			
		}

		// 조회수 증가 메서드
		public void upHit(String bno) {
			
			String sql ="update board set hit = hit + 1 where bno = ?";
			
			try {
				conn = ds.getConnection();
				
				pstmt = conn.prepareStatement(sql);
				pstmt.setString(1, bno);
				
				pstmt.executeUpdate();
				
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				JdbcUtil.close(conn, pstmt, rs);
			}
		}
}

파일명 : GetListServiceImpl.java

파일명 : RegistServiceImpl.java

파일명 : GetContentServiceImpl.java

파일명 : UpdateServiceImpl.java

파일명 : DeleteServiceImpl.java

파일명 : UpHItServiceImpl.java

@Override
	public void execute(HttpServletRequest request, HttpServletResponse response) {

		String bno = request.getParameter("bno");
		
		// 2. 쿠키는 서버측으로 자동으로 전송되고, 화면에서 넘어온 쿠키를 받아서 현재 조회번호와 같은지 검사.
		//	    조회수 실행여부 결정
		Cookie[] cookies = request.getCookies();

		boolean flag = true;
		if(cookies != null) {
			for(Cookie c : cookies) {
				if(c.getName().equals(bno)) { // 쿠키이름이 게시글 조회번호와 동일한지 검사
					flag = false; // 중복의 의미
					break;
				}
			}
		}
		
		if(flag) { // 중복이 없다면 true
			// DAO연결 조회수증가
			BoardDAO.getInstance().upHit(bno);
		}
		
		// 1. 마지막에 조회된 글 번호를 쿠키로 생성해서, 클라이언트 측으로 전송
		Cookie cookie = new Cookie(bno, bno); // 쿠키형식( 1:1 , 2:2 ).....
		cookie.setMaxAge(30); // 30초 수명설정
		response.addCookie(cookie);
	}

 

※ 커넥션 풀을 이용 중 입니다. ※

'JSP 공부' 카테고리의 다른 글

Day59 - [JSP]필터  (0) 2021.05.10
Day59 - [JSP]페이징  (1) 2021.05.10
Day57 - [JSP]URL패턴 , MVC2 전체적인 컴포넌트 설계  (0) 2021.05.06
Day56 - [JSP]연결풀(Connection pool)  (0) 2021.05.05
Day56 - [JSP]JSTL  (0) 2021.05.05