오늘이라도

[MyBatis] 18. 게시판 만들기 ① : MyBatis 준비 / DTO, DAO 작성 / MVC2 서블렛 구성 본문

취업성공패키지 SW 개발자 교육/Web

[MyBatis] 18. 게시판 만들기 ① : MyBatis 준비 / DTO, DAO 작성 / MVC2 서블렛 구성

upcake_ 2020. 6. 2. 10:34
반응형

https://github.com/upcake/Class_Examples

교육 중에 작성한 예제들은 깃허브에 올려두고 있습니다. 

gif 파일은 클릭해서 보는 것이 정확합니다.


 - 게시판 만들기 ① : MyBatis 준비 / DTO, DAO 작성 / MVC2 서블렛 구성 -

□ 진행 상황(※ 볼드체 : 오늘 다룬 파일들)

JAVA

- com.hanul.mybatis : board.sql, db.properties, SqlMapConfig.xml, boardMapper.xml

- com.hanul.dto : BoardDTO.java, SearchDTO.java

- com.hanul.dao : BoardDAO.java

- com.hanul.controller : BoardFrontController.java Servlet : web.xml에서 Mapping

- com.hanul.action : Action.java(Interface), ActionForward.java, Boardxxx.java(BoardListAction.java)

-----------------------------------------------------------------------------------------------------

WebContent

- boardMain.html

- board\ : *.jsp (boardList.jsp)

- css\ : *.css

- js\ : *.js

- images\ : *.png, *.gif, *.jpg

-----------------------------------------------------------------------------------------------------

boardMain.html boardList.do(*.do) web.xml BoardFrontController.java(Servlet)

BoardListAction.java BoardDAO.java boardMapper.xml BoardDAO.java

BoardListAction.java BoardFrontController.java ActionForward.java

boardList.jsp

 

□ 작동 화면 및 코드

 

 

▲작동 화면

 

▼board.sql : board 테이블 생성

--Eclipse와 DB 연동 오류 발생 시 해결 방법
--1. Eclipse 종료
--2. workspace\.metadata\.plugins\org.eclipse.datatools.sqltools.result
--3. 해당 폴더의 파일을 삭제 시킨 후 Eclipse 실행

--테이블 생성
CREATE TABLE tblBoard(
    b_num NUMBER PRIMARY KEY NOT NULL,
    b_subject VARCHAR2(50),
    b_pwd VARCHAR2(20),
    b_content VARCHAR2(2000),
    b_writer VARCHAR2(20),
    b_date VARCHAR2(20),
    b_readcount NUMBER
);

--전체 레코드 검색
SELECT * FROM tblBoard ORDER BY b_num DESC;

--자동 증가값 설정 : b_num → b_num_seq 변수
CREATE SEQUENCE b_num_seq START WITH 1;
--시퀀스는 기본적으로 20개 단위로 주어진다.
--1, 2, 3을 삭제해도 4, 5부터 시작하는 문제가 있다.
--테이블을 삭제해도 시퀀스는 살아있고, 새 테이블을 만들면 다음 20번을 줘서 21번부터 시작한다.


--임의의 레코드 삽입
INSERT INTO tblBoard VALUES(b_num_seq.nextval, 'subject', 'pwd', 'content', 'writer', sysdate, 0);

--전체 레코드 삭제
DELETE FROM tblBoard;

--테이블 삭제
DROP TABLE tblBoard;

--자동 증가 값 삭제
DROP SEQUENCE b_num_seq;

 

▼db.properties : DB 접속 정보

driver = oracle.jdbc.driver.OracleDriver
url = jdbc:oracle:thin:@127.0.0.1:1521:XE
username = hanul
password = 0000

 

▼SqlMapConfig.xml : MyBatis 설정

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<properties resource="com/hanul/mybatis/db.properties" />
	<typeAliases>
		<typeAlias type="com.hanul.dto.BoardDTO" alias="BoardDTO"/>
	</typeAliases>
	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="${driver}" />
				<property name="url" value="${url}" />
				<property name="username" value="${username}" />
				<property name="password" value="${password}" />
			</dataSource>
		</environment>
	</environments>
	<mappers>
		<mapper resource="com/hanul/mybatis/boardMapper.xml" />
	</mappers>
</configuration>

 

▼boardMapper.xml : 매핑, SQL문 작성

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hanul.mybatis.boardMapper.xml">
	<select id="boardSearchAll" resultType="BoardDTO">
		SELECT * FROM tblBoard ORDER BY b_num DESC
	</select>
</mapper>

 

▼BoardDTO.java : 게시글 정보 양식 클래스

package com.hanul.dto;

import java.io.Serializable;

public class BoardDTO implements Serializable {
	private int b_num;
	private String b_subject;
	private String b_pwd;
	private String b_content;
	private String b_writer;
	private String b_date;
	private int b_readcount;
	
	public BoardDTO() {}

	public BoardDTO(int b_num, String b_subject, String b_pwd, String b_content, String b_writer, String b_date,
			int b_readcount) {
		super();
		this.b_num = b_num;
		this.b_subject = b_subject;
		this.b_pwd = b_pwd;
		this.b_content = b_content;
		this.b_writer = b_writer;
		this.b_date = b_date;
		this.b_readcount = b_readcount;
	}

	public int getB_num() {
		return b_num;
	}

	public void setB_num(int b_num) {
		this.b_num = b_num;
	}

	public String getB_subject() {
		return b_subject;
	}

	public void setB_subject(String b_subject) {
		this.b_subject = b_subject;
	}

	public String getB_pwd() {
		return b_pwd;
	}

	public void setB_pwd(String b_pwd) {
		this.b_pwd = b_pwd;
	}

	public String getB_content() {
		return b_content;
	}

	public void setB_content(String b_content) {
		this.b_content = b_content;
	}

	public String getB_writer() {
		return b_writer;
	}

	public void setB_writer(String b_writer) {
		this.b_writer = b_writer;
	}

	public String getB_date() {
		return b_date;
	}

	public void setB_date(String b_date) {
		this.b_date = b_date;
	}

	public int getB_readcount() {
		return b_readcount;
	}

	public void setB_readcount(int b_readcount) {
		this.b_readcount = b_readcount;
	}
	
	
	
}

 

▼BoardDAO.java : 기능 담당 클래스

package com.hanul.dao;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import com.hanul.dto.BoardDTO;

public class BoardDAO {
	//①SqlSessionFactory 설정
	private static SqlSessionFactory sqlMapper;
	static {
		String resource = "com/hanul/mybatis/SqlMapConfig.xml";
		try {
			InputStream inputStream = Resources.getResourceAsStream(resource);
			sqlMapper = new SqlSessionFactoryBuilder().build(inputStream);
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("SqlSessionFactory Exception");
		}
	} //static
	
	//전체 목록 검색
	public List<BoardDTO> boardSearchAll() {
		SqlSession session = sqlMapper.openSession();
		List<BoardDTO> list = null;
		list = session.selectList("boardSearchAll");
		session.close();
		return list;
	} //boardSearchAll()
} //class

 

▼boardMain.html : 메인 화면

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>BoardMain</title>
</head>
<body>
<script type="text/javascript">
	location.href = "boardList.do";
	//MVC 패턴 1에서는 동작 하나 당 서블렛 하나였고, JSP에서 대부분의 기능을 맡았다.
	//MVC 패턴 2에서는 서블렛 하나로 여러 경로를 담당하고, View파트를 JSP에서 처리한다.
</script>
</body>
</html>

 

▼BoardFrontController.java : 클라이언트의 요청을 해당하는 비즈니스 로직으로 연결해주는 서블렛

package com.hanul.controller;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
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.hanul.action.Action;
import com.hanul.action.ActionForward;
import com.hanul.action.BoardListAction;

@WebServlet("/BoardFrontController.do")
public class BoardFrontController extends HttpServlet {
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//0. 불필요한 코드를 지우고 서비스 메서드만 남겨둔다.
		//1. 클라이언트가 어떤 요청을 했는지를 파악한다.
		request.setCharacterEncoding("utf-8");
		//localhost:8080/mbb/boardList.do
		//mbb : context root
		//mbb/boardList.do : uri-pattern
		//uri-pattern에서 context root를 잘라내서 boardList.do만 남긴다.
		String uri = request.getRequestURI();		//uri-pattern 값	: /mbb/XXX.do
		String ctx = request.getContextPath();		//Context root 값	: /mbb
		String command = uri.substring(ctx.length());	//실제 요청한 페이지 : /XXX.do
		//System.out.println("uri : " + uri);
		//System.out.println("ctx : " + ctx);
		//System.out.println("command : " + command);
		
		
		//2. 클라이언트의 요청(*.do → command)과 실제 처리할 비즈니스 로직(Action Class) 연결
		Action action = null;
		ActionForward forward = null;
		
		if(command.equals("/boardList.do")) {
			action = new BoardListAction();		//상위 객체(부모)쪽으로 업캐스팅 (다형성)
			forward = action.execute(request, response);
		}
		
		//3. 페이지 전환(프레젠테이션 로직) : sendRedirect(), forward()
		if(forward != null) {
			if(forward.isRedirect()) {	//true : sendRedirect() 페이지 전환
				response.sendRedirect(forward.getPath());
			} else {					//false : forward() 페이지 전환
				RequestDispatcher rd = request.getRequestDispatcher(forward.getPath());
				rd.forward(request, response);
			}	
		}
	}
}

 

▼web.xml : 위의 서블렛이 모든 do를 대응하게끔 매핑

<?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_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>06.MyBatisBoard</display-name>
  <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>
  <servlet>
  	<display-name>BoardFrontController</display-name>
  	<servlet-name>BoardFrontController</servlet-name>
  	<servlet-class>com.hanul.controller.BoardFrontController</servlet-class>
  </servlet>
  <servlet-mapping>
  	<servlet-name>BoardFrontController</servlet-name>
  	<url-pattern>*.do</url-pattern>
  	<!-- BoardFrontController 하나로 모든 *.do 대응 -->
  </servlet-mapping>
</web-app>

 

▼Action.java : servlet과 비슷한 역할을 하게 만든 인터페이스

package com.hanul.action;

import java.io.IOException;

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

public interface Action {
	//추상 메서드(abstract를 안걸어도 인터페이스에서는 어짜피 추상메서드라 상관이 없다)
	public abstract ActionForward execute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException;
}

 

▼ActionForward.java : 페이지 전환을 담당할 클래스

package com.hanul.action;

public class ActionForward {
	private String path;		//View Page(*.jsp)의 경로와 파일명을 저장할 변수
	private boolean isRedirect;	//페이지 전환 방식 ▶ true : sendRedirect()
//												   ▶ false : forward()
	
	//Getter & Setter 만든다
	public String getPath() {
		return path;
	}
	public void setPath(String path) {
		this.path = path;
	}
	public boolean isRedirect() {
		return isRedirect;
	}
	public void setRedirect(boolean isRedirect) {
		this.isRedirect = isRedirect;
	}
}

 

▼BoardListAction.java : boardList.jsp로의 페이지 연결을 담당하는 액션 클래스

package com.hanul.action;

import java.io.IOException;
import java.util.List;

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

import com.hanul.dao.BoardDAO;
import com.hanul.dto.BoardDTO;

public class BoardListAction implements Action {
	@Override
	public ActionForward execute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//DAO 연동하여 게시판 테이블의 전체 목록을 가져오는 작업을 수행 : 비즈니스 로직
		BoardDAO dao = new BoardDAO();
		List<BoardDTO> list = dao.boardSearchAll();
		request.setAttribute("list", list);
		
		//BoardListAction 작업을 마무리 했다 → 프레젠테이션 로직(페이지 전환) : ActionForward.java
		//① View Page(path) : board/boardList.jsp
		//② 페이지 전환 방식(isRedirect) : forward()
		ActionForward forward = new ActionForward();
		forward.setPath("board/boardList.jsp");
		forward.setRedirect(false); // true : sendRedirect() / false : forward()
		return forward;
	}
}

 

▼boardList.jsp : 게시판 목록을 보여줄 화면

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>BoardList JSP</title>
</head>
<body>
<div align="center">
	<h3>게시판 전체 목록 보기</h3>
</div>
</body>
</html>
반응형