커뮤니티 게시판 웹 어플리케이션 - 게시글 관리 에서 이어지는 포스팅입니다!
[JSP/MVC] 커뮤니티 게시판 웹 어플리케이션 - 게시글 관리 (Model2 Pattern)
[ 요구 사항 ] Model2 MVC 기반 커뮤니티 게시판 비로그인 상태에서는 '게시판 리스트' 정보만 제공된다. 상단부 화면에서 '로그인 할 수 있는 폼'이 제공된다. '게시판 리스트'에서는 '게시물 번호',
creamilk88.tistory.com
> 새로 추가된 기능은 paging 처리을 통해 home의 한 화면에서 5개씩 포스팅이 보여지게 하는 것입니다.
[ 기존 기능 ]
1. 게시물 리스트 테이블로 보기 (home 화면에서)
2. 게시물 상세보기 (로그인 상태에서)
3. 로그인 + 로그아웃
4. 게시글 등록
5. 게시글 수정
6. 게시글 삭제
+ [ 새로운 기능 ]
페이징 처리
→ 게시물 리스트 하단부에 페이지 그룹은 '4 페이지'로
→ 페이지 그룹 당 게시물 수는 '5개'로 처리한다.
[ 구현 순서 ]
- 추가 파일 및 메서드 / 수정 파일
- src의 model directory에 두 가지 java Beans를 추가한다.
1) PagingBean.java
- PagingBean은 '페이징 처리를 위한 비즈니스 계층의 클래스'이다.
2) ListVO.java
: 필수 생성 요소는 아니지만, 페이지 리스트(paging)에 대한 동작은 ListVO로 묶어서 제공하기 위해 생성한다.
- 인스턴스 변수 : 1) ArrayList<PostVO> 2)PagingBean
- 위 인스턴스 변수들을 반환한다. - [ step1. 게시글 5개 씩 나오도록 하기!]
BoardDAO에 getAllList(PaingBean) : 처음 게시글 리스트 뜨는 메서드를 수정한다.
: 최근 게시물 5개만 조회하도록 한다. (row_number 이용 & PagingBean을 매개변수로 추가) - BoardDAO에 getTotalPostCount() 메서드를 추가한다.
: 전체 포스팅의 개수를 반환하는 기능 - 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으로 리턴 - [ step2. 게시글 테이블 하단에 페이지 이동 bar 추가 !]
list.jsp에 paging navbar를 구성하여 추가한다. - 현 페이지 그룹의 startPage부터 endPage까지 forEach 를 이용해 출력한다
- 이전 페이지 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>
<a href="${pageContext.request.contextPath}/front?command=WritePostForm">글쓰기</a>
<strong>${sessionScope.memberVO.name}</strong>님 로그인
<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 ]
« : 왼쪽 화살표
» : 오른쪽 화살표
/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}">«</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}">»
</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>
<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>
<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)