회원제 게시판 프로그램 만들기 (1) - Member (23.05.30~31)

·2023년 5월 30일
0

Java

목록 보기
34/35
post-thumbnail

회원제 게시판 프로그램 중 회원(Member) 관련 메뉴와 메소드 만들기!


💡 Oracle SQL

✏️ JDBC_게시판프로그램.sql

ALTER SESSION SET "_ORACLE_SCRIPT"=true;

-- [관리자 계정] member 계정 생성
CREATE USER ash_member IDENTIFIED BY member1234;

-- [관리자 계정] CONNECT, RESOURCE + CREATE VIEW 권한 부여 + 객체 생성 공간 할당
GRANT CONNECT, RESOURCE, CREATE VIEW TO ash_member;
ALTER USER ash_member DEFAULT TABLESPACE SYSTEM QUOTA UNLIMITED ON SYSTEM;

-- ash_member 계정 접속 방법 추가

-- [멤버 계정]
CREATE TABLE MEMBER(
    MEMBER_NO NUMBER PRIMARY KEY,
    MEMBER_ID VARCHAR2(20) NOT NULL,
    MEMBER_PW VARCHAR2(20) NOT NULL,
    MEMBER_NM VARCHAR2(30) NOT NULL,
    MEMBER_GENDER CHAR(1) CHECK (MEMBER_GENDER IN('M', 'F')),
    ENROLL_DATE DATE DEFAULT SYSDATE,
    SECESSION_FL CHAR(1) DEFAULT 'N' CHECK (SECESSION_FL IN('Y', 'N'))
);

COMMENT ON COLUMN MEMBER.MEMBER_NO IS '회원 번호(PK)';
COMMENT ON COLUMN MEMBER.MEMBER_ID IS '회원 아이디';
COMMENT ON COLUMN MEMBER.MEMBER_PW IS '회원 비밀번호';
COMMENT ON COLUMN MEMBER.MEMBER_NM IS '회원 이름';
COMMENT ON COLUMN MEMBER.MEMBER_GENDER IS '회원 성별(M/F)';
COMMENT ON COLUMN MEMBER.ENROLL_DATE IS '회원 가입일';
COMMENT ON COLUMN MEMBER.SECESSION_FL IS '탈퇴여부(Y/N)';

-- 게시판 테이블
DROP TABLE BOARD;

CREATE TABLE BOARD(
    BOARD_NO NUMBER PRIMARY KEY,
    BOARD_TITLE VARCHAR2(200) NOT NULL,
    BOARD_CONTENT VARCHAR2(4000) NOT NULL,
    CREATE_DATE DATE DEFAULT SYSDATE,
    READ_COUNT NUMBER DEFAULT 0,
    MEMBER_NO NUMBER REFERENCES MEMBER -- MEMBER 테이블 PK값 참조
);

COMMENT ON COLUMN BOARD.BOARD_NO IS '게시글 번호';
COMMENT ON COLUMN BOARD.BOARD_TITLE IS '게시글 제목';
COMMENT ON COLUMN BOARD.BOARD_CONTENT IS '게시글 내용';
COMMENT ON COLUMN BOARD.CREATE_DATE IS '게시글 작성일';
COMMENT ON COLUMN BOARD.READ_COUNT IS '조회수';
COMMENT ON COLUMN BOARD.MEMBER_NO IS '회원 번호(작성자)';

-- 댓글 테이블
CREATE TABLE REPLY(
    REPLY_NO NUMBER PRIMARY KEY,
    REPLY_CONTENT VARCHAR2(500) NOT NULL,
    CREATE_DATE DATE DEFAULT SYSDATE,
    MEMBER_NO NUMBER REFERENCES MEMBER, -- MEMBER 테이블 PK 참조
    BOARD_NO NUMBER REFERENCES BOARD -- BOARD 테이블 PK 참조
);

COMMENT ON COLUMN REPLY.REPLY_NO IS '댓글 번호(PK)';
COMMENT ON COLUMN REPLY.REPLY_CONTENT IS '댓글 내용';
COMMENT ON COLUMN REPLY.CREATE_DATE IS '댓글 작성일';
COMMENT ON COLUMN REPLY.MEMBER_NO IS '회원 번호(작성자)';
COMMENT ON COLUMN REPLY.BOARD_NO IS '게시글 번호(어떤 게시글의 댓글인지 확인)';

-- 각 테이블 PK 생성용 시퀀스 생성
CREATE SEQUENCE SEQ_MEMBER_NO; -- 1부터 1씩 증가, 반복 X
CREATE SEQUENCE SEQ_BOARD_NO;
CREATE SEQUENCE SEQ_REPLY_NO;

ALTER SEQUENCE SEQ_MEMBER_NO INCREMENT BY 1;
ALTER SEQUENCE SEQ_BOARD_NO INCREMENT BY 1;
ALTER SEQUENCE SEQ_REPLY_NO INCREMENT BY 1;

💡 Java

✏️ ProjectRun 클래스

package edu.kh.jdbc.run;

import edu.kh.jdbc.main.view.MainView;

public class ProjectRun {

	public static void main(String[] args) {
		
		MainView view = new MainView();
		view.displayMenu();
		
	}

}

✏️ MainView 클래스

package edu.kh.jdbc.main.view;

import java.util.InputMismatchException;
import java.util.Scanner;

import edu.kh.jdbc.board.view.BoardView;
import edu.kh.jdbc.member.model.vo.Member;
import edu.kh.jdbc.member.view.MemberView;

public class MainView { // 메인 메뉴(메뉴 선택용/입력 화면)

	private Scanner sc = new Scanner(System.in);
	
	// 로그인한 회원의 정보가 저장된 객체를 참조할 변수
	private Member loginMember = null;
	
	// 회원 관련 기능 화면을 모아둔 객체를 참조할 변수
	private MemberView memberView = new MemberView();
	
	// 게시판 관련 기능 화면을 모아둔 객체를 참조할 변수
	private BoardView boardView = new BoardView();
	
	// alt + shift + j : 메소드/클래스 설명용 주석 생성
	/**
	 * 메인 메뉴 출력 메소드
	 */
	public void displayMenu() {
		
		int menuNum = -1; // 메뉴 선택 값 저장 변수
		// 초기 값을 -1로 지정하여, 반복문 첫 바퀴에서 오류 발생 시 종료되는 것을 방지
		
		do {
			
			try {

				if(loginMember == null) { // 로그인이 되어 있지 않은 경우
					
					System.out.println("\n************* 회원제 게시판 프로그램 *************\n");
					
					System.out.println("1. 로그인");
					System.out.println("2. 회원 가입");
					System.out.println("0. 프로그램 종료");
					
					System.out.print("메뉴를 선택해 주세요 >> ");
					
					menuNum = sc.nextInt(); // InputMismatchException
					sc.nextLine(); // 입력 버퍼 개행문자 제거
					System.out.println(); // 개행
					
					switch(menuNum) {
					case 1 : loginMember = memberView.login(); break;
					case 2 : memberView.signUp(); break;
					case 0 : System.out.println("----- 프로그램 종료 -----"); break;
					default : System.out.println("메뉴에 작성된 번호를 입력해 주세요.");
					}
					
				} else { // 로그인이 되어 있는 경우
					
					
					System.out.println("\n************** 회원 메뉴 **************\n");
					// - 로그인한 회원 정보 조회
					// - 회원 목록 조회
					// - 회원 정보 수정(이름, 성별)
					// - 비밀번호 변경
					// - 회원 탈퇴
					System.out.println("1. 내 정보 조회");
					System.out.println("2. 가입된 회원 목록 조회");
					System.out.println("3. 내 정보 수정(이름, 성별)");
					System.out.println("4. 비밀번호 변경");
					System.out.println("5. 회원 탈퇴");
					
					System.out.println("6. * 게시판 메뉴 화면 *");
					
					System.out.println("9. 로그아웃");
					
					System.out.print("메뉴를 선택해 주세요 >> ");
					menuNum =sc.nextInt();
					sc.nextLine();
					
					switch(menuNum) {
					case 1 : memberView.myInfo(loginMember); break;
					case 2 : memberView.selectAll(); break;
					case 3 : memberView.updateMyInfo(loginMember); break;
					case 4 : memberView.updatePw(loginMember); break;
					case 5 : 
						int result = memberView.secession(loginMember);
						if(result > 0) loginMember = null; // 로그아웃
						break;
						
					case 6 : boardView.boardMenu(loginMember); break;
					
					case 9 : loginMember = null; break;
					default : System.out.println("메뉴에 작성된 번호를 입력해 주세요.");
					}
					
				}
				
			} catch(InputMismatchException e) {
				System.out.println("\n입력 형식이 올바르지 않습니다. 다시 시도해 주세요.");
				sc.nextLine(); // 입력 버퍼에 남은 잘못된 문자열 제거
			}
			
		} while(menuNum != 0);
		
	}
	
}

✏️ MemberView 클래스

package edu.kh.jdbc.member.view;

import java.util.List;
import java.util.Scanner;

import edu.kh.jdbc.member.model.service.MemberService;
import edu.kh.jdbc.member.model.vo.Member;

public class MemberView { // 회원 관련 화면 입/출력

	private Scanner sc = new Scanner(System.in);

	// 회원 관련 서비스 제공 객체 생성 및 참조
	private MemberService service = new MemberService();
	
	/**
	 * 회원 가입 화면 출력용 메소드
	 */
	public void signUp() {
		System.out.println("[회원 가입]");
		
		try {
			
			String memberId = null;
			String memberPw = null;
			String memberPw2 = null;
			String memberName = null;
			char memberGender = ' ';
		
		while(true) { // 중복 아이디가 없을 경우 종료하는 if문 필요

			System.out.print("아이디 : ");
			memberId = sc.next();
			
			/* 아이디 중복 검사 (DB에 일치하는 아이디 있으면 "중복" -> 다시 아이디 입력 받기 */
			int result = service.duplicateCheck(memberId);
			// result는 중복이면 1, 아니면 0 반환될 예정
			
			if(result == 0) { // 중복 아니면 반복문 종료
				System.out.println("[사용 가능한 아이디입니다.]");
				break;
				
			} else {
				System.out.println("[이미 사용 중인 아이디입니다. 다시 입력해 주세요.]");
			}
			
			
		} // 중복 검사 while문 종료
		
		// 비밀번호, 비밀번호 확인을 각각 입력 받아
		// 일치할 때까지 무한 반복
		while(true) {
			
			System.out.print("비밀번호 : ");
			memberPw = sc.next();
			
			System.out.print("비밀번호 확인 : ");
			memberPw2 = sc.next();
			
			if(memberPw.equals(memberPw2)){ // 일치하면
				break;
				
			} else {
				System.out.println("\n[비밀번호가 일치하지 않습니다. 다시 입력해 주세요.]\n");
			}
		} // 비밀번호 확인 while 종료
		
		// 이름 입력
		System.out.print("회원 이름 : ");
		memberName = sc.next();
		
		// 성별이 'M' 또는 'F'가 입력될 때까지 반복
		while(true) {
			
			System.out.print("성별(M/F) : ");
			memberGender = sc.next().toUpperCase().charAt(0);
			// String.toUpperCase() : 문자열을 대문자로 변환
			
			if(memberGender != 'M' && memberGender != 'F') {
				System.out.println("\n[성별은 M 또는 F만 입력해 주세요.]\n");
			} else {
				break;
			}
			
		} // 성별 while문 종료
		
		// 입력 받은 값을 하나의 객체(Member)에 저장
		Member signUpMember = new Member(memberId, memberPw, memberName, memberGender);
		
		// 회원 가입 Service 호출 후 결과 반환
		// - 회원 가입 == DB에 회원 정보 삽입 == INSERT(DML)
		//	 -> DML 구문 수행 시 성공한 행의 개수가 반환됨 == int형 변수로 결과를 저장
		int result = service.signUp(signUpMember);
		
		// Service 결과에 따른 화면 처리
		if(result > 0) { // 가입 성공 시
			System.out.println("\n*** 회원 가입 성공 ***\n");
			
		} else {
			System.out.println("[회원 가입 실패]");
		}
		
		} catch(Exception e) {
			System.out.println("\n<회원 가입 중 예외 발생>");
			e.printStackTrace(); // 예외 내용 출력
		}
	
	}

	/** 로그인 메소드
	 * @return
	 */
	public Member login() {
		System.out.println("[로그인]");
		
		System.out.print("아이디 : ");
		String memberId = sc.next();
		
		System.out.print("비밀번호 : ");
		String memberPw = sc.next();
		
		// Member 객체를 생성하여 입력 받은 값 세팅
		Member mem = new Member();
		mem.setMemberId(memberId); // setter 이용해서 초기화
		mem.setMemberPw(memberPw);
		
		// 로그인 Service 수행 후 결과 반환 받기
		Member loginMember = null;
		
		try {
			loginMember = service.login(mem);
			
			if(loginMember != null) { // 참조하는 객체가 있다 == 로그인 성공
				System.out.println("\n***" + loginMember.getMemberName() + " 님 환영합니다. ***\n");
			
			} else { // 로그인 실패(아이디 또는 비밀번호 불일치)
				System.out.println("\n[아이디 또는 비밀번호가 일치하지 않습니다.]\n");
			}
			
		}catch(Exception e) {
			System.out.println("\n<로그인 과정에서 예외 발생>\n");
			e.printStackTrace();
		}
		
		return loginMember;
	}

	/** 내 정보 조회
	 * @param loginMember
	 */
	public void myInfo(Member loginMember) {
		
		System.out.println("[내 정보 조회]");
	
		System.out.println("회원 번호 : " + loginMember.getMemberNo());
		System.out.println("아이디 : " + loginMember.getMemberId());
		System.out.println("이름 : " + loginMember.getMemberName());
		
//		String gender = null;
//		
//		switch(loginMember.getMemberGender()) {
//		case 'M' : gender = "남성";
//		default : gender = "여성";
//		}
//
//		System.out.println("성별 : " + gender);
		
		if(loginMember.getMemberGender() == 'M') {
			System.out.println("성별 : 남성");
		} else {
			System.out.println("성별 : 여성");
		}
		
		System.out.println("가입일 : " + loginMember.getEnrollDate());
	}

	public void selectAll() {
		
		System.out.println("[가입된 회원 목록 조회]");
	
		// DB에서 회원 정보 모두 조회(아이디, 이름, 가입일)
		// 단, 탈퇴 회원 제외, 아이디 오름차순 조회
		
		try {
			// 회원 정보 조회 Service 호출 후 결과 반환 받기
			List<Member> memberList = service.selectAll();
			
			if(memberList.isEmpty()) { // 비어 있음 == 조회 결과 없음
				System.out.println("조회 결과가 없습니다.");
			
			} else {
				
				// 향샹된 for문
				for(Member mem : memberList) {
					System.out.printf("%12s   %12s   %s\n",
								mem.getMemberId(), mem.getMemberName(),
								mem.getEnrollDate().toString());
				}
			}
			
		} catch(Exception e) {
			System.out.println("\n<회원 목록 조회 과정에서 예외 발생>\n");
			e.printStackTrace();
		}
		
	}

	/** 내 정보 수정
	 * @param loginMember
	 */
	public void updateMyInfo(Member loginMember) {
		
		System.out.println("[내 정보 수정(이름, 성별)]");
		
		System.out.print("변경할 이름 : ");
		String memberName = sc.next();

		System.out.print("변경할 성별(M/F) : ");
		char memberGender = sc.next().toUpperCase().charAt(0);
		
		// 입력 받은 값 + 로그인한 회원 번호를 하나의 Member 객체에 저장
		// (로그인한 회원 번호 == 어떤 회원 정보를 수정할지 지정)
		Member updateMember = new Member();
		
		updateMember.setMemberName(memberName);
		updateMember.setMemberGender(memberGender);
		updateMember.setMemberNo(loginMember.getMemberNo());
		
		try {
			// UPDATE == DML == 수행 성공한 결과 행의 개수를 반환 == 정수형
			int result = service.updateMyInfo(updateMember);
			
			if(result > 0) { // 수정 성공
				System.out.println("\n[회원 정보가 수정되었습니다.]\n");
				
				// DB에 수정된 내용과 현재 로그인한 회원 정보를 일치 시킴
				// 얕은 복사 : 참조 주소만 복사하여 같은 객체를 참조
				// 특징 : 복사된 주소를 참조하여 수정하면 원본 객체가 수정된다.
				loginMember.setMemberName(memberName);
				loginMember.setMemberGender(memberGender);
			} else {
				
				// 수정 실패
				System.out.println("\n[회원 정보 수정에 실패하였습니다.]\n");
			}
			
		} catch(Exception e) {
			System.out.println("\n<내 정보 수정 중 예외 발생>\n");
			e.printStackTrace();
		}
		
	}

	/** 비밀번호 변경
	 * @param loginMember
	 */
	public void updatePw(Member loginMember) {
		
		System.out.println("[비밀번호 변경]");
		
		// 현재 비밀번호 --> DB Update 조건(WHERE)
		System.out.print("현재 비밀번호 : ");
		String currentPw = sc.next();
		
		// 새 비밀번호
		// 새 비밀번호 확인
		// -> 둘이 일치할 때까지 무한 반복
		String newPw = null;
		String newPw2 = null;
		
	
			while(true) {
				System.out.print("새 비밀번호 : ");
				newPw = sc.next();
				
				System.out.print("새 비밀번호 확인 : ");
				newPw2 = sc.next();
				
				if(newPw.equals(newPw2)) {
					break;
				} else {
					System.out.println("\n새 비밀번호가 일치하지 않습니다. 다시 입력해 주세요.\n");
				}
			}
			
			try {
				int result = service.updatePw(loginMember.getMemberNo(), currentPw, newPw);
				
				// 성공 : "[비밀번호가 변경되었습니다.]"
				// 실패 : "[비밀번호가 일치하지 않습니다.]"
				
				if(result > 0) {
					System.out.println("[비밀번호가 변경되었습니다.]");
		
				} else {
					System.out.println("[비밀번호가 일치하지 않습니다.]");
				}
				
		} catch (Exception e) {
			System.out.println("\n비밀번호 변경 중 예외 발생\n");
			e.printStackTrace();
			
		}
	}

	/** 회원 탈퇴
	 * @param loginMember
	 */
	public int secession(Member loginMember) {
		// loginMember = null;
		// -> 매개변수로 전달받은 값(주소 복사본)을 저장할 뿐이다.
		//  -> 복사본이 사라진다고 해도 원본(MainView의 loginMember)은
		//	   사라지지 않는다. -> 로그아웃이 안 된다!
		System.out.println("[회원 탈퇴]");
		
		// 1. 현재 비밀번호 입력 받기
		System.out.print("비밀번호 입력 : ");
		String memberPw = sc.next();
		
		// 2. "정말 탈퇴하시겠습니까?(Y/N)"
		System.out.print("정말 탈퇴하시겠습니까?(Y/N) : ");
		char ch = sc.next().toUpperCase().charAt(0);
		
		// 3. (Y 입력 시) 탈퇴 Service 수행
		if(ch == 'Y') {
			
			try {
				// 로그인한 회원 번호 + 입력 받은 비밀번호
				int result = service.secession(loginMember.getMemberNo(), memberPw);
				
				// 4. 탈퇴 Service 수행 성공 -> "탈퇴되었습니다." -> 로그아웃
				//	  탈퇴 Service 수행 실패 -> "비밀번호가 일치하지 않습니다."
				
				if(result > 0) {
					System.out.println("탈퇴되었습니다.");
					
				} else {
					System.out.println("비밀번호가 일치하지 않습니다.");
				}
				
				return result; // 현재 메소드를 종료하고 호출한 곳으로 돌아감
				
			} catch (Exception e) {
				System.out.println("\n<회원 탈퇴 과정에서 예외 발생>\n");
				e.printStackTrace();
			}
	
		} else {
		// (N 입력 시) "회원 탈퇴 취소"
		System.out.println("\n[회원 탈퇴 취소]\n");
		}
		
		return 0;
	}

}                              

✏️ MemberService 클래스

package edu.kh.jdbc.member.model.service;

// import static 구문 : static 메소드를 import하여
//					   클래스명.static메소드() 형태에서
//					   클래스명을 생략할 수 있게 하는 구문

import static edu.kh.jdbc.common.JDBCTemplate.getConnection;
import static edu.kh.jdbc.common.JDBCTemplate.close;
import static edu.kh.jdbc.common.JDBCTemplate.commit;
import static edu.kh.jdbc.common.JDBCTemplate.rollback;

import java.sql.Connection;
import java.util.List;

import edu.kh.jdbc.common.JDBCTemplate;
import edu.kh.jdbc.member.model.dao.MemberDAO;
import edu.kh.jdbc.member.model.vo.Member;

// Service : 데이터 가공(요청에 맞는 데이터를 만드는 것)
//			+ 트랜잭션 제어 처리
//			-> 하나의 Service 메소드에서 n개의 DAO 메소드를 호출할 수 있음
//				-> n개의 DAO에서 수행된 SQL을 한 번에 commit/rollback

// *** Service에서 트랜잭션을 처리하기 위해서는 Connection 객체가 필요하다. ***
//		== Service에서 Connection 객체를 생성하고 반환해야 한다.

public class MemberService {

	// 회원 관련 SQL 수행 및 결과를 반환할 DAO 객체 생성 및 참조
	private MemberDAO dao = new MemberDAO();
	
	/** 아이디 중복 검사 Service
	 * @param memberId
	 * @return
	 */
	public int duplicateCheck(String memberId) throws Exception {
		
		// 1. Connection 객체 생성
		// -> JDBCTemplate에 작성된 getConnection() 메소드를 이용해 생성 후 얻어옴
		Connection conn = getConnection(); // JDBCTemplate.getConnection()
		
		
		// 2. DAO 메소드(SELECT) 호출 후 결과 반환 받음
		int result = dao.duplicateCheck(conn, memberId);
		
		// (SELECT는 별도의 트랜잭션 제어 필요 없음)
		// 3. 사용한 Connection 객체 반환
		close(conn);
		
		// 4. 중복 검사 결과 View로 반환
		return result;
	}

	/** 회원 가입 Service
	 * @param signUpMember
	 * @return result
	 * @throws Exception
	 */
	public int signUp(Member signUpMember) throws Exception { // 모든 예외는 View에서 모아 처리
		
		// 1) Connection 생성
		Connection conn = getConnection();
		
		// 2) 회원 가입 DAO 메소드 호출하고 결과 반환 받기
		int result = dao.signUp(conn, signUpMember);
		
		// 3) DAO 수행 결과에 따라 트랜잭션 처리
		if(result > 0) commit(conn);
		else		   rollback(conn);
		
		// 4) 사용한 Connection 반환
		close(conn);
		
		// 5) DAO 수행 결과 View로 반환
		
		return result;
	}

	/** 로그인 Service
	 * @param mem
	 * @return loginMember
	 * @throws Exception
	 */
	public Member login(Member mem) throws Exception {
		
		// 1) Connection 생성
		Connection conn = getConnection();
		
		// 2) DAO 메소드 수행 후 결과 반환 받기
		Member loginMember = dao.login(conn, mem);
		
		// (SELECT 수행 -> 트랜잭션 제어 처리 X)
		
		// 3) Connection 반환
		close(conn);
		
		// 4) DAO 조회 결과 View로 반환
		
		return loginMember;
	}

	/** 가입된 회원 목록 조회 Service
	 * @return memberList
	 * @throws Exception
	 */
	public List<Member> selectAll() throws Exception {
		
		// 1) Connection 생성
		Connection conn = getConnection();
		
		// 2) DAO 메소드(SELECT 수행) 호출 후 결과 반환 받기
		List<Member> memberList = dao.selectAll(conn);
		
		// 3) Connection 반환
		close(conn);
		
		// 4) DAO 호출 결과 View 반환
		return memberList;
	}

	/** 내 정보 수정
	 * @param updateMember
	 * @return result
	 * @throws Exception
	 */
	public int updateMyInfo(Member updateMember) throws Exception{
		
		// 1) Connection 생성
		Connection conn = getConnection();
		
		// 2) DAO 수행(UPDATE) 후 결과 반환 받기
		int result = dao.updateMyInfo(conn, updateMember);
		
		// 3) 트랜잭션 처리
		if(result > 0) commit(conn);
		else		   rollback(conn);
		
		// 4) Connection 반환
		close(conn);
		
		// 5) DAO 수행 결과 View로 반환
		return result;
	}

	/** 비밀번호 변경 Service
	 * @param memberNo
	 * @param currentPw
	 * @param newPw
	 * @return result
	 * @throws Exception
	 */
	public int updatePw(int memberNo, String currentPw, String newPw) throws Exception {
		
		// 1) Connection 생성
		Connection conn = getConnection();
		
		// 2) DAO 수행(UPDATE) 후 결과 반환 받기
		int result = dao.updatePw(conn, memberNo, currentPw, newPw);
		
		// 3) 트랜잭션 처리
		if(result > 0) commit(conn);
		else		   rollback(conn);
		
		// 4) Connection 반환
		close(conn);
		
		// 5) DAO 수행 결과 View로 반환
		return result;		
	}

	/** 회원 탈퇴 Service
	 * @param memberNo
	 * @param memberPw
	 * @return result
	 * @throws Exception
	 */
	public int secession(int memberNo, String memberPw) throws Exception {
		
		Connection conn = getConnection();
		
		int result = dao.secession(conn, memberNo, memberPw);
		
		if(result > 0) commit(conn);
		else		   rollback(conn);
		
		close(conn);
		
		return result;
	}

}

✏️ MemberDAO 클래스

package edu.kh.jdbc.member.model.dao;

import static edu.kh.jdbc.common.JDBCTemplate.close;

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import edu.kh.jdbc.member.model.vo.Member;

// DAO (Data Access Object) : 데이터가 저장되어 있는 DB, 파일 등에 접근하는 객체
// 							  -> DB 접근할 수 있다 == SQL을 수행하고 결과를 반환 받을 수 있다.

// java에서 DB에 접근하고 결과를 반환 받기 위한 프로그래밍 API를 제공함
// == JDBC(Connection, Statement, PreparedStatement, ResultSet)

public class MemberDAO {

	private Statement stmt;
	private PreparedStatement pstmt;
	private ResultSet rs = null;
	
	private Properties prop = null;
	// Map인데 K, V가 모두 String, 외부 XML 파일 입출력 특화
	
	
	// MemberDAO 기본 생성자
	public MemberDAO() {
		// MemberDAO 객체 생성 시
		// member-sql.xml 파일의 내용을 읽어와
		// Properties 객체 생성
		
		try {
			prop = new Properties();
			prop.loadFromXML(new FileInputStream("member-sql.xml"));
			
		} catch(Exception e) {
			e.printStackTrace();
		}
		
	}
	
	
	
	/** 아이디 중복 검사 DAO 메소드
	 * @param conn
	 * @param memberId
	 * @return result
	 * @throws Exception
	 */
	public int duplicateCheck(Connection conn, String memberId) throws Exception {
		// throws : 호출한 메소드로 예외를 던짐
		
		// 1) 결과 저장용 변수
		int result = 0;
	
		try {
			// 2) SQL 작성
			String sql = "SELECT COUNT(*) FROM MEMBER WHERE MEMBER_ID = ? AND SECESSION_FL = 'N'";
			
			// 3) PreparedStatement 객체 생성(Connection, SQL 필요)
			pstmt = conn.prepareStatement(sql);
			
			// 4) 위치 홀더 '?'에 알맞은 값 세팅
			pstmt.setString(1, memberId);
			
			// 5) SQL 수행 후 결과 반환 받기
			rs = pstmt.executeQuery(); // SELECT 수행 결과 ResultSet을 반환 받음
			
			// 6) 조회 결과를 한 행씩 접근하여 원하는 컬럼 값 얻어오기
			// -> 아이디 중복 검사 SELECT 결과는 0 또는 1이라는 1행 결과가 무조건 나옴
			// -> while문보다 if문을 사용하는 게 효율적

			if(rs.next()) {
				result = rs.getInt(1); // 1은 컬럼 순서
			}
			
		} finally { // try - finally 구문 (catch는 throws에 의해서 생략)
			
			// 7) 사용한 JDBC 자원 반환(conn 제외)
			close(rs);
			close(pstmt);
		}
		
		// 8) SQL 수행 결과 반환
		return result;
	}

	/** 회원 가입 DAO
	 * @param conn
	 * @param signUpMember
	 * @return result
	 * @throws Exception
	 */
	public int signUp(Connection conn, Member signUpMember) throws Exception {
		
		int result = 0; // 결과 저장용 변수
		
		try {
			// 1) SQL 작성(Properties에 저장된 SQL 얻어오기)
			String sql = prop.getProperty("signUp");
			
			// 2) PreparedStatement 객체 생성(Connection, SQL 필요)
			pstmt = conn.prepareStatement(sql);
			
			// 3) 위치 홀더 '?'에 알맞은 값 세팅
			pstmt.setString(1, signUpMember.getMemberId());
			pstmt.setString(2, signUpMember.getMemberPw());
			pstmt.setString(3, signUpMember.getMemberName());
			pstmt.setString(4, signUpMember.getMemberGender() + "");
			// getMemberGender()의 반환형은 char
			// setString()의 매개변수는 String
			// -> 자료형 불일치로 오류 발생
			
			// --> char 자료형 + ""(빈 문자열) == 문자열
			
			// 4) SQL(INSERT) 수행 후 결과 반환 받기
			result = pstmt.executeUpdate(); // 성공한 행의 개수 반환
			
		} finally {
			// 5) 사용한 JDBC 자원 반환(Connection 제외)
			close(pstmt);
		}
		
		
		return result;
	}

	/** 로그인 DAO
	 * @param conn
	 * @param mem
	 * @return loginMember
	 * @throws Exception
	 */
	public Member login(Connection conn, Member mem) throws Exception {
		
		// 결과 저장용 변수 선언
		Member loginMember = null;
		
		try {
			
			// 1) SQL 작성(Properties에서 얻어오기)
			String sql =  prop.getProperty("login");
			
			// 2) PreparedStatement 생성
			pstmt = conn.prepareStatement(sql);
			
			// 3) 위치 홀더 '?'에 알맞은 값 세팅
			pstmt.setString(1, mem.getMemberId());
			pstmt.setString(2, mem.getMemberPw());
			
			// 4) SQL(SELECT) 수행 후 결과 반환(ResultSet) 받기 (rs 변수 사용)
			rs = pstmt.executeQuery();
			
			// 5) if 또는 while문을 이용해서 rs에 한 행씩 접근하여 원하는 값 얻어오기
			if(rs.next()) {
				int memberNo = rs.getInt("MEMBER_NO");
				String memberId = rs.getString("MEMBER_ID");
				String memberName = rs.getString("MEMBER_NM");
				char memberGender = rs.getString("MEMBER_GENDER").charAt(0);
				Date enrollDate = rs.getDate("ENROLL_DATE");
				
				// 6) 얻어온 컬럼 값을 이용해서 Member 객체를 생성하여 loginMember 변수에 저장
				loginMember = new Member();
				loginMember.setMemberNo(memberNo);
				loginMember.setMemberId(memberId);
				loginMember.setMemberName(memberName);
				loginMember.setMemberGender(memberGender);
				loginMember.setEnrollDate(enrollDate);
			}
			
		} finally {
			// 7) 사용한 JDBC 객체 자원 반환(Connection 제외)
			close(rs);
			close(pstmt);
		}
		
		// 8) DAO 수행 결과 반환
		return loginMember;
	}



	/** 가입된 회원 목록 조회 DAO
	 * @param conn
	 * @return memberList
	 * @throws Exception
	 */
	public List<Member> selectAll(Connection conn) throws Exception{
		
		// 결과 저장용 변수
		List<Member> memberList = new ArrayList<Member>();
		
		try {
			// 1) SQL 작성
			String sql = prop.getProperty("selectAll");
			
			// 2) Statement 객체 생성
			stmt = conn.createStatement();
			
			// 3) SQL(SELECT) 수행 후 결과(ResultSet) 반환 받기
			rs = stmt.executeQuery(sql);
			
			// 4) ResultSet을 한 행씩 접근(rs.next())하여 조회된 컬럼 값을 얻어와
			//	  Member 객체에 저장 (while문 사용하여 반복)
			while(rs.next()) {
				String memberId = rs.getString("MEMBER_ID");
				String memberName = rs.getString("MEMBER_NM");
				Date enrollDate = rs.getDate("ENROLL_DATE");
				
				Member member = new Member();
				member.setMemberId(memberId);
				member.setMemberName(memberName);
				member.setEnrollDate(enrollDate);
				
				// 5) 컬럼 값이 저장된 Member 객체를 List에 추가
				memberList.add(member);
			}
			
		} finally {
			// 6) 사용한 JDBC 자원 반환(Connection 제외)
			close(rs);
			close(stmt);
		}
		
		// 7) 결과 반환
		return memberList;
	}


	/** 내 정보 수정 DAO
	 * @param conn
	 * @param updateMember
	 * @return result
	 * @throws Exception
	 */
	public int updateMyInfo(Connection conn, Member updateMember) throws Exception {
		
		int result = 0; // 결과 저장용 변수 선언
		
		try {
			//1) SQL 작성
			String sql = prop.getProperty("updateMyInfo");
			
			// 2) PreparedStatement 객체 생성
			pstmt = conn.prepareStatement(sql);
			
			// 3) 위치 홀더에 알맞은 값 대입
			pstmt.setString(1, updateMember.getMemberName());
			pstmt.setString(2, updateMember.getMemberGender() + "");
			pstmt.setInt(3, updateMember.getMemberNo());
			
			// 4) SQL(UPDATE) 수행 후 결과(성공한 행의 개수) 반환
			result = pstmt.executeUpdate();
			
		} finally {
			
			// 5) 사용한 JDBC 자원 반환
			close(pstmt);
			
		}
		
		// 6) 결과 반환
		return result;
	}



	/** 비밀번호 변경 DAO
	 * @param conn
	 * @param memberNo
	 * @param currentPw
	 * @param newPw
	 * @return result
	 * @throws Exception
	 */
	public int updatePw(Connection conn, int memberNo, String currentPw, String newPw) throws Exception {
		
		int result = 0; // 결과 저장용 변수 선언
		
		try {
			// 1) SQL
			String sql = prop.getProperty("updatePw");
			
			// 2) PreparedStatement 생성
			pstmt = conn.prepareStatement(sql);
			
			// 3) 위치 홀더에 알맞은 값 대입
			pstmt.setString(1, newPw);
			pstmt.setInt(2, memberNo);
			pstmt.setString(3, currentPw);
			
			// 4) SQL(UPDATE) 수행 후 결과(성공한 행의 개수) 반환
			result = pstmt.executeUpdate();
			
		} finally {
			// 5) 사용한 JDBC 객체 자원 반환
			close(pstmt);
		}
		// 6) 결과 반환
		return result;
	}

	/** 회원 탈퇴 DAO
	 * @param conn
	 * @param memberNo
	 * @param memberPw
	 * @return result
	 * @throws Exception
	 */
	public int secession(Connection conn, int memberNo, String memberPw) throws Exception {

		int result = 0;
		
		try {
			String sql = prop.getProperty("secession");
			
			pstmt = conn.prepareStatement(sql);
			
			pstmt.setInt(1, memberNo);
			pstmt.setString(2, memberPw);
			
			result = pstmt.executeUpdate();
			
		} finally {
			close(pstmt);
		}
		
		return result;
	}
	
}

✏️ Member 클래스

package edu.kh.jdbc.member.model.vo;

import java.sql.Date;

// VO(Value Object) : 값을 저장하는 용도의 객체
// -> 여러 값을 하나의 객체에 저장하여 매개변수 전달, 반환, 컬렉션 등에 이용할 수 있음

public class Member {

	// 필드
	private int memberNo;
	private String memberId;
	private String memberPw;
	private String memberName;
	private char memberGender;
	private Date enrollDate;
	private char secessionFlag;
	
	// 기본 생성자(필수)
	public Member() {}

	// 회원 가입용 생성자(선택)
	public Member(String memberId, String memberPw, String memberName, char memberGender) {
		super();
		this.memberId = memberId;
		this.memberPw = memberPw;
		this.memberName = memberName;
		this.memberGender = memberGender;
	}

	// getter / setter (필수)
	public int getMemberNo() {
		return memberNo;
	}

	public void setMemberNo(int memberNo) {
		this.memberNo = memberNo;
	}

	public String getMemberId() {
		return memberId;
	}

	public void setMemberId(String memberId) {
		this.memberId = memberId;
	}

	public String getMemberPw() {
		return memberPw;
	}

	public void setMemberPw(String memberPw) {
		this.memberPw = memberPw;
	}

	public String getMemberName() {
		return memberName;
	}

	public void setMemberName(String memberName) {
		this.memberName = memberName;
	}

	public char getMemberGender() {
		return memberGender;
	}

	public void setMemberGender(char memberGender) {
		this.memberGender = memberGender;
	}

	public Date getEnrollDate() {
		return enrollDate;
	}

	public void setEnrollDate(Date enrollDate) {
		this.enrollDate = enrollDate;
	}

	public char getSecessionFlag() {
		return secessionFlag;
	}

	public void setSecessionFlag(char secessionFlag) {
		this.secessionFlag = secessionFlag;
	}

	// toString() 오버라이딩 (선택)
	@Override
	public String toString() {
		return "Member [memberNo=" + memberNo + ", memberId=" + memberId + ", memberPw=" + memberPw + ", memberName="
				+ memberName + ", memberGender=" + memberGender + ", enrollDate=" + enrollDate + ", secessionFlag="
				+ secessionFlag + "]";
	}
	
}

✏️ member-sql.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
	<comment>Member Service SQL</comment>
	
	<!-- 회원 가입 -->
	<entry key="signUp">
		INSERT INTO MEMBER
		VALUES(SEQ_MEMBER_NO.NEXTVAL, ?, ?, ?, ?, DEFAULT, DEFAULT)
	</entry>
	
	<!-- 로그인 -->
	<entry key="login">
		SELECT MEMBER_NO, MEMBER_ID, MEMBER_NM, MEMBER_GENDER, ENROLL_DATE
		FROM MEMBER
		WHERE MEMBER_ID = ?
		AND MEMBER_PW = ?
		AND SECESSION_FL = 'N'
	</entry>
	
	<!-- 가입된 회원 목록 조회 -->
	<entry key="selectAll">
		SELECT MEMBER_ID, MEMBER_NM, ENROLL_DATE
		FROM MEMBER
		WHERE SECESSION_FL = 'N'
		ORDER BY MEMBER_ID
	</entry>
	
	<!-- 내 정보 수정 -->
	<entry key="updateMyInfo">
		UPDATE MEMBER SET
		MEMBER_NM = ?,
		MEMBER_GENDER = ?
		WHERE MEMBER_NO = ?
	</entry>
	
	<!-- 비밀번호 변경 -->
	<entry key="updatePw">
		UPDATE MEMBER SET
		MEMBER_PW = ?
		WHERE MEMBER_NO = ?
		AND MEMBER_PW = ?
	</entry>
	
	<!-- 회원 탈퇴 -->
	<entry key="secession">
		UPDATE MEMBER SET
		SECESSION_FL = 'Y'
		WHERE MEMBER_NO = ?
		AND MEMBER_PW = ?
	</entry>
	
</properties>
profile
풀스택 개발자 기록집 📁

0개의 댓글