안녕하세요, 코린이의 코딩 학습기 채니 입니다.
개인 포스팅용으로 내용에 오류 및 잘못된 정보가 있을 수 있습니다.
MVC pattern 2
* run → 실행 메소드가 있는 실행 클래스
* view → 사용자가 보게 될 메뉴 제공
* controller → 사용자가 메뉴 선택하면 controller에서 요청을 받아 시작
* service → 업무로직 business logic 수행
* dao(Data Access Object) → DB에 접근하기 위한 클래스
* JdbcTemplate → 각종 중복 코드 모음 (Connection 객체 생성, close, commit, rollback)
Service 클래스
- 업무로직 business logic 수행
--------------SERVICE 시작--------------------
1. jdbc driver class 등록
2. Connection객체 생성 & setAUtoCommit(false)
-----------------DAO 시작---------------------
3. PreparedStatment객체 생성 & 미완성쿼리 값대입
4. 실행 & 결과 값 받기 (ResultSet, int)
5. 자원반납(pstmt, rset)
------------------DAO 끝----------------------
6. 트랜잭션 처리
7. 자원반납(conn)
---------------SERVICE 끝---------------------
Member(VO)
package member.model.vo;
import java.sql.Date;
import java.sql.Timestamp;
/**
* VO
* - Value Object
* - Database 테이블과 대응
* - field는 테이블의 컬럼과 대응
* - VO 객체 하나가 테이블의 레코드와 대응
*
*/
public class Member {
/*
ID NOT NULL VARCHAR2(20)
NAME NOT NULL VARCHAR2(100)
GENDER CHAR(1)
BIRTHDAY DATE
EMAIL NOT NULL VARCHAR2(500)
POINT NUMBER
REG_DATE TIMESTAMP(6)
*/
private String id;
private String name;
private String gender; // char여도 String으로 처리! 나중에 복잡해짐
private Date birthday;
private String email;
private int point;
private Timestamp regDate;
public Member(String id, String name, String gender, Date birthday, String email, int point, Timestamp regDate) {
super();
this.id = id;
this.name = name;
this.gender = gender;
this.birthday = birthday;
this.email = email;
this.point = point;
this.regDate = regDate;
}
public Member(String id, String name, String gender, Date birthday, String email) {
this.id = id;
this.name = name;
this.gender = gender;
this.birthday = birthday;
this.email = email;
}
public Member() {
super();
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public int getPoint() {
return point;
}
public void setPoint(int point) {
this.point = point;
}
public Timestamp getRegDate() {
return regDate;
}
public void setRegDate(Timestamp regDate) {
this.regDate = regDate;
}
@Override
public String toString() {
return "Member [id=" + id + ", name=" + name + ", gender=" + gender + ", birthday=" + birthday + ", email="
+ email + ", point=" + point + ", regDate=" + regDate + "]";
}
}
MemberRun
package member.run;
import member.view.MemberMenu;
public class MemberRun {
public static void main(String[] args) {
new MemberMenu().mainMenu();
System.out.println("이용해주셔서 감사합니다.");
}
}
MemberMenu(View)
package member.view;
import java.sql.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Scanner;
import member.controller.MemberController;
import member.model.vo.Member;
public class MemberMenu {
private MemberController memberController = new MemberController();
private Scanner sc = new Scanner(System.in);
private SimpleDateFormat simpleRegDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
public void mainMenu() {
String menu = "\n******** 회원 정보 관리2-1 ********\n"
+ "1. 전체 조회\n"
+ "2. 아이디 조회\n"
+ "3. 이름 검색 \n"
+ "4. 회원가입\n"
+ "5. 회원 정보 변경\n"
+ "6. 회원 탈퇴\n"
+ "0. 프로그램 종료\n"
+ "*****************************\n"
+ "선택 : ";
while(true) {
System.out.print(menu);
String choice = sc.next();
Member member = null;
List<Member> members = null;
int result = 0;
String id = null;
String name = null;
switch(choice) {
case "1" :
members = memberController.findAll();
printMembers(members);
break;
case "2" :
id = findId();
member = memberController.findById(id);
printMember(member);
break;
case "3" :
name = findName();
members = memberController.findByName(name);
printMembers(members);
break;
case "4" :
member = inputMember();
result = memberController.inputMember(member);
displayResult(result, "회원가입");
break;
case "5" :
updateMemberInfo();
break;
case "6" :
id = findId();
result = memberController.deleteMember(id);
displayResult(result, "회원탈퇴");
break;
case "0" : return;
default : System.out.println("잘못 입력하셨습니다.");
}
}
}
// 전체 회원 조회
private void printMembers(List<Member> members) {
if(members == null || members.isEmpty()) {
System.out.println("> 조회된 결과가 없습니다.");
} else {
System.out.printf("%s\t%s\t%s\t%s\t%s\t\t%s\t%s\t\n",
"id", "name", "gender", "birthday", "email", "point", "regDate");
System.out.println("-------------------------------------------------------------------------");
for(Member member : members) {
System.out.printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\t\n",
member.getId(),
member.getName(),
member.getGender(),
member.getBirthday(),
member.getEmail(),
member.getPoint(),
simpleRegDateFormat.format(member.getRegDate())
);
}
System.out.println("-------------------------------------------------------------------------");
}
}
// 아이디 조회
private String findId() {
System.out.print("> 아이디를 입력하세요 : ");
return sc.next();
}
// 회원 한 명 조회
private void printMember(Member member) {
if(member == null)
System.out.println("> 조회된 결과가 없습니다.");
else {
System.out.println("-------------------------------------------");
System.out.printf("%-10s : %s\n", "id", member.getId());
System.out.printf("%-10s : %s\n", "name", member.getName());
System.out.printf("%-10s : %s\n", "gender", member.getGender());
System.out.printf("%-10s : %s\n", "birthday", member.getBirthday());
System.out.printf("%-10s : %s\n", "email", member.getEmail());
System.out.printf("%-10s : %s\n", "point", member.getPoint());
System.out.printf("%-10s : %s\n", "regDate", simpleRegDateFormat.format(member.getRegDate()));
System.out.println("-------------------------------------------");
}
}
// 이름 검색
private String findName() {
System.out.print("> 이름을 입력하세요 : ");
return sc.next();
}
// 회원가입
private Member inputMember() {
Member member = new Member();
// 아이디 중복 검사
while(true) {
System.out.print("> 아이디를 입력하세요 : ");
String id = sc.next();
if(memberController.findById(id) != null) {
System.out.printf("> [%s]는 사용 불가능한 아이디입니다. 다시 입력하세요.", id);
} else {
System.out.printf("> [%s]는 사용 가능한 아이디입니다 :)", id);
member.setId(id);
break;
}
}
System.out.print("> 이름을 입력하세요 : ");
member.setName(sc.next());
System.out.print("> 성별을 입력하세요(M/F) : ");
member.setGender(String.valueOf(sc.next().toUpperCase().charAt(0)));
System.out.print("> 생년월일을 입력하세요(19990909) : ");
String temp = sc.next();
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
try {
member.setBirthday(new Date(sdf.parse(temp).getTime()));
} catch (ParseException e) {
e.printStackTrace();
}
System.out.print("> 이메일을 입력하세요 : ");
member.setEmail(sc.next());
return member;
}
// 회원 정보 수정
private void updateMemberInfo() {
String menu = "******* 회원 정보 변경 메뉴 *******\n"
+ "1. 이름 변경\n"
+ "2. 생일 변경\n"
+ "3. 이메일 변경\n"
+ "9. 메인 메뉴 돌아가기\n"
+ "*******************************\n"
+ "선택 : ";
String id = findId();
while(true) {
Member member = memberController.findById(id);
if(member == null) {
System.out.println("> 조회된 회원이 없습니다.");
return;
}
else {
System.out.println("================== 기존정보 =================");
printMember(member);
}
System.out.print(menu);
String input = sc.next();
int result = 0;
SimpleDateFormat birthdayFormat = new SimpleDateFormat("yyyyMMdd");
switch(input) {
case "1" :
System.out.print("> 변경할 이름을 입력하세요 : ");
String name = sc.next();
result = memberController.updateMember("name", id, name);
break;
case "2" :
System.out.print("> 변경할 생년월일을 입력하세요 : ");
String temp = sc.next();
Date birthday = null;
try {
birthday = new Date(birthdayFormat.parse(temp).getTime());
} catch (ParseException e) {
e.printStackTrace();
}
result = memberController.updateMember("birthday", id, birthday);
break;
case "3" :
System.out.print("> 변경할 이메일을 입력하세요 : ");
String email = sc.next();
result = memberController.updateMember("email", id, email);
break;
case "9" : return;
default : System.out.println("잘못 입력하셨습니다.");
}
if(result > 0) {
displayResult(result, "정보변경");
System.out.println("================== 변경 후 =================");
printMember(memberController.findById(id));
}
}
}
private void displayResult(int result, String type) {
if(result > 0)
System.out.println("> " + type + " 성공!");
else
System.out.println("> " + type + " 실패!");
}
}
MemberController
package member.controller;
import java.util.List;
import member.model.service.MemberService;
import member.model.vo.Member;
public class MemberController {
private MemberService memberService = new MemberService();
// 1. 전체 회원 조회
public List<Member> findAll() {
return memberService.findAll();
}
// 2. 아이디 조회
public Member findById(String id) {
return memberService.findById(id);
}
// 3. 이름 조회
public List<Member> findByName(String name) {
return memberService.findByName(name);
}
// 4. 회원가입
public int inputMember(Member member) {
return memberService.inputMember(member);
}
// 5. 정보 변경
public int updateMember(String type, String id, Object changeVal) {
return memberService.updateMember(type, id, changeVal);
}
// 6. 회원 탈퇴
public int deleteMember(String id) {
return memberService.deleteMember(id);
}
}
MemberService
package member.model.service;
// 클래스 명 없이도 static 자원을 불러올 수 있음!
import static member.common.JdbcTemplate.close;
import static member.common.JdbcTemplate.commit;
import static member.common.JdbcTemplate.getConnection;
import static member.common.JdbcTemplate.rollback;
import java.sql.Connection;
import java.util.List;
import member.model.dao.MemberDao;
import member.model.vo.Member;
/**
* Service 클래스
* - 업무로직 business logic 수행
* --------------SERVICE 시작--------------------
* 1. jdbc driver class 등록
* 2. Connection객체 생성 & setAUtoCommit(false)
* -----------------DAO 시작---------------------
* 3. PreparedStatment객체 생성 & 미완성쿼리 값대입
* 4. 실행 & 결과 값 받기 (ResultSet, int)
* 5. 자원반납(pstmt, rset)
* ------------------DAO 끝----------------------
* 6. 트랜잭션 처리
* 7. 자원반납(conn)
* ---------------SERVICE 끝---------------------
*
*/
public class MemberService {
private MemberDao memberDao = new MemberDao();
// 전체 회원 조회
public List<Member> findAll() {
Connection conn = getConnection(); // 커밋, 롤백에 대한 처리 필요없음!
List<Member> members = memberDao.findAll(conn);
close(conn);
return members;
}
// 아이디 조회
public Member findById(String id) {
Connection conn = getConnection();
Member member = memberDao.findById(conn, id);
close(conn);
return member;
}
// 이름 조회
public List<Member> findByName(String name) {
Connection conn = getConnection();
List<Member> members = memberDao.findByName(conn, name);
close(conn);
return members;
}
// 회원가입
public int inputMember(Member member) {
int result = 0;
Connection conn = null;
// 예외 발생 여부에 따라 커밋인지 롤백인지 결정하므로 try~catch 필요
try {
conn = getConnection();
result = memberDao.inputMember(conn, member);
commit(conn);
} catch (Exception e) {
rollback(conn);
e.printStackTrace();
} finally {
close(conn);
}
return result;
}
// 회원 정보 수정
public int updateMember(String type, String id, Object changeVal) {
Connection conn = null;
int result = 0;
try {
conn = getConnection();
result = memberDao.updateMember(conn, type, id, changeVal);
commit(conn);
} catch(Exception e) {
rollback(conn);
e.printStackTrace();
} finally {
close(conn);
}
return result;
}
// 회원 탈퇴
public int deleteMember(String id) {
Connection conn = null;
int result = 0;
// 예외 발생 여부에 따라 커밋인지 롤백인지 결정하므로 try~catch 필요
try {
conn = getConnection();
result = memberDao.deleteMember(conn, id);
commit(conn);
} catch(Exception e) {
rollback(conn);
e.printStackTrace();
}
return result;
}
}
import static 패키지명.클래스명.* 하면 해당 클래스의 모든 static 메소드들을 import 가능!
MemberDao
package member.model.dao;
import static member.common.JdbcTemplate.close;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import member.model.vo.Member;
/**
* --------------SERVICE 시작--------------------
* 1. jdbc driver class 등록
* 2. Connection객체 생성 & setAUtoCommit(false)
* -----------------DAO 시작---------------------
* 3. PreparedStatment객체 생성 & 미완성쿼리 값대입
* 4. 실행 & 결과 값 받기 (ResultSet, int)
* 5. 자원반납(pstmt, rset)
* ------------------DAO 끝----------------------
* 6. 트랜잭션 처리
* 7. 자원반납(conn)
* ---------------SERVICE 끝---------------------
*
*/
public class MemberDao {
// 전체 회원 조회
public List<Member> findAll(Connection conn) {
PreparedStatement pstmt = null;
ResultSet rset = null;
List<Member> members = new ArrayList<>();
String sql = "select * from member order by reg_date desc";
try {
pstmt = conn.prepareStatement(sql);
rset = pstmt.executeQuery();
while(rset.next()) {
members.add(handleMemberResult(rset));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(rset);
close(pstmt);
}
return members;
}
// 아이디 조회
public Member findById(Connection conn, String id) {
PreparedStatement pstmt = null;
ResultSet rset = null;
Member member = null;
String sql = "select * from member where id = ?";
try {
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, id);
rset = pstmt.executeQuery();
while(rset.next()) {
member = handleMemberResult(rset);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(rset);
close(pstmt);
}
return member;
}
// 이름 조회
public List<Member> findByName(Connection conn, String name) {
PreparedStatement pstmt = null;
ResultSet rset = null;
List<Member> members = new ArrayList<>();
String sql = "select * from member where name like ?";
try {
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "%" + name + "%");
rset = pstmt.executeQuery();
while(rset.next()) {
Member member = handleMemberResult(rset);
members.add(member);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(rset);
close(pstmt);
}
return members;
}
// 회원 가입
public int inputMember(Connection conn, Member member) {
PreparedStatement pstmt = null;
int result = 0;
String sql = "insert into member values(?, ?, ?, ?, ?, default, default)";
try {
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, member.getId());
pstmt.setString(2, member.getName());
pstmt.setString(3, member.getGender());
pstmt.setDate(4, member.getBirthday());
pstmt.setString(5, member.getEmail());
result = pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(pstmt);
}
return result;
}
// 회원 정보 수정
public int updateMember(Connection conn, String type, String id, Object changeVal) {
PreparedStatement pstmt = null;
int result = 0;
String sql = "update member set % = ? where id = ?";
try {
pstmt = conn.prepareStatement(sql.replace("%", type));
pstmt.setObject(1, changeVal);
pstmt.setString(2, id);
result = pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(pstmt);
}
return result;
}
// 회원 탈퇴
public int deleteMember(Connection conn, String id) {
PreparedStatement pstmt = null;
int result = 0;
String sql = "delete from member where id = ?";
try {
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, id);
result = pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(pstmt);
}
return result;
}
// ResultSet의 현재 행을 Member VO객체로 변환
public Member handleMemberResult(ResultSet rset) throws SQLException {
Member member = new Member();
member.setId(rset.getString("id"));
member.setName(rset.getString("name"));
member.setGender(rset.getString("gender"));
member.setBirthday(rset.getDate("birthday"));
member.setEmail(rset.getString("email"));
member.setPoint(rset.getInt("point"));
member.setRegDate(rset.getTimestamp("reg_date"));
return member;
}
}
※ MemberDao와 MemberService에서 사용한 자원들만 반납해야하는 점 주의!!!
JdbcTemplate
package member.common;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* JDBC API를 사용하면서 중복된 코드를 static 메소드로 작성
*
*/
public class JdbcTemplate {
static final String driverClass = "oracle.jdbc.OracleDriver";
static final String url = "jdbc:oracle:thin:@localhost:1521:xe"; // db접속프로토콜@ip:포트:db명(sid)
static final String user = "student";
static final String password = "비번";
static {
// driver class 등록 - application 실행 시 최초 1회만
try {
Class.forName(driverClass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* Connection 객체 생성
* setAutoCommit(false) - 트랙잭션을 직접 관리 (DQM, DML)
*/
public static Connection getConnection() {
Connection conn = null;
try {
conn = DriverManager.getConnection(url, user, password);
conn.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public static void close(PreparedStatement pstmt) {
try {
if(pstmt != null && !pstmt.isClosed())
pstmt.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void close(Connection conn) {
try {
if(conn != null && !conn.isClosed())
conn.close();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void close(ResultSet rset) {
try {
if(rset != null && !rset.isClosed())
rset.close();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void commit(Connection conn) {
try {
conn.commit();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void rollback(Connection conn) {
try {
conn.rollback();
} catch (Exception e) {
e.printStackTrace();
}
}
}
driver class는 application 실행 시 최초 1회만 실행해도 되므로, static 블럭에 작성하였습니다.
이렇게 코드의 중복성을 제거 및 직관적으로 볼 수 있게 할 수 있습니다.
'Java > JDBC' 카테고리의 다른 글
JDBC) Properties 이용하여 정보 보호, SQL문 관리, 예외처리 (0) | 2022.05.10 |
---|---|
JDBC) MVC pattern (회원관리 프로젝트, 회원가입 처리) (0) | 2022.05.04 |
JDBC) JDBC Coding 절차 (DQL, DML) (0) | 2022.05.04 |
JDBC) 환경 설정 및 이클립스와 오라클 연동 (0) | 2022.05.04 |