본문 바로가기

Languages/Java

(2) MVC 패턴 활용 - 간단한 CRUD

저번 글과 이어지는 글 입니다

프로그램 흐름 

 

1. 사용자의 입력을 받아 생성 / 검색 / 수정 / 삭제 / 출력 을 수행한다

2. 생성에는 회원 생성하기

3. 검색에는 아이디/이름/이메일 로 검색하기

4. 수정에는 비밀번호 / 이름 / 이메일 수정하기

5. 삭제에는 특정 회원 삭제하기 / 모든 회원 삭제하기

6. 종료

 

실행 화면

 

전체적인 패키지 구조입니다

패키지 구조

 

MVC 패턴이 무엇인지 부터 보고 가겠습니다 

MVC 패턴? 
MVC 패턴은 소프트웨어 구조를 깔끔하게 나누어 유지보수·확장성을 높이는 아키텍처 패턴이다

M → Model (데이터)
V → View (화면)
C → Controller (흐름 / 로직제어)

 

이 글에서는 Service 와 Repository 도 함께 만들어 사용해보았습니다.

 

흐름 :  [View]  →  [Controller]  →  [Service]  →  [ Repository  ]  →  [ Model ]


메인

import member.view.MemberMenu;

public class Main {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new MemberMenu();
	}

}

 

   설명   
 

  • 실제 실행하는 Main 에서 view 에 해당되는 Menu 객체를 생성해 메서드를 시작한다.

메뉴 (view)

// 메인 메뉴 출력문구와 사용자 입력 문구 
class UI {
	void printMenu(boolean max) {
		System.out.println( max ? "1. 새 회원 등록" : "회원 수가 모두 꽉 찼기 때문에 일부 메뉴만 오픈됩니다");
		System.out.println("2. 회원 검색");
		System.out.println("3. 회원 정보 수정");
		System.out.println("4. 회원 삭제");
		System.out.println("5. 모두 출력");
		System.out.println("9. 끝내기");
		printUserInput();
	}

	void printUserInput() {
		System.out.print("#사용자 : ");
	}

	void printUserInput(String text) {
		System.out.println();
		System.out.print("#" + text + " :");
	}
}

// 메인 메뉴 클래스
public class MemberMenu implements Search, Update, Delete {
	Scanner sc = new Scanner(System.in);
	MemberController mc = new MemberController();
	UI show = new UI();

	public MemberMenu() {
		boolean max; // 회원 count
		boolean isRunning = true; // 메인 메뉴 9번으로 탈출

		while (isRunning) {
			max = mc.existMemberNum() != 10; // 반복마다 회원 수 체크
			show.printMenu(max);
			try {
				switch (sc.nextInt()) {
				case 1:
					if (!max) {
						System.out.println("회원 수가 모두 꽉 찼기 때문에 일부 메뉴만 오픈됩니다");
						break;
					}
					insertMember();
					break;
				case 2:
					new SearchMember(this).run(sc);
					break;
				case 3:
					new UpdateMember(this).run(sc);
					break;
				case 4:
					new DeleteMember(this).run(sc);
					break;
				case 5:
					printAll();
					break;
				case 9:
					System.out.println("프로그램을 종료합니다");
					isRunning = false;
					break;
				default:
					System.out.println("잘못 입력하셨습니다. 다시 입력해주세요.");
				}
				// InputMismatchException => Int 가 아닌 다른 타입의 입력값이 들어오면 에러
			} catch (InputMismatchException e) {
				System.out.println("잘못된 입력입니다.");
				System.err.println("에러코드 :" + e);
				sc.next(); // 버퍼 안 비워주면 무한 에러
			}
		}

	}

 

   설명   

  • 정의해둔  interface implements
  • 스캐너 생성 , 컨트롤러 객체 생성 , UI 객체생성 (출력문구 모음) 
  • 9를 입력받지 않으면 계속 반복
  • switch 문으로 각 입력에 맞는 메서드 실행 
  • InputMismatchException 예외처리 

 

각 케이스 별 설명

 

코드가 menu -> Controller -> service -> repo 까지 이어지는 경우가 있어 

 

코드 혹은 사진으로만 대체하는 경우가 있습니다 . 

 

사진 설명과 함께 눈으로 흐름만 읽어주세요

 

흐름 :  [View]  →  [Controller]  →  [Service]  →  [ Repository  ]  →  [ Model ]


 

menu - case 1 

void insertMember() {
		String id;
		char gender;
		System.out.println("===== 정보입력 =====");
		while (true) { //재입력받기
			show.printUserInput("아이디");
			id = sc.next();
			if (mc.checkId(id)) {
				System.out.println("중복된 아이디입니다.");
				continue;
			}
			break;
		}
		show.printUserInput("비밀번호");
		String pw = sc.next();
		show.printUserInput("이름");
		String name = sc.next();
		show.printUserInput("이메일");
		String email = sc.next();
		while (true) {//재입력받기
			show.printUserInput("성별 m(M) / f(F)");
			gender = sc.next().charAt(0);
			if (mc.checkGender(gender)) {
				break;
			}
			System.out.println("잘못된 성별 m(M) / f(F) 로만 입력해주세요");
		}
		show.printUserInput("나이");
		int age = sc.nextInt();
		System.out.println(mc.insertMember(id, name, pw, email, gender, age) ?
										"회원 등록 완료":
										"등록 오류");
	}

 

   설명   

  • 회원 생성을 위한 id,pw,name,email,gender,age 입력 받기
  • id 는 컨트롤러에게 중복 검사를 받고 true를 받을때까지 반복
  • gender는 컨트롤러에게 유효성검사를 받고 true를 받을때까지 반복

id, gender 체크 - controller

 

id, gender 체크 - service (실제 로직)

  • 입력을 다 받고 컨트롤러에게 값을 전달 , 회원생성 후 결과를 출력 
public boolean insertMember(String id, String name ,String password, String email, char gender, int age) {
		try {
			mRepo.addArr(id, name, password, email, gender, age);
            //전달받은 값을 실제 데이터 저장/관리하는 repo 메서드로 넘겨준다
			return true;	
		} catch (Exception e) {
			return false;
		}
	}

 

회원 생성 - Repository

 


 

menu - case 2 (전 글에서 다뤘기에 로직만 다루겠습니다)

new SearchMember(this).run(sc);

 

템플릿 메서드로 Search 클래스에서 호출되는 메서드

Search  각 view 메서드

 

아이디 / 이름 / 이메일을 입력받아 컨트롤러에게 전달 하고

결과값을 출력한다 .

이름과 이메일은 문자열 타입의 ArrayList로  받아 반복문을 이용하여 출력한

Search  각 controller 메서드

ID 확인은 ID가 존재한다면 그 ID의 회원 정보를 RETURN 

NAME, EMAIL 확인은 똑같이 name, email 이 존재한다면 그 존재를 ArrayList에 받아 반환 

package member.service;

import java.util.ArrayList;

import member.member.Member;

public class SearchService {
	
	Member[] members;
	
	public SearchService(Member[] members) {
		this.members = members;
	}
	
	public String SearchId (String id, String info) {
		for(Member m : members) {
			if(m == null) {break;}
			if(id.equals(m.getId())) {
				info = m.inform();
			}
		}
		return info;
	}
	
	public ArrayList<String> searchName (String name) {
		ArrayList<String> searchResults = new ArrayList<>();
		for(Member m : members) {
			if(m == null) {break;}
			if(name.equals(m.getName())) {
				searchResults.add(m.inform());
			}
		}
		return searchResults;
	}
	
	public ArrayList<String> searchEmail (String email) {
		ArrayList<String> searchResults = new ArrayList<>();
		for(Member m : members) {
			if(m == null) {break;}
			if(email.equals(m.getEmail())) {
				searchResults.add(m.inform());
			}
		}
		return searchResults;
	}
}

Search - Service (실제 로직)

 

m이 null 이라면 끝내고 (이게 중요함 ,  이게 없을 때 null 오류가 계속해서 떠서 골치아팠음)

그렇지 않다면 model에서 가져오는 각각의 데이터 값과 같은 값이 존재한다면

그에 맞는 info를 리턴해주는 로직이다



menu - case 3
 (전 글에서 다뤘기에 로직만 다루겠습니다)

new UpdateMember(this).run(sc);

Update - view
update - controller

package member.service;

import member.member.Member;

public class UpdateService {
	Member[] members;
	
	public UpdateService(Member[] members) {
		this.members = members;
	}
	
	public boolean updatePassword(String id , String password) {
		for(Member m : members) {
			if(m == null) {break;}
			if(id.equals(m.getId())) {
				m.setPassword(password);
				return true;
			}
		}
		return false;
	}
	
	public boolean updateName(String id , String name) {
		for(Member m : members) {
			if(m == null) {break;}
			if(id.equals(m.getId())) {
				m.setName(name);
				return true;
			}
		}
		return false;
	}
	
	public boolean updateEmail(String id, String email) {
		for(Member m : members) {
			if(m == null) {break;}
			if(id.equals(m.getId())) {
				m.setEmail(email);
				return true;
			}
		}
		return false;
	}
	
	
	
	
}

update - service

Update - repo

 

m이 null 이라면 끝내고 

그렇지 않다면 model에서 가져오는 각각의 데이터 값과 같은 값이 존재한다면

model 에서 제공하는 get/set 메서드를 이용해서

입력받은 값으로 변경한다.


menu - case 4 (전 글에서 다뤘기에 로직만 다루겠습니다)

new DeleteMember(this).run(sc);

delete - view
delete - controller

package member.service;

import member.member.Member;
import member.repo.MemberRepo;

public class DeleteService {
	
	MemberRepo repo;
	
	public DeleteService(MemberRepo repo) {
		this.repo = repo;
	}

	public boolean delete(String id) {
		Member[] arr = repo.getArr();
		for (int i = 0; i < arr.length; i++) {
			if (arr[i] == null) {
				break;
			}
			if (id.equals(arr[i].getId())) {
				for (int j = i; j < arr.length-1; j++) {
					repo.updateArr(j);
				}
				repo.updateArrEnd();
				return true;
			}
		}
		return false;
	}
	
	public boolean deleteAll() {
		repo.delAllArr();
		return true;
	}
}

delete - service (로직)

 

delete - repo

 


menu - case 5

menu

 

view
controller

package member.service;

import java.util.ArrayList;

import member.member.Member;

public class PrintService {
	ArrayList<String> arr = new ArrayList<>();
	
	PrintService () {}
	
	public PrintService (Member[] members) {
		arr.clear();
		for(Member m : members) {
			if(m == null) {break;}
			arr.add(m.inform());
		}
	}
	
	public ArrayList<String> getPrintAll() {
		return arr;
	}

}

 


 

 

 

전체 총 정리

  • mvc 패턴을 사용해 구조를 깔끔하게 나누어 유지보수·확장성을 높인다
  • 템플릿 메서드 패턴을 적용하면서 중복되던 메뉴 처리 코드가 사라졌다
  • 제네릭 , 인터페이스에 대한 개념을 알게 되었다
  • 컨트롤러에서 직접 데이터에 접근하기보다는 데이터를 관리하는 repo 를 만들어서 관리하는 게 더 좋다
  • 코드가 조금 길고 파일이 많아져도 구조를 잡고 나눠서 하는 것이 
    유지보수와 확장에 도움이 된다
  • 10번은 돌려보며 적용했지만 그래도 어렵다 

 

MVC-member.zip
0.03MB