MVC 흐름
① [Run 클래스] 실행하여 View 클래스 호출
② [View 클래스] 사용자가 전달값을 입력(Scanner)한 후 Controller 클래스 호출
③ [Controller 클래스] 사용자의 요청을 전달받은 후 데이터를 가공 처리하여 Dao에 전달 및 호출
④ [Dao 클래스]
ⓐ Connection을 생성하여 DB에 접속
ⓑ SQL 구문 실행
ⓒ 해당하는 결과 받기
- SELECT문의 경우: ResultSet으로
- DML문의 경우: int형 타입으로
ⓓ DML문일 경우엔 트랜잭션 처리(commit(); / rollback();)
ⓔ 결과를 Controller 클래스로 리턴
⑤ [Controller 클래스] Dao 클래스로부터 반환받은 결과에 따라 View(성공 또는 실패 화면) 결정 및 호출
⑥ [View 클래스] 출력(print)
VO(Value Object)
: DB 테이블의 한 행에 대한 데이터를 기록할 수 있는 저장용 객체 클래스이다.
- 유사 용어: DTO(Data Transfer Object), DO(Domain Object), Entity, bean
- VO의 조건
① 반드시 캡슐화를 적용해야 한다.
② 기본 생성자 및 매개변수 생성자를 작성해야 한다.
③ 모든 필드에 대해 getter/setter 메소드를 작성해야 한다.
package member.model.vo;
import java.sql.Date;
public class Member {
//DB 테이블의 컬럼 정보와 유사하게 작성한다.
private int userNo;// USERNO NUMBER PRIMARY KEY,
private String userId;// USERID VARCHAR2(20) UNIQUE NOT NULL,
private String userPw;// USERPW VARCHAR2(20) NOT NULL,
private String userName;// USERNAME VARCHAR2(20) NOT NULL,
private String gender;// GENDER CHAR(1) CHECK (GENDER IN('M', 'F')),
private int age;// AGE NUMBER,
private String email;// EMAIL VARCHAR2(30),
private String phone;// PHONE CHAR(11),
private String address;// ADDRESS VARCHAR2(100),
private String hobby;// HOBBY VARCHAR2(50),
private Date enrollDate;// ENROLLDATE DATE DEFAULT SYSDATE NOT NULL
public Member() {
super();
}
public Member(int userNo, String userId, String userPw, String userName
, String gender, int age, String email, String phone, String address
, String hobby, Date enrollDate) {
super();
this.userNo = userNo;
this.userId = userId;
this.userPw = userPw;
this.userName = userName;
this.gender = gender;
this.age = age;
this.email = email;
this.phone = phone;
this.address = address;
this.hobby = hobby;
this.enrollDate = enrollDate;
}
// 회원 추가용 생성자(userNo와 enrollDate 제외한 매개변수 생성자)
public Member(String userId, String userPw, String userName, String gender
, int age, String email, String phone, String address, String hobby) {
super();
this.userId = userId;
this.userPw = userPw;
this.userName = userName;
this.gender = gender;
this.age = age;
this.email = email;
this.phone = phone;
this.address = address;
this.hobby = hobby;
}
public int getUserNo() {
return userNo;
}
public void setUserNo(int userNo) {
this.userNo = userNo;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserPw() {
return userPw;
}
public void setUserPw(String userPw) {
this.userPw = userPw;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
public Date getEnrollDate() {
return enrollDate;
}
public void setEnrollDate(Date enrollDate) {
this.enrollDate = enrollDate;
}
@Override
public String toString() {
return "Member [userNo=" + userNo + ", userId=" + userId + ", userPw=" + userPw + "
, userName=" + userName, gender=" + gender + ", age=" + age + "
, email=" + email + ", phone=" + phone + ", address=" + address + "
, hobby=" + hobby + ", enrollDate=" + enrollDate + "]";
}
}
Run
: 실행하는 클래스
package member.run;
import member.view.View;
public class Run {
public static void main(String[] args) {
new View().mainMenu();
}
}
View
: 사용자가 보는 화면(시각적 요소)을 담당하는 클래스
package member.view;
import java.util.ArrayList;
import java.util.Scanner;
import member.controller.Controller;
import member.model.vo.Member;
public class View {
// 전역으로 쓸 수 있는 Scanner 객체 생성
private Scanner sc = new Scanner(System.in);
// 전역으로 MemberController에 요청할 수 있는 객체 생성
private MemberController mc = new MemberController();
public void mainMenu() {
// 프로그램 종료 전까지 메뉴 선택을 반복하기 위해 while문으로 감싸기
while(true) {
System.out.println("========회원관리 프로그램=========");
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("0. 프로그램 종료");
System.out.println("=================================");
System.out.println("원하는 메뉴 번호를 입력하세요. ");
int menu = sc.nextInt();
sc.nextLine();
switch(menu) {
case 1: insertMember(); break;
case 2: selectAll(); break;
case 3: searchById(); break;
case 4: searchByName(); break;
case 5: updateMember(); break;
case 6: deleteMember(); break;
case 0: System.out.println("프로그램을 종료합니다."); return;
// break;를 쓰면 스위치문에서만 벗어나고 다시 반복됨
default: System.out.println("메뉴번호를 잘못 입력하였습니다.");
}
}
}
// 추가하고자 하는 회원의 정보를 입력받아 Controller에 추가 요청을 하는 화면
// 1. 회원 추가 화면
public void insertMember() {
System.out.println("----------회원 추가----------");
// 입력
// 회원번호(시퀀스)와 enrollDate(default SYSDATE) 두 컬럼에 대해서는 입력받지 않는다.
System.out.println("아이디: ");
String userId = sc.nextLine();
System.out.println("비밀번호: ");
String userPw = sc.nextLine();
System.out.println("이름: ");
String userName = sc.nextLine();
System.out.println("성별: ");
String gender = sc.nextLine();
System.out.println("나이: ");
int age = sc.nextInt();
sc.nextLine(); // 엔터 날리기
System.out.println("이메일: ");
String email = sc.nextLine();
System.out.println("휴대번호: (- 없이 숫자만 입력)");
String phone = sc.nextLine();
System.out.println("주소: ");
String address = sc.nextLine();
System.out.println("취미: ");
String hobby = sc.nextLine();
// 입력받은 정보를 매개변수로 넘겨서 회원 추가 요청
// Controller에 있는 메소드를 호출.
mc.insertMember(userId, userPw, userName, gender, age, email, phone, address, hobby);
}
// 2. 회원 전체 조회 화면
public void selectAll() {
System.out.println("--------회원 전체 조회--------");
// Controller에 회원 전체 조회 요청
mc.selectAll();
}
// 3. 회원 아이디로 검색하는 화면
public void searchById() {
System.out.println("-------회원 아이디로 검색-------");
System.out.println("검색할 회원의 아이디 입력: ");
String userId = sc.nextLine();
// 입력한 아이디로 Controller에 요청하기
mc.searchById(userId);
}
// 4. 회원 이름으로 검색하는 화면
public void searchByName() {
System.out.println("--------회원 이름으로 검색--------");
System.out.println("검색할 회원의 이름 입력: ");
String userName = sc.nextLine();
mc.searchByName(userName);
}
// 5. 회원 정보를 수정하는 화면
public void updateMember() {
System.out.println("---------회원 정보 변경---------");
// 변경할 회원의 아이디
System.out.println("변경할 회원의 아이디: ");
String userId = sc.nextLine();
// 해당 회원의 변경할 정보들
System.out.println("변경할 비밀번호 입력: ");
String userPw = sc.nextLine();
System.out.println("변경할 이메일 입력: ");
String email = sc.nextLine();
System.out.println("변경할 휴대번호 입력: ");
String phone = sc.nextLine();
System.out.println("변경할 주소 입력: ");
String address = sc.nextLine();
// 회원 정보 수정 요청
mc.updateMember(userId, userPw, email, phone, address);
}
// 6. 회원 탈퇴하는 화면
//
public void deleteMember() {
System.out.println("---------회원 탈퇴---------");
System.out.println("회원 탈퇴할 아이디: ");
String userId = sc.nextLine();
mc.deleteMember(userId);
}
//---------------------------------------------------
// 서비스 요청 시 사용자가 보게 될 응답(성공 또는 실패) 화면
// 서비스 요청 성공 시 응답 화면
public void displaySuccess(String message) {
System.out.println("서비스 요청 성공: " + message);
}
// 서비스 요청 실패시 응답 화면
public void displayFail(String message) {
System.out.println("서비스 요청 실패: " + message);
}
// 전체 조회 결과가 없을 때 응답 화면
public void displayNoData(String message) {
System.out.println(message);
}
// 전체 조회 결과가 있을 때 응답 화면
public void displayList(ArrayList<Member> list) {
System.out.println("조회된 결과는 " + list.size() + "건입니다.");
// 향상된 for문: for(반환할타입 변수명 : 반복할저장소(컬렉션/배열))
for(Member m : list) {
System.out.println(m);
}
}
// 조회결과가 하나일 때
public void displayOne(Member m) {
System.out.println("조회된 결과는 다음과 같습니다.");
System.out.println(m);
}
}
Controller
: 사용자의 요청 처리를 담당하는 클래스
- View에서의 요청 처리를 담당하며, 해당 메소드로 전달된 데이터들을 VO 객체에 담아 가공 처리한 후
Dao를 호출한다.
- Dao에서 반환받은 결과에 따라 사용자가 보게 될 화면을 지정한다.
package member.controller;
import java.util.ArrayList;
import member.model.dao.Dao;
import member.model.vo.Member;
import member.view.View;
public class Controller {
public void insertMember(String userId, String userPw, String userName, String gender, int age, String email,
String phone, String address, String hobby) {
// 1. 전달된 데이터들을 Member 객체에 담기(가공 처리)
Member m = new Member(userId, userPw, userName, gender, age, email, phone, address, hobby);
// 2. Dao의 insertMember 메소드를 호출(가공된 멤버객체를 보낸다.)
int result = new MemberDao().insertMember(m);
// 3. Dao에서 작업한 결과값에 따라 View에 보여질 화면을 정해준다.
if(result > 0) {
// 성공했으니 성공 메시지를 보낸다.
new MemberView().displaySuccess("회원 추가 성공");
} else {
// 실패했으니 실패 메시지를 보낸다.
new MemberView().displayFail("회원 추가 실패");
}
}
// 사용자의 회원 전체 조회 요청을 처리해주는 메소드
public void selectAll() {
// view에서 controller로 전체조회 요청 받음 -> Dao에게 DB로부터 전체조회해오라고 요청함
// -> Dao가 Controller에게 전체조회한 결과값을 전달해줌
// 결과값을 담을 변수
// SELECT - ResultSet -> ArrayList<Member>
ArrayList<Member> list = new MemberDao().selectAll();
// DAO에서 작업을 끝마친 결과를 전달받아 해당 결과를 토대로 어떤 화면을 보여줄 지 정하여 view에 전달한다.
// 조회결과가 있는지 없는지 판단 후 사용자가 보게될 화면을 지정한다.
if(list.isEmpty()) { // list가 비어있어 true인 경우
new MemberView().displayNoData("전체 조회 결과가 없습니다.");
} else { // list 조회된 경우 list에 Member가 담겨있음
new MemberView().displayList(list);
}
}
// 사용자가 입력한 아이디로 검색 요청을 처리해주는 메소드
public void searchById(String userId) {
Member m = new MemberDao().searchById(userId); // m(조회된 회원 정보)
// 조회된 회원 정보가 담긴 객체 m이 null이면 조회x
if(m == null) {
new MemberView().displayNoData(userId+"에 해당하는 회원정보가 없습니다.");
} else {
new MemberView().displayOne(m);
}
}
// 사용자가 입력한 이름으로 검색 요청을 처리해주는 메소드
public void searchByName(String userName) {
ArrayList<Member> list = new MemberDao().searchByName(userName);
if(list.isEmpty()) {
new MemberView().displayNoData("조회된 결과가 없습니다.");
} else {
new MemberView().displayList(list);
}
}
// 사용자가 입력한 정보들을 변경 요청을 처리해주는 메소드
public void updateMember(String userId, String userPw, String email, String phone, String address) {
Member m = new Member();
m.setUserId(userId);
m.setUserPw(userPw);
m.setEmail(email);
m.setPhone(phone);
m.setAddress(address);
int result = new MemberDao().updateMember(m);
// view 성공 실패 시 보여줄 화면 결정
if(result > 0) {
// 성공했으니 성공 메시지를 보낸다.
new MemberView().displaySuccess("회원 정보 변경 성공");
} else {
// 실패했으니 실패 메시지를 보낸다.
new MemberView().displayFail("회원 정보 변경 실패");
}
}
public void deleteMember(String userId) {
int result = new MemberDao().deleteMember(userId);
if(result > 0) {
// 성공했으니 성공 메시지를 보낸다.
new MemberView().displaySuccess("회원 탈퇴 성공");
} else {
// 실패했으니 실패 메시지를 보낸다.
new MemberView().displayFail("회원 탈퇴 실패");
}
}
}
DAO(Data Access Object)
: DB와 직접적 접근을 담당하는 클래스
- Controller에 의해 호출되며, Controller에서 요청받은 작업을 수행한다.
package member.model.dao;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import member.model.vo.Member;
public class Dao {
// 사용자에게 회원 정보를 입력받아 회원을 추가하는 메소드
public int insertMember(Member m) {
int result = 0;
Connection conn = null;
Statement stmt = null;
String sql = "INSERT INTO MEMBER VALUES (SEQ_USERNO.NEXTVAL, "
+"'"+m.getUserId()+"', "
+"'"+m.getUserPw()+"', "
+"'"+m.getUserName()+"', "
+"'"+m.getGender()+"', "
+ m.getAge()+", "
+"'"+m.getEmail()+"', "
+"'"+m.getPhone()+"', "
+"'"+m.getAddress()+"', "
+"'"+m.getHobby()+"', "
+"SYSDATE)";
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "JDBC", "JDBC");
stmt = conn.createStatement();
result = stmt.executeUpdate(sql);
if(result > 0) {
conn.commit();
} else {
conn.rollback();
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
try {
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return result; // DML문이 작업된 행 수
}
// 전체조회하는 메소드
public ArrayList<Member> selectAll(){
Connection conn = null;
Statement stmt = null;
ResultSet rset = null;
// 회원정보가 여러 개이면 여러 개의 회원정보를 담아야 하므로 ArrayList에 담는다.
ArrayList<Member> list = new ArrayList<>(); // 빈 리스트 생성
// 실행할 SQL문
String sql = "SELECT * FROM MEMBER";
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "JDBC", "JDBC");
stmt = conn.createStatement();
rset = stmt.executeQuery(sql);
while(rset.next()) {
Member m = new Member();
m.setUserNo(rset.getInt("USERNO"));
m.setUserId(rset.getString("USERID"));
m.setUserPw(rset.getString("USERPW"));
m.setUserName(rset.getString("USERNAME"));
m.setGender(rset.getString("GENDER"));
m.setAge(rset.getInt("AGE"));
m.setEmail(rset.getString("EMAIL"));
m.setPhone(rset.getString("PHONE"));
m.setAddress(rset.getString("ADDRESS"));
m.setHobby(rset.getString("HOBBY"));
m.setEnrollDate(rset.getDate("ENROLLDATE"));
// 한 행에 대한 모든 컬럼의 데이터값을 Member 객체 필드에 각각 담았다.
list.add(m);
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
try {
rset.close();
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return list;
// 행의 데이터를 갖고 있는 Member 객체들이 인덱스에 담겨있는 리스트를 반환한다.
}
// 사용자에게 입력받은 아이디로 해당 회원이 있는지 정보 검색 처리하는 메소드
public Member searchById(String userId) {
// 필요 도구 생성하기
Connection conn = null;
Statement stmt = null;
ResultSet rset = null;
Member m = null; // 조회된 회원의 정보를 담을 Member 객체
String sql = "SELECT * FROM MEMBER WHERE USERID = '" + userId + "'";
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "JDBC", "JDBC");
stmt = conn.createStatement();
rset = stmt.executeQuery(sql);
// 조회 결과가 담긴 rset을 옮긴다.
if(rset.next()) { // 커서가 가르킬 곳에 조회될 결과가 있는 경우
// 조회된 행에 있는 컬럼들의 데이터를 Member 객체에 한번에 모아 보낸다.
// 매개변수 생성자로 값 넣기
m = new Member(rset.getInt("USERNO")
, rset.getString("USERID")
, rset.getString("USERPW")
, rset.getString("USERNAME")
, rset.getString("GENDER")
, rset.getInt("AGE")
, rset.getString("EMAIL")
, rset.getString("PHONE")
, rset.getString("ADDRESS")
, rset.getString("HOBBY")
, rset.getDate("ENROLLDATE"));
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
try {
rset.close();
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return m;
}
// 사용자에게 입력 받은 이름으로 회원 조회하는 메소드
public ArrayList<Member> searchByName(String userName) {
Connection conn = null;
Statement stmt = null;
ResultSet rset = null;
String sql = "SELECT * FROM MEMBER WHERE USERNAME LIKE '%"+ userName + "%'";
ArrayList<Member> list = new ArrayList<>();
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "JDBC", "JDBC");
stmt = conn.createStatement();
rset = stmt.executeQuery(sql);
while(rset.next()) {
list.add(new Member(rset.getInt("USERNO")
, rset.getString("USERID")
, rset.getString("USERPW")
, rset.getString("USERNAME")
, rset.getString("GENDER")
, rset.getInt("AGE")
, rset.getString("EMAIL")
, rset.getString("PHONE")
, rset.getString("ADDRESS")
, rset.getString("HOBBY")
, rset.getDate("ENROLLDATE")));
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
try {
rset.close();
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return list;
}
// 사용자에게 변경 정보를 입력받아 해당 회원의 정보를 변경하는 메소드
public int updateMember(Member m) {
Connection conn = null;
Statement stmt = null;
int result = 0;
String sql = "UPDATE MEMBER "
+ "SET USERPW = '"+m.getUserPw()+"'"
+ " , EMAIL = '"+m.getEmail()+"'"
+ " , PHONE = '"+m.getPhone()+"'"
+ " , ADDRESS = '"+m.getAddress()+"'"
+ "WHERE USERID = '"+m.getUserId()+"'";
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "JDBC", "JDBC");
stmt = conn.createStatement();
result = stmt.executeUpdate(sql);
if(result > 0) {
conn.commit();
} else {
conn.rollback();
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
try {
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return result;
}
// 사용자에게 입력을 받아 회원을 탈퇴시키는 메소드
public int deleteMember(String userId) {
Connection conn = null;
Statement stmt = null;
int result = 0;
// DELETE FROM MEMBER WHERE USERID='admin';
String sql ="DELETE FROM MEMBER WHERE USERID='"+userId+"'";
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
conn=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe","JDBC","JDBC");
stmt=conn.createStatement();
result=stmt.executeUpdate(sql);
if(result>0) {
conn.commit();
}else {
conn.rollback();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
stmt.close();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return result;
}
}