System.out.print() vs out.print()
- System.out.print() 는 JAVA 코드이고 콘솔창에 출력됨
- out.println() 은 JSP 코드이고 브라우저에 출력됨
id값 넘기기
- 수정폼에서 id 는 input=text 가 아니기때문에 넘어가지 않으므로 hidden 객체로 넘겨야한다
- hidden 으로 값을 넘기므로, update.jsp 에서 세션으로부터 id 를 구해오지 않아도 됨
회원관리 프로그램 : 정보수정 기능 (이어서)
- 이전에는 수정폼을 했다
- 이젠 수정폼에서 '회원수정' 버튼을 눌렀을때의 진짜 수정(update) 기능 을 구현할 것
- 넘어온 id 값으로 비밀번호를 끄집어내서 일치할때 수정을 해야한다
- update.jsp
<%@page import="member.MemberDAO"%>
<%@page import="member.MemberDTO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
request.setCharacterEncoding("utf-8");
%>
<jsp:useBean id="member" class="member.MemberDTO"/>
<jsp:setProperty property="*" name="member"/>
<%
String[] hobby = request.getParameterValues("hobby");
// 취미를 하이픈(-)을 붙여서 저장 : ex) 공부-게임-등산-
String h = ""; // h = "공부-게임-등산-"
for(String h1 : hobby) {
h += h1 + "-";
}
member.setHobby(h);
MemberDAO dao = MemberDAO.getInstance();
// 한 사람의 상세 정보 구하기
MemberDTO old = dao.getMember(member.getId());
// 비번 비교
if(old.getPasswd().equals(member.getPasswd())) { // 비번 일치시
int result = dao.update(member); // update SQL문 실행
if(result == 1) {
%>
<script>
alert("회원정보 수정 성공");
location.href = "main.jsp";
</script>
<% }
} else { // 비번 불일치시 %>
<script>
alert("비밀번호가 일치하지 않습니다.");
history.go(-1);
</script>
<% } %>
<수정폼에서 넘어온 값 받아서 DTO 객체에 저장>
- 한글값이 넘어올 수 있으므로 인코딩
- 수정폼에서 넘어온 값을 저장하기 위한 DTO 객체 member 를 생성 = 힙메모리에 값들이 저장됨
- setProperty 를 사용해서 DTO 객체 member 에 값 저장
- 수정폼에서 넘어어온 '취미' 는 체크박스이므로 따로 getParamterValues() 메소드로 따로 받아야한다
- member.jsp 에서 했던 것 처럼 취미는 따로 받은 후에 "-"(하이픈) 을 붙여서 setHobby() 로 객체에 저장해야함
<수정전 비밀번호 일치 확인>
- 가장 처음으로, 넘어온 id 값으로 DB 의 비밀번호를 끄집어내서 수정폼의 비밀번호와 일치한지 확인해야한다
- DB 와 연동할 DAO 의 메소드를 사용해야하므로 DAO 객체를 만든다
- 한명의 상세정보를 구하는 메소드가 필요하므로, 수정폼에서 사용했던 메소드인 getMember() 를 사용한다
- getMember() 의 리턴자료형은 DTO, 즉 한명에 대한 상세정보를 DTO 객체 old 로 반환
- old.getPasswd() 는 DB 의 비밀번호이고, member.getPasswd() 는 수정폼에서 사용자가 입력한 비밀번호이다, 두개가 일치하는지 확인한다
- 비번 일치시 update 를 하는 DAO 의 메소드인 update() 를 호출하고 결과를 int result 로 돌려받는다
- 비번 불일치시 수정폼으로 돌아간다
- 이제 DAO 클래스에서 update() 메소드를 작성하자
DAO 클래스 회원 수정하기
- update() 메소드 작성
- MemberDAO.java (추가)
// DAO (Data Access Object)
package member;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
public class MemberDAO {
// 싱글톤 : 객체 생성을 한번만 수행하는 것
private static MemberDAO instance = new MemberDAO();
public static MemberDAO 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();
}
// ID 중복 검사
public int memberAuth(String id) {
int result = 0;
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = getConnection(); // 커넥션 풀에서 커넥션을 구해옴
String sql = "select * from member where id=?";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, id);
rs = pstmt.executeQuery(); // SQL문 실행
if(rs.next()) { // 조건식을 만족하는 데이터를 구해옴
result = 1;
}
} catch(Exception e) {
} 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;
}
// 회원 가입
public int insert(MemberDTO member) {
int result = 0;
Connection con = null;
PreparedStatement pstmt = null;
try {
con = getConnection(); // 커넥션풀에서 커넥션을 구해온다
String sql = "insert into member ";
sql += " values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,sysdate)";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, member.getId());
pstmt.setString(2, member.getPasswd());
pstmt.setString(3, member.getName());
pstmt.setString(4, member.getJumin1());
pstmt.setString(5, member.getJumin2());
pstmt.setString(6, member.getMailid());
pstmt.setString(7, member.getDomain());
pstmt.setString(8, member.getTel1());
pstmt.setString(9, member.getTel2());
pstmt.setString(10, member.getTel3());
pstmt.setString(11, member.getPhone1());
pstmt.setString(12, member.getPhone2());
pstmt.setString(13, member.getPhone3());
pstmt.setString(14, member.getPost());
pstmt.setString(15, member.getAddress());
pstmt.setString(16, member.getGender());
pstmt.setString(17, member.getHobby());
pstmt.setString(18, member.getIntro());
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 memberCheck (MemberDTO member) {
int result = 0;
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = getConnection(); // 커넥션풀에서 커넥션을 구해온다
String sql = "select * from member where id=?";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, member.getId());
rs = pstmt.executeQuery(); // SQL문 실행
if(rs.next()) { // ID 일치
if(rs.getString("passwd").equals(member.getPasswd())) {
result = 1; // ID, 비번 일치 (회원인증 성공)
} else {
result = -1; // 비번 불일치
}
} else { // ID 불일치
result = -2;
}
} 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;
}
// 회원 수정폼 : 한 사람의 상세정보 구하기
public MemberDTO getMember(String id) {
MemberDTO member = new MemberDTO();
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = getConnection(); // 커넥션풀에서 커넥션을 구해온다
String sql = "select * from member where id=?";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, id);
rs = pstmt.executeQuery(); // SQL문 실행
if(rs.next()) {
// member.id = "test"; // 접근 안됨(private 접근제어자)
member.setId(rs.getString("id"));
member.setPasswd(rs.getString("passwd"));
member.setName(rs.getString("name"));
member.setJumin1(rs.getString("jumin1"));
member.setJumin2(rs.getString("jumin2"));
member.setMailid(rs.getString("mailid"));
member.setDomain(rs.getString("domain"));
member.setTel1(rs.getString("tel1"));
member.setTel2(rs.getString("tel2"));
member.setTel3(rs.getString("tel3"));
member.setPhone1(rs.getString("phone1"));
member.setPhone2(rs.getString("phone2"));
member.setPhone3(rs.getString("phone3"));
member.setPost(rs.getString("post"));
member.setAddress(rs.getString("address"));
member.setGender(rs.getString("gender"));
member.setHobby(rs.getString("hobby"));
member.setIntro(rs.getString("intro"));
member.setRegister(rs.getTimestamp("register"));
}
} 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 member;
}
// 회원정보 수정
public int update(MemberDTO member) {
int result = 0;
Connection con = null;
PreparedStatement pstmt = null;
try {
con = getConnection(); // 커넥션풀에서 커넥션을 구해온다
String sql = "update member set name=?,jumin1=?,jumin2=?,mailid=?,";
sql +="domain=?,tel1=?,tel2=?,tel3=?,phone1=?,phone2=?,phone3=?,";
sql +="post=?,address=?,gender=?,hobby=?,intro=? where id=?";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, member.getName());
pstmt.setString(2, member.getJumin1());
pstmt.setString(3, member.getJumin2());
pstmt.setString(4, member.getMailid());
pstmt.setString(5, member.getDomain());
pstmt.setString(6, member.getTel1());
pstmt.setString(7, member.getTel2());
pstmt.setString(8, member.getTel3());
pstmt.setString(9, member.getPhone1());
pstmt.setString(10, member.getPhone2());
pstmt.setString(11, member.getPhone3());
pstmt.setString(12, member.getPost());
pstmt.setString(13, member.getAddress());
pstmt.setString(14, member.getGender());
pstmt.setString(15, member.getHobby());
pstmt.setString(16, member.getIntro());
pstmt.setString(17, member.getId());
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;
}
}
<update() 메소드 형식 작성>
- 수정폼에서 사용자가 입력한 값을 저장하는 DTO 객체를 매개변수로 받을 것이므로 자료형은 DTO
- 업데이트 된 개수를 돌려줄 것이므로 int 형으로 리턴
<update() 메소드 내용 작성>
1. Connection, PreparedStatement 객체 생성
2. try-catch-finally 문을 만들고 try 안에서 getConnection() 으로 커넥션 풀에서 커넥션을 구해옴
3. 아이디와 비밀번호를 제외한 정보를 변경하는 것이므로 update sql 문에 id, passwd 는 쓰지 않음
- where 조건절에 id 를 써서, 원하는 데이터 1개(1명) 만 수정할 수 있도록 한다
4. Connection 객체 con 으로 작성한 SQL 문을 읽어서 PreparedStatement 객체 생성
5. update 하고자하는 값을 매개변수로 받은 객체 member 에서 값을 가져와서 setString() 으로 ? 에 설정
6. sql 문을 executeUpdate() 메소드로 실행
- update sql 문이 잘 실행되면 1을 돌려준다
- update 를 하면 끝
7. PreparedStatement 객체, Connection 객체 닫기
+ 다른 메소드 더 추가할 것, 아직 DAO 미완성
- 추가한 update() 부분 코드만
- 로그인 폼부터 로그인 하고 메인페이지에서 '정보수정' 을 누르고 수정폼에서 정보를 입력후 '회원수정' 을 클릭시 실행됨
- 맞는 비밀번호 입력시
- 다시 수정폼에 들어가면 회원정보가 수정되어있음을 확인 가능
- 틀린 비밀번호 입력시
- 그 후 다시 수정폼으로 돌아감
- 이제 회원탈퇴 관련 기능을 구현하자
- 우선 메인페이지에서 삭제폼인 deleteform.jsp 로 링크 걸기
회원탈퇴 기능 링크 연결
- main.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String id = (String) session.getAttribute("id");
if(id != null) { // 세션이 있는 경우 (정상적인 로그인)
%>
<%=id %>님 환영합니다. <br><br><br>
<a href="updateform.jsp">정보수정</a> <br>
<a href="logout.jsp">로그아웃 </a> <br>
<a href="deleteform.jsp">회원탈퇴</a> <br>
<% } else { // 세션이 없는 경우 %>
<a href="memberform.html">회원가입</a> <br>
<a href="loginform.html">로그인</a> <br>
<% } %>
- 이제 deleteform.jsp 파일을 생성하자
회원관리 프로그램 : 회원탈퇴 기능
- 먼저 deleteform.jsp 라는 삭제폼을 만들것
- deleteform.jsp
<%@page import="member.MemberDAO"%>
<%@page import="member.MemberDTO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String id = (String) session.getAttribute("id");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원 삭제 폼</title>
<script src="http://code.jquery.com/jquery-latest.js"></script>
<!-- 외부 자바스크립트 파일 불러오기 -->
<script src="member.js"></script>
</head>
<body>
<form method="post" action="delete.jsp">
<input type="hidden" name="id" value="<%=id %>">
<table border=1 width=450 align="center">
<caption>회원 삭제 폼</caption>
<tr><td>비밀번호</td>
<td><input type=password id="passwd" name="passwd">
</td>
</tr>
<tr><td colspan=2 align=center>
<input type=submit value="회원삭제">
<input type=reset value="취소">
</td>
</tr>
</table>
</form>
</body>
</html>
- deleteform.jsp는 updateform.jsp 파일의 내용을 복붙한 다음 필요없는 대부분 지우기
- 삭제폼에서 한명의 상세정보를 가져올때 했었던 DB 연동도 필요하지 않다
- 비밀번호 일치 확인은 deleteform.jsp 가 아닌 delete.jsp 에서 할 것
- 세션에서 받아온 id 를 받아서 form 을 통해 hidden 으로 delete.jsp 로 전송한다
- 이렇게 delete.jsp 로 넘어간 id 값을 delete.jsp 에서 사용자가 삭제폼에 입력한 비밀번호와 DB 에서 비밀번호가 일치하는지 확인하는데 사용할 것
- 비밀번호 입력양식만 남긴다
- 로그인 후 main.jsp 에서 '회원탈퇴' 누르며 삭제 폼이 나타난다
- 다음으로 DB 와 연동하여 비밀번호를 확인한 후 삭제를 수행하는 delete.jsp 를 생성 후 작성하자
- delete.jsp
<%@page import="member.MemberDAO"%>
<%@page import="member.MemberDTO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
request.setCharacterEncoding("utf-8");
%>
<jsp:useBean id="member" class="member.MemberDTO"/>
<jsp:setProperty property="*" name="member"/>
<%
MemberDAO dao = MemberDAO.getInstance();
// 한 사람의 상세 정보 구하기
MemberDTO old = dao.getMember(member.getId());
// 비번 비교
if(old.getPasswd().equals(member.getPasswd())) { // 비번 일치시
int result = dao.delete(member.getId()); // update SQL문 실행
if(result == 1) {
session.invalidate(); // 세션 삭제
%>
<script>
alert("회원 탈퇴 성공");
location.href = "main.jsp";
</script>
<% }
} else { // 비번 불일치시 %>
<script>
alert("비밀번호가 일치하지 않습니다.");
history.go(-1);
</script>
<% } %>
- update.jsp 의 내용을 복붙해서 수정, 취미 부분 지우기
- 삭제폼에서 넘어온 id 와 비밀번호를 DTO 객체인 member 를 생성하여 저장
- hidden 으로 넘어온 id 값으로 DB 의 비밀번호를 가져와야하므로, DAO의 getMember() 를 그대로 사용
- 비밀번호 비교하는 부분은 그대로 두기, DAO 클래스의 delete() 메소드로 삭제
- delete() 메소드를 수행할때 필요한 id 값을 매개변수로 전달
- delete() 메소드로 회원정보 삭제가 성공시 세션을 삭제시켜야함!
- 삭제 성공시 세션 삭제 후 main.jsp 로 가는데, 세션정보가 없으므로 '회원가입' '로그인' 등의 메뉴가 뜨는 화면으로 간다
- 삭제된 데이터 개수를 int 형 변수 result 로 받아서 저장
- 실제로 delete 를 수행해주는 DAO 클래스의 delete() 를 작성하자
DAO 클래스 회원 탈퇴 메소드
- delete() 메소드 작성
- MemberDAO.java (추가)
// DAO (Data Access Object)
package member;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;
public class MemberDAO {
// 싱글톤 : 객체 생성을 한번만 수행하는 것
private static MemberDAO instance = new MemberDAO();
public static MemberDAO 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();
}
// ID 중복 검사
public int memberAuth(String id) {
int result = 0;
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = getConnection(); // 커넥션 풀에서 커넥션을 구해옴
String sql = "select * from member where id=?";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, id);
rs = pstmt.executeQuery(); // SQL문 실행
if(rs.next()) { // 조건식을 만족하는 데이터를 구해옴
result = 1;
}
} catch(Exception e) {
} 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;
}
// 회원 가입
public int insert(MemberDTO member) {
int result = 0;
Connection con = null;
PreparedStatement pstmt = null;
try {
con = getConnection(); // 커넥션풀에서 커넥션을 구해온다
String sql = "insert into member ";
sql += " values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,sysdate)";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, member.getId());
pstmt.setString(2, member.getPasswd());
pstmt.setString(3, member.getName());
pstmt.setString(4, member.getJumin1());
pstmt.setString(5, member.getJumin2());
pstmt.setString(6, member.getMailid());
pstmt.setString(7, member.getDomain());
pstmt.setString(8, member.getTel1());
pstmt.setString(9, member.getTel2());
pstmt.setString(10, member.getTel3());
pstmt.setString(11, member.getPhone1());
pstmt.setString(12, member.getPhone2());
pstmt.setString(13, member.getPhone3());
pstmt.setString(14, member.getPost());
pstmt.setString(15, member.getAddress());
pstmt.setString(16, member.getGender());
pstmt.setString(17, member.getHobby());
pstmt.setString(18, member.getIntro());
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 memberCheck (MemberDTO member) {
int result = 0;
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = getConnection(); // 커넥션풀에서 커넥션을 구해온다
String sql = "select * from member where id=?";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, member.getId());
rs = pstmt.executeQuery(); // SQL문 실행
if(rs.next()) { // ID 일치
if(rs.getString("passwd").equals(member.getPasswd())) {
result = 1; // ID, 비번 일치 (회원인증 성공)
} else {
result = -1; // 비번 불일치
}
} else { // ID 불일치
result = -2;
}
} 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;
}
// 회원 수정폼 : 한 사람의 상세정보 구하기
public MemberDTO getMember(String id) {
MemberDTO member = new MemberDTO();
Connection con = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
con = getConnection(); // 커넥션풀에서 커넥션을 구해온다
String sql = "select * from member where id=?";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, id);
rs = pstmt.executeQuery(); // SQL문 실행
if(rs.next()) {
// member.id = "test"; // 접근 안됨(private 접근제어자)
member.setId(rs.getString("id"));
member.setPasswd(rs.getString("passwd"));
member.setName(rs.getString("name"));
member.setJumin1(rs.getString("jumin1"));
member.setJumin2(rs.getString("jumin2"));
member.setMailid(rs.getString("mailid"));
member.setDomain(rs.getString("domain"));
member.setTel1(rs.getString("tel1"));
member.setTel2(rs.getString("tel2"));
member.setTel3(rs.getString("tel3"));
member.setPhone1(rs.getString("phone1"));
member.setPhone2(rs.getString("phone2"));
member.setPhone3(rs.getString("phone3"));
member.setPost(rs.getString("post"));
member.setAddress(rs.getString("address"));
member.setGender(rs.getString("gender"));
member.setHobby(rs.getString("hobby"));
member.setIntro(rs.getString("intro"));
member.setRegister(rs.getTimestamp("register"));
}
} 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 member;
}
// 회원정보 수정
public int update(MemberDTO member) {
int result = 0;
Connection con = null;
PreparedStatement pstmt = null;
try {
con = getConnection(); // 커넥션풀에서 커넥션을 구해온다
String sql = "update member set name=?,jumin1=?,jumin2=?,mailid=?,";
sql +="domain=?,tel1=?,tel2=?,tel3=?,phone1=?,phone2=?,phone3=?,";
sql +="post=?,address=?,gender=?,hobby=?,intro=? where id=?";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, member.getName());
pstmt.setString(2, member.getJumin1());
pstmt.setString(3, member.getJumin2());
pstmt.setString(4, member.getMailid());
pstmt.setString(5, member.getDomain());
pstmt.setString(6, member.getTel1());
pstmt.setString(7, member.getTel2());
pstmt.setString(8, member.getTel3());
pstmt.setString(9, member.getPhone1());
pstmt.setString(10, member.getPhone2());
pstmt.setString(11, member.getPhone3());
pstmt.setString(12, member.getPost());
pstmt.setString(13, member.getAddress());
pstmt.setString(14, member.getGender());
pstmt.setString(15, member.getHobby());
pstmt.setString(16, member.getIntro());
pstmt.setString(17, member.getId());
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(String id) {
int result = 0;
Connection con = null;
PreparedStatement pstmt = null;
try {
con = getConnection(); // 커넥션풀에서 커넥션을 구해온다
String sql = "delete from member where id=?";
pstmt = con.prepareStatement(sql);
pstmt.setString(1, id);
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;
}
}
<delete() 메소드 형식 작성>
- 매개변수는 패스워드가 일치한 경우 그 사람의 아이디가 넘어가야하므로 String 형
- 리턴자료형은 삭제된 데이터의 개수를 돌려받을 수 있는 int 형
<delete() 메소드 내용 작성>
1. Connection, PreparedStatement 객체 생성
2. try-catch-finally 문을 만들고 try 안에서 getConnection() 으로 커넥션 풀에서 커넥션을 구해옴
3. 삭제하기 위해 데이터를 식별하는 id 만 있으면 되므로 매개변수로 넘겨받은 id 값을 sql 문에 적기
4. Connection 객체 con 으로 작성한 SQL 문을 읽어서 PreparedStatement 객체 생성
5. delete 하고자하는 데이터를 매개변수로 받은 id 로 구분하므로 ? 에 id 를 세팅
6. sql 문을 executeUpdate() 메소드로 실행
- delete sql 문이 잘 실행되면 1 을 리턴
7. PreparedStatement 객체, Connection 객체 닫기
- 추가한 delete() 부분 코드만
- 잘 구현되었는지 확인하기 위해 삭제해보자
- 틀린 비밀번호 입력시
- 맞는 비밀번호 입력시
- DB 에서 회원 삭제(탈퇴) 성공시 세션이 끊겨서 세션이 없으므로 main.jsp 에서 이 화면을 보여준다
+ 주의해야하는 부분
- 아이디, 비밀번호를 넘길때 공백이 들어가지 않도록 주의한다
ex) 비번으로 "1999 " 을 입력시 DB 의 "1999" 와 다른 비밀번호로 인식
- JSP Model 1 회원관리 프로그램 완성되었다
- 다음은 JSP로 일반게시판을 만들 것
Model 1 DBCP 방식으로 일반게시판 만들기
일반게시판 : 주요 기능 소개
1. Connection Pool
2. 액션태그
3. DTO, DAO 클래스
4. 페이징 처리 ( inline View )
- SQL 문 상에 서브쿼리 형태로 만드는 인라인뷰
- 페이징 처리가 주요 기능이다
일반게시판 : 프로젝트 생성
- 이렇게 구조를 만들기 위해
- board 라는 프로젝트부터 생성
- 이후 board 프로젝트의 WebContent 폴더 하위에 초기에 보여줄 파일인 index.jsp 를 생성
일반게시판 : 기초 파일 가져오기
- 클라우드에서 게시판 글 작성 양식, 환경설정 코드가 있는 board 폴더를 가져옴
일반게시판 : 몇가지 환경 구축
1) board 폴더 안의 context.xml 파일을 META-INF 폴더로 옮기기
- 커넥션 풀의 환경설정 파일이다
2) lib 폴더 안에 오라클용 JDBC Driver 인 ojdbc.jar 가져오기, 다른 프로젝트에서 가져오면 된다
일반게시판 : Connection Pool 테스트
- dbcpAPITest.jsp 파일을 실행해서 커넥션 풀에서 커넥션 가져오기 테스트
- dbcpAPITest.jsp
- 커넥션 풀에서 커넥션 가져오기 테스트 성공
+ 추후 DAO 클래스 만들때 커넥션풀에서 커넥션 구하기 3줄 코드를 DAO 클래스에 넣을 것
Context init = new InitialContext();
DataSource ds = (DataSource) init.lookup("java:comp/env/jdbc/orcl");
conn = ds.getConnection();
일반게시판 : 테이블 및 시퀀스 생성
- 이전에 회원관리 프로그램에서 사용했던 오라클계정인 totoro 계정에 board0 테이블 생성
- 아래 양식으로 테이블을 생성한다
create table board0(
num number primary key,
writer varchar2(20) not null,
email varchar2(30),
subject varchar2(50) not null,
passwd varchar2(20) not null,
reg_date timestamp not null,
readcount number default 0,
content varchar2(2000) not null,
ip varchar2(20) not null );
create sequence board0_seq
start with 1
increment by 1
nocache;
- num : 화면에 출력되는 번호가 아니라, 내부적으로만 있는 번호
- passwd : 글을 수정/삭제 시 비번이 맞는 경우에만 삭제되도록 하기위함
- readcount : 조회수이므로 number 타입, 디폴트는 0
- ip : 글을 작성한 사용자의 ip 값이 저장됨
- 시퀀스는 num 이라는 기본키 컬럼에 들어갈 시퀀스이다
- WebContent 하위에 sql 폴더를 만들고 안에 board.sql 파일 생성
- 커넥션 프로파일을 Oracle_11, New Oracle(totoro), xe 로 해준다
- 테이블과 시퀀스를 생성한다
- 시퀀스는 num 이라는 기본키 컬럼에 들어갈 시퀀스이다
- 테이블과 시퀀스 생성 확인
- 생성확인 완료
일반게시판 : DAO 와 DTO 클래스 만들기
+ 이후 Model 2 에선 기능에 따라 세분화하므로 DAO, DTO 가 다른 패키지에 들어감
- 지금은 같은 패키지인 board 안에 넣자
일반게시판 : DTO 클래스 작성
- 이걸 가져와서 DTO 클래스에 복붙
- varchar2 는 String 으로, number 는 int 로, timestamp 는 Timestamp로 바꿔서 자바 변수(프로퍼티) 만들기
+ 프로퍼티의 접근제어자는 private
+ java.sql 의 Timestamp import
- getter / setter 메소드 추가
- DTO 클래스 BoardDataBean.java 완성 코드
// DTO (Data Transfer Object)
package board;
import java.sql.Timestamp;
public class BoardDataBean {
private int num; // 프로퍼티(property)
private String writer;
private String email;
private String subject;
private String passwd;
private Timestamp reg_date;
private int readcount;
private String content;
private String ip;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getWriter() {
return writer;
}
public void setWriter(String writer) {
this.writer = writer;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getPasswd() {
return passwd;
}
public void setPasswd(String passwd) {
this.passwd = passwd;
}
public Timestamp getReg_date() {
return reg_date;
}
public void setReg_date(Timestamp reg_date) {
this.reg_date = reg_date;
}
public int getReadcount() {
return readcount;
}
public void setReadcount(int readcount) {
this.readcount = readcount;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
}
일반게시판 : DAO 클래스 작성
DAO 에 들어갈 내용
1. 싱글톤
2. 정적메소드 getInstance() 생성
3. Connection Pool 에서 커넥션 구해오는 메소드
4. 그 이후 일반게시판 CRUD 관련 메소드
1. 싱글톤
- 외부 접근 불가능하게 private, 공유하기 위해 static 해서 자기자신의 클래스로 객체 생성을 한번만 하기
2. 정적메소드 getInstance() 생성
3. Connection Pool 에서 커넥션 구해오는 메소드
- 메소드 호출시 Connection Pool 에서 커넥션을 구해주도록 함
- DBCP 방식으로 DB 와 연결하므로 이 DB 연결시 커넥션을 구해오는 이 메소드를 사용해야한다
- 커넥션 구할때 예외처리를 해야한다, 여기선 throws 로 Exception 던지기
+ Connection 클래스 import
- 테스트할때 사용했던 dbcpAPITest.jsp 3줄을 복사해서 넣는다
- 단축키 Ctrl + Shift + O 로 import 시키기
- javax.naming.Context 를 선택후 Next, 다음은 javax.sql.DataSource 선택후 Finish
- getConnection() 메소드 완성
- 가져온 커넥션을 리턴하는 코드로 바꿈
4. 그 이후 일반게시판 CRUD 관련 메소드
- 가장 먼저 글작성 메소드를 만들어야한다, 그 후 다양한 메소드들을 DAO에 작성
일반게시판 : 파일별 기능 및 구조 설명
- 만들어야할 파일들 보기
+ check.jsp 는 유효성 검사
- 글작성 메소드인 writeForm.jsp 먼저 작성
일반게시판 : 글 작성 기능
- writeForm.jsp 에서 글 작성시 write.jsp 로 넘어감
- writeForm.jsp
<%@ page contentType="text/html; charset=utf-8" %>
<%@ include file="color.jsp"%>
<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>
- 여기서 입력한 값을 writePro.jsp 로 전송한다
- wirtePro.jsp 생성 후 작성하자
- writePro.jsp
<%@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:useBean>
<jsp:setProperty property="*" name="board"/>
<%
// 글을 작성한 사용자의 IP주소를 구해오는 메소드
String ip = request.getRemoteAddr();
board.setIp(ip);
BoardDBBean dao = BoardDBBean.getInstance();
int result = dao.insert(board); // insert SQL문 실행
if(result == 1) {
%>
<script>
alert("글 작성 성공");
location.href = "list.jsp";
</script>
<% } else {%>
<script>
alert("글 작성 실패");
history.go(-1);
</script>
<% }%>
0. 화면 출력을 할때만 HTML 코드가 필요하다, 여기선 출력을 하지 않으므로 위의 2줄 제외하고 HTML 코드를 지운다
1. writeForm.html 에서 한글값이 post 로 넘어오므로 한글 인코딩
2. 폼에서 넘어온 값을 DTO 객체에 저장해야하므로 DTO 객체를 생성하고 각 프로퍼티에 값 저장
- useBean action tag 의 class 속성에는 패키지부터 시작해서 클래스까지 적어줌
- setProperty action tag 의 property 속성에는 "*", id 속성에는 객체명을 써야하므로 board 를 쓴다
- DTO 객체에 저장 = 폼에서 넘어온 값을 힙메모리상에 저장
3. 폼에서 넘어가지 않는 값들은 setProperty action tag 에 의해 DTO 객체에 값이 저장되지 않음, 이들은 다른 방법으로 값 설정해야함
- writer, email, subject, passwd, content 는 폼에서 넘어와서 서버측 메모리 (DTO 객체) 에 저장된다
- num, reg_date, readcount, ip 는 폼에서 넘어오지 않으므로 DTO 에 저장되지 않았음
- 대신, 필드에 있는 int 형 변수는 자동으로 0 으로 초기화 되므로 num, readcount 는 0 이 됨
- num 값은 sequence 로 값을 입력, reg_date 는 sysdate 로 값을 입력, readcount 는 기본값 0, ip 는 request.getRemoteAddr() 로 클라이언트의 ip를 구해서 직접 집어넣기
- ip 프로퍼티는 이렇게 값을 설정한다
- 나머지는 오라클에 insert 할때 값 넣기
4. 사용자가 글 작성시 입력한 것들과 정보를 DB 에 insert 하기위한 DAO 의 메소드 insert() 생성
- 서버측 메모리(DTO 객체) 에 저장된 데이터를 DB 에 저장
- DAO 객체 생성 선행
5. 삽입 성공시 1을 리턴받게해서 if문을 통해 list.jsp (목록페이지) 로 가게함
6. 삽입 실패시 다시 글 작성 폼으로 돌아가게 함
- DAO 클래스로 가서 글작성 메소드인 insert() 를 작성하자
DAO 클래스 글 작성 기능 메소드
- insert() 메소드 작성
- BoardDBBean.java
// DAO (Data Access Object)
package board;
import java.sql.Connection;
import java.sql.PreparedStatement;
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;
}
}
<insert() 메소드 형식 작성>
- 삽입 성공시 1을 반환하도록 하기 위해 리턴자료형은 int
- 삽입할 데이터를 매개변수로 가져와야하므로 매개변수 자료형은 DTO
<insert() 메소드 내용 작성>
1. Connection, PreparedStatement 객체 생성
2. try-catch-finally 문을 만들고 try 안에서 getConnection() 으로 커넥션 풀에서 커넥션을 구해옴
3. insert SQL 문에 num 컬럼은 sequence 로, reg_date 컬럼은 sysdate 로 값을 채우기, 나머지는 ? 로 채우기
- board0_seq.nextval 을 num 컬럼 자리에 넣기
- ip 는 wiretPro.jsp 에서 값을 DTO 객체에 넣었었다
4. Connection 객체 con 으로 작성한 SQL 문을 읽어서 PreparedStatement 객체 생성
5. ? 에 값을 세팅할때 자료형에 따라 메소드가 다름을 주의
- number 형은 setInt, varchar2 형은 setString
- readcount 컬럼은 board.getReadcount() 로 할당해도되고 0 으로 직접 설정해도 된다
- readcount 프로퍼티가 자동으로 0 으로 초기화되었기때문에 board.getReadcount() 는 0 이다
6. insert sql 문을 executeUpdate() 메소드로 실행
- insert sql 문이 잘 실행되면 1 을 리턴
7. PreparedStatement 객체, Connection 객체 닫기
+ DAO 클래스 아직 미완성, 더 추가할 것
- 추가한 코드 부분만
- sql 파일에서 select 로 검색해보면 성공적으로 삽입 되었음을 확인 가능하다
- 이제 list.jsp (목록 페이지) 를 생성하자
일반게시판 : 게시판 목록 페이지 (페이징 처리)
- 페이징 처리를 잘 이해하며 구현하기 위해서 우선 강제로 101개 이상의 데이터를 board.sql 파일에서 강제로 삽입하자
- Alt + X 로 여러번 실행해서 101 개 이상의 데이터를 입력하자
- 130 개의 데이터가 board0 테이블에 삽입된 상태이다
- list.jsp 파일 생성 후 작성
- list.jsp (미완성, 이후 추가)
<%@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);
%>
</body>
</html>
- 코드는 아래에서 설명
페이징 처리를 위해서 만들어야하는 변수
- 기본변수를 3개 만들어야함
- 연산에 의해 기본변수로부터 파생된 변수를 5 ~ 6 개 만들어야함
- 총 8 ~ 9 개 변수를 만들어야 페이징 처리 가능
기본 변수 3가지
// 1. 한 화면에 출력할 데이터 갯수
int page_size = 10;
String pageNum = request.getParameter("page");
if(pageNum == null) {
pageNum = "1"; // 1 page : 최근글이 보이는 페이지
}
// 2. 현재 페이지 번호가 저장되는 변수
int currentPage = Integer.parseInt(pageNum);
1. int page_size : 한 화면에 몇개의 데이터를 출력할지 정의하기 위한 기본 변수
- 현재는 10 으로 지정
- 한 페이지에 보이는 글의 개수를 의미
+ String pageNum : 'page' 란 변수를 통해 넘어오는 값을 저장
2. int currentPage : 현재 페이지 번호를 저장하는 기본 변수
- 문자형 변수인 pageNum 을 int 형으로 변환한 값을 저장하는 변수
- 사용자가 '1' 을 클릭시 현페이지인 list.jsp 로 링크를 걸고 get 방식으로 값을 전달, list.jsp?page=1 로 값 1을 전달한다
- list.jsp 에서 list.jsp 를 링크거는것임, 다시 list.jsp 가 로딩됨
- 그럼 그 page 란 변수에 저장된 1 을 저장하는 변수가 String pageNum 변수
pageNum 이 null 값인 경우
1) 지금처럼 list.jsp 를 그냥 실행했을 경우,
2) 글 작성에 성공하고 list.jsp 로 가는 경우이다
- pageNum 이 null 일땐 1 페이지를 출력
+ 1 page 는 가장 최근글이 나오는 곳
- 다음은 이 기본변수들로 파생된 변수 만들기
currentPage 파생 변수
1) int startRow : 각 page에 출력할 데이터의 시작번호
2) int endRow : 각 page에 출력할 데이터의 끝번호
ex) page = 1 : startRow=1, endRow=10 // 사용자가 1 페이지 선택시
ex) page = 2 : startRow=11, endRow=20 // 사용자가 2 페이지 선택시
ex) page = 3 : startRow=21, endRow=30 // 사용자가 3 페이지 선택시
int startRow = (currentPage - 1) * page_size + 1;
int endRow = currentPage * page_size;
- 잘라주기 위한 첫번째 번호가 startRow, 마지막 번호가 endRow
- rownum 자리에 넣을 컬럼이 startRow, endRow
- currentPage 에 의해 좌우되므로 사용자가 몇번 페이지를 눌렀냐에 따라 starRow, endRow 값이 달라짐
3. int count : DB 에서 그룹함수로 구하는 총 데이터 갯수를 저장하는 기본 변수
- 이제 DAO 클래스로 가서 데이터의 총 개수를 반환하는 getCount() 메소드를 생성하자
DAO 클래스 데이터 총 개수 반환 메소드
- BoardDBBean.java (추가)
// DAO (Data Access Object)
package board;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
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;
}
}
- DB 와 연동해서 그룹함수 count(*) 로 데이터의 총 개수를 가져오기
- 결과를 리턴할 ResultSet 객체 rs 만들기
- 추가한 부분 코드만
- 실행시 콘솔창에 총 데이터 개수가 출력된다
- 다시 list.jsp 로 돌아가서 List 를 만들자
- count 가 0 보다 크면 = 값이 있으면
- DAO 클래스의 getList 메소드로 리스트를 자를 것
- 잘라주기 위한 startRow, endRow 를 전달 ex) 사용자가 1 페이지 클릭시 1, 10 전달
- getList() 는 자른 후 잘라진 리스트를 반한다
- DAO 클래스에서 getList() 메소드 만들기
DAO 클래스 특정 인덱스 사이 데이터만 추출한 목록 구하기
- getList() 메소드 작성
- 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;
}
}
- 중간에 있는 데이터 10개를 추출하기 위해 서브쿼리 형태의 인라인 뷰 사용
- 사용자가 1 선택시 1, 10 이 매개변수로 넘어오고 그럼 1 ~ 10 사이의 데이터를 DB 로부터 가져와서 rs 에 저장
- 그 rs 에서 데이터를 하나씩 가져와서 DTO 객체 안에 저장하고 그걸 list 에 add 해서 추가
- 그럼 1 ~ 10 까지의 데이터가 list 안에 저장되고 그게 리턴된다
- 각각의 글이 저장된 각 DTO 객체가 list 안에 저장되었으므로, 각 데이터가 있는 위치의 주솟값이 콘솔창에 출력된다
- 현재는 page_size 를 10으로 설정했으므로 10개가 출력되고 있다
+ DTO 객체는 데이터가 저장된 위치를 가리키는 주소값
- 추가된 부분 코드만 캡처
- 그럼 이 메소드를 호출한 list.jsp 에서는 1 ~ 10 까지의 데이터만을 저장한 리스트를 돌려받음
+ 현재 getList() 로 가져온 글
- list.jsp 에서 이렇게 출력시 129 가 나온다
- 현재는 그냥 list.jsp 를 실행만 하므로 pageNum 은 "1", currentPage 는 1 이므로 1 ~ 10 까지의 데이터를 DB 에서 가져왔다
- get(1) 은 두번째로 최근에 입력된 글이므로 list.get(1).getNum() 은 129 가 나옴
- get(0) 은 가장 최근에 입력된 글이므로 list.get(0).getNum() 은 130 이 나온다
- 즉 가장 최근 글 부터 10번째 최근 글까지를 저장한 list 를 getList() 메소드를 통해 가져온 것
- 이렇게 getList() 로 가져온 리스트를 아래에 출력하자
- list.jsp (추가)
<%@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>
<%
for(int i = 0 ; i < list.size() ; i++) {
BoardDataBean board = list.get(i);
%>
<tr>
<td></td>
<td><%=board.getSubject() %></td>
<td><%=board.getWriter() %></td>
<td><%=board.getReg_date() %></td>
<td><%=board.getReadcount() %></td>
<td><%=board.getIp() %></td>
</tr>
<%
} // for end
%>
</table>
<% }%>
</body>
</html>
- 번호값은 내부에서 쓰는 값과 화면에 출력되는 번호는 다른 값을 쓸 것이므로 출력하지 않았다
- list.jsp 수정할 부분
1. 번호값은 화면출력 번호로 따로 설정
2. 날짜 시간 포맷을 수정하자
num 값 vs 화면 출력 번호
- num 값은 내부에서 쓰는 번호로서, 중간에 데이터가 지워져도 건너뛴다
- 화면 출력 변호값은 중간에 데이터가 지워지면 번호가 땡겨진다
- 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;
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.getReg_date() %></td>
<td><%=board.getReadcount() %></td>
<td><%=board.getIp() %></td>
</tr>
<%
} // for end
%>
</table>
<% }%>
</body>
</html>
- 추가된 코드에 대한 설명은 아래
1. 번호값은 화면출력 번호로 따로 설정
// number : 각 페이지에 출력될 시작 번호
int number = count - (currentPage - 1) * page_size;
- number 변수는 각 페이지에 출력될 시작 번호를 구해서 저장한다
- 데이터가 130개일때, 1 페이지를 클릭시 number 는 130 이 되고, 2 페이지를 클릭시 number 는 120 이 된다
- 그리고 list 에서 가져온 데이터를 하나씩 출력하기위한 for문 안에서 이렇게 감소시켜준다
2. 등록 날짜 포맷
- for 문 위쪽 바깥에서 SimpleDateFormat 객체 생성
- 그리고 list 에서 가져온 데이터를 하나씩 출력하기위한 for문 안에서 이렇게 등록날짜를 출력시켜준다
- 결과 캡처
- URL 상에 ?page=2 를 추가한 뒤 실행하면 두번째 페이지가 나타나면서 120 이 number 가 되고 다른 것들은 전부 -- 로 인해 구해짐