Study Web Development

1월 21일

이전으로

Servlet & JSP

9. MVC

mvcMain

MVC
  1. kr.controller 패키지에 새 인터페이스 Action 생성
package kr.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public interface Action {
	// 추상 메서드
	public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception;
}
  1. 새 패키지 kr.board.action 생성하고 새 클래스 ListAction 생성
package kr.board.action;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import kr.controller.Action;

public class ListAction implements Action {

	@Override
	public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
		
		// request에 데이터 저장
		request.setAttribute("message", "게시판 목록입니다.");
		
		// JSP 경로 반환
		return "/views/list.jsp";
	}

}
  1. views 폴더에 새 JSP 파일 list.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>목록</title>
</head>
<body>
${message}
</body>
</html>
  1. kr.board.action 패키지에 새 클래스 WriteAction 생성
package kr.board.action;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import kr.controller.Action;

public class WriteAction implements Action {

	@Override
	public String execute(HttpServletRequest request, HttpServletResponse response) {
		
		// request에 데이터 저장
		request.setAttribute("result", "전송된 데이터를 저장했습니다.");
		
		// JSP 경로 반환
		return "views/write.jsp";
	}

}
  1. views 폴더에 새 JSP 파일 write.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>글쓰기</title>
</head>
<body>
${result}
</body>
</html>
  1. kr.board.action 패키지에 새 클래스 DetailAction 생성
package kr.board.action;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import kr.controller.Action;

public class DetailAction implements Action {

	@Override
	public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {

		// request에 데이터 저장
		request.setAttribute("detail", "게시판 상세 정보입니다.");
		
		// JSP 경로 반환
		return "views/detail.jsp";
	}
	
}
  1. views 폴더에 새 JSP 파일 detail.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>게시판 상세 정보</title>
</head>
<body>
${detail}
</body>
</html>
  1. WEB-INF 폴더의 web.xml를 열고, 왼쪽 하단의 Source 탭 선택 후 <servlet> 태그 사이의 내용을 다음처럼 수정
  <servlet-mapping>
  	<servlet-name>DispatcherServlet</servlet-name>
  	<url-pattern>*.do</url-pattern>
  </servlet-mapping>
  1. kr.board.action 패키지에 새 클래스 UpdateAction 생성
package kr.board.action;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import kr.controller.Action;

public class UpdateAction implements Action {

	@Override
	public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
		
		// request에 데이터 저장
		request.setAttribute("msg", "내용을 수정했습니다.");
		
		// JSP 경로 반환
		return "views/update.jsp";
	}

}
  1. views 폴더에 새 JSP 파일 update.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>게시물 수정</title>
</head>
<body>
${msg}
</body>
</html>
  1. kr.board.action 패키지에 새 클래스 DeleteAction 생성
package kr.board.action;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import kr.controller.Action;

public class DeleteAction implements Action {

	@Override
	public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
		
		// request에 데이터 저장
		request.setAttribute("result", "삭제를 완료했습니다.");
		
		// JSP 경로 반환
		return "views/delete.jsp";
	}

}
  1. views 폴더에 새 JSP 파일 delete.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>글 삭제</title>
</head>
<body>
${result}
</body>
</html>
  1. kr.controller 패키지의 DispatcherServlet의 메서드 내용을 다음처럼 수정
	private void requestPro(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		Action com = null;
		String view = null;
		
		// 요청 URI 반환; /mvcMain/list.do 형식
		String command = request.getRequestURI();
		
		if(command.indexOf(request.getContextPath())==0) { // URI가 Context Path로 시작하면
			command = command.substring(request.getContextPath().length()); // URI에서 Context Path 이후의 문자열을 추출
		}
		
		if(command.equals("/list.do")) {
			com = new ListAction();	
		}
		else if(command.equals("/write.do")) {
			com = new WriteAction();
		}
		else if(command.equals("/detail.do")) {
			com = new DetailAction();
		}
		else if(command.equals("/update.do")) {
			com = new UpdateAction();
		}
		else if(command.equals("/delete.do")) {
			com = new DeleteAction();
		}
		
		try {
			// 모델 클래스의 execute() 메서드를 호출하고 JSP 경로를 반환받음
			view = com.execute(request, response);
		}
		catch(Exception e) {
			e.printStackTrace();
		}
		
		// forward 방식으로 JSP(View) 호출
		RequestDispatcher dispatcher = request.getRequestDispatcher(view);
		dispatcher.forward(request, response);
	}

mvcBoard

프로젝트 생성 및 설정
  1. 새 다이나믹 웹 프로젝트를 생성하여 프로젝트명에 mvcBoard 입력 후 Next-Next-Generate web.xml depolyment descriptor 선택 후 Finish
  2. 프로젝트를 오른쪽 클릭하여 Build Path-Configure Build Path... 선택하고 Libraries 탭에서 JRE System Library를 선택 후 Edit...에서 JavaSE-1.8(jre)로 변경
  3. 프로젝트를 오른쪽 클릭하여 Properties 선택하고 좌측 목록에서 Project Facets 선택 후 Java의 Version을 1.8로 변경
  4. src/main/java 오른쪽 클릭하여 새 패키지 kr.controller 생성 후 새 클래스 DispatcherServlet 생성
package kr.controller;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
  
public class DispatcherServlet extends HttpServlet{
	private static final long serialVersionUID = 4068304416616773907L;
	
	private Map<String,Action> commandMap = 
			                  new HashMap<String,Action>();

	@Override
	public void init(ServletConfig config) throws ServletException {
		Properties pr = new Properties();
		//"/WEB-INF/ActionMap.properties" 반환
		String props = config.getInitParameter("propertiesPath");
		//ActionMap.properties 파일의 절대 경로 구하기
		String path = config.getServletContext().getRealPath(props);
		FileInputStream fis = null;
		try{
			fis = new FileInputStream(path);
			//파일 스트림을 Properties 객체 넘겨 key와 value 구분
			pr.load(fis);
		}catch(IOException e){
			throw new ServletException(e);
		}finally{
			if(fis!=null)try{fis.close();}catch(IOException e){}
		}
		
		//Properties 객체에서 key구하기
		Iterator<?> keyIter = pr.keySet().iterator();
		while(keyIter.hasNext()){
			String command = (String)keyIter.next();//key
			String className = pr.getProperty(command);//value
			
			try {
				//문자열을 이용해 클래스를 찾아 Class 타입으로 반환
				Class<?> commandClass = Class.forName(className);
				//객체로 생성
				Object commandInstance = commandClass.getDeclaredConstructor().newInstance();
				//HashMap에 key와 value로 등록
				commandMap.put(command, (Action)commandInstance);
			} catch (Exception e) {
				throw new ServletException(e);
			} 
		}
	}
	@Override
	protected void doGet(HttpServletRequest request, 
			            HttpServletResponse response)
			throws ServletException, IOException {
		requestPro(request,response);
	}
	@Override
	protected void doPost(HttpServletRequest request, 
			             HttpServletResponse response)
			throws ServletException, IOException {
		requestPro(request,response);
	}
	private void requestPro(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		String view = null;
		Action com = null;
		
		String command = request.getRequestURI();
		
		if(command.indexOf(request.getContextPath())==0){
			command = command.substring(request.getContextPath().length());
		}
		
		//HashMap에 key를 넣어서 value(모델 객체)를 얻음
		com = commandMap.get(command);
		
		try{
			//데이터를 생성해서 request에 저장하고 
			//jsp 경로 반환
			view = com.execute(request, response);
		}catch(Exception e){
			throw new ServletException(e);
		}
		
		if(view.startsWith("redirect:")){//리다이렉트
			view = view.substring("redirect:".length());
			response.sendRedirect(request.getContextPath()+view);
		}else{
			//forward 방식으로 view(jsp) 호출
			RequestDispatcher dispatcher =
					request.getRequestDispatcher(view);
			dispatcher.forward(request, response);
		}
	}
}
  1. mvcMain 프로젝트의 kr.controller 패키지에서 Action.java를 복사하여 mvcBoard 프로젝트의 kr.controller 패키지에 붙여넣기
  2. C:\javaWork\apps에서 ojdbc8.jar, jstl-1.2.jar를 복사하여 C:\javaWork\workspace_jsp\mvcBoard\src\main\webapp\WEB-INF\lib에 붙여넣기
  3. WEB-INF 폴더의 web.xml를 열고, 왼쪽 하단의 Source 탭 선택
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0">
  <display-name>mvcBoard</display-name>
  <servlet>
  	<servlet-name>DispatcherServlet</servlet-name>
  	<servlet-class>kr.controller.DispatcherServlet</servlet-class>
  	<init-param>
  		<param-name>propertiesPath</param-name>
  		<param-value>/WEB-INF/ActionMap.properties</param-value>
  	</init-param>
  </servlet>
  <servlet-mapping>
  	<servlet-name>DispatcherServlet</servlet-name>
  	<url-pattern>*.do</url-pattern> <!-- * 앞에 / 붙이면 에러 발생 -->
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
</web-app>
  1. WEB-INF 폴더 오른쪽 클릭하고 새 파일 ActionMap.properties 생성
    • 뷰와 모델을 추가할 때마다 Servlet의 내용을 변경하면 매번 다시 컴파일되므로, Servlet은 그대로 두고 뷰와 모델의 매핑을 별도의 설정 파일로 처리
# 요청 URL=모델 클래스
/list.do=kr.board.action.ListAction
/writeForm.do=kr.board.action.WriteFormAction
/write.do=kr.board.action.WriteAction
  1. 이클립스에서 Help-Eclipse Marketplace... 선택하고 Simple Properties Editor 1.0.5 설치
  2. ActionMap.properties 오른쪽 클릭 후 Open With-SimplePropertiesEditor 선택하면 한글 주석 확인 가능
  3. webapp 폴더 오른쪽 클릭하고 새 JSP 파일 index.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	response.sendRedirect(request.getContextPath() + "/list.do");
%>
  1. webapp 폴더 오른쪽 클릭하고 새 폴더 sql 생성
  2. m1_board 프로젝트의 src/main/webapp/sql 폴더에서 table.sql을 복사하여 mvcBoard 프로젝트의 src/main/webapp/sql 폴더에 붙여넣기
  3. m1_board 프로젝트의 src/main/webapp 폴더에서 css 폴더를 복사하여 mvcBoard 프로젝트의 src/main/webapp 폴더에 붙여넣기
  4. m1_board 프로젝트의 src/main/webapp/META-INF 폴더에서 context.xml을 복사하여 mvcBoard 프로젝트의 src/main/webapp/META-INF 폴더에 붙여넣기
  5. src/main/java 오른쪽 클릭하여 새 패키지 kr.util 생성
  6. m1_board 프로젝트의 kr.util 패키지에서 PagingUtil.java를 복사하여 mvcBoard 프로젝트의 kr.util 패키지에 붙여넣기
  7. webapp 폴더 오른쪽 클릭하고 새 폴더 js 생성 후 validateLength.js 생성
function validateSubmit(id) {
	document.getElementById(id).onsubmit = function() {
		let list = document.getElementsByTagName('li');
		for(let i=0;i<list.length;i++) {
			let input = list[i].querySelector('input,textarea');
			input.value = input.value.trim();
			if(!input.value) {
				let word = list[i].querySelector('label').textContent;
				let post = (word.charCodeAt(word.length-1) - ''.charCodeAt(0)) % 28 > 0 ? '' : '';
				alert(word + post + ' 입력하세요!');
				input.focus();
				return false;
			}
		}
	};
}

function getBytesLength(str) {
    let bytes = 0;
    for(let i=0;i<str.length;i++) {
        let unicode = str.charCodeAt(i);
        bytes += unicode >> 11 ? 3 : (unicode >> 7 ? 2 : 1); // 2^11=2048로 나누었을 때 몫이 있으면 3bytes, 그보다 작은 수이면서 2^7=128로 나누었을 때 몫이 있으면 2bytes, 그 외에는 1byte
    }
    return bytes;
}

function validateBytesLength(obj) {
	for(let key in obj) {
		document.getElementById(key).onkeyup = function() {
			while(getBytesLength(this.value)>obj[key]) {
				this.value = this.value.slice(0, -1);
			}
		};
	}
}
Model
  1. src/main/java 오른쪽 클릭하고 새 패키지 kr.board.action 생성 후 새 클래스 ListAction 생성
package kr.board.action;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import kr.board.dao.BoardDAO;
import kr.board.vo.BoardVO;
import kr.controller.Action;
import kr.util.PagingUtil;

public class ListAction implements Action {

	@Override
	public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
		String pageNum = request.getParameter("pageNum");
		if(pageNum==null) {
			pageNum = "1";
		}
		
		BoardDAO dao = BoardDAO.getInstance();
		int count = dao.getCount();
		
		// 페이지 처리
		PagingUtil page = new PagingUtil(Integer.parseInt(pageNum), count, 20, 10, "list.do"); // currentPage, totalCount, rowCount, pageCount, pageUrl
		
		List<BoardVO> list = null;
		if(count > 0) {
			list = dao.getList(page.getStartCount(), page.getEndCount());
		}
		
		request.setAttribute("count", count);
		request.setAttribute("list", list);
		request.setAttribute("pagingHtml", page.getPagingHtml());
		
		// JSP 경로 반환
		return "/WEB-INF/views/list.jsp"; // WEB-INF는 클라이언트에서 직접 호출 불가; WEB-INF 하위에 위치한 JSP 페이지는 (Servlet을 통한) forward 방식으로만 접근 가능
	}

}
  1. 새 클래스 WriteFormAction 생성
package kr.board.action;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import kr.controller.Action;

public class WriteFormAction implements Action {

	@Override
	public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
		
		// JSP 경로 반환
		return "/WEB-INF/views/writeForm.jsp";
	}

}
  1. 새 클래스 WriteAction 생성
package kr.board.action;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import kr.board.dao.BoardDAO;
import kr.board.vo.BoardVO;
import kr.controller.Action;

public class WriteAction implements Action {

	@Override
	public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
		// 전송된 데이터 인코딩 처리
		request.setCharacterEncoding("UTF-8");
		
		// 자바빈 객체 생성
		BoardVO vo = new BoardVO();	
		vo.setTitle(request.getParameter("title"));
		vo.setName(request.getParameter("name"));
		vo.setPasswd(request.getParameter("passwd"));
		vo.setContent(request.getParameter("content"));
		vo.setIp(request.getRemoteAddr());
		
		// DAO 호출
		BoardDAO dao = BoardDAO.getInstance();
		// 글 작성
		dao.insert(vo);
		
		// JSP 경로 반환
		return "/WEB-INF/views/write.jsp";
	}

}
View
  1. WEB-INF 폴더 오른쪽 클릭하고 새 폴더 views 생성 후 새 JSP 파일 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" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>게시판 목록</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/layout.css">
</head>
<body>
<div class="page-main">
	<h2>게시판 목록</h2>
	<div class="align-right">
		<input type="button" value="글쓰기" onclick = "location.href = 'writeForm.do';">
	</div>
	<c:if test="${count == 0}">
	<div class="result-display">
		등록된 게시물이 없습니다.
	</div>
	</c:if>
	<c:if test="${count > 0 }">
	<table>
		<tr>
			<th>글 번호</th>
			<th>제목</th>
			<th>작성자</th>
			<th>작성일</th>
		</tr>
		<c:forEach var="board" items="${list}">
		<tr>
			<td>${board.num}</td>
			<td><a href="detail.do?num=${board.num}">${board.title}</a></td>
			<td>${board.name}</td>
			<td>${board.reg_date}</td>
		</tr>
		</c:forEach>
	</table>
	<div class="align-center">
		${pagingHtml}
	</div>
	</c:if>
</div>
</body>
</html>
  1. 새 JSP 파일 writeForm.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>글쓰기</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/layout.css">
</head>
<body>
<div class="page-main">
	<h2>글쓰기</h2>
	<form id="register_form" action="write.do" method="post">
		<ul>
			<li>
				<label for="title">제목</label>
				<input type="text" name="title" id="title" size="30">
			</li>
			<li>
				<label for="name">이름</label>
				<input type="text" name="name" id="name" size="10">
			</li>
			<li>
				<label for="passwd">비밀번호</label>
				<input type="password" name="passwd" id="passwd" size="12">
			</li>
			<li>
				<label for="content">내용</label>
				<textarea rows="5" cols="40" name="content" id="content"></textarea>
			</li>
		</ul>
		<div class="align-center">
			<input type="submit" value="등록">
			<input type="button" value="목록" onclick="location.href = 'list.do';">
		</div>
	</form>
</div>
<script type="text/javascript" src="${pageContext.request.contextPath}/js/validateLength.js"></script>
<script type="text/javascript">
	validateSubmit('register_form');

	validateBytesLength({
		title:150,
		name:30,
		passwd:12
	});
</script>
</body>
</html>
  1. 새 JSP 파일 write.jsp 생성
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<script type="text/javascript">
	alert('글쓰기 완료!');
	location.href = 'list.do';
</script>
자바빈
  1. src/main/java 오른쪽 클릭하여 새 패키지 kr.board.vo 생성 후 새 클래스 BoardVO 생성
package kr.board.vo;

import java.sql.Date;

public class BoardVO {
	private int num; // 글 번호
	private String title; // 제목
	private String name; // 작성자
	private String passwd; // 비밀번호
	private String content; // 내용
	private String ip; // IP 주소
	private Date reg_date; // 등록일
	
	// 비밀번호 일치 여부 체크
	public boolean isCheckedPassword(String userPasswd) {
		if(passwd.equals(userPasswd)) {
			return true;
		}
		return false;
	}
	
	public int getNum() {
		return num;
	}
	public void setNum(int num) {
		this.num = num;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getPasswd() {
		return passwd;
	}
	public void setPasswd(String passwd) {
		this.passwd = passwd;
	}
	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;
	}
	public Date getReg_date() {
		return reg_date;
	}
	public void setReg_date(Date reg_date) {
		this.reg_date = reg_date;
	}
}
DAO
  1. src/main/java 오른쪽 클릭하여 새 패키지 kr.board.dao 생성 후 새 클래스 BoardDAO 생성
package kr.board.dao;

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.sql.DataSource;

import kr.board.vo.BoardVO;

public class BoardDAO {
	// 싱글턴 패턴
	private static BoardDAO instance = new BoardDAO();
	public static BoardDAO getInstance() {
		return instance;
	}
	private BoardDAO() {}

	// context.xml에서 설정 정보를 읽어들여 커넥션 풀로부터 커넥션을 할당받음
	private Connection getConnection() throws Exception {
		Context initCtx = new InitialContext();
		DataSource ds = (DataSource)initCtx.lookup("java:comp/env/jdbc/xe");
		return ds.getConnection();
	}
	
	// 자원 정리
	private void executeClose(ResultSet rs, PreparedStatement pstmt, Connection conn) {
		if(rs!=null) try {rs.close();} catch(SQLException e) {}
		if(pstmt!=null) try {pstmt.close();} catch(SQLException e) {}
		if(conn!=null) try {conn.close();} catch(SQLException e) {}
	}
	
	// 글 저장
	public void insert(BoardVO vo) throws Exception {
		Connection conn = null;
		PreparedStatement pstmt = null;
		String sql = null;
		
		try {
			// 커넥션 풀로부터 커넥션을 할당
			conn = getConnection();
			
			// SQL문 작성
			sql = "INSERT INTO sboard (num, title, name, passwd, content, ip, reg_date) "
				+ "VALUES (sboard_seq.NEXTVAL, ?, ?, ?, ?, ?, SYSDATE)";
			
			// PreparedStatement 객체 생성
			pstmt = conn.prepareStatement(sql);
			// ?에 데이터를 바인딩
			pstmt.setString(1, vo.getTitle());
			pstmt.setString(2, vo.getName());
			pstmt.setString(3, vo.getPasswd());
			pstmt.setString(4, vo.getContent());
			pstmt.setString(5, vo.getIp());
			
			// SQL문 실행
			pstmt.executeUpdate();
		}
		catch(Exception e) {
			throw new Exception(e);
		}
		finally {
			// 자원 정리
			executeClose(null, pstmt, conn);
		}
	}
	
	// 글의 총 갯수
	public int getCount() throws Exception {
		int count = 0;
		
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		String sql = null;
		
		try {
			// 커넥션 풀로부터 커넥션을 할당
			conn = getConnection();
			
			// SQL문 작성
			sql = "SELECT COUNT(*) FROM sboard";
			
			// PreparedStatement 객체 생성
			pstmt = conn.prepareStatement(sql);
			
			// SQL문을 실행해서 결과 행을 ResultSet에 담아 반환
			rs = pstmt.executeQuery();
			if(rs.next()) {
				count = rs.getInt(1);
			}
		}
		catch(Exception e) {
			throw new Exception(e);
		}
		finally {
			// 자원 정리
			executeClose(rs, pstmt, conn);
		}
		
		return count;
	}
	
	// 목록
	public List<BoardVO> getList(int startRow, int endRow) throws Exception {
		List<BoardVO> list = null;
		
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		String sql = null;
		
		try {
			// 커넥션 풀로부터 커넥션을 할당
			conn = getConnection();
			
			// SQL문 작성
			sql = "SELECT * FROM (SELECT sb.*, ROWNUM AS rnum "
				+ "FROM (SELECT * FROM sboard ORDER BY num DESC) sb) "
				+ "WHERE rnum >= ? AND rnum <= ?";
			
			// PreparedStatement 객체 생성
			pstmt = conn.prepareStatement(sql);
			// ?에 데이터를 바인딩
			pstmt.setInt(1, startRow);
			pstmt.setInt(2, endRow);
			
			// SQL문을 실행해서 결과 행들을 ResultSet에 담아 반환
			rs = pstmt.executeQuery();
			// 반복문을 이용해서 자바빈을 생성하고 정보를 저장
			list = new ArrayList<BoardVO>();
			while(rs.next()) {
				// 자바빈 생성
				BoardVO vo = new BoardVO();
				vo.setNum(rs.getInt("num"));
				vo.setTitle(rs.getString("title"));
				vo.setName(rs.getString("name"));
				vo.setReg_date(rs.getDate("reg_date"));
				
				// 자바빈을 ArrayList에 저장
				list.add(vo);
			}
		}
		catch(Exception e) {
			throw new Exception(e);
		}
		finally {
			// 자원 정리
			executeClose(rs, pstmt, conn);
		}
		
		return list;
	}
	
	// 글 상세 정보
	public BoardVO getBoard(int num) throws Exception {
		BoardVO vo = null;

		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		String sql = null;
		
		try {
			// 커넥션 풀로부터 커넥션을 할당
			conn = getConnection();
			
			// SQL문 작성
			sql = "SELECT * FROM sboard WHERE num=?";
			
			// PreparedStatement 객체 생성
			pstmt = conn.prepareStatement(sql);
			// ?에 데이터를 바인딩
			pstmt.setInt(1, num);
			
			// SQL문을 실행해서 결과 행을 ResultSet에 담아 반환
			rs = pstmt.executeQuery();
			if(rs.next()) {
				vo = new BoardVO();
				vo.setNum(num);
				vo.setTitle(rs.getString("title"));
				vo.setName(rs.getString("name"));
				vo.setPasswd(rs.getString("passwd"));
				vo.setContent(rs.getString("content"));
				vo.setIp(rs.getString("ip"));
				vo.setReg_date(rs.getDate("reg_date"));
			}
		}
		catch (Exception e) {
			throw new Exception(e);
		}
		finally {
			// 자원 정리
			executeClose(rs, pstmt, conn);
		}
		
		return vo;
	}
	
	// 글 수정
	public void update(BoardVO vo) throws Exception {
		Connection conn = null;
		PreparedStatement pstmt = null;
		String sql = null;
		
		try {
			// 커넥션 풀로부터 커넥션을 할당
			conn = getConnection();
			
			// SQL문 작성
			sql = "UPDATE sboard SET title=?, name=?, content=?, ip=?, reg_date=SYSDATE "
				+ "WHERE num=?";
			
			// PreparedStatement 객체 생성
			pstmt = conn.prepareStatement(sql);
			// ?에 데이터를 바인딩
			pstmt.setString(1, vo.getTitle());
			pstmt.setString(2, vo.getName());
			pstmt.setString(3, vo.getContent());
			pstmt.setString(4, vo.getIp());
			pstmt.setInt(5, vo.getNum());
			
			// SQL문 실행
			pstmt.executeUpdate();
		}
		catch (Exception e) {
			throw new Exception(e);
		}
		finally {
			// 자원 정리
			executeClose(null, pstmt, conn);
		}		
	}
	
	// 글 삭제
	public void delete(int num) throws Exception {
		Connection conn = null;
		PreparedStatement pstmt = null;
		String sql = null;
		
		try {
			// 커넥션 풀로부터 커넥션을 할당
			conn = getConnection();
			
			// SQL문 작성
			sql = "DELETE FROM sboard WHERE num=?";
			
			// PreparedStatement 객체 생성
			pstmt = conn.prepareStatement(sql);
			// ?에 데이터를 바인딩
			pstmt.setInt(1, num);
			
			// SQL문 실행
			pstmt.executeUpdate();
		}
		catch (Exception e) {
			throw new Exception(e);
		}
		finally {
			// 자원 정리
			executeClose(null, pstmt, conn);
		}		
	}
}

다음으로