지금까지 자바 웹 개발에 필요한
서블릿, 자바 빈즈, JSP, JDBC를 학습했습니다.
(이전 글들을 참고해 주세요.)
웹 개발자들 사이에서 우스갯소리로 혼자서 게시판을 만들 줄 알면
웹을 다 만들 수 있다는 말이 있다고 합니다. 😂
그동안 배운 것들을 활용해서
웹 게시판을 MVC 모델 2로 구현해 봅시다.
📝MVC 모델 2란?
✔예전 포스팅 참고
https://hyunki99.tistory.com/46?category=1099323
⦁ MVC 모델 2
디자인 부분과 로직 부분을 나누어서 개발합니다.
따라서 유지보수가 좋고, 디자이너와 개발자의 분업이 편리합니다.
View(보여지는 화면)는 JSP로,
Model(DB와 연동, 비즈니스 로직 등)은 자바 빈즈로 개발합니다.
서로 독립적으로 코딩하기 때문에 둘 사이에 연결이 필요합니다.
따라서 서블릿을 Controller로 사용합니다.
MVC 패턴에서 중심 역할을 하게 됩니다.
📝 1. View ( JSP )
⦁ View
WebContent/board/qna_borad_list.jsp
WebContent/board/qna_borad_write.jsp
✔ 뷰를 담당하는 JSP 파일입니다. 위 경로에 넣어줍니다.
📑 qna_borad_list.jsp
<%@ page language="java" contentType="text/html; charset=EUC-KR"%>
<%@ page import="java.util.*"%>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import="net.board.db.*" %>
<%
List boardList=(List)request.getAttribute("boardlist");
int listcount=((Integer)request.getAttribute("listcount")).intValue();
int nowpage=((Integer)request.getAttribute("page")).intValue();
int maxpage=((Integer)request.getAttribute("maxpage")).intValue();
int startpage=((Integer)request.getAttribute("startpage")).intValue();
int endpage=((Integer)request.getAttribute("endpage")).intValue();
%>
<html>
<head>
<title>MVC 게시판</title>
</head>
<body>
<!-- 게시판 리스트 -->
<table width=50% border="0" cellpadding="0" cellspacing="0">
<tr align="center" valign="middle">
<td colspan="4">MVC 게시판</td>
<td align=right>
<font size=2>글 개수 : ${listcount }</font>
</td>
</tr>
<tr align="center" valign="middle" bordercolor="#333333">
<td style="font-family:Tahoma;font-size:8pt;" width="8%" height="26">
<div align="center">번호</div>
</td>
<td style="font-family:Tahoma;font-size:8pt;" width="50%">
<div align="center">제목</div>
</td>
<td style="font-family:Tahoma;font-size:8pt;" width="14%">
<div align="center">작성자</div>
</td>
<td style="font-family:Tahoma;font-size:8pt;" width="17%">
<div align="center">날짜</div>
</td>
<td style="font-family:Tahoma;font-size:8pt;" width="11%">
<div align="center">조회수</div>
</td>
</tr>
<%
for(int i=0;i<boardList.size();i++){
BoardBean bl=(BoardBean)boardList.get(i);
%>
<tr align="center" valign="middle" bordercolor="#333333"
onmouseover="this.style.backgroundColor='F8F8F8'"
onmouseout="this.style.backgroundColor=''">
<td height="23" style="font-family:Tahoma;font-size:10pt;">
<%=bl.getBOARD_NUM()%>
</td>
<td style="font-family:Tahoma;font-size:10pt;">
<div align="left">
<%if(bl.getBOARD_RE_LEV()!=0){ %>
<%for(int a=0;a<=bl.getBOARD_RE_LEV()*2;a++){ %>
<%} %>
▶
<%}else{ %>
▶
<%} %>
<a href="./BoardDetailAction.bo?num=<%=bl.getBOARD_NUM()%>">
<%=bl.getBOARD_SUBJECT()%>
</a>
</div>
</td>
<td style="font-family:Tahoma;font-size:10pt;">
<div align="center"><%=bl.getBOARD_NAME() %></div>
</td>
<td style="font-family:Tahoma;font-size:10pt;">
<div align="center"><%=bl.getBOARD_DATE() %></div>
</td>
<td style="font-family:Tahoma;font-size:10pt;">
<div align="center"><%=bl.getBOARD_READCOUNT() %></div>
</td>
</tr>
<%} %>
<tr align=center height=20>
<td colspan=7 style=font-family:Tahoma;font-size:10pt;>
<%if(nowpage<=1){ %>
[이전]
<%}else{ %>
<a href="./BoardList.bo?page=<%=nowpage-1 %>">[이전]</a>
<%} %>
<%for(int a=startpage;a<=endpage;a++){
if(a==nowpage){%>
[<%=a %>]
<%}else{ %>
<a href="./BoardList.bo?page=<%=a %>">[<%=a %>]</a>
<%} %>
<%} %>
<%if(nowpage>=maxpage){ %>
[다음]
<%}else{ %>
<a href="./BoardList.bo?page=<%=nowpage+1 %>">[다음]</a>
<%} %>
</td>
</tr>
<tr align="right">
<td colspan="5">
<a href="./BoardWrite.bo">[글쓰기]</a>
</td>
</tr>
</table>
</body>
</html>
📑 qna_borad_write.jsp
<%@ page language="java" contentType="text/html; charset=EUC-KR"%>
<html>
<head>
<title>MVC 게시판</title>
<script language="javascript">
function addboard(){
boardform.submit();
}
</script>
</head>
<body>
<!-- 게시판 등록 -->
<form action="./BoardAddAction.bo" method="post"
enctype="multipart/form-data" name="boardform">
<table cellpadding="0" cellspacing="0">
<tr align="center" valign="middle">
<td colspan="5">MVC 게시판</td>
</tr>
<tr>
<td style="font-family:돋음; font-size:12" height="16">
<div align="center">글쓴이</div>
</td>
<td>
<input name="BOARD_NAME" type="text" size="10" maxlength="10"
value=""/>
</td>
</tr>
<tr>
<td style="font-family:돋음; font-size:12" height="16">
<div align="center">비밀번호</div>
</td>
<td>
<input name="BOARD_PASS" type="password" size="10" maxlength="10"
value=""/>
</td>
</tr>
<tr>
<td style="font-family:돋음; font-size:12" height="16">
<div align="center">제 목</div>
</td>
<td>
<input name="BOARD_SUBJECT" type="text" size="50" maxlength="100"
value=""/>
</td>
</tr>
<tr>
<td style="font-family:돋음; font-size:12">
<div align="center">내 용</div>
</td>
<td>
<textarea name="BOARD_CONTENT" cols="67" rows="15"></textarea>
</td>
</tr>
<tr>
<td style="font-family:돋음; font-size:12">
<div align="center">파일 첨부</div>
</td>
<td>
<input name="BOARD_FILE" type="file"/>
</td>
</tr>
<tr bgcolor="cccccc">
<td colspan="2" style="height:1px;">
</td>
</tr>
<tr><td colspan="2"> </td></tr>
<tr align="center" valign="middle">
<td colspan="5">
<a href="javascript:addboard()">[등록]</a>
<a href="javascript:history.go(-1)">[뒤로]</a>
</td>
</tr>
</table>
</form>
<!-- 게시판 등록 -->
</body>
</html>
📝 2. Model (자바 빈즈)
⦁ CREATE TABLE
✔ DB를 사용할 것이기 때문에 테이블을 생성해 줍니다.
CREATE TABLE BOARD(
BOARD_NUM INT,
BOARD_NAME VARCHAR2(20),
BOARD_PASS VARCHAR2(15),
BOARD_SUBJECT VARCHAR2(50),
BOARD_CONTENT VARCHAR2(2000),
BOARD_FILE VARCHAR2(50),
BOARD_RE_REF INT,
BOARD_RE_LEV INT,
BOARD_RE_SEQ INT,
BOARD_READCOUNT INT,
BOARD_DATE DATE,
PRIMARY KEY(BOARD_NUM)
);
⦁ 파일 위치 및 설명
net.board.db 패키지를 만들고 다음과 같이 2개의 자바 파일을 만들어 주세요.
BoardBean.java 파일은 테이블의 컬럼을 필드로 가지고 있는 클래스입니다.
BoardDAO.java는 커넥션 풀을 이용해서 DB에 접속하고 메서드를 통해
쿼리문을 실행합니다.
❗ JDBC에 대해 잘 모른다면 이 글을 참고하세요.
몇 가지 설정이 필요합니다.😀
https://hyunki99.tistory.com/55
📑 BoardBean.java
package net.board.db;
import java.sql.Date;
public class BoardBean {
private int BOARD_NUM;
private String BOARD_NAME;
private String BOARD_PASS;
private String BOARD_SUBJECT;
private String BOARD_CONTENT;
private String BOARD_FILE;
private int BOARD_RE_REF;
private int BOARD_RE_LEV;
private int BOARD_RE_SEQ;
private int BOARD_READCOUNT;
private Date BOARD_DATE;
public int getBOARD_NUM() {
return BOARD_NUM;
}
public void setBOARD_NUM(int bOARD_NUM) {
BOARD_NUM = bOARD_NUM;
}
public String getBOARD_NAME() {
return BOARD_NAME;
}
public void setBOARD_NAME(String bOARD_NAME) {
BOARD_NAME = bOARD_NAME;
}
public String getBOARD_PASS() {
return BOARD_PASS;
}
public void setBOARD_PASS(String bOARD_PASS) {
BOARD_PASS = bOARD_PASS;
}
public String getBOARD_SUBJECT() {
return BOARD_SUBJECT;
}
public void setBOARD_SUBJECT(String bOARD_SUBJECT) {
BOARD_SUBJECT = bOARD_SUBJECT;
}
public String getBOARD_CONTENT() {
return BOARD_CONTENT;
}
public void setBOARD_CONTENT(String bOARD_CONTENT) {
BOARD_CONTENT = bOARD_CONTENT;
}
public String getBOARD_FILE() {
return BOARD_FILE;
}
public void setBOARD_FILE(String bOARD_FILE) {
BOARD_FILE = bOARD_FILE;
}
public int getBOARD_RE_REF() {
return BOARD_RE_REF;
}
public void setBOARD_RE_REF(int bOARD_RE_REF) {
BOARD_RE_REF = bOARD_RE_REF;
}
public int getBOARD_RE_LEV() {
return BOARD_RE_LEV;
}
public void setBOARD_RE_LEV(int bOARD_RE_LEV) {
BOARD_RE_LEV = bOARD_RE_LEV;
}
public int getBOARD_RE_SEQ() {
return BOARD_RE_SEQ;
}
public void setBOARD_RE_SEQ(int bOARD_RE_SEQ) {
BOARD_RE_SEQ = bOARD_RE_SEQ;
}
public int getBOARD_READCOUNT() {
return BOARD_READCOUNT;
}
public void setBOARD_READCOUNT(int bOARD_READCOUNT) {
BOARD_READCOUNT = bOARD_READCOUNT;
}
public Date getBOARD_DATE() {
return BOARD_DATE;
}
public void setBOARD_DATE(Date bOARD_DATE) {
BOARD_DATE = bOARD_DATE;
}
}
📑BoardDAO.java
package net.board.db;
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;
public class BoardDAO {
Connection con;
PreparedStatement pstmt;
ResultSet rs;
public BoardDAO() {
try {
Context init = new InitialContext();
DataSource ds = (DataSource) init.lookup("java:comp/env/jdbc/OracleDB");
con = ds.getConnection();
} catch(Exception ex) {
System.out.println("DB : "+ex);
return;
}
}
public int getListCount() {
int x = 0;
try {
pstmt = con.prepareStatement("select count(*) from board");
rs = pstmt.executeQuery();
if(rs.next()) {
x=rs.getInt(1);
}
} catch(Exception ex) {
System.out.println("getListCount : " + ex);
} finally {
if(rs!=null) try {rs.close();} catch(SQLException ex) {}
if(pstmt!=null) try {pstmt.close();} catch(SQLException ex) {}
}
return x;
}
public List getBoardList(int page,int limit){
String board_list_sql="select * from "+
"(select rownum rnum,BOARD_NUM,BOARD_NAME,BOARD_SUBJECT,"+
"BOARD_CONTENT,BOARD_FILE,BOARD_RE_REF,BOARD_RE_LEV,"+
"BOARD_RE_SEQ,BOARD_READCOUNT,BOARD_DATE from "+
"(select * from board order by BOARD_RE_REF desc,BOARD_RE_SEQ asc)) "+
"where rnum>=? and rnum<=?";
List list = new ArrayList();
int startrow=(page-1)*10+1;
int endrow=startrow+limit-1;
try{
pstmt = con.prepareStatement(board_list_sql);
pstmt.setInt(1, startrow);
pstmt.setInt(2, endrow);
rs = pstmt.executeQuery();
while(rs.next()){
BoardBean board = new BoardBean();
board.setBOARD_NUM(rs.getInt("BOARD_NUM"));
board.setBOARD_NAME(rs.getString("BOARD_NAME"));
board.setBOARD_SUBJECT(rs.getString("BOARD_SUBJECT"));
board.setBOARD_CONTENT(rs.getString("BOARD_CONTENT"));
board.setBOARD_FILE(rs.getString("BOARD_FILE"));
board.setBOARD_RE_REF(rs.getInt("BOARD_RE_REF"));
board.setBOARD_RE_LEV(rs.getInt("BOARD_RE_LEV"));
board.setBOARD_RE_SEQ(rs.getInt("BOARD_RE_SEQ"));
board.setBOARD_READCOUNT(rs.getInt("BOARD_READCOUNT"));
board.setBOARD_DATE(rs.getDate("BOARD_DATE"));
list.add(board);
}
return list;
}catch(Exception ex){
System.out.println("getBoardList ���� : " + ex);
}finally{
if(rs!=null) try{rs.close();}catch(SQLException ex){}
if(pstmt!=null) try{pstmt.close();}catch(SQLException ex){}
}
return null;
}
public Connection getCon() {
return con;
}
public void setCon(Connection con) {
this.con = con;
}
public PreparedStatement getPstmt() {
return pstmt;
}
public void setPstmt(PreparedStatement pstmt) {
this.pstmt = pstmt;
}
public ResultSet getRs() {
return rs;
}
public void setRs(ResultSet rs) {
this.rs = rs;
}
}
📝 3. Controller (서블릿)
⦁ 요청을 받아서 Model과 View를 연결시켜주는 통로 역할입니다.
⦁ 파일 위치 및 설명
✔ BoardFrontController 파일은 컨트롤러의 가장 핵심이 되는 파일입니다.
꼭 서블릿으로 생성해 줍니다.
마치 리액트의 라우팅처럼 사용자가 어느 주소로 접속하면 보여줄 페이지를 지정합니다.
그리고 redirect / forward 중 어떤 방식으로 접속했는지 확인하고 다른 동작을 실행합니다.
⦁ 서블릿 매핑
#WebContent/WEB-INF/web.xml 파일
<servlet>
<servlet-name>BoardFrontController</servlet-name>
<servlet-class>net.board.action.BoardFrontController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>BoardFrontController</servlet-name>
<url-pattern>*.bo</url-pattern>
</servlet-mapping>
✔ *.bo 로 설정하면 뒤에 .bo가 붙은 모든 url에 대해서 매핑됩니다.
⦁ 소스코드
📑 BoardFrontController 서블릿
package net.board.action;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
public class BoardFrontController extends HttpServlet implements Servlet{
protected void doProcess(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
String RequestURI = request.getRequestURI();
String contextPath = request.getContextPath();
String command = RequestURI.substring(contextPath.length());
ActionForward forward=null;
Action action = null;
if(command.equals("/BoardList.bo")){ // 게시판 리스트는 DB를 가지고온다.
action = new BoardListAction();
try{
forward = action.execute(request, response);
} catch(Exception e){
e.printStackTrace();
}
} else if(command.equals("/BoardWrite.bo")){ // 글쓰기
forward = new ActionForward();
forward.setRedirect(false);
forward.setPath("./board/qna_board_write.jsp");
}
if(forward.isRedirect()){
response.sendRedirect(forward.getPath());
}else{
RequestDispatcher dispatcher =
request.getRequestDispatcher(forward.getPath());
dispatcher.forward(request, response);
}
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doProcess(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doProcess(request, response);
}
}
📑 ActionForward.java
✔ isRedirect, path 필드와 get/set 메서드를 가지고 있습니다.
package net.board.action;
public class ActionForward {
private boolean isRedirect=false;
private String path=null;
public boolean isRedirect() {
return isRedirect;
}
public void setRedirect(boolean isRedirect) {
this.isRedirect = isRedirect;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
}
📑 Action 인터페이스
✔ xxxxAction 클래스가 사용할 인터페이스입니다.
요청과 응답 객체를 전달받고, 포워딩 정보를 저장한 ActionForward 객체를 리턴하도록 정의합니다.
public interface Action {
public ActionForward execute(
HttpServletRequest request,
HttpServletResponse response) throws Exception;
}
📑 BoardListAction.java
✔ BoardDAO클래스를 생성하고 getBoardList 메서드를 통해 게시글 목록을 가져옵니다.
package net.board.action;
import java.util.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.board.db.BoardDAO;
public class BoardListAction implements Action {
public ActionForward execute(HttpServletRequest request, HttpServletResponse response) throws Exception{
BoardDAO boarddao = new BoardDAO();
List boardlist = new ArrayList();
int page=1;
int limit=10;
if(request.getParameter("page")!=null){
page=Integer.parseInt(request.getParameter("page"));
}
int listcount = boarddao.getListCount();
boardlist = boarddao.getBoardList(page,limit);
int maxpage=(int)((double)listcount/limit+0.95);
int startpage = (((int) ((double)page / 10 + 0.9)) - 1) * 10 + 1;
int endpage = maxpage;
if (endpage>startpage+10-1) endpage=startpage+10-1;
request.setAttribute("page", page);
request.setAttribute("maxpage", maxpage);
request.setAttribute("startpage", startpage);
request.setAttribute("endpage", endpage);
request.setAttribute("listcount",listcount);
request.setAttribute("boardlist", boardlist);
ActionForward forward= new ActionForward();
forward.setRedirect(false);
forward.setPath("./board/qna_board_list.jsp");
return forward;
}
}
MVC 모델 2를 구현했습니다.
다음 포스팅에서는 게시판의 기능들을
구현해 보겠습니다.
참고 문헌 :
'Front-End > JSP' 카테고리의 다른 글
[JSP] MVC 모델2 게시판 만들기-2 (기능 구현) (2) | 2022.10.18 |
---|---|
[JSP] JDBC 회원가입 및 관리자 페이지 구현 실습 (1) | 2022.10.11 |
[JSP] JSP에서 DB연동하기 (JDBC, 오라클, 커넥션 풀) (3) | 2022.10.08 |
[JSP] 자바빈즈로 회원가입 페이지 구현하기 (useBean 액션 사용, 미사용 버전 2가지) (1) | 2022.09.21 |
[JSP] 간단한 장바구니 구현하기 (세션 사용) (2) | 2022.09.20 |