본문 바로가기
카테고리 없음

[JSP/MVC] 커뮤니티 게시판 웹 어플리케이션 - Paging 페이징 (Model2 Pattern)

by 파프리카_ 2020. 10. 5.
728x90
반응형

커뮤니티 게시판 웹 어플리케이션 - 게시글 관리 에서 이어지는 포스팅입니다!

 

[JSP/MVC] 커뮤니티 게시판 웹 어플리케이션 - 게시글 관리 (Model2 Pattern)

[ 요구 사항 ] Model2 MVC 기반 커뮤니티 게시판 비로그인 상태에서는 '게시판 리스트' 정보만 제공된다. 상단부 화면에서 '로그인 할 수 있는 폼'이 제공된다. '게시판 리스트'에서는 '게시물 번호',

creamilk88.tistory.com

> 새로 추가된 기능은 paging 처리을 통해 home의 한 화면에서 5개씩 포스팅이 보여지게 하는 것입니다.

 

[ 기존 기능 ]

1. 게시물 리스트 테이블로 보기 (home 화면에서)

2. 게시물 상세보기 (로그인 상태에서)

3. 로그인 + 로그아웃

4. 게시글 등록

5. 게시글 수정

6. 게시글 삭제

 

+ [ 새로운 기능 ]

페이징 처리 

→ 게시물 리스트 하단부에 페이지 그룹은 '4 페이지'

→ 페이지 그룹 당 게시물 수는 '5개'로 처리한다.


[ 구현 순서 ] 

  1. 추가 파일 및 메서드 / 수정 파일
  2. src의 model directory에 두 가지 java Beans를 추가한다.
    1) PagingBean.java
        - PagingBean은 '페이징 처리를 위한 비즈니스 계층의 클래스'이다.
    2) ListVO.java
      :  필수 생성 요소는 아니지만, 페이지 리스트(paging)에 대한 동작은 ListVO로 묶어서 제공하기 위해 생성한다.
       -  인스턴스 변수 : 1) ArrayList<PostVO>  2)PagingBean 
       -  위 인스턴스 변수들을 반환한다.
  3. [ step1. 게시글 5개 씩 나오도록 하기!]

    BoardDAO getAllList(PaingBean) : 처음 게시글 리스트 뜨는 메서드를 수정한다.
     : 최근 게시물 5개만 조회하도록 한다. (row_number 이용 & PagingBean을 매개변수로 추가)
  4. BoardDAO에 getTotalPostCount() 메서드를 추가한다.
    : 전체 포스팅의 개수를 반환하는 기능
  5. HomeController.java도 PagingBean과 ListVO를 활용하여 수정한다.
    1) 전체 포스팅의 개수를 받아옴
    2) 현재 페이지 번호를 받아옴 (pageNo : list.jsp에서 보냄)
    3) 만약 페이지 번호가 null이면 -> PagingBean(전체포스팅개수) 객체 생성
         null이 아니면 -> PagingBean(전체포스팅개수, 현재페이지번호) 객체 생성
    4) getAllList(PagingBean)과 연동하여, 페이지에 맞는 포스팅 5개 리스트 반환받기
       + listVO 객체 생성 (반환 받은 list, pagingBean) 
    5) request에 담아 listVO공유
    6) reqquest에 담아 url공유 (list.jsp) - layout으로 리턴
  6. [ step2. 게시글 테이블 하단에 페이지 이동 bar 추가 !]

    list.jsppaging navbar를 구성하여 추가한다.
  7. 현 페이지 그룹의 startPage부터 endPage까지 forEach 를 이용해 출력한다
  8. 이전 페이지 or 다음 페이지 그룹이 있으면 화살표 보여준다
    (이미지에 이전 그룹의 마지막 페이지번호를 링크한다.)

 


[ SQL  (DB) ]

 > 인라인 뷰를 통해 row_number 생성

 

row_number() over( [조건] ) 
 : 조회된 row(행)에 대한 순차적인 번호를 제공하는 오라클 함수

SELECT   ROW_NUMBER() OVER(ORDER BY [column name] DESC) AS rnum
FROM     [table name];

   


Inline View
 : SQL 문장에서 FROM절에 사용되는 서브쿼리
 : FROM절에 서브쿼리로 SELECT되는 조회결과를 테이블처럼 사용 

SELECT rnum,[column1 name]
FROM   (SELECT row_number() over(ORDER BY [column2 name] DESC) AS rnum, [column name]
        FROM   [table name])
WHERE  rnum BETWEEN [number] AND [number];

[ 구현 코드 ]  

Model

/DataBaseManager.java

package model;

import javax.sql.DataSource;

import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;

public class DataSourceManager {
	//1. singleton pattern
	private static DataSourceManager instance = new DataSourceManager();
	//DataSource는 java.sql에서의 interface를 가져온다.
	private DataSource dataSource;
	
	//2. constructor에 Connection Pool 생성되도록
	private DataSourceManager() {
		
		//was tomcat에서 제공하는 dbcp를 생성한다.
		BasicDataSource dbcp = new BasicDataSource();
		
		//dbcp(datasource)에 driver와 db connection 정보를 설정
		dbcp.setDriverClassName("oracle.jdbc.OracleDriver");
		dbcp.setUrl("jdbc:oracle:thin:@127.0.0.1:1521:xe");
		dbcp.setUsername("scott");
		dbcp.setPassword("tiger");
		
		//setInitialSize( ) : 처음 로드될 때 생성할 connection 개수 설정
		dbcp.setInitialSize(3);
		
		//setMaxTotal( ) : 사용할 최대 connection 개수 설정
		dbcp.setMaxTotal(10);
		
		//인스턴스 변수인 dataSource에 위를 통해 설정한 dbcp를 할당한다
		this.dataSource = dbcp;
	}
	
	//3. singleton pattern
	public static DataSourceManager getInstance() {
		return instance;
	}
	
	//4. DataBase Connection Pool을 만들어둔, 
	//   dpcp(DataSource)에 설정해 놓은 dbcp를 dataSource의 이름으로
	//   가져온다.
	public DataSource getDataSource() {
		return dataSource;
	}
	
}

> Paging

 

페이징 처리를 위한 비즈니스 계층의 클래스 PagingBean method 구현순서
 * getStartRowNumber() : 현재 페이지 번호에 해당하는 시작 게시물의 row number를 반환
 * getEndRowNumber() : 현재 페이지 번호에 해당하는 마지막 게시물의 row number를 반환
 * getTotalPage() : 게시글이 5개씩 묶여있는 총 페이지 수를 반환
 * getTotalPageGroup() : 게시글이 5개씩 묶여있는 페이지를 4개씩 묶은 페이지 그룹의 수를 반환
 * getNowPageGroup() : 현재 페이지가 속한 그룹이 몇 번째 페이지 그룹(페이지 그룹 번호)를 반환
 * getStartPageOfPageGroup() : 현재 페이지가 속한 페이지 그룹 번호에서 시작 페이지 번호를 반환
 * getEndPageOfPageGroup() :  : 현재 페이지가 속한 페이지 그룹 번호에서 마지막 페이지 번호를 반환
 * isPreviousPageGroup() : 이전 페이지 그룹이 있는지 여부를 체크하여 boolean 타입으로 반환
 * isNextPageGroup() : 다음 페이지 그룹이 있는지 여부를 체크하여 boolean 타입으로 반환

 

/PagingBean.java

package model;

/**
 * 페이징 처리를 위한 비즈니스 계층의 클래스 PagingBean method 구현순서 getStartRowNumber()
 * getEndRowNumber() getTotalPage() getTotalPageGroup() getNowPageGroup()
 * getStartPageOfPageGroup() getEndPageOfPageGroup() isPreviousPageGroup()
 * isNextPageGroup()
 * 
 * @author kosta
 *
 */
public class PagingBean {
	/**
	 * 현재 페이지
	 */
	private int nowPage = 1;
	
	/**
	 * 페이지당 게시물수
	 */
	private int postCountPerPage = 5;
	
	/**
	 * 페이지 그룹당 페이지수
	 */
	private int pageCountPerPageGroup = 4;
	
	/**
	 * database에 저장된 총게시물수
	 */
	private int totalPostCount;

	public PagingBean(int totalPostCount) {
		this.totalPostCount = totalPostCount;
	}

	public PagingBean(int totalPostCount, int nowPage) {
		this.totalPostCount = totalPostCount;
		this.nowPage = nowPage;
	}

	public int getNowPage() {
		return nowPage;
	}

	/**
	 * 현재 페이지번호에 해당하는 시작 게시물의 row number를 반환 
	 * hint : 이전페이지의 마지막 번호 + 1
	 * 
	 * @return
	 */
	public int getStartRowNumber() {
		int no = (nowPage-1)*postCountPerPage + 1;
		return no;
	}

	/**
	 * 현재 페이지에서 보여줄 게시물 행(row)의 마지막 번호 현재페이지 
	 * *postCountPerPage
	 * 만약 총게시물수보다 연산결과의 번호가 클 경우 
	 * 총게시물수가 마지막 번호가 되어야 한다
	 *  ex) 총게시물수 7 개 총페이지는 2페이지 
	 *  : 1 2 3 4 5 | 6 7 |
	 * 		1page     2page
	 *  현재페이지는 2페이지이고  2*5(페이지당 게시물수) 는 10 이고 실제 마지막 번호 7이다 
	 *  -> 연산결과가 총게시물수보다 클 경우 총게시물수가 마지막번호가 되어야 함
	 * 
	 * @return
	 */
	public int getEndRowNumber() {
		int endRowNumber = nowPage * postCountPerPage;
		if (endRowNumber > totalPostCount )
			endRowNumber = totalPostCount;
		return endRowNumber;
	}

	/**
	 * 총 페이지 수를 return한다. 
	 * 1. 전체 데이터(게시물) % 한 페이지에 보여줄 데이터 개수 
	 * 	=> 0 이면 둘을 / 값이 총 페이지 수
	 * 2. 전체 데이터(게시물) % 한 페이지에 보여줄 데이터 개수 
	 * 	=> 0보다 크면 둘을 / 값에 +1을 한 값이 총 페이지 수 게시물수 
	 * 1 2 3 4 5 || 6 7 8 9 10 || 11 12 
	 * 1페이지 1~5 || 2페이지 6~10 || 3페이지 11,12 
	 * ex) 게시물 32 개 , 페이지당 게시물수 5개-> 7 페이지
	 * 
	 * @return
	 */
	private int getTotalPage() {
		int totalPage = totalPostCount % postCountPerPage;
		
		if (totalPage == 0)
			totalPage =  totalPostCount / postCountPerPage;
		else 
			totalPage =  totalPostCount / postCountPerPage + 1;
		
		return totalPage;
	}

	/**
	 * 총 페이지 그룹의 수를 return한다. 
	 * 1. 총 페이지수 % Page Group 당 Page 수. 
	 * 	=> 0 이면 둘을 / 값이 총 페이지 수 
	 * 2. 총 페이지수 % Page Group 당 Page 수. 
	 * 	=> 0보다 크면 둘을 / 값에 +1을 한 값이 총 페이지 수 
	 * 
	 * ex) 총게시물 수 23 개
	 * 		 총 페이지 ? 페이지 1 2 3 4 5
	 * 		 총 페이지 그룹수 ? 페이지그룹 1234(1그룹) 5(2그룹)
	 */
	private int getTotalPageGroup() {
		int totalPageGroup = getTotalPage() % pageCountPerPageGroup;
		if (totalPageGroup == 0)
			totalPageGroup = getTotalPage() / pageCountPerPageGroup;
		else
			totalPageGroup =  getTotalPage() / pageCountPerPageGroup + 1;
		return totalPageGroup;
	}

	/**
	 * 현재 페이지가 속한 페이지 그룹 번호(몇 번째 페이지 그룹인지) 을 return 하는 메소드 
	 * 1. 현재 페이지 % Page Group 당 Page 수
	 * 	 => 0 이면 둘을 / 값이 현재 페이지 그룹. 
	 * 2. 현재 페이지 % Page Group 당 Page 수 
	 * 	=> 0 크면 둘을 / 값에 +1을 한 값이 현재 페이지 그룹 
	 * 페이지 1 2 3 4 /5 6 7 8 / 9 10 
	 *         1그룹    2그룹    3그룹
	 * 
	 * @return
	 */
	private int getNowPageGroup() {
		int nowPageGroup = nowPage % pageCountPerPageGroup ; 
		if (nowPageGroup == 0)
			nowPageGroup = nowPage / pageCountPerPageGroup ; 
		else
			nowPageGroup = nowPage / pageCountPerPageGroup + 1 ; 
		return nowPageGroup;
	}

	/**
	 * 현재 페이지가 속한 페이지 그룹의 시작 페이지 번호를 return 한다. 
	 * Page Group 내 Page 수*(현재 페이지 그룹 -1) + 1 을 한 값이 첫 페이지이다. 
	 * (페이지 그룹*페이지 그룹 개수, 그룹의 마지막 번호이므로) 
	 * 페이지 그룹 1 2 3 4 -> 5 6 7 8 -> 9 10
	 * 
	 * @return
	 */
	public int getStartPageOfPageGroup() {
		int startPageOfPageGroup = pageCountPerPageGroup * (getNowPageGroup() -1) + 1;
		return startPageOfPageGroup;
	}

	/**
	 * 현재 페이지가 속한 페이지 그룹의 마지막 페이지 번호를 return 한다. 
	 * 1. 현재 페이지 그룹 * 페이지 그룹 개수 가 마지막 번호이다. 
	 * 2. 그 그룹의 마지막 페이지 번호가 전체 페이지의 마지막 페이지 번호보다 
	 * 큰 경우는 전체 페이지의 마지막 번호를 return한다. 
	 * 1 2 3 4 -> 5 6 7 8 -> 9 10
	 * 
	 * @return
	 */
	public int getEndPageOfPageGroup() {
		int endPageOfPageGroup = getNowPageGroup() * pageCountPerPageGroup;
		
		if (endPageOfPageGroup > totalPostCount)
			endPageOfPageGroup = getTotalPage();
			
		return endPageOfPageGroup;
	}

	/**
	 * 이전 페이지 그룹이 있는지 체크하는 메서드 
	 * 현재 페이지가 속한 페이지 그룹이 1보다 크면 true 
	 * ex ) 페이지 1 2 3 4 / 5 6 7 8 / 9 10 
	 *               1         2        3 group
	 * 
	 * @return
	 */
	public boolean isPreviousPageGroup() {
		boolean flag = false;
		if (getNowPageGroup() > 1 )
			flag = true;
		return flag;
	}

	/**
	 * 다음 페이지 그룹이 있는지 체크하는 메서드
	 * 현재 페이지 그룹이 마지막 페이지 그룹( 마지막 페이지 그룹 == 총 페이지 그룹 수) 보다
	 * 작으면 true
	 * ex ) 페이지 1 2 3 4 / 5 6 7 8 / 9 10 
	 *               1         2        3 group
	 * 
	 * @return
	 */
	public boolean isNextPageGroup() {
		boolean flag = false;
		if (getTotalPageGroup() > getNowPageGroup())
			flag = true;
		return flag;
	}

	//체크를 위한 main method
	public static void main(String args[]) {
		PagingBean p = new PagingBean(70, 6);
		// 현페이지의 시작 row number 를 조회 
		System.out.println("getBeginRowNumber:" + p.getStartRowNumber());
		// 현페이지의 마지막 row number 를 조회 
		System.out.println("getEndRowNumber:" + p.getEndRowNumber());
		// 전체 페이지 수 
		System.out.println("getTotalPage:" + p.getTotalPage());
		// 전체 페이지 그룹 수 
		System.out.println("getTotalPageGroup:" + p.getTotalPageGroup());
		System.out.println("////////////////////////////");
		p = new PagingBean(70, 6);// 게시물수 70 현재 페이지 6
		// 현페이지의 시작 row number 를 조회 
		System.out.println("getStartRowNumber:" + p.getStartRowNumber());
		// 현페이지의 마지막 row number 를 조회 
		System.out.println("getEndRowNumber:" + p.getEndRowNumber());

		// 현재 페이지 그룹 
		System.out.println("getNowPageGroup:" + p.getNowPageGroup());
		// 페이지 그룹의 시작 페이지
		System.out.println("getStartPageOfPageGroup:" + p.getStartPageOfPageGroup());
		// 페이지 그룹의 마지막 페이지 
		System.out.println("getEndPageOfPageGroup:" + p.getEndPageOfPageGroup());
		// 이전 페이지 그룹이 있는 지 
		System.out.println("isPreviousPageGroup:" + p.isPreviousPageGroup());
		// 다음 페이지 그룹이 있는 지 
		System.out.println("isNextPageGroup:" + p.isNextPageGroup());
	}
}

 

필수 생성 요소는 아니지만, 페이지 리스트에 관한 정보는 ListVO에 묶어서 제공하기 위해서 생성한다.

/ListVO.java

package model;

import java.util.ArrayList;

public class ListVO {
	private ArrayList<PostVO> list;
	private PagingBean pagingBean;
	
	public ListVO() {
		super();
	}

	public ListVO(ArrayList<PostVO> list, PagingBean pagingBean) {
		super();
		this.list = list;
		this.pagingBean = pagingBean;
	}

	public ArrayList<PostVO> getList() {
		return list;
	}

	public void setList(ArrayList<PostVO> list) {
		this.list = list;
	}

	public PagingBean getPagingBean() {
		return pagingBean;
	}

	public void setPagingBean(PagingBean pagingBean) {
		this.pagingBean = pagingBean;
	}
	
}

> Member

 

/MemebrVO.java

package model;

public class MemberVO {
	private String id;
	private String password;
	private String name;
	
	public MemberVO() {
		super();
	}

	public MemberVO(String id, String password, String name) {
		super();
		this.id = id;
		this.password = password;
		this.name = name;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "MemberVO [id=" + id + ", password=" + password + ", name=" + name + "]";
	}
	
	
}

 

/MemberDAO.java

package model;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.sql.DataSource;

public class MemberDAO {
	//singleton pattern
	private static MemberDAO instance = new MemberDAO();
	private DataSource dataSource;
	
	private MemberDAO() {
		dataSource = DataSourceManager.getInstance().getDataSource();
	}
	
	public static MemberDAO getInstance() {
		return instance;
	}
	
	//closeAll(rs, pstmt, con) method 
	public void closeAll(ResultSet rs, PreparedStatement pstmt, Connection con) 
			throws SQLException {
		if(rs != null)
			rs.close();
		if (pstmt != null)
			pstmt.close();
		// Connection을 dbcp에 반납한다(소멸하는 것이 아니다!)
		if (con != null)
			con.close();
	}
	
	/*
	 * login method
	 * login(String id, String password) : MemberVO
	 */
	public MemberVO login(String id, String password) throws SQLException {
		MemberVO memberVO = null;
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try {
			con = dataSource.getConnection();
			String sql = "SELECT * FROM board_member "
					+ "WHERE id=? AND password=?";
			pstmt = con.prepareStatement(sql);
			pstmt.setString(1, id);
			pstmt.setString(2, password);
			rs = pstmt.executeQuery();
			if (rs.next())
				memberVO = new MemberVO(id, password, rs.getString("name"));
		} finally {
			closeAll(rs, pstmt, con);
		}
		
		return memberVO;
	}
	
}

> Board

 

/PostVO.java

package model;

public class PostVO {
	private String no;
	private String title;
	private String content;
	private int hits ;
	private String timePosted;
	private MemberVO memberVO;
	
	public PostVO() {
		super();
	}

	public PostVO(String no, String title, String content, int hits, String timePosted, MemberVO memberVO) {
		super();
		this.no = no;
		this.title = title;
		this.content = content;
		this.hits = hits;
		this.timePosted = timePosted;
		this.memberVO = memberVO;
	}

	public String getNo() {
		return no;
	}

	public void setNo(String no) {
		this.no = no;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public int getHits() {
		return hits;
	}

	public void setHits(int hits) {
		this.hits = hits;
	}

	public String getTimePosted() {
		return timePosted;
	}

	public void setTimePosted(String timePosted) {
		this.timePosted = timePosted;
	}

	public MemberVO getMemberVO() {
		return memberVO;
	}

	public void setMemberVO(MemberVO memberVO) {
		this.memberVO = memberVO;
	}

	@Override
	public String toString() {
		return "PostVO [no=" + no + ", title=" + title + ", content=" + content + ", hits=" + hits + ", timePosted="
				+ timePosted + ", memberVO=" + memberVO + "]";
	}

}

 

/BoardDAO.java

package model;

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

import javax.sql.DataSource;

public class BoardDAO {
	private static BoardDAO instance = new BoardDAO();
	//DBCP에서 connection pool을 이용한다
	//(dataSource는 dbcp에 여러 정보들을 담아놓은 변수이다)
	private DataSource dataSource;
	
	// 생성자에 private를 명시하여 외부해서 생성하지 못하게 막는다
	private BoardDAO() {
		/* DBCP를 통해 driver loading & connection pool 생성 */
		 //이 DataSourceManager에 있는 dataSource는
		// 이미 driver/user/password로 연결이 되어있는 상태이다.
		this.dataSource = DataSourceManager.getInstance().getDataSource();
	}
	// public static 메서드로 외부에 객체 생성을 공유한다.
	public static BoardDAO getInstance() {
		return instance;
	}
	
	//closeAll(pstmt, con) method 
	public void closeAll(PreparedStatement pstmt, Connection con) 
			throws SQLException {
		if (pstmt != null)
			pstmt.close();
		// Connection을 dbcp에 반납한다(소멸하는 것이 아니다!)
		if (con != null)
			con.close();
	}
	
	//closeAll(rs, pstmt, con) method 
	public void closeAll(ResultSet rs, PreparedStatement pstmt, Connection con) 
			throws SQLException {
		if (rs != null)
			rs.close();
		this.closeAll(pstmt, con);
	}
	
	
	/**
	 * 페이지 번호에 해당하는 게시물 목록 리스트를 반환하는 메서드 
	 * LIST SQL -> Test 후 반영하세요 
	    SELECT b.no,b.title,b.hits,to_char(time_posted,'YYYY.MM.DD') as time_posted,m.id,m.name 
		FROM board b , board_member m
		WHERE b.id=m.id
		order by no desc
		
		step2 : row_number() 를 적용해서 최근 게시물 5개만 조회하도록 한다 
		SELECT B.* , M.NAME
		FROM(
			SELECT row_number() over(ORDER BY NO DESC) as rnum,no,title,hits,
			to_char(time_posted,'YYYY.MM.DD') as time_posted,id
			FROM board
		) B, BOARD_MEMBER M 
		WHERE B.id=M.id AND rnum BETWEEN 1 AND 5
		
		
	 * @param pageNo
	 * @return
	 * @throws SQLException
	 */
	public ArrayList<PostVO> getAllList(PagingBean pagingBean) throws SQLException {
		ArrayList<PostVO> list = new ArrayList<PostVO>();
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try {
			con = dataSource.getConnection();
			StringBuilder sql = new StringBuilder();
			sql.append("SELECT b.*, m.name ");
			sql.append("FROM   ( SELECT row_number() over(ORDER BY no DESC) AS rnum, ");
			sql.append("no, title, hits, ");
			sql.append("TO_CHAR(time_posted, 'YYYY-MM-DD') AS time_posted, id ");
			sql.append("FROM   board) b, BOARD_MEMBER m ");
			sql.append("WHERE  b.id = m.id AND rnum BETWEEN ? AND ?	 ");
			pstmt = con.prepareStatement(sql.toString());
			//start, endRowNumber 할당한다 
			pstmt.setInt(1, pagingBean.getStartRowNumber());
			pstmt.setInt(2, pagingBean.getEndRowNumber());
			rs = pstmt.executeQuery();
			
			while(rs.next()) {
				MemberVO memberVO = new MemberVO();
				memberVO.setId(rs.getString("id"));
				memberVO.setName(rs.getString("name"));
				
				PostVO postVO = new PostVO();
				postVO.setNo(rs.getNString("no"));
				postVO.setTitle(rs.getNString("title"));
				postVO.setTimePosted(rs.getString("time_posted"));
				postVO.setHits(rs.getInt("hits"));
				postVO.setMemberVO(memberVO);
				
				list.add(postVO);
			}
			
		} finally {
			closeAll(rs, pstmt, con);
		}
		
		return list;
	}

	/**
	 * DB에 저장된 전체 포스팅의 개수를 반환
	 * getTotalPostCount() : int totalPostCount
	 * @throws SQLException 
	 */
	public int getTotalPostCount() throws SQLException {
		int totalPostCount = 0;
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try {
			con = dataSource.getConnection();
			String sql = "SELECT COUNT(*) FROM  board";
			pstmt = con.prepareStatement(sql);
			rs = pstmt.executeQuery();
			if (rs.next()) 
				totalPostCount = rs.getInt(1);
		} finally {
			closeAll(rs, pstmt, con);
		}
		
		return totalPostCount;
	}
	
	
	
	/**
	 * list.jsp에서 title을 누르면 게시글 상세보기 제공
	 * '게시물 번호','제목', '작성자', '작성일시', '조회수',  '게시물 본문 내용'
	 * getPostDetailByNo(String No) : PostVO
	 * @throws SQLException 
	 */
	public PostVO getPostDetailByNo(String no) throws SQLException {
		PostVO postVO  = null;
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try {
			con = dataSource.getConnection();
			StringBuilder sql = new StringBuilder();
			sql.append("SELECT b.no, b.title, m.name, m.id, ");
			sql.append("TO_CHAR(time_posted, 'YYYY-MM-DD HH24:MI:SS') AS time_posted, ");
			sql.append("b.hits, b.content ");
			sql.append("FROM board b, BOARD_MEMBER m ");
			sql.append("WHERE  b.id = m.id AND b.no=? ");
			pstmt = con.prepareStatement(sql.toString());
			pstmt.setString(1, no);
			
			rs = pstmt.executeQuery();
			if(rs.next()) {
				MemberVO memberVO = new MemberVO();
				memberVO.setId(rs.getString("id"));
				memberVO.setName(rs.getString("name"));
				
				postVO = new PostVO();
				postVO.setNo(rs.getString("no"));
				postVO.setTitle(rs.getString("title"));
				postVO.setTimePosted(rs.getString("time_posted"));
				postVO.setHits(rs.getInt("hits"));
				postVO.setContent(rs.getString("content"));
				postVO.setMemberVO(memberVO);
			}
			
		} finally {
			closeAll(rs, pstmt, con);
		}
		
		return postVO;
	}
	
	
	/**
	 * title을 누르면 조회 수 증가 (hits)
	 * addHits(String no) : void
	 * @throws SQLException 
	 */
	public void addHits(String no) throws SQLException {
		Connection con = null;
		PreparedStatement pstmt = null;
		
		try {
			con = dataSource.getConnection();
			String sql = "UPDATE BOARD SET hits=1 WHERE no=?";
			pstmt = con.prepareStatement(sql);
			pstmt.setString(1, no);
			
			pstmt.executeUpdate();
			
		} finally {
			closeAll(pstmt, con);
		}
		
	}
	
	/**
	 * 새로운 게시글 등록 기능
	 * + 게시물 등록 후 생성된 시퀀스(게시글 no)를 BoardVO에 setting 한다
	 * writePost(PostVO) : void
	 * @throws SQLException 
	 */
	public void writePost(PostVO postVO) throws SQLException {
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try {
			con = dataSource.getConnection();
			StringBuilder sql=new StringBuilder();
			sql.append("insert into board(no,title,content,id,time_posted) ");
			sql.append("values(board_seq.nextval,?,?,?,sysdate)");	
			pstmt = con.prepareStatement(sql.toString());
			pstmt.setString(1, postVO.getTitle());
			pstmt.setString(2, postVO.getContent());
			pstmt.setString(3, postVO.getMemberVO().getId());
			pstmt.executeUpdate();
			pstmt.close();
			
			String sql2 = "SELECT board_seq.currval FROM dual";
			pstmt = con.prepareStatement(sql2);
			rs = pstmt.executeQuery();
			if(rs.next())
				//기존에 받아온 postVO의 no를 
				//새로 만든 게시글 번호(현재 시퀀스)로 재할당해준다.
				postVO.setNo(rs.getString(1));
			
		} finally {
			closeAll(rs, pstmt, con);
		}
		
	}
	
	/**
	 * '삭제'버튼을 누르면 해당 게시글 삭제 기능
	 * removePost(String no) : void
	 * @throws SQLException 
	 */
	public void removePost(String no) throws SQLException {
		Connection con = null;
		PreparedStatement pstmt = null;
		
		try {
			con = dataSource.getConnection();
			String sql = "DELETE board WHERE no=?";
			pstmt = con.prepareStatement(sql);
			pstmt.setString(1, no);
			pstmt.executeUpdate();
			
		} finally {
			closeAll(pstmt, con);
		}
	}
	
	/**
	 * 게시글 수정하기
	 * updatePost(PostVO postVO) : void
	 * @throws SQLException 
	 */
	public void updatePost(PostVO postVO) throws SQLException {
		Connection con = null;
		PreparedStatement pstmt = null;
		
		try {
			con = dataSource.getConnection();
			String sql = "UPDATE BOARD SET title=?, content=? "
					+ "WHERE no=?";
			pstmt = con.prepareStatement(sql);
			pstmt.setString(1, postVO.getTitle());
			pstmt.setString(2, postVO.getContent());
			pstmt.setString(3, postVO.getNo());
			
			pstmt.executeUpdate();
			
		} finally {
			closeAll(pstmt, con);
		}
	}
	
}//class

View

[ template ]

 

/index.jsp 

index를 실행하면 <jsp:forward> 방식으로 layout.jsp로 간다

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core"  prefix="c"%>  
<jsp:forward page="front">
	<jsp:param value="home" name="command"/>
</jsp:forward>

 

/template/header.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core"  prefix="c"%>  

<script type="text/javascript">
	function logout() {
		if (confirm("로그아웃 하시겠습니까?")) { 
			location.href = "${pageContext.request.contextPath}/front?command=logout";
		}
	}
</script>

<c:choose>
	<c:when test="${sessionScope.memberVO == null}">
	<form action="front" method="POST">
		<input type="hidden" name="command" value="login">
		<input type="text" name="id" required="required" placeholder="아이디">
		<input type="password" name="password" required="required" 
			placeholder="패스워드">
		<input type="submit" value="로그인">
	</form>
	</c:when>
	<c:otherwise>
		<a href="${pageContext.request.contextPath}/front?command=home">HOME</a>
		&nbsp;&nbsp;&nbsp;
		<a href="${pageContext.request.contextPath}/front?command=WritePostForm">글쓰기</a>
		&nbsp;&nbsp;&nbsp;
		<strong>${sessionScope.memberVO.name}</strong>님 로그인 
		&nbsp;&nbsp;&nbsp;
		 <a href="javascript:logout()">로그아웃</a>
	</c:otherwise>
</c:choose>

 

/template/layout.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8" session="false"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>게시판 HOME</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet"
	href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script
	src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script
	src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/myhome.css"/>

</head>
<body>
	<div class="container-fluid">

	<%-- "row", "col-[size]-[num] : 한 행의 열을 잡아줌 --%>
	
	<%-- Header 영역 --%>
	<div class="row header">
		<div class="col-sm-8 col-sm-offset-2" align="right">
			<%-- JSTL import --%>
			<c:import url="/template/header.jsp"></c:import>
		</div>
	</div>

	<%-- Main 화면 영역 --%>
	<div class="row main">
		<%-- Main 동작 영역 --%>			
		<div class="col-sm-8 col-sm-offset-2">
		<%--
			메인 화면에 대한 view 정보(url or jsp파일명)를 컨트롤러에서
			동적으로 할당받는다 
		 --%>
		 <c:import url="${requestScope.url}"/>
		</div>
	</div>
	
	</div>
</body>
</html>

[ CSS ]

 

/css/myhome.css

@charset "UTF-8";
.header {
	padding-top: 20px;
	padding-bottom: 30px;
}
.title {
	width: 50%;
}

.boardlist th,.boardlist td,.btnArea,.pagingArea{
	text-align: center;
}

--  기능 1 : 게시판 리스트 

 

'게시물 번호', '제목', '작성자', '작성일', '조회수' 제공

로그인 상태일 때, '제목'이 링크 활성화 되어, 게시글 상세보기로 넘어간다.

 

[ bootstrap ]

&laquo; : 왼쪽 화살표

&raquo; : 오른쪽 화살표

 

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

<table class="table table-hover boardlist">
	<thead>
		<tr align="center" class="warning">
			<th>번호</th>
			<th>제목</th>
			<th>작성자</th>
			<th>작성일</th>
			<th>조회수</th>
		</tr>
	</thead>
	<tbody>	
		<c:forEach items="${requestScope.lvo.list}" var="post">
		<tr>
			<td>${post.no}</td>
			<td>
			<c:choose>
				<c:when test="${sessionScope.memberVO != null}">
					<a href="${pageContext.request.contextPath}/front?command=PostDetail&no=${post.no}">
						${post.title}
					</a>
				</c:when>
				<c:otherwise>
					${post.title}
				</c:otherwise>
			</c:choose>
			</td>
			<td>${post.memberVO.name}</td>
			<td>${post.timePosted}</td>
			<td>${post.hits}</td>
		</tr>
		</c:forEach>
	</tbody>
</table>


<%-- Paging 처리 --%>
<c:set var="pb" value="${requestScope.lvo.pagingBean}"/>
<div class="pagingArea">
<ul class="pagination">

<!-- 
	step2 
	
	1) 이전 페이지 그룹이 있으면 화살표 보여준다
       페이징빈의 previousPageGroup 이용 
    2) 이미지에 이전 그룹의 마지막 페이지번호를 링크한다. 
        hint) startPageOfPageGroup-1 하면 됨   
 -->  
 	<c:if test="${pb.previousPageGroup}">
		<li>
		<a href="front?command=home&pageNo=${pb.startPageOfPageGroup-1}">&laquo;</a>
		</li>
	</c:if>
<!-- 
	step1

	 1) 현 페이지 그룹의 startPage부터 endPage까지 forEach 를 이용해 출력한다

	 2) 현 페이지가 아니면 링크를 걸어서 서버에 요청할 수 있도록 한다.
        현 페이지이면 링크를 처리하지 않는다.  
        PagingBean의 nowPage - jstl choose 를 이용  
        예) <a href="front?command=List&pageNo=...">    
 -->
	<c:forEach var="i" begin="${pb.startPageOfPageGroup}" 
				end="${pb.endPageOfPageGroup}">
		<c:choose>
			<c:when test="${pb.nowPage!=i}">
				<li><a href="front?command=home&pageNo=${i}">${i}</a></li>
			</c:when>
			<c:otherwise>
				<li class="active"><a href="#">${i}</a></li>
			</c:otherwise>
		</c:choose>
	</c:forEach>

<!-- 
	step3 
	
	1) 다음 페이지 그룹이 있으면 화살표 보여준다. 
	   - 페이징빈의 nextPageGroup 이용 
    2) 이미지에 이전 그룹의 마지막 페이지번호를 링크한다. 
        hint)   endPageOfPageGroup+1 하면 됨   
 --> 
 	<c:if test="${pb.nextPageGroup}">
		<li>
			<a href="front?command=home&pageNo=${pb.endPageOfPageGroup+1}">&raquo;
			</a>
		</li>
	</c:if>
	
</ul>  
</div>

 기능 2 : 게시글 상세보기

 

/board/post-detail.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core"  prefix="c"%>  

<script>
	function removePost() {
		if(confirm("게시글을 삭제하시겠습니까?")){
			document.removeForm.submit();
		} else {
			return;
		}
	}
	
	function updatePost() {
		if(confirm("게시글을 수정하시겠습니까??")){
			document.updateForm.submit();
		} else {
			return;
		}
	}
</script>


 <h3 align="left"><${requestScope.postVO.title}>의 상세정보</h3>
 <ul class="list-group detailList">
   <li class="list-group-item"><strong>게시물 번호</strong></li>
   <li class="list-group-item">${requestScope.postVO.no}</li>
   <li class="list-group-item"><strong>제목</strong></li>
   <li class="list-group-item">${requestScope.postVO.title}</li>
   <li class="list-group-item"><strong>작성자</strong></li>
   <li class="list-group-item">${requestScope.postVO.memberVO.name}</li>
   <li class="list-group-item"><strong>작성일시</strong></li>
   <li class="list-group-item">${requestScope.postVO.timePosted}</li>
   <li class="list-group-item"><strong>조회수</strong></li>
   <li class="list-group-item">${requestScope.postVO.hits}</li>
   <li class="list-group-item"><strong>줄거리</strong></li>
   <li class="list-group-item"><pre>${requestScope.postVO.content}</pre></li>
 
 <c:if test="${requestScope.postVO.memberVO.id == sessionScope.memberVO.id}">
 	<form name="removeForm"
 		action="${pageContext.request.contextPath}/front" method="POST">
 		<input type="hidden" name="command" value="RemovePost">
 		<input type="hidden" name="no" value="${requestScope.postVO.no}">
	</form>

 	<form name="updateForm"
 		action="${pageContext.request.contextPath}/front" method="POST">
 		<input type="hidden" name="command" value="UpdatePostForm">
 		<input type="hidden" name="no" value="${requestScope.postVO.no}">
	</form>
	
 	<li class="list-group-item" align="right">
	<button type="button" class="btn btn-info" onclick="updatePost()">
		수정</button>
	<button type="button" class="btn btn-danger" onclick="removePost()">
		삭제</button>
 	</li>
 </c:if>
 
 </ul>

 기능 3 : 로그인 + 로그아웃

 

로그인 실패 시

/member/login-fail.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core"  prefix="c"%>  

<script type="text/javascript">
	alert("로그인에 실패했습니다!\n\n아이디와 비밀번호를 확인해주세요.");
	location.href ="${pageContext.request.contextPath}/index.jsp";
</script>

 

로그아웃  클릭하면, 여부 물어볼 javascript

/member/logout.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core"  prefix="c"%>  

<script type="text/javascript">
	if (confirm("로그아웃 하시겠습니까?")) { 
		location.href = "${pageContext.request.contextPath}/front?command=home"	
	} else {
		location.href = "${pageContext.request.contextPath}/index.jsp"	
	}
</script>

 기능 4 : 게시글 등록

 

/board/write-post-form.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

<form action="${pageContext.request.contextPath}/front" method="POST">
	<input type="hidden" name="command" value="WritePost">
	<table class="table">
		<tr>
			<td>
				<h4>제목</h4>
				<input type="text" name="title" 
					placeholder="게시글 제목을 입력하세요" 
					required="required">
			</td>
		</tr>

		<tr>
			<td>
				<h4>본문 내용</h4>
				<textarea cols="90" rows="15" name="content" 
					required="required" 
					placeholder=" 본문내용을 입력하세요"></textarea>
			</td>
		</tr>
		
		<tr>
			 <td>
				<div class="btnArea">
					<button type="submit" class="btn-success">게시글 올리기</button>
					&nbsp;&nbsp; &nbsp;&nbsp;
					<button type="reset" class="btn-warning">다시 쓰기</button>
				</div>
			 </td>
		</tr>
	</table>
</form>

 기능 5 : 게시글 수정

 

/board/update-post-form.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core"  prefix="c"%>  

 <form action="${pageContext.request.contextPath}/front" method="POST" >
	<input type="hidden" name="command" value="UpdatePost"></input>
	<input type="hidden" name="no" value="${postVO.no}"></input>
	<table class="table">
		<tr>
			<td>
				<strong>제목</strong>
			<br>
				<input type="text" name="title" value="${postVO.title}"
					required="required">
			</td>
		</tr>
		
		<tr>
			<td>
				<strong>줄거리</strong>
			<br>
				<textarea cols="90" rows="15" name="content" 
					required="required">${postVO.content}</textarea>
			</td>
		</tr>
		
		<tr>
			 <td colspan="2">
				<div class="btnArea">
					<button type="submit" class="btn btn-success">수정 완료</button>
					&nbsp;&nbsp; &nbsp;&nbsp;
					<button type="reset" class="btn btn-warning">글 초기화</button>
				</div>
			 </td>
		</tr>
	</table>
</form>


Controller

/Controller.java

package controller;

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

public interface Controller {
	//execute(request, response) : String -> url
	public String execute(HttpServletRequest request, HttpServletResponse response) 
			throws Exception;
}

 

/ HandlerMapping.java

package controller;


public class HandlerMapping {
	private static HandlerMapping instance = new HandlerMapping();
	private HandlerMapping() {}
	public static HandlerMapping getInstance() {
		return instance;
	}
	
	public Controller create(String command) {
		Controller controller = null;
		if (command.contentEquals("home"))
			controller = new HomeController();
		else if (command.contentEquals("login"))
			controller = new LoginController();
		else if (command.contentEquals("logout"))
			controller = new LogoutController();
		else if (command.contentEquals("PostDetail"))
			controller = new PostDetailController();
		else if (command.contentEquals("PostDetailNoHits"))
			controller = new PostDetailNoHitsController();
		else if (command.contentEquals("WritePostForm"))
			controller = new WritePostFormController();
		else if (command.contentEquals("WritePost"))
			controller = new WritePostController();
		else if (command.contentEquals("RemovePost"))
			controller = new RemovePostController();
		else if (command.contentEquals("UpdatePostForm"))
			controller = new UpdatePostFormController();
		else if (command.contentEquals("UpdatePost"))
			controller = new UpdatePostController();
		return controller;
	}
}

 

/DispatcherServlet.java

handleRequest method 작동 방식

1. 에러(예외) 발생 시, 콘솔에 메세지 발생 경로 출력 후,  error.jsp로  redirect 방식으로 view로 이동한다.

2. 클라이언트가 전송한 command 정보를 받는다.

3. HandlerMapping 을 이용해 개별 컨트롤러 객체를 컨트롤러 인터페이스 타입으로 반환받는다.

4. 개별 컨트롤러를 실행한다.

5. 실행 후 반환된 String url 정보를 이용해,

     forward 방식 or redirect 방식으로 view로 이동해 응답하게 한다.

package 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;


@WebServlet("/front")
public class DispatcherServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		this.HandleRequest(request, response);
	}


	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		request.setCharacterEncoding("utf-8");
		this.HandleRequest(request, response);
	}
	
	public void HandleRequest(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		
		try {
		//view에서 보낸 command를 받는다.
		String command = request.getParameter("command");
		
		//HandlerMapping을 이용해 개별 컨트롤러 객체를 컨트롤러 인터페이스 타입으로 반환받는다.
		Controller controller = HandlerMapping.getInstance().create(command);
		
		//개별 컨트롤러를 실행한다.
		String url = controller.execute(request, response);
		
		// 실행 후 반환된 String url 정보를 이용해,
		//forward 방식 or redirect 방식으로 view로 이동해 응답하게 한다.
		if(url.startsWith("redirect:")) {
			response.sendRedirect(url.substring(9));
		} else {
			request.getRequestDispatcher(url).forward(request, response);
		}
		
		} catch (Exception e) {
			//error 발생 시, console에 에러 메세지를 표기하고,
			e.printStackTrace();
			//error.jsp로 이동한다.
			response.sendRedirect("error.jsp");
		}
	}
}

기능 1 : 게시물 리스트 (command=home)

 

/HomeController.java

package controller;

import java.util.ArrayList;

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

import model.BoardDAO;
import model.ListVO;
import model.PagingBean;
import model.PostVO;

public class HomeController implements Controller {

	@Override
	public String execute(HttpServletRequest request, 
			HttpServletResponse response) throws Exception {
		//1. 전체 포스팅의 개수를 받아온다.
		int totalPostCount = BoardDAO.getInstance().getTotalPostCount();
		
		//2. 현재 페이지 번호를 받아옴
		String pageNo = request.getParameter("pageNo");
		
		PagingBean pagingBean = null;
		
		//3. 만약 페이지 번호가 null이면 -> PagingBean(전체포스팅개수) 객체 생성
		if (pageNo == null)
			pagingBean = new PagingBean(totalPostCount);
		//null이 아니면 -> PagingBean(전체포스팅개수, 현재페이지번호) 객체 생성
		else
			pagingBean = new PagingBean(totalPostCount, Integer.parseInt(pageNo));
		
		//4) getAllList(PagingBean)과 연동하여,
		//페이지에 맞는 포스팅 5개 리스트 반환받기
		ArrayList<PostVO> list 
			= BoardDAO.getInstance().getAllList(pagingBean);
		
		// + ListVO list와 PagingBean넣어 객체 생성
		ListVO listVO = new ListVO(list,pagingBean);
		
		//5) request에 담아 listVO공유
		request.setAttribute("lvo", listVO);
		
		//6) reqquest에 담아 url공유 (list.jsp) - layout으로 리턴
		request.setAttribute("url", "/board/list.jsp");
		return "/template/layout.jsp";
	}

}

기능 2 :  게시물 상세 보기 Controller

command = postDetail : 본인 외의 게시물을 보았을 때, 조회수가 증가함

command = postDetailNoHits : 본인의 게시물을 보았을 때, 조회수가 증가하지 않음

 

/PostDetailController.java

package controller;

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

import model.BoardDAO;
import model.PostVO;

public class PostDetailController implements Controller {

	@Override
	public String execute(HttpServletRequest request, 
			HttpServletResponse response) throws Exception {
		
		HttpSession session=request.getSession(false);
		
		if(session==null||session.getAttribute("memberVO")==null){
			return "redirect:index.jsp";
		}
		
		String no = request.getParameter("no");
		//조회수 증가
		BoardDAO.getInstance().addHits(no);
		//게시글 상세정보
		PostVO postVO = BoardDAO.getInstance().getPostDetailByNo(no);
		
		//상세정보 공유 (조회수 증가함)
		request.setAttribute("postVO", postVO);
		//url에 상세정보 페이지로 이동
		request.setAttribute("url", "/board/post-detail.jsp");

		
		return "/template/layout.jsp";
	}

}

 

/PostDetailNohitsController.java

package controller;

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

import model.BoardDAO;
import model.PostVO;

public class PostDetailNoHitsController implements Controller {

	@Override
	public String execute(HttpServletRequest request, 
			HttpServletResponse response) throws Exception {
		
		HttpSession session=request.getSession(false);
		if(session==null||session.getAttribute("memberVO")==null){
			return "redirect:index.jsp";
		}
		
		//WritePostController에서 보낸 no받음
		String no = request.getParameter("no");
		
		//조회수 증가 안함
		
		//게시글 상세정보
		PostVO postVO = BoardDAO.getInstance().getPostDetailByNo(no);
		
		//상세정보 공유 (조회수 증가 안함)
		request.setAttribute("postVO", postVO);
		//url에 상세정보 페이지로 이동
		request.setAttribute("url", "/board/post-detail.jsp");
		
		return "/template/layout.jsp";
	}

}

기능 3 :  로그인 + 로그아웃 Controller

 

/LoginController.java

package controller;

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

import model.MemberDAO;
import model.MemberVO;

public class LoginController implements Controller {

	@Override
	public String execute(HttpServletRequest request, 
			HttpServletResponse response) throws Exception {
		String id = request.getParameter("id");
		String password = request.getParameter("password");
		MemberVO memberVO = MemberDAO.getInstance().login(id, password);
		
		//memberVO가 있다면
		if (memberVO != null) {
			//session 새로 만들기
			HttpSession session = request.getSession();
			//session에 로그인 정보 넣기
			session.setAttribute("memberVO", memberVO);
			
			//다시 index로 보내기
			return "redirect:index.jsp";
			
		} else { //memberVO가 없다면 
			return "redirect:member/login-fail.jsp";
		}
	}

}

 

/LogoutController.java

package controller;

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

public class LogoutController implements Controller {

	@Override
	public String execute(HttpServletRequest request, 
			HttpServletResponse response) throws Exception {
		
		HttpSession session = request.getSession(false);
		
		if (session != null && session.getAttribute("memberVO")!= null) {
			session.invalidate();
		}
		
		return "redirect:index.jsp";
	}

}

기능 4 :  게시글 등록 기능  Controller

 

/WritePostFormController.java

package controller;

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

public class WritePostFormController implements Controller {

	@Override
	public String execute(HttpServletRequest request, 
			HttpServletResponse response) throws Exception {
		//로그인 여부 체크
		HttpSession session=request.getSession(false);
		if(session==null||session.getAttribute("memberVO")==null){
			return "redirect:index.jsp";
		}
		
		request.setAttribute("url", "/board/write-post-form.jsp");		
		return "/template/layout.jsp";
	}

}

 

/WritePostController.java

package controller;

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

import model.BoardDAO;
import model.MemberVO;
import model.PostVO;

public class WritePostController implements Controller {

	@Override
	public String execute(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		
		HttpSession session=request.getSession(false);

		//로그인 여부 체크 + POST방식으로 form을 보냈는지 체크
		if(session==null||session.getAttribute("memberVO")==null ||
				request.getMethod().equals("POST")==false) {
			return "redirect:index.jsp";
		}
		
		/*게시글 등록*/
		
		//1. write-post-form.jsp에서 title과 content 받아오기
		String title = request.getParameter("title");
		String content = request.getParameter("content");
		
		//2. postVO에 새로 입력받은 글로 새로운 postVO 만들기
		PostVO postVO = new PostVO();
		postVO.setTitle(title);
		postVO.setContent(content);
		
		//3. session에 있는 MemberVO도 postVO에 넣어주기
		//   (다운캐스팅 필요)
		postVO.setMemberVO((MemberVO)session.getAttribute("memberVO"));
		
		//4. 로그인 정보와 글 정보를 담은 postVO를 작성하기
		// - 이 과정에서 자동으로 no와 date가 postVO에 입력된다
		BoardDAO.getInstance().writePost(postVO);
		
		//5. veiw-post-detail-noHit.jsp (조회수 없는 게시판 리스트 뷰 페이지)에
		//   PostVO의 no 정보를 담아 보내기 (redirect 방식으로)
		//   -> why? 해당 게시물의 no 정보를 받기 위해서
		// **path에 담아 return 한다!**
		String path = "redirect:front?command=PostDetailNoHits&no"+postVO.getNo();
		
		return path;
	}

}

기능 5 :  본인 게시물 수정 기능  Controller

 

/UpdatePostFormController.java

package controller;

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

import model.BoardDAO;
import model.PostVO;

public class UpdatePostFormController implements Controller {

	@Override
	public String execute(HttpServletRequest request,
			HttpServletResponse response) throws Exception {
		
		HttpSession session=request.getSession(false);
		if(session==null||session.getAttribute("memberVO")==null){
			return "redirect:index.jsp";
		}
		
		String no = request.getParameter("no");
		PostVO postVO = BoardDAO.getInstance().getPostDetailByNo(no);
		
		request.setAttribute("postVO", postVO);
		request.setAttribute("url", "/board/update-post-form.jsp");		
		
		return "/template/layout.jsp";
	}

}

 

/UpdatePostController.java

package controller;

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

import model.BoardDAO;
import model.PostVO;

public class UpdatePostController implements Controller {

	@Override
	public String execute(HttpServletRequest request, 
			HttpServletResponse response) throws Exception {
		
		HttpSession session=request.getSession(false);
		
		if(session==null||session.getAttribute("memberVO")==null||
				request.getMethod().equals("POST")==false){
			return "redirect:index.jsp";
		}	
		
		String title = request.getParameter("title");
		String content = request.getParameter("content");
		
		PostVO postVO = new PostVO();
		
		postVO.setNo(request.getParameter("no"));
		postVO.setTitle(title);
		postVO.setContent(content);
		
		BoardDAO.getInstance().updatePost(postVO);
			
		String path = "redirect:front?command=PostDetailNoHits&no="+postVO.getNo();
		
		return path;
	}

}

기능 6 : 본인 게시물 삭제 기능  Controller

 

/RemovePostController.java

package controller;

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

import model.BoardDAO;

public class RemovePostController implements Controller {

	@Override
	public String execute(HttpServletRequest request, 
			HttpServletResponse response) throws Exception {
		
		HttpSession session=request.getSession(false);
		if(session==null||session.getAttribute("memberVO")==null){
			return "redirect:index.jsp";
		}
		
		String no = request.getParameter("no");
		BoardDAO.getInstance().removePost(no);
		
		return "redirect:front?command=home";
	}

}

[ 브라우저 화면 ] 

기능 1. 게시물 리스트가 보이는 첫 화면 (로그인X)

 

728x90
반응형