MyBatis with Board Project
MyBatis 를 이용한 Struts 2 게시판
Configuration.xml
<?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="board/db.properties" />
<typeAliases>
<typeAlias type="board.BoardVO" alias="Board" />
</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="board/BoardMapper.xml" />
</mappers>
</configuration>
struts.xml 에 선언된 액션의 이름은 PageUtilBean의 link 속성의 값(private String link = "boardList")과 일치해야한다.
<action name="boardList" class="board.BoardAction" method="boardList">
<interceptor-ref name="params"/>
<result>board/boardList.jsp</result>
</action>
BoardAction.java
public class BoardAction extends ActionSupport implements Preparable, ModelDriven<BoardVO> {
private BoardVO board;
private String resultMsg; //입력, 수정, 삭제시 결과 메시지 저장
private List<BoardVO> boardList;
private int num; //글번호
private int page = 1; //이용자가 요청한 페이지 번호,처음 실행시 오류를 방지하려면 반드시 1 로 초기화해야 함
private PageUtilBean pageBean;
......
...........(중략)
/** 이용자가 리스트 요청시 실행되는 액션 메소드
PageUtilBean의 인스턴스를 생성하고 Service 객체로 전달한다
Service 객체의 getBoardList(page) 호출시 메소드 내부에서 PageUtilBean.init()호출하여 초기화 됨
PageUtilBean이 초기화되면 뒤 이어 호출되는 JSP에서 Action 의 멤버변수인 pageBean을 사용함
struts.xml 에 등록한 액션의 이름은 boardList 이므로 PageUtilBean을 이용할 경우 반드시 확인하여 일치하도록 설정해야 함
*/
public String boardList() throws Exception {
pageBean = new PageUtilBean();
BoardService service = new BoardService(pageBean);
boardList = service.getBoardList(page);
return SUCCESS;
}
/** 이용자가 요청한 특정 페이지 번호는 params 인터셉터에 의해 현재 액션의 멤버 변수인 page 에 설정된다 */
public void setPage(int page) {
this.page = page;
}
/** JSP 에서 ${pageBean.navStr}, ${pageBean.currPage}, ${pageBean.totalPages} 등을 사용할 수 있도록 getter 메소드 선언*/
public PageUtilBean getPageBean() {
return pageBean;
}
...........
........(생략)
}
BoardMapper.java
package board;
import java.util.*;
import org.apache.ibatis.annotations.Param;
public interface BoardMapper {
public List<BoardVO> boardList();
public List<BoardVO> boardListPg(@Param("pageNo")int page, @Param("rowsPerPage")int rowsPerPage);
public BoardVO getBoard(int num);
public int boardInsert(BoardVO board);
public int boardUpdate(BoardVO board);
public int boardDelete(int num);
}
BoardMapper.xml (아래의 선언에서 SELECT 문장은 Board(별칭)와 매핑되므로 SELECT 문장의 컬럼명과 Board 클래스의 속성명이 일치해야 한다
<?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="board.BoardMapper">
<select id="boardList" resultType="Board">
SELECT num, subject, writer, reg_date
FROM board
ORDER BY num DESC
</select>
<select id="boardListPg" resultType="Board">
SELECT num, subject, writer, reg_date, pageNo, totalPages, totalCnt FROM
(
SELECT T1.*,
CEIL(ROWNUM/#{rowsPerPage}+1) AS pageNo,
CEIL(totalCnt/#{rowsPerPage}+1) AS totalPages FROM
(
SELECT num, subject, writer, reg_date, COUNT(*)OVER() AS totalCnt
FROM board b ORDER BY num DESC
) T1
)
WHERE pageNo=#{pageNo}
</select>
<select id="getBoard" resultType="Board">
SELECT num, subject, writer, reg_date, email, content
FROM board
WHERE num=#{num}
</select>
<insert id="boardInsert" parameterType="Board">
INSERT INTO board (num, subject, content, writer, passwd, reg_date, ref)
VALUES (BOARD_NUM.NEXTVAL,
#{subject}, #{content},#{writer},#{passwd},sysdate,#{ref})
</insert>
<update id="boardUpdate" parameterType="Board">
UPDATE board SET subject=#{subject}, content=#{content}
WHERE num=#{num}
</update>
<delete id="boardDelete">
DELETE FROM board WHERE num=#{num}
</delete>
</mapper>
BoardMybatisDAO.java
package board;
import java.io.*;
import java.util.*;
import org.apache.ibatis.io.*;
import org.apache.ibatis.session.*;
public class BoardMybatisDAO {
private static BoardMybatisDAO instance = new BoardMybatisDAO();
private String resource = "board/Configuration.xml"; //DB 연결정보, DB인터페이스, SQL문장, 모델클래스 정보
private Reader reader;
private SqlSessionFactory sqlMapper;
public static BoardMybatisDAO getInstance() {
return instance;
}
private BoardMybatisDAO() {
try {
reader = Resources.getResourceAsReader(resource);
sqlMapper = new SqlSessionFactoryBuilder().build(reader);
} catch (IOException e) {
e.printStackTrace();
}
}
public List<BoardVO> boardList() {
List<BoardVO> boardList = null;
SqlSession session = sqlMapper.openSession();
try {
BoardMapper mapper = session.getMapper(BoardMapper.class);
boardList = mapper.boardList();
//session.commit();
} finally {
session.close();
}
return boardList;
}
public List<BoardVO> boardList(int page, int rowsPerPage) {
List<BoardVO> boardList = null;
SqlSession session = sqlMapper.openSession();
try {
BoardMapper mapper = session.getMapper(BoardMapper.class); //DB인터페이스 객체생성
boardList = mapper.boardListPg(page, rowsPerPage);
//session.commit();
} finally {
session.close();
}
return boardList;
}
public BoardVO getBoard(int num) {
BoardVO board = null;
SqlSession session = sqlMapper.openSession();
try {
BoardMapper mapper = session.getMapper(BoardMapper.class);
board = mapper.getBoard(num);
//session.commit();
} finally {
session.close();
}
return board;
}
public boolean boardInsert(BoardVO board) {
SqlSession session = sqlMapper.openSession();
try {
BoardMapper mapper = session.getMapper(BoardMapper.class);
int rows = mapper.boardInsert(board);
if(rows>0) {
session.commit();
return true;
}
} finally {
session.close();
}
return false;
}
public boolean boardUpdate(BoardVO board) {
SqlSession session = sqlMapper.openSession();
try {
BoardMapper mapper = session.getMapper(BoardMapper.class);
int rows = mapper.boardUpdate(board);
if(rows>0) {
session.commit();
return true;
}
} finally {
session.close();
}
return false;
}
public boolean boardDelete(int num) {
SqlSession session = sqlMapper.openSession();
try {
BoardMapper mapper = session.getMapper(BoardMapper.class);
int rows = mapper.boardDelete(num);
if(rows>0) {
session.commit();
return true;
}
} finally {
session.close();
}
return false;
}
}
Pageable.java
package board;
/**
* 이 인터페이스는 데이터베이스 테이블의 한개의 레코드 정보를 저장할 클래스(VO)가
* 구현할 경우 PageUtilBean에서 연결하여 페이지 하단에 페이지 네비게이션 링크를 생성
* 하는 기능을 사용할 수 있다. DAO 측에서는 SQL을 사용하여 총 레코드 수(ttcnt),
* 총 페이지 수(ttpage), 현재 페이지 번호(page)를 VO에게 설정해야 주어야만
* PageUtilBean에서 VO에 접근하여 해당 정보를 기반으로 페이지 네비게이션 링크를 생성할 수 있다
* DAO측에서 사용하는 SQL문장의 형태는 이 코드 아래에 있는 예문을 참고하기 바란다
*/
public interface Pageable {
/**현재 페이지 번호*/
public int getPageNo();
public void setPageNo(int pageNo);
/**총 레코드 수*/
public int getTotalCnt();
public void setTotalCnt(int totalCnt);
/**총 페이지 수*/
public int getTotalPages();
public void setTotalPages(int totalPages);
}
/*
select rn, empno, ename, page, ttpage, ttcnt from
(
select T1.*, rownum rn,
FLOOR((rownum-1)/?+1) as page,
FLOOR((TTCNT-1)/?+1) as TTPAGE from
(
select e.*,COUNT(*)OVER() as TTCNT from emp e order by empno
) T1
)
where page=?
?:rowsPerPage
?:rowsPerPage
?:page
*/
BoardVO.java
package board;
import java.util.Date;
public class BoardVO implements Pageable {
private int num;
private String writer;
private String email;
private String subject;
private String passwd;
private Date reg_date;
private int ref;
private String content;
/* Fields for Pageable. MyBatis를 사용할 경우 아래의 변수명은 MyBatis의 SQL문장의 SELECT 절에서 사용되는 컬럼명과 일치해야 함 */
private int pageNo;
private int totalCnt;
private int totalPages;
public BoardVO(){
}
public BoardVO(int num, String writer, String email, String subject,
String passwd, Date reg_date, int ref, String content) {
super();
this.num = num;
this.writer = writer;
this.email = email;
this.subject = subject;
this.passwd = passwd;
this.reg_date = reg_date;
this.ref = ref;
this.content = content;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getWriter() {
return writer;
}
public void setWriter(String writer) {
this.writer = writer;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getPasswd() {
return passwd;
}
public void setPasswd(String passwd) {
this.passwd = passwd;
}
public Date getReg_date() {
return reg_date;
}
public void setReg_date(Date reg_date) {
this.reg_date = reg_date;
}
public int getRef() {
return ref;
}
public void setRef(int ref) {
this.ref = ref;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "BoardVO [num=" + num + ", writer=" + writer + ", email="
+ email + ", subject=" + subject + ", passwd=" + passwd
+ ", reg_date=" + reg_date + ", ref=" + ref + ", content="
+ content + "]";
}
@Override
public int getPageNo() {
return pageNo;
}
@Override
public void setPageNo(int pageNo) {
this.pageNo = pageNo;
}
@Override
public int getTotalCnt() {
return totalCnt;
}
@Override
public void setTotalCnt(int totalCnt) {
this.totalCnt = totalCnt;
}
@Override
public int getTotalPages() {
return totalPages;
}
@Override
public void setTotalPages(int totalPages) {
this.totalPages = totalPages;
}
}
PageUtilBean 이 사용되는 경우의 BoardService.java 의 내용
package board;
import java.util.List;
import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
public class BoardService {
private PageUtilBean pageBean;
public BoardService(){}
public BoardService(PageUtilBean pageBean){
this.pageBean = pageBean;
}
public boolean boardSave(BoardVO vo){
if(isLogon()){
Map<String,Object> map = ActionContext.getContext().getSession();
vo.setWriter((String)map.get("id"));
vo.setPasswd((String)map.get("pwd"));
/*
BoardDao dao = new BoardDao();
return dao.boardInsert(vo);*/
BoardMybatisDAO dao = BoardMybatisDAO.getInstance();
return dao.boardInsert(vo);
}
return false;
}
public List<BoardVO> getBoardList() {
/*BoardDao dao = new BoardDao();
return dao.boardList();*/
BoardMybatisDAO dao = BoardMybatisDAO.getInstance();
return dao.boardList();
}
public List<BoardVO> getBoardList(int page) {
BoardMybatisDAO dao = BoardMybatisDAO.getInstance();
int rowsPerPage = 3;
List<BoardVO> list = dao.boardList(page, rowsPerPage);
pageBean.init(page, list, rowsPerPage, 5); // page(액션에서 전달된 요청페이지 번호), list<Pageable>, rowsPerPage, numsPerPage
return list;
}
public BoardVO getBoard(int num){
/*BoardDao dao = new BoardDao();
return dao.boardDetail(num);*/
BoardMybatisDAO dao = BoardMybatisDAO.getInstance();
return dao.getBoard(num);
}
public boolean updateBoard(BoardVO board) {
/*BoardDao dao = new BoardDao();
return dao.boardUpdate(board);*/
BoardMybatisDAO dao = BoardMybatisDAO.getInstance();
return dao.boardUpdate(board);
}
public boolean deleteBoard(int num) {
/*BoardDao dao = new BoardDao();
return dao.boardDelete(num);*/
BoardMybatisDAO dao = BoardMybatisDAO.getInstance();
return dao.boardDelete(num);
}
public boolean isLogon() {
if(ActionContext.getContext().getSession().get("logon")==null) {
return false;
}
return true;
}
}
boardList.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="EUC-KR"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html>
<html>
<head>
<title>게시판 리스트 </title>
<style type="text/css">
body {text-align: center; }
table { margin:0 auto;}
table caption {text-align: right; }
td{ border-bottom: dotted ;}
th{ background-color: gray;}
body{ text-align: center;}
a { text-decoration: none; }
#navTd { border:none; text-align: center; height:40px;}
#navBar {display:inline; text-align: center; height:40px;}
</style>
<script type="text/javascript">
function search(){
}
</script>
</head>
<body>
<h2>[ 게 시 판 ]</h2>
<table >
<caption>${pageBean.currPage} / ${pageBean.totalPages} </caption>
<tr><th width="70">글번호</th><th width="300">제목</th><th width="100">작성자</th><th width="100">작성일</th></tr>
<s:iterator value="boardList">
<tr>
<td><s:property value="num"/></td>
<td align="left">
<s:url id="readUrl" action="boardRead">
<s:param name="num"><s:property value="num"/></s:param>
</s:url>
<s:a href="%{readUrl}"><s:property value="subject"/></s:a>
</td>
<td><s:property value="writer"/></td>
<td><s:date name="reg_date" format="yyyy-MM-dd"/></td>
</tr>
</s:iterator>
<tr><td id="navTd" colspan="4">${pageBean.navStr}</td></tr>
</table>
<a href="boardInput"> <input type="button" value="글쓰기"> </a>
<s:form name="searchform" action="boardSearch">
<select name='sel'>
<option value="none">선택</option>
<option value="writer">작성자</option>
<option value="content">글 내용</option>
</select>
<input type="text" id="sitext" name="sntext" >
<input type="button" value="검색" onclick="search();">
</s:form>
</body>
</html>
struts2_board_pageBean_mybatis.zip