복습
일반게시판 테이블 컬럼 num
- 게시판엔 번호가 있다, 번호가 들어가는 컬럼이 주로 primary key 가 된다
+ 회원관리에선 id 를 주로 primary key 가 된다
- primary key 로 설정된 컬럼은 where 조건절에 넣어서 원하는 데이터 1개의 상세정보를 구한다
- num 은 화면에 출력되는 번호와 관련이 없는 내부 번호
+ 화면 출력 번호는 중간에 데이터가 지워지더라도 연속적인 번호
일반게시판 테이블 컬럼 passwd
- 글 작성시 비번을 입력하고, 글 수정/삭제 시 비번이 일치해야만 삭제 가능
일반게시판 테이블 컬럼 readcount
- 조회수이며, number 타입이다
- 디폴트 0 이므로 값을 설정하지 않았을때 0 이 들어간다
+ 숫자 중 값의 변화가 자주 일어나는 것은 number 타입, 자주 바뀌지 않는 값은 varchar2 타입으로 주로 설정한다
ex) 우편번호, 주민번호는 숫자지만 varchar2
일반게시판 : 글 목록 / 게시판 목록
일반게시판 페이징 처리 변수 1
1. 기본변수 page_size
- 한 화면에 출력될 데이터의 개수
- 현재는 10
변수 pageNum
- 데이터가 11개가 넘어가면 2 페이지가 만들어지고, 21개가 넘어가면 3 페이지가 만들어진다
- 그 페이지번호에 현재 페이지인 list.jsp 링크를 걸것, 현재 페이지가 다시 시작됨
- 2 를 클릭시 list.jsp?page=2 가 링크가 됨
- 그걸 getParameter() 로 받고 pageNum 에 저장하는 것임
2. 기본변수 currentPage
- 변수 pageNum 을 int 형으로 형변환한 변수
- 산술적인 연산을 하기 위해 기본자료형으로 변환한 것이다
- 사용자가 페이지를 선택하지 않았을때 1 이 저장됨
pageNum 이 null 일때
- 페이지 값이 전달되지 않은 경우를 의미
ex) 바로 list.jsp 를 실행하거나 로그인 성공후 list.jsp 로 넘어왔을때, 즉 사용자가 어떤 페이지를 볼지 클릭하지 않았을때
- pageNum 이 null 인 경우 pageNum = "1" 로 설정해야 int 형으로 형변환 하는 코드에서 오류가 생기지 않음
- 이 코드가 없으면 500 오류 발생
+ 전체데이터를 내림차순 정렬할 것이므로 가장 최근글이 보이는 페이지가 1 페이지
3. 기본변수 count
- 총 데이터 개수를 저장
- DB와 연동하여 count(*) 그룹함수로 값을 구해온다
- 페이지를 계산하기 위해 필요
+ 현재 데이터 개수 : 130
+ DAO 클래스의 getCount()
파생변수 startRow & 파생변수 endRow
- startRow : 각 page에 출력할 데이터의 시작 번호
- endRow : 각 page에 출력할 데이터의 끝 번호
ex) 사용자가 2 페이지를 누르면 (2-1)*(10) +1 로 인해 startRow은 11
ex) 사용자가 2 페이지를 누르면 (2)*(10) 로 인해 endRow 는 20
- DAO의 getList() 를 호출할떄 매개변수로 들어간다
- 그 후 목록을 잘라주는 역할을 하는 SQL문의 rownum 컬럼 자리에 들어간다
String sql = "select * from (select rownum rnum, board.* from ";
sql += " (select * from board0 order by num desc) board ) ";
sql += " where rnum >= ? and rnum <= ?";
- num값 기준 내림차순 이므로 num값이 큰값이 위로 간다
- 전체 데이터를 내림차순해서 사용자가 2 페이지 클릭시 11번 ~ 20번 까지의 글을 보여주는 것
- 기본변수 3개와 파생변수 2개를 했다, 파생변수 약 6개 필요, 잠시 메소드 봤다가 이후 이어서 작성할 것
getList() 메소드
호출하는 list.jsp 부분
List<BoardDataBean> list = null;
if(count > 0) {
// 게시판 목록
list = dao.getList(startRow, endRow);
}
System.out.println("list : " + list);
/* System.out.println(list.get(1).getNum()); */
호출되는 BoardDBBean.java 부분
// 게시판 목록 구하기 : 데이터 10개 추출
public List<BoardDataBean> getList(int start, int end) {
List<BoardDataBean> list = new ArrayList<BoardDataBean>();
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = getConnection();
String sql = "select * from (select rownum rnum, board.* from ";
sql += " (select * from board0 order by num desc) board ) ";
sql += " where rnum >= ? and rnum <= ?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, start);
pstmt.setInt(2, end);
rs = pstmt.executeQuery(); // SQL문 실행
while(rs.next()) {
BoardDataBean board = new BoardDataBean();
board.setNum(rs.getInt("num"));
board.setWriter(rs.getString("writer"));
board.setEmail(rs.getString("email"));
board.setSubject(rs.getString("subject"));
board.setPasswd(rs.getString("passwd"));
board.setReg_date(rs.getTimestamp("reg_date"));
board.setReadcount(rs.getInt("readcount"));
board.setContent(rs.getString("content"));
board.setIp(rs.getString("ip"));
list.add(board);
}
} catch (Exception e){
e.printStackTrace();
} finally {
if(rs != null) try { rs.close(); } catch(Exception e) {}
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return list;
}
- 여러개의 데이터를 반환하므로 리턴자료형이 리스트
- 한개의 데이터를 반환할때는 리턴자료형이 DTO
- 검색된 데이터를 리스트에 바로 저장하는 것이 아니라 DTO 객체를 만든 후 컬럼단위로 잘라서 세팅한 후 리스트에 DTO 객체를 add() 해준다
- 그리고 모든 데이터가 저장된 리스트를 리턴해준다
목록을 자르는 서브쿼리 형태의 인라인뷰 SQL문
호출하는 list.jsp 부분
- 힙메모리 상의 주소가 출력됨
- 즉 DTO 객체의 값이다 (힙메모리상에 있는 데이터의 주솟값)
- 이후 list.jsp 에서 돌려받은 리스트에서 하나씩 데이터를 꺼내서 테이블에 출력한다
+ list 에서 get() 사용시 다운캐스팅
- 제네릭을 쓰고 있으므로 다운캐스팅시 자료형을 명시할 필요 없다
일반게시판 : 글 목록 / 게시판 목록 (이어서)
일반게시판 페이징 처리 변수 2 (이어서)
파생변수 number
- 화면에 출력하기 위한 번호
- 각 페이지에 출력될 시작 번호
- ex) 총 데이터가 130개이고, 사용자가 2페이지를 눌렀을때, 130 - (2 - 1) * 10 = 120 이 나온다
- 후행연산이므로 먼저 출력하고 for문에서 반복될떄마다 하나씩 감소되어 출력됨
+ 날짜시간 (list.jsp 부분)
- 포멧을 통해 출력
페이지 메뉴 바 설계
- 다음은 아래에 나타나는 페이지를 선택할수있는 메뉴를 만들자
- < 를 누르면 1p로 이동, > 를 누르면 마지막 페이지로 이동
- << 를 누르면 이전 '블럭' 으로 이동, >> 를 누르면 다음 '블럭' 으로 이동
- 한개의 블럭 당 10개의 '페이지' 가 출력되도록 하자
* 1 블럭 = 1 ~ 10 페이지 = 최신 100개 글
* 2 블럭 11 ~ 20 페이지 = 최신 101 ~ 200 글 100개
페이지 메뉴 바 코드 (list.jsp 부분)
<!-- 페이지 링크 설정 -->
<center>
<%
if(count > 0) {
// pageCount : 총 페이지 수
int pageCount = count/page_size + ((count%page_size==0) ? 0 : 1);
System.out.println("pageCount : " + pageCount);
// startPage : 각 블럭의 시작 페이지 번호 : 1, 11, 21 ...
// endPage : 각 블럭의 끝 페이지 번호 : 10, 20, 30 ...
int startPage = ((currentPage-1)/10) * 10 + 1;
int block = 10; // 1개의 블럭의 크기 : 10개의 페이지로 구성
int endPage = startPage + block - 1;
}
%>
</center>
- 표 가운데 나타나게 하기 위해 <center></center> 태그 안에 작성
- 글이 있는 경우만 출력하도록 if(count > 0)
<파생변수 pageCount>
- 총 페이지 수를 의미하는 파생변수 pageCount 를 출력해보면
- 현재 13 페이지가 필요하다
<파생변수 startPage>
+ 각 파생변수는 아래에서 자세히 설명
파생변수 pageCount
// pageCount : 총 페이지 수
int pageCount = count/page_size + ((count%page_size==0) ? 0 : 1);
- pageCount : 총 페이지 수
- int형과 int형 연산이므로 나머지가 사라지므로, 나머지가 0 이 아닌경우는 1페이지를 추가해줘야하므로 1 을 더한다
- 나머지가 0 인경우는 더하지 않는다 (0을 더한다)
파생변수 startPage & 파생변수 endPage
// startPage : 각 블럭의 시작 페이지 번호 : 1, 11, 21 ...
// endPage : 각 블럭의 끝 페이지 번호 : 10, 20, 30 ...
int startPage = ((currentPage-1)/10) * 10 + 1;
int block = 10; // 1개의 블럭의 크기 : 10개의 페이지로 구성
int endPage = startPage + block - 1;
- startPage : 각 블럭의 시작 페이지 번호 : 1, 11, 21 ...
- endPage : 각 블럭의 끝 페이지 번호 : 10, 20, 30 ...
- int형 끼리 연산시 int형이 나오므로, currentPage가 1 이어도 startPage는 1, currentPage가 10 이어도 startPage는 1
ex) 사용자가 2 페이지 클릭시, ((2-1)/10) * 10 + 1 = 1 , 즉 2 페이지가 속한 블럭의 첫번째 페이지 번호는 1 이란 의미
ex) 사용자가 12 페이지 클릭시, ((12-1)/10) * 10 + 1 = 11 , 즉 12 페이지가 속한 블럭의 첫번째 페이지 번호는 11 이란 의미
ex) 사용자가 22 페이지 클릭시, ((22-1)/10) * 10 + 1 = 21 , 즉 22 페이지가 속한 블럭의 첫번째 페이지 번호는 21 이란 의미
- 각 블럭의 시작 페이지 번호가 startPage
- 각 블럭의 끝 페이지 번호가 endPage
블럭에 페이지 뿌리고 링크 걸기 (list.jsp 부분)
- 이후 블럭에 페이지 뿌려야한다
- 반복문으로 1 블럭에 1 ~ 10 페이지까지 뿌리고, 2 블럭에 11 ~ 20 페이지까지 뿌리는 작업을 해야한다
// 각 블럭당 10개의 페이지 출력
for(int i = startPage; i <= endPage; i++) {
if(i == currentPage) { %>
[<%=i %>]
<% } else {%>
<a href="list.jsp?page=<%=i %>">[<%=i %>]</a>
<% }
}
- 현재 보고있는 페이지를 제외한 나머지 9개의 페이지에 링크를 걸어서 list.jsp 로 다시 실행시킨다
ex) 현재 1 페이지이면 1 페이지를 제외한 보이는 9개의 페이지에 링크 걸기
- 사용자가 선택한 페이지 번호값을 get 방식으로 list.jsp로 전송하자
- 이걸 list.jsp 위에서 작성했던 코드인 여기서 자르는 것이다
- 이렇게 currentPage 가 설정되는 것이다
- 즉 현재 페이지 번호에 따라 startRow 와 endRow 가 결정되어 SQL 문에서 해당 페이지의 글들을 가져옴
- list.jsp 안에서 값을 전달하기도 하고, 받기도 하고 있다
+ 11 페이지로 이동하려면?
- 그 다음 블럭인 2블럭으로 가야한다, 버튼을 만들어서 다음 블럭으로 이동하는 것을 만들 것
+ 문제점
- 1블럭이면 무조건 1 ~ 10페이지, 2블럭이면 무조건 11 ~ 20 페이지를 출력하므로 마지막 페이지에 문제가 생김
- 나중에 해결
1p 로 이동 (list.jsp 부분)
<!-- 1page로 이동 -->
<a href="list.jsp?page=1" style="text-decoration:none"> << </a>
- 내가 몇번째 페이지에 있든 상관없이 '<<' 클릭시 1페이지로 이동
- 밑줄을 없애기 위해 CSS 사용
마지막 페이지로 이동 (list.jsp 부분)
<!-- 마지막 페이지로 이동 -->
<a href="list.jsp?page=<%=pageCount %>" style="text-decoration:none"> >> </a>
- 클릭시 가장 마지막 페이지로 이동
- 마지막 페이지 번호 = 총 페이지 수
- 어느 페이지에 있던 '>>' 를 클릭시 가장 마지막 페이지로 이동
- 가장 마지막 페이지인 13 페이지로 이동했다
+ 잘못된 표 수정했다
+ 문제점
- 13 페이지가 마지막 페이지이다
- 실제 존재하지 않는 페이지 14,15.. 가 나타난다
- for문으로 endPage 정의 부분에서 문제가 생김
- 1블럭이면 무조건 1 ~ 10페이지, 2블럭이면 무조건 11 ~ 20 페이지를 출력하므로 마지막 페이지에 문제가 생김
문제 해결
- 가장 마지막 페이지의 endPage 값을 pageCount 값으로 설정해야함
// 가장 마지막 블럭에 endPage값을 pageCount로 수정
if(endPage > pageCount) { //
endPage = pageCount;
}
- pageCount는 13 이고, 1블럭일때, endPage 는 10 이다.
- pageCount는 13 이고, 2블럭일때, endPage 는 20 이다.
- 즉, 2블럭에서 endPage > pageCount 를 만족하므로, 마지막 블럭인 2블럭에서 endPage 값은 pageCount값이 됨
-' >>' 를 눌렀을때 캡처
이전 블럭과 다음 블럭으로 이동
- '[이전]' 을 눌렀을때 이전 블럭으로, '[다음]' 를 눌렀을때 다음 블럭으로 넘어가자
- 조건문을 써서 이전 블럭과 다음 블럭이 존재하는 경우에만 '이전' 과 '다음' 이 보이도록 하자
이전 블럭으로 이동 (list.jsp 부분)
// 이전 블럭으로 이동
if(startPage > 10){
<a href="list.jsp?page=<%=startPage-10 %>">[이전]</a>
}
- startPage 가 10 보다 큰 경우만, 즉 2블럭 이상만 이전 블럭 메뉴가 나타나도록 함
- 첫번째 블럭에서는 startPage 가 1 이므로 [이전] 메뉴가 나타나지 않음
- '[이전]' 블럭의 가장 작은 페이지로 이동하자
- 두번째 블럭에 있을때, startPage 는 11이다, 그 값에서 10 을 빼면 이전 블럭의 가장 작은 페이지인 1 로 이동
- 세번째 블럭에 있을때, startPage 는 21이다, 그 값에서 10 을 빼면 이전 블럭의 가장 작은 페이지인 11 로 이동
다음 블럭으로 이동 (list.jsp 부분)
// 다음 블럭으로 이동
if(endPage < pageCount) {
<a href="list.jsp?page=<%=startPage+10 %>">[다음]</a>
}
- endPage 가 pageCount 보다 작은 경우 = 다음 블럭이 존재하는 경우
- 첫번째 블럭은 endPage 가 10, pageCount 는 13 이므로 조건식 만족, [다음] 나타남
- 마지막 블럭인 두번째 블럭은 endPage 가 20. pageCount 는 13 이므로 조건식 불만족, 즉 마지막 페이지에서는 [다음] 나타나지 않음
- '[다음]' 블럭의 가장 작은 페이지로 이동하자
- 첫번째 블럭에 있을때, startPage는 1이다, 10을 더하면 다음 블럭의 가장 작은 페이지인 11 로 이동
- 두번째 블럭에 있을때, startPage는 11이다, 10을 더하면 다음 블럭의 가장 작은 페이지인 21 로 이동
list.jsp 코드 (최종)
- 목록을 나타냄
- 페이징 처리 적용
<%@page import="java.text.SimpleDateFormat"%>
<%@page import="board.BoardDataBean"%>
<%@page import="java.util.List"%>
<%@page import="board.BoardDBBean"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>게시판 목록</title>
</head>
<body>
<%
// 1. 한 화면에 출력할 데이터 갯수
int page_size = 10;
String pageNum = request.getParameter("page");
if(pageNum == null) {
pageNum = "1"; // 1 page : 최근글이 보이는 페이지
}
// 2. 현재 페이지 번호가 저장되는 변수
int currentPage = Integer.parseInt(pageNum);
// startRow : 각 page에 출력할 데이터의 시작번호
// endRow : 각 page에 출력할 데이터의 끝번호
// page = 1 : startRow=1, endRow=10
// page = 2 : startRow=11, endRow=20
// page = 3 : startRow=21, endRow=30
int startRow = (currentPage - 1) * page_size + 1;
int endRow = currentPage * page_size;
// 3. 총 데이터 갯수
int count = 0;
BoardDBBean dao = BoardDBBean.getInstance();
count = dao.getCount();
System.out.println("count : " + count);
List<BoardDataBean> list = null;
if(count > 0) {
// 게시판 목록
list = dao.getList(startRow, endRow);
}
System.out.println("list : " + list);
/* System.out.println(list.get(1).getNum()); */
if(count == 0) {
%>
작성된 글이 없습니다.
<% } else { %>
<a href="writeForm.jsp">글작성</a> 글갯수 : <%=count %>
<table border=1 width=700 align=center>
<caption>게시판 목록</caption>
<tr>
<td>번호</td>
<td>제목</td>
<td>작성자</td>
<td>작성일</td>
<td>조회수</td>
<td>IP주소</td>
</tr>
<%
SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// number : 각 페이지에 출력될 시작 번호
int number = count - (currentPage - 1) * page_size;
// page=1 : number = 130 - ( 1 - 1) * 10 ; -> 130
// page=2 : number = 130 - ( 2 - 1) * 10 ; -> 120
for(int i = 0 ; i < list.size() ; i++) {
BoardDataBean board = list.get(i);
%>
<tr>
<td><%=number-- %></td>
<td><%=board.getSubject() %></td>
<td><%=board.getWriter() %></td>
<td><%=sd.format(board.getReg_date()) %></td>
<td><%=board.getReadcount() %></td>
<td><%=board.getIp() %></td>
</tr>
<%
} // for end
%>
</table>
<% }%>
<!-- 페이지 링크 설정 -->
<center>
<%
if(count > 0) {
// pageCount : 총 페이지 수
int pageCount = count/page_size + ((count%page_size==0) ? 0 : 1);
System.out.println("pageCount : " + pageCount);
// startPage : 각 블럭의 시작 페이지 번호 : 1, 11, 21 ...
// endPage : 각 블럭의 끝 페이지 번호 : 10, 20, 30 ...
int startPage = ((currentPage-1)/10) * 10 + 1;
int block = 10; // 1개의 블럭의 크기 : 10개의 페이지로 구성
int endPage = startPage + block - 1;
// 가장 마지막 블럭에 endPage값을 pageCount로 수정
if(endPage > pageCount) { //
endPage = pageCount;
}
%>
<!-- 1page로 이동 -->
<a href="list.jsp?page=1" style="text-decoration:none"> << </a>
<%
// 이전 블럭으로 이동
if(startPage > 10){ %>
<a href="list.jsp?page=<%=startPage-10 %>">[이전]</a>
<% }
// 각 블럭당 10개의 페이지 출력
for(int i = startPage; i <= endPage; i++) {
if(i == currentPage) { %>
[<%=i %>]
<% } else {%>
<a href="list.jsp?page=<%=i %>">[<%=i %>]</a>
<% }
}// for end
// 다음 블럭으로 이동
if(endPage < pageCount) {
%>
<a href="list.jsp?page=<%=startPage+10 %>">[다음]</a>
<% } %>
<!-- 마지막 페이지로 이동 -->
<a href="list.jsp?page=<%=pageCount %>" style="text-decoration:none"> >> </a>
<%}%>
</center>
</body>
</html>
페이징 처리 변수 정리
기본변수
1. page_size : 한 화면에 출력할 데이터 갯수
2. currentPage : 현재 페이지 번호가 저장되는 변수
3. count : 총 데이터 갯수
파생변수
1. startRow : 각 page에 출력할 데이터의 시작번호
2. endRow : 각 page에 출력할 데이터의 끝번호
ex) page = 1 : startRow=1, endRow=10
ex) page = 2 : startRow=11, endRow=20
ex) page = 3 : startRow=21, endRow=30
3. number : 각 페이지에 출력될 시작 번호
4. pageCount : 총 페이지 수
5. startPage : 각 블럭의 시작 페이지 번호 ex) 1, 11, 21 ...
6. endPage : 각 블럭의 끝 페이지 번호 ex) 10, 20, 30 ...
- 제목에 링크를 걸어서 그 글에 대한 상세 페이지 content.jsp 로 넘기자
목록에서 특정 글 제목 클릭시 상세 페이지로 넘어가기 (list.jsp 부분)
<td>
<a href="content.jsp?num=<%=board.getNum()%>&page=<%=currentPage%>">
<%=board.getSubject() %>
</a>
</td>
- get 방식으로 글 번호 와 현재 page 번호를 가져가야한다
- 글 번호는 어떤 글의 상세정보를 보여주기 위해 , DB 검색위해서 필요
- page 번호는 글을 본 후 다시 게시판 목록으로 돌아올때 어떤 페이지로 돌아올지 알수있다
ex) 5 페이지에서 어떤 글을 눌러서 글의 상세페이지로 간 다음 돌아올 때 5 페이지로 돌아오기
- list.jsp 에서 제목을 눌러서 상세 페이지 content.jsp 로 이동
- get 방식으로 내부 글번호와 페이지 번호를 content.jsp 로 전달한다
일반게시판 : 글 상세페이지
상세페이지에서 할 일
1. 조회수 증가
2. 전달받은 num 값으로 DB 연동해서 글의 상세정보 출력
- content.jsp
<%@page import="board.BoardDataBean"%>
<%@page import="board.BoardDBBean"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
int num = Integer.parseInt(request.getParameter("num"));
String nowpage = request.getParameter("page");
BoardDBBean dao = BoardDBBean.getInstance();
// 조회수 1 증가 + 상세정보 구하기
BoardDataBean board = dao.updateContent(num);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>상세 페이지</title>
</head>
<body>
<table border=1 width=500 align=center>
<caption>상세 페이지</caption>
<tr>
<td>번호</td>
<td><%=board.getNum() %></td>
<td>조회수</td>
<td><%=board.getReadcount() %></td>
</tr>
<tr>
<td>작성자</td>
<td><%=board.getWriter() %></td>
<td>작성일</td>
<td><%=board.getReg_date() %></td>
</tr>
<tr>
<td>제목</td>
<td colspan=3><%=board.getSubject() %></td>
</tr>
<tr>
<td>내용</td>
<td colspan=3><%=board.getContent() %></td>
</tr>
<tr>
<td colspan=4 align=center>
<input type="button" value="글수정">
<input type="button" value="글삭제">
<input type="button" value="글목록">
</td>
</tr>
</table>
</body>
</html>
1. 전달된 num값(글번호)과 페이지번호를 가져온다
- DAO 메소드의 SQL문에서 setInt()를 할때 int형 값이 들어가야하므로 전달된 num값을 int형으로 형변환 해야한다.
- 페이지 지시어 태그와 키워드가 일치하므로 변수명으로 page 를 쓰지 못함, nowpage 로 페이지번호를 받자
2. 조회수 1 증가 + 상세정보 구하기를 역할을 하는 DAO의 메소드 updateContent() 를 호출하여 DB와 연동하자
- 글 번호인 num 을 매개변수로 넘겨줘서 그 글에 대한 정보를 구할 수 있도록 하자
- 리턴자료형을 DTO 클래스로 해서 상세정보를 받자
+ 돌려받을 상세정보는 한개의 글에 대한 (한개의 데이터) 상세정보이므로 DTO 가 리턴자료형
- 이후 돌려받은 상세정보를 테이블에 뿌려주고 있다
- 이제 DAO 클래스에서 DB 와 연동하여 조회수 1 증가 + 상세정보 구하기를 해줄 updateContent() 메소드를 성하자
DAO 클래스 조회수 1 증가 & 상세정보 구하기 메소드 작성
- 메소드 updateContent() 에서 2개의 sql문을 실행해야한다
1. 조회수 1 증가 = update문
2. 상세정보 구하기 = select문
- BoardDBBean.java (추가)
// DAO (Data Access Object)
package board;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
public class BoardDBBean {
// 싱글톤 : 객체 생성을 한번만 수행하는 것
private static BoardDBBean instance = new BoardDBBean();
public static BoardDBBean getInstance() {
return instance;
}
// 커넥션풀에서 커넥션을 구해오는 메소드
private Connection getConnection() throws Exception {
Context init = new InitialContext();
DataSource ds = (DataSource) init.lookup("java:comp/env/jdbc/orcl");
return ds.getConnection();
}
// 글 작성
public int insert(BoardDataBean board) {
int result = 0;
Connection con = null;
PreparedStatement pstmt = null;
try {
con = getConnection();
String sql = "insert into board0 ";
sql += "values(board0_seq.nextval,?,?,?,?,sysdate,?,?,?)";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, board.getWriter());
pstmt.setString(2, board.getEmail());
pstmt.setString(3, board.getSubject());
pstmt.setString(4, board.getPasswd());
pstmt.setInt(5, board.getReadcount()); // 0
pstmt.setString(6, board.getContent());
pstmt.setString(7, board.getIp());
result = pstmt.executeUpdate(); // SQL문 실행
} catch (Exception e) {
e.printStackTrace();
} finally {
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return result;
}
// 총 데이터 갯수 구하기
public int getCount() {
int result = 0;
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = getConnection();
String sql = "select count(*) from board0";
pstmt = con.prepareStatement(sql);
rs = pstmt.executeQuery(); // SQL문 실행
if(rs.next()) {
// result = rs.getInt(1); // 아래와 같다
result = rs.getInt("count(*)");
}
} catch(Exception e) {
e.printStackTrace();
} finally {
if(rs != null) try { rs.close(); } catch(Exception e) {}
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return result;
}
// 게시판 목록 구하기 : 데이터 10개 추출
public List<BoardDataBean> getList(int start, int end) {
List<BoardDataBean> list = new ArrayList<BoardDataBean>();
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = getConnection();
String sql = "select * from (select rownum rnum, board.* from ";
sql += " (select * from board0 order by num desc) board ) ";
sql += " where rnum >= ? and rnum <= ?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, start);
pstmt.setInt(2, end);
rs = pstmt.executeQuery(); // SQL문 실행
while(rs.next()) {
BoardDataBean board = new BoardDataBean();
board.setNum(rs.getInt("num"));
board.setWriter(rs.getString("writer"));
board.setEmail(rs.getString("email"));
board.setSubject(rs.getString("subject"));
board.setPasswd(rs.getString("passwd"));
board.setReg_date(rs.getTimestamp("reg_date"));
board.setReadcount(rs.getInt("readcount"));
board.setContent(rs.getString("content"));
board.setIp(rs.getString("ip"));
list.add(board);
}
} catch (Exception e){
e.printStackTrace();
} finally {
if(rs != null) try { rs.close(); } catch(Exception e) {}
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return list;
}
// 상세 페이지 : 조회수 1 증가 + 상세정보 구하기
public BoardDataBean updateContent(int num) {
BoardDataBean board = new BoardDataBean();
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = getConnection();
String sql = "update board0 set readcount=readcount+1 ";
sql += "where num=?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, num);
pstmt.executeUpdate(); // 첫번째 SQL문 실행
sql = "select * from board0 where num=?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, num);
rs = pstmt.executeQuery(); // 두번째 SQL문 실행
if(rs.next()) { // 조건식을 만족하는 데이터 1개를 가져온다.
board.setNum(rs.getInt("num"));
board.setWriter(rs.getString("writer"));
board.setEmail(rs.getString("email"));
board.setSubject(rs.getString("subject"));
board.setPasswd(rs.getString("passwd"));
board.setReg_date(rs.getTimestamp("reg_date"));
board.setReadcount(rs.getInt("readcount"));
board.setContent(rs.getString("content"));
board.setIp(rs.getString("ip"));
}
} catch(Exception e) {
e.printStackTrace();
} finally {
if(rs != null) try { rs.close(); } catch(Exception e) {}
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return board;
}
}
- 검색결과가 1개의 데이터이므로 DTO 가 리턴자료형, DTO 객체를 돌려줘야한다
- DTO 객체를 가장 위에서 만들고 거기에 검색결과 상세정보 저장할 것
<조회수 1 증가>
- 첫번째 SQL문으로 조회수 값을 1 증가시키기 위한 update 문을 작성한다
<상세정보 구하기>
- 두번째 SQL문으로 상세정보를 구하기 위한 select 문을 작성한다
- 1개의 데이터이므로 if문과 rs.next 로 데이터를 가져온다
- rs 에서 가져온 값을 DTO 객체에 저장한다
+ 컬럼 자료형에 따라 getInt(), getString(), getTimestamp() 등 다른 메소드 사용
- 추가한 부분 코드만
- 완성
- list.jsp 를 먼저 실행해서 특정 글의 제목을 클릭해보자
- 글 수정 / 삭제시 글번호값과 페이지번호값을 3번을 가져갈 것인데, 출발점이 list.jsp 이다
- URL 에서 글번호 num 과 페이지번호 page 가 넘어왔음을 확인 가능
- '글목록' 을 눌렀을때 원래 페이지로 돌아가기 위해 페이지번호 page 가 필요
줄바꿈 문제점
- '내용' 인 textarea 에 여러줄을 입력해도 출력시엔 <td> 태그 안에 출력되니 한줄로 나타난다
줄바꿈 문제 해결 두가지 방법
1. <pre> 태그로 감싸주기
- <pre> 태그로 감싸주면 줄이 바뀐다
2. replace() 로 치환하기
- "\n" 을 "<br>" 로 치환하기
- content 를 출력시 제대로 줄바꿈이 된다
날짜 포맷 문제점 해결
- 원하느 날짜 시간 포맷으로 설정하기
- SimpleDateFormat 객체 생성
- 이제 세가지 버튼 클릭 이벤트를 처리하자
버튼 이벤트 처리
1. 글목록 버튼 이벤트 처리
- 페이지번호를 가져왔기 때문에 원래 페이지로 돌아갈 수 있다
- 페이지번호를 가져오지 않았더라면 1 페이지로만 돌아갈 수 있다
- Lay's diary 글에서 '글목록' 클릭시 13 페이지로 돌아오는 것을 볼 수 있다
+ 조회수가 1 증가했음도 확인 가능
+ 한번 더 Lay's diary 클릭시 조회수가 다시 1 증가
+ 전체 흐름
2. 글수정 버튼 이벤트 처리
- 글수정 을 눌러서 수정 폼으로 넘어갈때, 글삭제 를 눌러서 삭제 폼으로 넘어갈때도 계속 글번호와 페이지번호를 전달
- 먼저 content.jsp 에서 이벤트 처리 해주기
일반게시판 : 글 수정
- 수정폼 updateForm.jsp 생성 후 작성
<%@page import="board.BoardDataBean"%>
<%@page import="board.BoardDBBean"%>
<%@ page contentType="text/html; charset=utf-8" %>
<%@ include file="color.jsp"%>
<%
int num = Integer.parseInt(request.getParameter("num"));
String nowpage = request.getParameter("page");
BoardDBBean dao = BoardDBBean.getInstance();
// 상세 정보 구하기
BoardDataBean board = dao.getContent(num);
%>
<html>
<head>
<title>글수정</title>
<link href="style.css" rel="stylesheet" type="text/css">
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script src="check.js"></script>
</head>
ㄴ
<body bgcolor="<%=bodyback_c%>">
<center><b>글수정</b>
<br>
<form method="post" name="writeform" action="writePro.jsp">
<table width="430" border="1" cellspacing="0" cellpadding="0" bgcolor="<%=bodyback_c%>" align="center">
<tr>
<td align="right" colspan="2" bgcolor="<%=value_c%>">
<a href="list.jsp"> 글목록</a>
</td>
</tr>
<tr>
<td width="100" bgcolor="<%=value_c%>" align="center">이 름</td>
<td width="330">
<input type="text" size="10" maxlength="10" id="writer" name="writer"></td>
</tr>
<tr>
<td width="100" bgcolor="<%=value_c%>" align="center" >제 목</td>
<td width="330">
<input type="text" size="40" maxlength="50" id="subject" name="subject"></td>
</tr>
<tr>
<td width="100" bgcolor="<%=value_c%>" align="center">Email</td>
<td width="330">
<input type="text" size="40" maxlength="30" id="email" name="email" ></td>
</tr>
<tr>
<td width="100" bgcolor="<%=value_c%>" align="center" >내 용</td>
<td width="330" >
<textarea id="content" name="content" rows="13" cols="40"></textarea> </td>
</tr>
<tr>
<td width="100" bgcolor="<%=value_c%>" align="center" >비밀번호</td>
<td width="330" >
<input type="password" size="8" maxlength="12" id="passwd" name="passwd">
</td>
</tr>
<tr>
<td colspan=2 bgcolor="<%=value_c%>" align="center">
<input type="submit" value="글쓰기" >
<input type="reset" value="다시작성">
<input type="button" value="목록보기" OnClick="window.location='list.jsp'">
</td></tr></table>
</form>
</body>
</html>
- wirteForm.jsp 파일 내용을 전부 복붙후 수정
1. 가장 먼저 윗부분에서 content.jsp 에서 넘어온 글번호값과 페이지번호값을 받음
- 나중에 setInt() 메소드를 사용해야하므로 글번호값을 미리 int 형으로 형변환함
2. 상세정보를 구해오기 위한 DAO의 getContent() 메호드 호출
- 상세정보를 구할때 글번호가 필요하므로 num 을 매개변수로 넘긴다
- 상세정보를 담아올 DTO 객체가 필요하므로 리턴자료형을 DTO 로 한다
- 앞의 updateContent() 는 조회수 증가 + 상세정보 구하기 둘다 하는 메소드였다
- 이번에는 getContent() 메소드로 상세정보만 구해오는 메소드를 호출
3. 이후 받아온 값을 가공하는 부분은 DAO 클래스에 메소드를 작성한 후 다시 돌아와서 작성
- 아래에 이어서 작성
- DAO 클래스에 getContent() 메소드를 작성하자
DAO 클래스 상세정보 구하기 메소드 작성
- BoardDBBean.java (추가)
// DAO (Data Access Object)
package board;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
public class BoardDBBean {
// 싱글톤 : 객체 생성을 한번만 수행하는 것
private static BoardDBBean instance = new BoardDBBean();
public static BoardDBBean getInstance() {
return instance;
}
// 커넥션풀에서 커넥션을 구해오는 메소드
private Connection getConnection() throws Exception {
Context init = new InitialContext();
DataSource ds = (DataSource) init.lookup("java:comp/env/jdbc/orcl");
return ds.getConnection();
}
// 글 작성
public int insert(BoardDataBean board) {
int result = 0;
Connection con = null;
PreparedStatement pstmt = null;
try {
con = getConnection();
String sql = "insert into board0 ";
sql += "values(board0_seq.nextval,?,?,?,?,sysdate,?,?,?)";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, board.getWriter());
pstmt.setString(2, board.getEmail());
pstmt.setString(3, board.getSubject());
pstmt.setString(4, board.getPasswd());
pstmt.setInt(5, board.getReadcount()); // 0
pstmt.setString(6, board.getContent());
pstmt.setString(7, board.getIp());
result = pstmt.executeUpdate(); // SQL문 실행
} catch (Exception e) {
e.printStackTrace();
} finally {
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return result;
}
// 총 데이터 갯수 구하기
public int getCount() {
int result = 0;
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = getConnection();
String sql = "select count(*) from board0";
pstmt = con.prepareStatement(sql);
rs = pstmt.executeQuery(); // SQL문 실행
if(rs.next()) {
// result = rs.getInt(1); // 아래와 같다
result = rs.getInt("count(*)");
}
} catch(Exception e) {
e.printStackTrace();
} finally {
if(rs != null) try { rs.close(); } catch(Exception e) {}
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return result;
}
// 게시판 목록 구하기 : 데이터 10개 추출
public List<BoardDataBean> getList(int start, int end) {
List<BoardDataBean> list = new ArrayList<BoardDataBean>();
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = getConnection();
String sql = "select * from (select rownum rnum, board.* from ";
sql += " (select * from board0 order by num desc) board ) ";
sql += " where rnum >= ? and rnum <= ?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, start);
pstmt.setInt(2, end);
rs = pstmt.executeQuery(); // SQL문 실행
while(rs.next()) {
BoardDataBean board = new BoardDataBean();
board.setNum(rs.getInt("num"));
board.setWriter(rs.getString("writer"));
board.setEmail(rs.getString("email"));
board.setSubject(rs.getString("subject"));
board.setPasswd(rs.getString("passwd"));
board.setReg_date(rs.getTimestamp("reg_date"));
board.setReadcount(rs.getInt("readcount"));
board.setContent(rs.getString("content"));
board.setIp(rs.getString("ip"));
list.add(board);
}
} catch (Exception e){
e.printStackTrace();
} finally {
if(rs != null) try { rs.close(); } catch(Exception e) {}
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return list;
}
// 상세 페이지 : 조회수 1 증가 + 상세정보 구하기
public BoardDataBean updateContent(int num) {
BoardDataBean board = new BoardDataBean();
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = getConnection();
String sql = "update board0 set readcount=readcount+1 ";
sql += "where num=?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, num);
pstmt.executeUpdate(); // 첫번째 SQL문 실행
sql = "select * from board0 where num=?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, num);
rs = pstmt.executeQuery(); // 두번째 SQL문 실행
if(rs.next()) { // 조건식을 만족하는 데이터 1개를 가져온다.
board.setNum(rs.getInt("num"));
board.setWriter(rs.getString("writer"));
board.setEmail(rs.getString("email"));
board.setSubject(rs.getString("subject"));
board.setPasswd(rs.getString("passwd"));
board.setReg_date(rs.getTimestamp("reg_date"));
board.setReadcount(rs.getInt("readcount"));
board.setContent(rs.getString("content"));
board.setIp(rs.getString("ip"));
}
} catch(Exception e) {
e.printStackTrace();
} finally {
if(rs != null) try { rs.close(); } catch(Exception e) {}
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return board;
}
// 수정 폼 : 상세 정보 구하기
public BoardDataBean getContent(int num) {
BoardDataBean board = new BoardDataBean();
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = getConnection();
String sql = "select * from board0 where num=?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, num);
rs = pstmt.executeQuery(); // 두번째 SQL문 실행
if(rs.next()) { // 조건식을 만족하는 데이터 1개를 가져온다.
board.setNum(rs.getInt("num"));
board.setWriter(rs.getString("writer"));
board.setEmail(rs.getString("email"));
board.setSubject(rs.getString("subject"));
board.setPasswd(rs.getString("passwd"));
board.setReg_date(rs.getTimestamp("reg_date"));
board.setReadcount(rs.getInt("readcount"));
board.setContent(rs.getString("content"));
board.setIp(rs.getString("ip"));
}
} catch(Exception e) {
e.printStackTrace();
} finally {
if(rs != null) try { rs.close(); } catch(Exception e) {}
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return board;
}
}
- updateContent() 메소드에서 조회수 증가 부분만 제외하면 똑같다
- 추가한 부분 코드만
- 다시 updateForm.jsp 로 돌아와서 돌려받은 값을 화면에 뿌려주자
- updateForm.jsp
<%@page import="board.BoardDataBean"%>
<%@page import="board.BoardDBBean"%>
<%@ page contentType="text/html; charset=utf-8" %>
<%@ include file="color.jsp"%>
<%
int num = Integer.parseInt(request.getParameter("num"));
String nowpage = request.getParameter("page");
BoardDBBean dao = BoardDBBean.getInstance();
// 상세 정보 구하기
BoardDataBean board = dao.getContent(num);
%>
<html>
<head>
<title>글수정</title>
<link href="style.css" rel="stylesheet" type="text/css">
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script src="check.js"></script>
</head>
ㄴ
<body bgcolor="<%=bodyback_c%>">
<center><b>글수정</b>
<br>
<form method="post" name="writeform" action="updatePro.jsp">
<input type="hidden" name="num" value="<%=num %>">
<input type="hidden" name="page" value="<%=nowpage %>">
<table width="430" border="1" cellspacing="0" cellpadding="0" bgcolor="<%=bodyback_c%>" align="center">
<tr>
<td align="right" colspan="2" bgcolor="<%=value_c%>">
<a href="list.jsp?page<%=nowpage%>"> 글목록</a>
</td>
</tr>
<tr>
<td width="100" bgcolor="<%=value_c%>" align="center">이 름</td>
<td width="330">
<input type="text" size="10" maxlength="10" id="writer"
name="writer" value="<%=board.getWriter() %>"></td>
</tr>
<tr>
<td width="100" bgcolor="<%=value_c%>" align="center" >제 목</td>
<td width="330">
<input type="text" size="40" maxlength="50" id="subject"
name="subject" value="<%=board.getSubject() %>"></td>
</tr>
<tr>
<td width="100" bgcolor="<%=value_c%>" align="center">Email</td>
<td width="330">
<input type="text" size="40" maxlength="30" id="email"
name="email" value="<%=board.getEmail() %>"></td>
</tr>
<tr>
<td width="100" bgcolor="<%=value_c%>" align="center" >내 용</td>
<td width="330" >
<textarea id="content" name="content" rows="13" cols="40"><%=board.getContent() %></textarea> </td>
</tr>
<tr>
<td width="100" bgcolor="<%=value_c%>" align="center" >비밀번호</td>
<td width="330" >
<input type="password" size="8" maxlength="12" id="passwd" name="passwd">
</td>
</tr>
<tr>
<td colspan=2 bgcolor="<%=value_c%>" align="center">
<input type="submit" value="글수정" >
<input type="reset" value="다시작성">
<input type="button" value="목록보기"
OnClick="window.location='list.jsp?page=<%=nowpage%>'">
</td></tr></table>
</form>
</body>
</html>
- writeForm.jsp에서 어느 부분을 수정했는지 아래에 설명
- action 값을 updatePro.jsp 로 수정, 타이틀 수정 해주기
- 글목록 클릭시 원래의 페이지로 돌아가도록 하기
- 이름, 제목, 이메일에 value 속성을 추가해서 수정폼에서 그 부분이 나타나도록하기
+ 비밀번호는 사용자가 수정폼에 직접 입력해야하므로 value 속성 추가하지 않기
- 목록보기에서 원래 페이지로 돌아가게끔 get 방식으로 페이지번호 넘기기
글번호와 페이지번호 넘기기 (updateForm.jsp 부분)
- 글수정을 하기위해 updatePro.jsp 로 넘어갈때, 글번호 값인 num 을 hidden 으로 updatePro.jsp 로 넘겨줘야함
- 수정 완료 후 돌아올때 원래 페이지로 돌아가기 위해 nowpage 를 hidden 으로 updatePro.jsp 로 넘겨줘야함
- 글번호, 페이지번호는 화면에 보이지 않지만 넘어가야하므로 hidden 으로 post 방식으로 넘겨주기
- 글번호, 페이지번호가 3번째 전달되고 있다, 시작은 list.jsp 에서 시작
- DB 에서 비번 끄집어낼때, DB 에서 update 실행할때 글번호인 num 이 필요
- 수정 완료 후 다시 목록페이지로 돌아가야하는데, 이때 원래 페이지로 돌아가기 위해 페이지번호인 page 가 필요
- 이제 수정폼 기능이 끝났고 진짜 수정(update) 기능을 구현하자
- 수정폼에서 입력한 비밀번호가 일치해야 수정이 되도록 할것인데, 비밀번호가 일치하는지 확인하는 곳
- updatePro.jsp 파일을 생성 후 작성
<%@page import="board.BoardDataBean"%>
<%@page import="board.BoardDBBean"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
request.setCharacterEncoding("utf-8");
%>
<jsp:useBean id="board" class="board.BoardDataBean"/>
<jsp:setProperty property="*" name="board"/>
<%
String nowpage = request.getParameter("page");
BoardDBBean dao = BoardDBBean.getInstance();
BoardDataBean old = dao.getContent(board.getNum());
// 비번 비교
if(old.getPasswd().equals(board.getPasswd())) { // 비번 일치시
int result = dao.update(board); // update SQL문 실행
if(result == 1) {
%>
<script>
alert("글 수정 성공");
location.href="list.jsp?page=<%=nowpage%>";
</script>
<% }
} else { // 비번 불일치시 %>
<script>
alert("비번이 일치하지 않습니다.");
history.go(-1);
</script>
<% } %>
1. 한글값이 post 값으로 전달되므로 한글 인코딩
2. useBean action tag, setProperty action tag 로 수정할 내용, 즉 수정폼에서 사용자가 입력한 값을 DTO 객체 board 를 생성해서 저장
3. 페이지번호인 page 는 DTO 클래스의 프로퍼티가 아니기때문에 setProperty 로 DTO에 저장 불가능하므로 따로 다른 변수에 받아야함
4. DB 에서 비밀번호를 가져와서 사용자가 수정폼에 입력한 비밀번호와 맞는지 확인해야하므로 DAO 객체 먼저 생성
5. DTO 객체 board 에서 getNum() 으로 글번호값을 구해와서, DAO 클래스의 getContent() 의 매개변수를 넣어서 구해진 그 글의 상세정보를 새로운 DTO 객체 old 에 저장
- 수정폼에서 사용했던 이미 만들어진 메소드인 getContent()
6. DB 에서 구해진 상세정보를 저장하는 old 객체의 비밀번호 old.getPasswd() 와, 사용자가 수정폼에 입력한 정보를 저장하는 board 객체의 비밀번호 board.getPasswd() 가 같은지 비교
7. 비번이 일치하는 경우 DAO 클래스의 update() 메소드를 호출해서 수정
- 매개변수는 사용자가 수정폼에 입력한 값들을 저장하는 DTO 객체 board 를 넘겨주고 있다
- 업데이트에 성공한 데이터의 개수를 리턴받고 있다
- 비번 일치 후 수정까지 성공시 목록페이지의 원래 페이지로 돌아간다
8. 비번이 일치하지 않는 경우는 이전 페이지인 수정폼 페이지로 돌아간다
- DAO 클래스에서 update() 메소드 작성하자
DAO 클래스 수정 메소드 작성
- update() 메소드를 작성하자
- BoardDBBean.java (추가)
// DAO (Data Access Object)
package board;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
public class BoardDBBean {
// 싱글톤 : 객체 생성을 한번만 수행하는 것
private static BoardDBBean instance = new BoardDBBean();
public static BoardDBBean getInstance() {
return instance;
}
// 커넥션풀에서 커넥션을 구해오는 메소드
private Connection getConnection() throws Exception {
Context init = new InitialContext();
DataSource ds = (DataSource) init.lookup("java:comp/env/jdbc/orcl");
return ds.getConnection();
}
// 글 작성
public int insert(BoardDataBean board) {
int result = 0;
Connection con = null;
PreparedStatement pstmt = null;
try {
con = getConnection();
String sql = "insert into board0 ";
sql += "values(board0_seq.nextval,?,?,?,?,sysdate,?,?,?)";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, board.getWriter());
pstmt.setString(2, board.getEmail());
pstmt.setString(3, board.getSubject());
pstmt.setString(4, board.getPasswd());
pstmt.setInt(5, board.getReadcount()); // 0
pstmt.setString(6, board.getContent());
pstmt.setString(7, board.getIp());
result = pstmt.executeUpdate(); // SQL문 실행
} catch (Exception e) {
e.printStackTrace();
} finally {
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return result;
}
// 총 데이터 갯수 구하기
public int getCount() {
int result = 0;
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = getConnection();
String sql = "select count(*) from board0";
pstmt = con.prepareStatement(sql);
rs = pstmt.executeQuery(); // SQL문 실행
if(rs.next()) {
// result = rs.getInt(1); // 아래와 같다
result = rs.getInt("count(*)");
}
} catch(Exception e) {
e.printStackTrace();
} finally {
if(rs != null) try { rs.close(); } catch(Exception e) {}
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return result;
}
// 게시판 목록 구하기 : 데이터 10개 추출
public List<BoardDataBean> getList(int start, int end) {
List<BoardDataBean> list = new ArrayList<BoardDataBean>();
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = getConnection();
String sql = "select * from (select rownum rnum, board.* from ";
sql += " (select * from board0 order by num desc) board ) ";
sql += " where rnum >= ? and rnum <= ?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, start);
pstmt.setInt(2, end);
rs = pstmt.executeQuery(); // SQL문 실행
while(rs.next()) {
BoardDataBean board = new BoardDataBean();
board.setNum(rs.getInt("num"));
board.setWriter(rs.getString("writer"));
board.setEmail(rs.getString("email"));
board.setSubject(rs.getString("subject"));
board.setPasswd(rs.getString("passwd"));
board.setReg_date(rs.getTimestamp("reg_date"));
board.setReadcount(rs.getInt("readcount"));
board.setContent(rs.getString("content"));
board.setIp(rs.getString("ip"));
list.add(board);
}
} catch (Exception e){
e.printStackTrace();
} finally {
if(rs != null) try { rs.close(); } catch(Exception e) {}
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return list;
}
// 상세 페이지 : 조회수 1 증가 + 상세정보 구하기
public BoardDataBean updateContent(int num) {
BoardDataBean board = new BoardDataBean();
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = getConnection();
String sql = "update board0 set readcount=readcount+1 ";
sql += "where num=?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, num);
pstmt.executeUpdate(); // 첫번째 SQL문 실행
sql = "select * from board0 where num=?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, num);
rs = pstmt.executeQuery(); // 두번째 SQL문 실행
if(rs.next()) { // 조건식을 만족하는 데이터 1개를 가져온다.
board.setNum(rs.getInt("num"));
board.setWriter(rs.getString("writer"));
board.setEmail(rs.getString("email"));
board.setSubject(rs.getString("subject"));
board.setPasswd(rs.getString("passwd"));
board.setReg_date(rs.getTimestamp("reg_date"));
board.setReadcount(rs.getInt("readcount"));
board.setContent(rs.getString("content"));
board.setIp(rs.getString("ip"));
}
} catch(Exception e) {
e.printStackTrace();
} finally {
if(rs != null) try { rs.close(); } catch(Exception e) {}
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return board;
}
// 수정 폼 : 상세 정보 구하기
public BoardDataBean getContent(int num) {
BoardDataBean board = new BoardDataBean();
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = getConnection();
String sql = "select * from board0 where num=?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, num);
rs = pstmt.executeQuery(); // 두번째 SQL문 실행
if(rs.next()) { // 조건식을 만족하는 데이터 1개를 가져온다.
board.setNum(rs.getInt("num"));
board.setWriter(rs.getString("writer"));
board.setEmail(rs.getString("email"));
board.setSubject(rs.getString("subject"));
board.setPasswd(rs.getString("passwd"));
board.setReg_date(rs.getTimestamp("reg_date"));
board.setReadcount(rs.getInt("readcount"));
board.setContent(rs.getString("content"));
board.setIp(rs.getString("ip"));
}
} catch(Exception e) {
e.printStackTrace();
} finally {
if(rs != null) try { rs.close(); } catch(Exception e) {}
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return board;
}
// 글수정
public int update(BoardDataBean board) {
int result = 0;
Connection con = null;
PreparedStatement pstmt = null;
try {
con = getConnection();
String sql = "update board0 set writer=?,email=?,subject=?,";
sql += "content=? where num=?";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, board.getWriter());
pstmt.setString(2, board.getEmail());
pstmt.setString(3, board.getSubject());
pstmt.setString(4, board.getContent());
pstmt.setInt(5, board.getNum());
result = pstmt.executeUpdate(); // SQL문 실행
} catch(Exception e) {
e.printStackTrace();
} finally {
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return result;
}
}
- 매개변수로 넘어온 DTO 객체 중 hidden 으로 넘어왔던 글번호 board.getNum() 을 where 조건절에 넣기
- 특정 데이터를 수정
- 추가한 부분 코드만
- list.jsp 를 먼저 실행하고 수정하고자 하는 글의 제목을 클릭했을때
- 수정폼에서 맞는 비번을 입력할 때
- 목록페이지의 원래 페이지로 돌아왔다
- 수정폼에서 틀린 비번을 입력할 때
+ 수정 성공시 목록페이지가 아닌 상세페이지로 가게끔 처리도 가능
- 상세페이지 content.jsp 로 이동하기 위해 updatePro.jsp 부분을 수정
- content.jsp 에서는 2개의 값을 받고 있기때문에 상세페이지로 가려면 글번호와 페이지번호 get 방식 전달
일반게시판 : 글 삭제
3. 글삭제 버튼 이벤트 처리
- 글수정 을 눌러서 수정 폼으로 넘어갈때, 글삭제 를 눌러서 삭제 폼으로 넘어갈때도 계속 글번호와 페이지번호를 전달
- 먼저 content.jsp 에서 이벤트 처리 해주기
- 삭제 폼인 deleteForm.jsp 파일 생성 후 작성
<%@page import="board.BoardDataBean"%>
<%@page import="board.BoardDBBean"%>
<%@ page contentType="text/html; charset=utf-8" %>
<%@ include file="color.jsp"%>
<%
int num = Integer.parseInt(request.getParameter("num"));
String nowpage = request.getParameter("page");
%>
<html>
<head>
<title>글삭제</title>
<link href="style.css" rel="stylesheet" type="text/css">
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script src="check.js"></script>
</head>
<body bgcolor="<%=bodyback_c%>">
<center><b>글삭제</b>
<br>
<form method="post" name="writeform" action="deletePro.jsp">
<input type="hidden" name="num" value="<%=num %>">
<input type="hidden" name="page" value="<%=nowpage %>">
<table width="430" border="1" cellspacing="0" cellpadding="0" bgcolor="<%=bodyback_c%>" align="center">
<tr>
<td align="right" colspan="2" bgcolor="<%=value_c%>">
<a href="list.jsp?page<%=nowpage%>"> 글목록</a>
</td>
</tr>
<tr>
<td width="100" bgcolor="<%=value_c%>" align="center" >비밀번호</td>
<td width="330" >
<input type="password" size="8" maxlength="12" id="passwd" name="passwd">
</td>
</tr>
<tr>
<td colspan=2 bgcolor="<%=value_c%>" align="center">
<input type="submit" value="글삭제" >
<input type="reset" value="다시작성">
<input type="button" value="목록보기"
OnClick="window.location='list.jsp?page=<%=nowpage%>'">
</td></tr></table>
</form>
</body>
</html>
- updateForm.jsp 의 내용을 복사 후 많은 부분 삭제, 수정
- hidden 으로 글번호, 페이지번호 넘기는 부분은 그대로 남기기
- 삭제폼에서는 비밀번호 입력란만 있으면 되므로 다른 입력양식은 지우기
- '글수정' -> '글삭제' 로 변경, action 을 deletePro.jsp 로 수정
- 여기서는 수정폼처럼 상세정보를 구해서 뿌려줄 필요가 없으므로 DB 연결 부분 삭제
+ 비밀번호 비교는 deletePro.jsp
- deletePro.jsp 에서 DB 와 연동해서 비밀번호 비교를 하기 위해 글번호인 num 을 전달해야함
- deletePro.jsp 에서 삭제 후 원래 페이지로 돌아가기 위해 페이지번호 page 를 전달해야함
삭제 폼에서 넘어가는 3가지 값
1. 글번호 num
2. 페이지번호 page
3. 사용자가 삭제폼에서 입력한 비밀번호 passwd
- 삭제폼에서 넘어온 비밀번호가 맞는지 DB 비밀번호와 비교후 진짜 삭제(delete) 를 해주는 deletePro.jsp 생성 후 작성
- deletePro.jsp
<%@page import="board.BoardDataBean"%>
<%@page import="board.BoardDBBean"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
request.setCharacterEncoding("utf-8");
%>
<jsp:useBean id="board" class="board.BoardDataBean"/>
<jsp:setProperty property="*" name="board"/>
<%
String nowpage = request.getParameter("page");
BoardDBBean dao = BoardDBBean.getInstance();
BoardDataBean old = dao.getContent(board.getNum());
// 비번 비교
if(old.getPasswd().equals(board.getPasswd())) { // 비번 일치시
int result = dao.delete(board.getNum()); // update SQL문 실행
if(result == 1) {
%>
<script>
alert("글 삭제 성공");
location.href="list.jsp?page=<%=nowpage%>";
</script>
<% }
} else { // 비번 불일치시 %>
<script>
alert("비번이 일치하지 않습니다.");
history.go(-1);
</script>
<% } %>
- updatePro.jsp 를 복붙 후 수정
- update() 를 delete() 로 수정 후 매개변수로는 글번호만 있으면 되므로 board 에서 board.getNum() 으로 변경
- 비번 일치 후 글 삭제 성공시 목록페이지인 list.jsp 의 원래 페이지로 돌아간다
- 이제 DAO 클래스에서 delete() 메소드를 작성하자
DAO 클래스 삭제 메소드 작성
- delete() 메소드 작성
- BoardDBBean.java (추가)
// DAO (Data Access Object)
package board;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
public class BoardDBBean {
// 싱글톤 : 객체 생성을 한번만 수행하는 것
private static BoardDBBean instance = new BoardDBBean();
public static BoardDBBean getInstance() {
return instance;
}
// 커넥션풀에서 커넥션을 구해오는 메소드
private Connection getConnection() throws Exception {
Context init = new InitialContext();
DataSource ds = (DataSource) init.lookup("java:comp/env/jdbc/orcl");
return ds.getConnection();
}
// 글 작성
public int insert(BoardDataBean board) {
int result = 0;
Connection con = null;
PreparedStatement pstmt = null;
try {
con = getConnection();
String sql = "insert into board0 ";
sql += "values(board0_seq.nextval,?,?,?,?,sysdate,?,?,?)";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, board.getWriter());
pstmt.setString(2, board.getEmail());
pstmt.setString(3, board.getSubject());
pstmt.setString(4, board.getPasswd());
pstmt.setInt(5, board.getReadcount()); // 0
pstmt.setString(6, board.getContent());
pstmt.setString(7, board.getIp());
result = pstmt.executeUpdate(); // SQL문 실행
} catch (Exception e) {
e.printStackTrace();
} finally {
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return result;
}
// 총 데이터 갯수 구하기
public int getCount() {
int result = 0;
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = getConnection();
String sql = "select count(*) from board0";
pstmt = con.prepareStatement(sql);
rs = pstmt.executeQuery(); // SQL문 실행
if(rs.next()) {
// result = rs.getInt(1); // 아래와 같다
result = rs.getInt("count(*)");
}
} catch(Exception e) {
e.printStackTrace();
} finally {
if(rs != null) try { rs.close(); } catch(Exception e) {}
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return result;
}
// 게시판 목록 구하기 : 데이터 10개 추출
public List<BoardDataBean> getList(int start, int end) {
List<BoardDataBean> list = new ArrayList<BoardDataBean>();
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = getConnection();
String sql = "select * from (select rownum rnum, board.* from ";
sql += " (select * from board0 order by num desc) board ) ";
sql += " where rnum >= ? and rnum <= ?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, start);
pstmt.setInt(2, end);
rs = pstmt.executeQuery(); // SQL문 실행
while(rs.next()) {
BoardDataBean board = new BoardDataBean();
board.setNum(rs.getInt("num"));
board.setWriter(rs.getString("writer"));
board.setEmail(rs.getString("email"));
board.setSubject(rs.getString("subject"));
board.setPasswd(rs.getString("passwd"));
board.setReg_date(rs.getTimestamp("reg_date"));
board.setReadcount(rs.getInt("readcount"));
board.setContent(rs.getString("content"));
board.setIp(rs.getString("ip"));
list.add(board);
}
} catch (Exception e){
e.printStackTrace();
} finally {
if(rs != null) try { rs.close(); } catch(Exception e) {}
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return list;
}
// 상세 페이지 : 조회수 1 증가 + 상세정보 구하기
public BoardDataBean updateContent(int num) {
BoardDataBean board = new BoardDataBean();
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = getConnection();
String sql = "update board0 set readcount=readcount+1 ";
sql += "where num=?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, num);
pstmt.executeUpdate(); // 첫번째 SQL문 실행
sql = "select * from board0 where num=?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, num);
rs = pstmt.executeQuery(); // 두번째 SQL문 실행
if(rs.next()) { // 조건식을 만족하는 데이터 1개를 가져온다.
board.setNum(rs.getInt("num"));
board.setWriter(rs.getString("writer"));
board.setEmail(rs.getString("email"));
board.setSubject(rs.getString("subject"));
board.setPasswd(rs.getString("passwd"));
board.setReg_date(rs.getTimestamp("reg_date"));
board.setReadcount(rs.getInt("readcount"));
board.setContent(rs.getString("content"));
board.setIp(rs.getString("ip"));
}
} catch(Exception e) {
e.printStackTrace();
} finally {
if(rs != null) try { rs.close(); } catch(Exception e) {}
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return board;
}
// 수정 폼 : 상세 정보 구하기
public BoardDataBean getContent(int num) {
BoardDataBean board = new BoardDataBean();
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = getConnection();
String sql = "select * from board0 where num=?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, num);
rs = pstmt.executeQuery(); // 두번째 SQL문 실행
if(rs.next()) { // 조건식을 만족하는 데이터 1개를 가져온다.
board.setNum(rs.getInt("num"));
board.setWriter(rs.getString("writer"));
board.setEmail(rs.getString("email"));
board.setSubject(rs.getString("subject"));
board.setPasswd(rs.getString("passwd"));
board.setReg_date(rs.getTimestamp("reg_date"));
board.setReadcount(rs.getInt("readcount"));
board.setContent(rs.getString("content"));
board.setIp(rs.getString("ip"));
}
} catch(Exception e) {
e.printStackTrace();
} finally {
if(rs != null) try { rs.close(); } catch(Exception e) {}
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return board;
}
// 글수정
public int update(BoardDataBean board) {
int result = 0;
Connection con = null;
PreparedStatement pstmt = null;
try {
con = getConnection();
String sql = "update board0 set writer=?,email=?,subject=?,";
sql += "content=? where num=?";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, board.getWriter());
pstmt.setString(2, board.getEmail());
pstmt.setString(3, board.getSubject());
pstmt.setString(4, board.getContent());
pstmt.setInt(5, board.getNum());
result = pstmt.executeUpdate(); // SQL문 실행
} catch(Exception e) {
e.printStackTrace();
} finally {
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return result;
}
// 글 삭제
public int delete(int num) {
int result = 0;
Connection con = null;
PreparedStatement pstmt = null;
try {
con = getConnection();
String sql = "delete from board0 where num=?";
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, num);
result = pstmt.executeUpdate(); // SQL문 실행
} catch(Exception e) {
e.printStackTrace();
} finally {
if(pstmt != null) try { pstmt.close(); } catch(Exception e) {}
if(con != null) try { con.close(); } catch(Exception e) {}
}
return result;
}
}
- 글번호만 매개변수로 넘어오므로 매개변수의 자료형은 int
- 삭제에 성공한 데이터 개수를 돌려줄 것이므로 리턴 자료형은 int
- update() 메소드의 내용을 복붙 후 수정
- SQL문 부분을 delete문으로 수정하면 된다
- 추가된 부분 코드만
- list.jsp 로 먼저 가서 126 번 글 클릭
- 126번 글을 삭제해보자
index.jsp
- index.jsp 는 가장 먼저 자동으로 실행되는 파일이므로 여기에서 list.jsp 로 이동하는 코드를 쓰자
- 바로 목록페이지로 이동하게끔 하자
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<script>
location.href="board/list.jsp";
</script>
</body>
</html>
- index.jsp 파일을 기준으로 list.jsp 파일은 board 폴더 안에 있으므로 board/list.jsp 를경로로 적음
- index.jsp 실행시 list.jsp 로 바로 이동함