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 가 되고 다른 것들은 전부 -- 로 인해 구해짐

+ Recent posts