run 클래스
|
view클래스
|
vo 클래스
|
Controller 클래스
|
Dao클래스
|
실제로 실행하는 클래스
|
사용자에게 메뉴 노출
사용자의 입력값 처리 메뉴 선택시 controller의 메소드 호출(요청) |
Value Object Class
Database테이블과 대응한다. field는 테이블의 컬럼과 대응한다. VO객체 하나가 테이블의 레코드와 대응한다. |
MVC패턴의 가장 중추역할
요청시 view로부터 요청을 받아 dao로 다시 요청을 전달하는 구조. 응답시 dao의 처리 결과값을 받아 view로 리턴처리 |
Database Access Object
전달받은 데이터를 바탕으로 database에 질의(DQL/DML)하는 객체 |
지난 시간에 다음과 같은 클래스를 통해서 회원가입을 하는 코드를 작성했다.
이제 남은 기능인 회원 정보변경, 회원 탈퇴, 회원 전체조회, 이름검색조회 기능을 구현해 보려고 한다.
DQL
//1. jdbc driver class 등록
//2. Connection 객체 생성
//3. PreparedStatement 객체 생성 & 미완성 쿼리 값대입
//4. executeQuery 실행 & ResultSet 리턴받기
//5. ResultSet 처리
//6. 자원반납
DML
//1. jdbc driver class 등록
//2. Connection 객체 생성 & autoCommit false로 설정
//3. PreparedStatement 객체 생성 & 미완성 쿼리 값대입
//4. executeQuery 실행 & ResultSet 리턴받기
//5. 트랜잭션 하기 (commit)
//6. 자원반납
코드를 짜는 방식은 MemberMenu(View)의 switch문에서 컨트롤러로 보내는 코드 작성(리턴값 필수) -> Controller에서 Dao로 보내는 코드 작성 (리턴값 필수) -> Dao에서 기능 실현 (리턴값 필수)
리턴값이 있어야 응답하는 값도 존재하기 때문에 꼭 제대로 리턴해주어야한다!
코드의 구조
이제 방법을 알았으니 하나하나 짜보도록 한다.
회원 전체조회(DQL)
1. View에서 Controller로 보내는 코드를 작성한다.
1-1. MemberMenu의 switch문 내에 작성하기.
switch(choice) {
case "1":
//전체조회 : select * from member order by reg_date desc
members=memberController.findAll();
printMembers(members);
break;
case "2": break;
case "3": break;
case "4":
member=inputMember();
System.out.println("member@mainMenu = "+member);
result = memberController.insertMember(member);
System.out.println(result >0?"> 회원가입 성공!":"> 회원가입 실패!");
break;
case "5": break;
//이름, 성별, 생일, 이메일을 한번에 변경할 것.
case "6": break;
case "0": return;
default : System.out.println("잘못 입력하셨습니다.");
}
1-2. printMembers 함수 view에 만들기
printMembers는 0~n건을 한번에 조회한다. 실제 조회 결과가 0건이면 빈 ArrayList를 반환하도록 코드를 짜본다.
(실제로 오라클에서도 조회 결과가 0건이어도 빈 결과를 나타내기 때문)
눌러서 printMembers 작성
private void printMembers(List<Member> members) {
if(members==null||members.isEmpty()) {
System.out.println("> 조회된 결과가 없습니다.");
}
else {
System.out.println("-----------------------------------------");
System.out.printf("%s\t%s\t%s\t%s\t%s\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.getEmail(),
member.getBirthday(),
member.getEmail(),
member.getPoint(),
simpleRegDateFormat.format(member.getRegDate()));
}
}
}
마지막의 simpleRegDateFormat은 우리가 원하는 포맷으로 나오게 하기 위함으로,
MemberMenu 클래스 안 가장 상단에
SimpleDateFormat simpleRegDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");
와 같이 써주면 우리가 원하는 형식으로 나오게 된다!
2. Controller에서 Dao로 보내는 코드를 작성한다.
2-1. MemberMenu에서 Create method 'findAll()' in type 'MemberController' 선택
2-2. MemberController에서 findAll 함수 작성
public List<Member> findAll() {
List<Member> members = memberDao.findAll();
return members;
}
3. Dao에서 기능 실현
3-1. MemberController에서 Create method 'findAll()' in type 'MemberDao' 클릭
3-2. findAll()에서 DQL 기능 실현
DQL 레시피
//1. jdbc driver class 등록
//2. Connection 객체 생성
//3. PreparedStatement 객체 생성 & 미완성 쿼리 값대입
//4. executeQuery 실행 & ResultSet 리턴받기
//5. ResultSet 처리
//6. 자원반납
public List<Member> findAll() {
Connection conn=null;
PreparedStatement pstmt=null;
ResultSet rset=null;
List<Member> members = new ArrayList<>();
String sql="select * from member order by reg_date desc";
try {
// 1. jdbc driver class 등록
Class.forName(driverClass);
// 2. Connection객체 생성
conn = DriverManager.getConnection(url, user, password);
// 3. PreparedStatment객체 생성 & 미완성쿼리 값대입
pstmt = conn.prepareStatement(sql);
// 4. executeQuery 실행 & ResultSet 리턴받기
rset = pstmt.executeQuery();
// 5. ResultSet 처리
while(rset.next()) {
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"));
members.add(member);
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
// 6. 자원반납 : 생성의 역순으로 반환
try {
rset.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
pstmt.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return members;
}
Member Run 에서 돌려보면
다음과 같이 제대로 보여지는 것을 확인할 수 있다.
다른 기능들도 DQL이냐, DML이냐에 따라 MemberDao만 조금 다를 뿐, 거의 같은 내용이므로 위와 같은 순서에 따라 작성한다.
회원 아이디로 조회(DQL)
1. View에서 Controller로 보내는 코드를 작성한다.
1-1. MemberMenu의 switch문 내에 작성하기.
while(true) {
System.out.println(menu);
String choice = sc.next();
Member member=null;
String id=null;
String name=null;
int result=0;
List<Member> members=null;
switch(choice) {
case "1":
//전체조회 : select * from member order by reg_date desc
members=memberController.findAll();
printMembers(members);
break;
case "2":
//이름조회 : select * from member where id =?
member=memberController.findById(id);
printMember(member);
break;
case "3": break;
case "4":
member=inputMember();
System.out.println("member@mainMenu = "+member);
result = memberController.insertMember(member);
System.out.println(result >0?"> 회원가입 성공!":"> 회원가입 실패!");
break;
case "5": break;
//이름, 성별, 생일, 이메일을 한번에 변경할 것.
case "6": break;
case "0": return;
default : System.out.println("잘못 입력하셨습니다.");
}
}
1-2. PrintMember작성 - printMember는 조회 결과가 0건이면 null을 리턴한다.
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("---------------------------------");
}
}
2. Controller에서 Dao로 보내는 코드를 작성한다.
2. MemberController에서 findById 함수 작성
public Member findById(String id) {
Member member= memberDao.findById(id);
return member;
}
3. Dao에서 기능 실현
3. MemberDao 의 findById()에서 DQL 기능 실현
DQL 레시피
//1. jdbc driver class 등록
//2. Connection 객체 생성
//3. PreparedStatement 객체 생성 & 미완성 쿼리 값대입
//4. executeQuery 실행 & ResultSet 리턴받기
//5. ResultSet 처리
//6. 자원반납
public Member findById(String id) {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rset = null;
Member member = null; // 0 ~ 1건이 조회시, 실제조회결과가 0건이면, null를 리턴.
String sql = "select * from member where id = ?";
try {
// 1. jdbc driver class 등록
Class.forName(driverClass);
// 2. Connection객체 생성
conn = DriverManager.getConnection(url, user, password);
// 3. PreparedStatment객체 생성 & 미완성쿼리 값대입
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, id);
// 4. executeQuery 실행 & ResultSet 리턴받기
rset = pstmt.executeQuery();
// 5. ResultSet 처리
while(rset.next()) {
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"));
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
// 6. 자원반납 : 생성의 역순으로 반환
try {
rset.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
pstmt.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return member;
}
제대로 출력되는 것 확인.
회원 정보 변경 (DML)
1. View에서 Controller로 보내는 코드를 작성한다.
1-1. MemberMenu의 switch문 내에 작성하기.
while(true) {
System.out.println(menu);
String choice = sc.next();
Member member=null;
String id=null;
String name=null;
int result=0;
List<Member> members=null;
switch(choice) {
case "1":
//전체조회 : select * from member order by reg_date desc
members=memberController.findAll();
printMembers(members);
break;
case "2":
//이름조회 : select * from member where id =?
member=memberController.findById(id);
printMember(member);
break;
case "3": break;
case "4":
member=inputMember();
System.out.println("member@mainMenu = "+member);
result = memberController.insertMember(member);
System.out.println(result >0?"> 회원가입 성공!":"> 회원가입 실패!");
break;
case "5": break;
//이름, 성별, 생일, 이메일을 한번에 변경할 것.
// update member set name = ?, gender = ?, birthday = ?, email = ? where id = ?
member = updateMember();
result = memberController.updateMember(member);
System.out.println(result > 0 ? "> 회원정보 수정 성공!" : "> 회원정보 수정 실패!");
case "6": break;
case "0": return;
default : System.out.println("잘못 입력하셨습니다.");
}
}
1-2. updateMember작성 - 이름, 성별, 생일, 이메일을 한꺼번에 수정한다.
private Member updateMember() {
System.out.println("> 수정할 회원 아이디를 입력하세요.");
System.out.print("아이디 : ");
String id = sc.next();
System.out.println("> 수정할 회원 정보를 입력하세요.");
System.out.print("이름 : ");
String name = sc.next();
System.out.print("성별(M/F) : ");
String gender = String.valueOf(sc.next().toUpperCase().charAt(0)); // "mm" -> "MM" -> 'M'
System.out.print("생일(19990909) : ");
String temp = sc.next();
Date birthday = null;
// 문자열 -> java.util.Date -> java.sql.Date
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
try {
birthday = new Date(sdf.parse(temp).getTime());
} catch (ParseException e) {
e.printStackTrace();
}
System.out.print("이메일 : ");
String email = sc.next();
return new Member(id, name, gender, birthday, email, 0, null);
}
2. Controller에서 Dao로 보내는 코드를 작성한다.
2. MemberController에서 updateMember 함수 작성
public int updateMember(Member member) {
return memberDao.updateMember(member);
}
3. Dao에서 기능 실현
3. MemberDao 의 updateMember()에서 DML 기능 실현
DML 레시피
//1. jdbc driver class 등록
//2. Connection 객체 생성 & autoCommit false로 설정
//3. PreparedStatement 객체 생성 & 미완성 쿼리 값대입
//4. executeQuery 실행 & ResultSet 리턴받기
//5. 트랜잭션 하기 (commit)
//6. 자원반납
public int updateMember(Member member) {
int result = 0;
Connection conn = null;
PreparedStatement pstmt = null;
// 여러줄 작성시 키워드, 값 사이의 공란추가할 것!
String sql = "update member "
+ "set name = ?, "
+ "gender = ?, "
+ "birthday = ?, "
+ "email = ?, "
+ "where id = ?";
try {
// 1. jdbc driver class 등록
Class.forName(driverClass);
// 2. Connection객체 생성 & autoCommit false로 설정
conn = DriverManager.getConnection(url, user, password);
conn.setAutoCommit(false);
//3. PreparedStatment객체 생성 & 미완성쿼리 값대입
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, member.getName());
pstmt.setString(2, member.getGender());
pstmt.setDate(3, member.getBirthday());
pstmt.setString(4, member.getEmail());
pstmt.setString(5, member.getId());
// 4. executeUpdate 실행 & 정수형(처리된 행수) 리턴값
result = pstmt.executeUpdate();
// 5. 트랜잭션
conn.commit();
} catch (ClassNotFoundException | SQLException e) {
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
e.printStackTrace();
} finally {
// 6. 자원반납 : 생성의 역순으로 반환
try {
pstmt.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
}
return result;
}
Run에서 돌려보면
제대로 수정되는 것 확인.
요약 )
run -> view -> controller -> dao -> db 를 거치면서 데이터가 전달된다.
db -> dao -> controller -> view -> run 으로 다시 돌아오면서 (return 받으면서 전달) 데이터가 다시 돌아온다.
이 과정을 거치면서 jdbc에서 데이터 입출력수정 등이 가능해진다.