본문 바로가기
카테고리 없음

24. 08. 02 개발자교육 6주차 금요일 Membership 마무리! 자바진도 끝!

by 융기융 2024. 8. 2.
반응형

자바수업이 드디어 끝났다

그중에서도 가장 어려웠던 Membership 프로그램 만들기....그럼 시작!!!!!!!!!!!! 하겠습니다!!!!!!!!!!!

 

코드만 쓰는게 전부가 아니고 정말 어려움의 끝을 치닫는 자바...

 

 

기본적인 정보 + 자료드를 모아놓은 dto

package dto;

 

import java.io.Serializable;

 

import lombok.AllArgsConstructor;

import lombok.EqualsAndHashCode;

import lombok.Getter;

import lombok.NoArgsConstructor;

import lombok.Setter;

import lombok.ToString;

 

@Getter // 컴파일 할때 getter 구문을 자동추가

@Setter // 컴파일 할때 setter 구문을 자동추가

@NoArgsConstructor // 기본생성자

@AllArgsConstructor // 전체 필드 매개변수 생성자

@ToString // toString() 오버라이딩

@EqualsAndHashCode // equals(), hahshcode() 오버라이딩

 

public class Member implements Serializable{ // + 직렬화

 

// DTO(Data Transfer Object) : 데이터 전달용 객체

// - 여러 데이터를 한번에 담아서

// 계층간 데이터를 전달하는 목적으로 사용하는 객체

 

// (계층 : view, service, dao 등 다른 클래스)

 

// 등급을 나타내는 상수

public static final int COMMON = 0;

public static final int GOLD = 1;

public static final int DIAMOND = 2;

 

// 회원정보를 저장 할 필드

private String name;

private String phone;

private int amount;

private int grade;

}

가장 코드가 많은 , 보여지는 view

package view;

 

import java.io.BufferedReader;

import java.io.IOException;

import java.io.InputStreamReader;

import java.util.List;

 

import dto.Member;

import service.MemberService;

import service.MemberServiceImpl;

 

// View : 사용자에게 보여지는 역할을 하는 클래스/객체

// - 보여줄 화면을 출력 / 필요한 데이터를 입력

public class MemberView {

 

private MemberService service = null;

private BufferedReader br = null;

 

// 기본 생성자

public MemberView() {

 

try {

// 객체 생성 중 발생한 예외를 View에 모아서 처리

service = new MemberServiceImpl();

 

// 키보드를 입력 받기 위한 스트림 생성

br = new BufferedReader(new InputStreamReader(System.in));

 

}catch (Exception e) {

 

System.out.println("*** 프로그램 실행 중 오류 발생 ***");

e.printStackTrace();

System.exit(0); // 프로그램 종료

}

}

 

 

// -------------------------------------------------------------------

// [메인 메뉴]

public void mainMenu() {

 

int input = 0;

do {

 

try {

// 메뉴 출력 후 입력된 번호를 반환 받기

input = selectMenu();

 

 

// 선택된 메뉴 번호에 따라 case 선택

switch(input) {

case 1: addMember(); break;

case 2: selectAll(); break;

case 3: selectName(); break;

case 4: updateAmount(); break;

case 5: updateMember(); break;

case 6: deleteMember(); break;

case 0: System.out.println("*** 프로그램 종료 ***"); break;

default : System.out.println("### 메뉴에 작성된 번호만 입력 해주세요 ###");

}

 

System.out.println("=====================================");

 

 

} catch(NumberFormatException e) {

System.out.println("\n### 숫자만 입력 해주세요 ###\n");

input = -1; // 첫 반복에서 종료되지 않게 값 변경

 

} catch(IOException e) {

System.out.println("\n### 입출력 관련 예외 발생 ###\n");

e.printStackTrace(); // 예외 추적

 

} catch(Exception e) { // 나머지 예외 처리

e.printStackTrace();

}

 

 

}while(input != 0);

 

 

}

 

 

// -------------------------------------------------------------------

// [메뉴 출력/선택하는 메서드]

 

private int selectMenu() throws NumberFormatException, IOException {

 

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("0. 종료");

 

System.out.print("메뉴 선택 >>> ");

 

// 입력 받은 문자열을 int 형태로 변환

int input = Integer.parseInt( br.readLine() );

System.out.println(); // 줄바꿈

 

return input;

}

 

 

// ---------------------------------------------------------------

// [1. 회원 가입(추가)]

 

private void addMember() throws IOException {

System.out.println("\n----- 회원 가입(추가) -----\n");

 

System.out.print("이름 : ");

String name = br.readLine();

 

// 정상 입력(11글자)이 될 때 까지 다시 입력 받기

String phone = null;

 

while(true) {

System.out.print("휴대폰 번호(- 제외) : ");

phone = br.readLine();

 

if(phone.length() != 11) {

System.out.println("*** 다시 입력 해주세요 ***\n");

continue;

}

 

break;

}

 

 

// 회원 추가 서비스 호출 후 결과 반환 받기

boolean result = service.addMember(name, phone);

 

if(result) {

System.out.println("\n*** 회원이 추가 되었습니다 ***\n");

 

} else {

System.out.println("\n### 중복되는 휴대폰 번호가 존재합니다 ###\n");

}

 

}

 

 

 

 

// -------------------------------------------------------------

// [2. 회원 전체 조회]

 

private void selectAll() {

System.out.println("\n----- 회원 전체 조회 -----\n");

 

// 회원 목록을 조회해 반환하는 서비스 호출

List<Member> memberList = service.getMemberList();

 

// 조회된 회원 목록이 없을 경우

// -> MemberDaoImpl 생성자 코드에 의해서

// memberList는 "절대로" null이 될 수 없다!!!!

 

// -> 참조하는 List는 있지만 비어있는지 검사를 해야한다!

if(memberList.isEmpty()) {

System.out.println("\n### 회원이 존재하지 않습니다 ###\n");

return;

}

 

 

String[] gradeArr = {"일반", "골드", "다이아"};

 

 

System.out.println("-------------------------------------------");

 

System.out.printf("%-5s %-7s %8s %4s \n",

"[이름]", "[휴대폰 번호]", "[누적금액]", "[등급]");

 

System.out.println("-------------------------------------------");

 

 

// 향상된 for문

for(Member member : memberList) {

 

System.out.printf("%-6s %-12s %8d %5s \n",

member.getName(), member.getPhone(),

member.getAmount(), gradeArr[member.getGrade()] );

 

}

}

 

 

 

// ------------------------------------------------------------------------

// [3. 이름으로 검색(동명이인)]

 

private void selectName() throws IOException {

System.out.println("\n----- 이름 검색(동명이인 있으면 모두 조회) -----\n");

 

// 검색할 이름 입력 받기

System.out.print("검색할 이름 입력 : ");

String searchName = br.readLine();

 

// 이름 검색 서비스 호출 후 결과 반환 받기

List<Member> searchList = service.selectName(searchName);

 

// 검색 결과가 없을 경우

if(searchList.isEmpty()) {

System.out.println("\n### 검색 결과가 없습니다 ###\n");

return;

}

 

 

// 검색 결과가 있을 경우

for(Member member : searchList) {

System.out.println(member);

}

 

 

}

 

//------------------------------------------------------------

// [4. 특정 회원 사용 금액 누적하기]

 

private void updateAmount() throws IOException {

System.out.println("\n----- 특정 회원 사용 금액 누적하기 -----\n");

 

System.out.print("회원 이름 입력 : ");

String targetName = br.readLine();

 

// 이름이 일치하는 회원 모두 조회

List<Member> searchList = service.selectName(targetName);

 

// 이름이 일치하는 회원이 없을 경우

if(searchList.isEmpty()) {

System.out.println("\n### 이름이 일치하는 회원이 존재하지 않습니다 ###\n");

return;

}

 

 

// 금액 증가 대상 회원만 참조할 Member 참조 변수 선언

Member target = null;

 

// 1) 동명이인이 있을 경우

// -> 이름/전화번호를 출력해서 한 명만 선택하게 함

if(searchList.size() > 1) {

System.out.println("\n*** 대상 회원을 선택 해주세요 ***\n");

 

// 일반 for문 사용 이유 -> i 값 활용하고 싶어서

for(int i = 0 ; i < searchList.size() ; i++) {

System.out.printf("%d) %s (%s)\n",

i+1,

searchList.get(i).getName(),

searchList.get(i).getPhone());

}

 

System.out.print("선택할 회원의 번호를 입력 : ");

int input = Integer.parseInt( br.readLine() ) - 1;

// 문자열 -> 정수로 변환

// 입력된 번호를 index에 맞추기 위해 -1

 

// 입력된 번호가 searchList의 index범위를 초과한 경우

if(input < 0 || input >= searchList.size()) {

System.out.println("\n### 없는 회원 번호 입니다. 다시 시도 해주세요 ###\n");

return;

}

 

// target에 회원 저장

target = searchList.get(input);

 

} else {

// 2) 동명이인이 없을 경우

target = searchList.get(0);

}

 

 

 

// 누적할 금액 입력

System.out.print("누적할 금액 입력 : ");

int acc = Integer.parseInt(br.readLine());

 

 

// 대상 회원, 누적할 금액을 서비스로 전달하여 결과 반환

// - 금액 누적

// - 등급 조정

// - 파일에 데이터 저장

 

// - 서비스에서 반환 받을 문자열

// ex) 신짱구 회원님의 누적 금액

// 2000 -> 100000

// * 골드 * 등급으로 변경 되셨습니다

 

String result = service.updateAmount(target, acc);

 

System.out.println(result);

}

 

// ----------------------------------------

// [5. 회원 정보 수정]

private void updateMember() throws IOException {

System.out.println("\n----- 회원 정보 수정 -----\n");

 

System.out.print("회원 이름 입력 : ");

 

String targetName = br.readLine();

 

// 이름이 일치하는 회원 모두 조회

List<Member> searchList = service.selectName(targetName);

 

// 이름이 일치하는 회원이 없을 경우

if(searchList.isEmpty()) {

System.out.println("\n### 이름이 일치하는 회원이 존재하지 않습니다 ###\n");

return;

}

 

// 수정 대상을 참조할 변수 선언

Member target = null;

 

if(searchList.size() > 1) { // 동명이인 있을 경우

 

System.out.println("\n*** 대상 회원을 선택 해주세요 ***\n");

 

for(int i = 0 ; i < searchList.size() ; i++) {

System.out.printf("%d) %s (%s)\n",

i+1,

searchList.get(i).getName(),

searchList.get(i).getPhone());

}

 

System.out.print("선택할 회원의 번호를 입력 : ");

int input = Integer.parseInt( br.readLine() ) - 1;

 

if(input < 0 || input >= searchList.size()) {

System.out.println("\n### 없는 회원 번호 입니다. 다시 시도 해주세요 ###\n");

return;

}

 

target = searchList.get(input);

 

} else { // 동명이인 없을 경우

target = searchList.get(0);

}

 

while(true) {

System.out.print("휴대폰 번호(- 제외) : ");

String phone = br.readLine();

 

if(phone.length() != 11) {

System.out.println("*** 다시 입력 해주세요 ***\n");

continue;

}

 

break;

}

 

// 수정할 전화번호 입력받기

System.out.print("수정할 전화번호 입력 : ");

String phone = br.readLine();

 

// 정보수정 서비스 호출 후 결과 문자열 반환받기

String result = service.updateMember(target, phone);

System.out.println(result);

 

 

 

}

 

// ------------------------------------------------------

// [회원 탈퇴]

 

private void deleteMember() throws IOException {

System.out.println("\n---- 회원 탈퇴 ----\n");

 

System.out.print("회원 이름 입력 : ");

 

String targetName = br.readLine();

 

// 이름이 일치하는 회원 모두 조회

List<Member> searchList = service.selectName(targetName);

 

// 이름이 일치하는 회원이 없을 경우

if(searchList.isEmpty()) {

System.out.println("\n### 이름이 일치하는 회원이 존재하지 않습니다 ###\n");

return;

}

 

// 탈퇴 대상을 참조할 변수 선언

Member target = null;

 

if(searchList.size() > 1) { // 동명이인 있을 경우

 

System.out.println("\n*** 대상 회원을 선택 해주세요 ***\n");

 

for(int i = 0 ; i < searchList.size() ; i++) {

System.out.printf("%d) %s (%s)\n",

i+1,

searchList.get(i).getName(),

searchList.get(i).getPhone());

}

 

System.out.print("선택할 회원의 번호를 입력 : ");

int input = Integer.parseInt( br.readLine() ) - 1;

 

if(input < 0 || input >= searchList.size()) {

System.out.println("\n### 없는 회원 번호 입니다. 다시 시도 해주세요 ###\n");

return;

}

 

target = searchList.get(input);

 

} else { // 동명이인 없을 경우

target = searchList.get(0);

}

 

// 정말 탈퇴를 할 것인지 확인

System.out.print("정말 탈퇴처리 하시겠습니까? (y/n)");

 

// 입력받은 문자열을 소문자로 만들어

// 제일 앞 문자 하나만 반환받기

char check = br.readLine().toLowerCase().charAt(0);

 

if(check == 'n') {

System.out.print("\n### 탈퇴 취소 ###\n");

return;

}

if(check != 'y'){

System.out.println("\n### 잘못 입력하셨습니다. 다시 시도해주세요###\n");

return;

}

 

// y 입력된 경우

 

// 탈퇴서비스 호출 후 결과 문자열 반환받기

String result = service.deleteMember(target);

 

System.out.println(result);

 

 

}

 

}

 

 

MemberDao

package dao;

 

import java.io.IOException;

import java.util.List;

 

import dto.Member;

 

// DAO(Data Access Object) :

// - 데이터가 저장된 곳(파일/DB)에 접근하는 역할의 객체

// - 데이터 저장/수정/삭제/조회 가능

 

public interface MemberDao {

 

// 인터페이스 메서드는

// 묵시적(암묵적)으로 public abstract다!!

 

/**

* DAO 객체가 가지고 있는 memberList 반환

* @return memberList

*/

List<Member> getMemberList();

 

 

/**

* 회원 추가

* @param member

* @return true

* @throws IOException

*/

boolean addMember(Member member) throws IOException;

 

 

/**

* 파일 저장

*/

void saveFile() throws IOException;

 

 

}

 

 

 

 

MemberDaoImpl 파일경로 지정, Override

package dao;

 

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.util.ArrayList;

import java.util.List;

 

import dto.Member;

 

// MemberDao 인터페이스를 상속 받아 구현

public class MemberDaoImpl implements MemberDao{

 

// 회원 데이터가 저장될 파일 경로를 상수로 지정

private final String FILE_PATH = "/io_test/membership.dat";

 

// 회원 목록을 저장해둘 List 객체

private List<Member> memberList = null;

 

// 스트림 객체 참조 변수

private ObjectInputStream ois = null;

private ObjectOutputStream oos = null;

 

 

// 기본 생성자

// - 회원 다수를 관리할 회원 목록(List)이 필요한데

// 이미 파일로 저장된 회원 목록이 있으면 읽어오고

// 없으면 새로 만들기

public MemberDaoImpl() throws FileNotFoundException, IOException, ClassNotFoundException {

 

// membership.dat 파일이 존재하는지 검사

File file = new File(FILE_PATH);

 

if( file.exists() ) { // 존재하는 경우

try {

// 스트림 생성

ois = new ObjectInputStream(new FileInputStream(FILE_PATH));

 

// 저장된 객체를 파일에서 읽어와

// 다운 캐스팅하여 memberList가 참조하게함

memberList = (ArrayList<Member>)ois.readObject();

 

} finally {

// try에서 발생하는 예외를

// throws 구문으로 처리하면

// catch() 구문을 작성하지 않아도 된다!!

 

if(ois != null) ois.close();

}

}

 

// 파일이 존재하지 않는 경우

else {

// 새로운 ArrayList를 만들어서 참조

memberList = new ArrayList<Member>();

}

}

 

 

// memberList 반환

@Override

public List<Member> getMemberList() {

return memberList;

}

 

 

// 회원 추가

@Override

public boolean addMember(Member member) throws IOException {

 

// 1) 매개 변수로 전달 받은 새 회원 정보를

// memberList에 추가

memberList.add(member);

 

// 2) memberList를 지정된 파일로 출력(저장)

// -> 현재 메서드 말고

// 다른 메서드에서도 파일 출력(저장) 기능이

// 자주 사용될 예정!!!

// --> saveFile() 메서드 만들어 호출

saveFile();

 

return true; // 예외 발생하지 않고 성공적으로 파일에 저장됨

}

 

 

 

// 파일 저장

@Override

public void saveFile() throws IOException {

 

// memberList를 지정된 파일에 출력(저장)

 

try {

oos = new ObjectOutputStream(new FileOutputStream(FILE_PATH));

oos.writeObject(memberList);

} finally {

if(oos != null) oos.close(); // flush() + 메모리 반환

}

}

}

 

MemberService   View 다음으로 가장많이 쓰이는 sevice!!! sevice에서 service imli로 가면서 오버라이딩이 나오게됨~!!

package service;

 

import java.io.IOException;

import java.util.List;

 

import dto.Member;

 

// Service : 기능(비지니스 로직)제공 클래스/객체

// - 프로그램의 핵심기능 작성

public interface MemberService {

 

// 인터페이스의 메서드

// - public abstract method(중요)

// - default method

 

/**

* 전달받은 이름, 휴대폰번호를 이용해서 회원추가

* 단, 목록에 있는 회원 중 같은 번호의 회원이 존재하면

* false 반환 / 없으면 가입 후 true 반환

* @param name

* @param phone

* @return true / false(중복된 번호)

*/

public abstract boolean addMember(String name, String phone) throws IOException;

 

/**

* 전체 회원 목록 조회

* @return memberList

*/

public abstract List<Member> getMemberList();

 

/**

* searchName과 같은 이름을 지닌 회원조회

* - 동명이인이 존재하면 모두조회

* @param searchName

* @return searchList ( 저장된 요소 0개 이상 )

*/

List<Member> selectName(String searchName);

 

/**

* 전달받은 회원의 금액 누적하기

* @param target

* @param acc

* @return 결과 문자열

* @throws IOException

* @throws I

*/

String updateAmount(Member target, int acc) throws IOException; //public abstract 앞에 이거 지워도 오류x

 

/**

* 회원 정보(전화번호)수정

* @param target

* @param phone

* @return 결과 문자열

* @throws IOException

*/

String updateMember(Member target, String phone) throws IOException;

 

/**

* 회원 탈퇴

* @param target

* @return 결과 문자열

* @throws IOException

*/

String deleteMember(Member target) throws IOException;

 

}

 

 

MemberServiceImpl @Override

package service;

 

import java.io.FileNotFoundException;

import java.io.IOException;

import java.util.ArrayList;

import java.util.List;

 

import dao.MemberDao;

import dao.MemberDaoImpl;

import dto.Member;

 

/* 왜 Service, Dao 인터페이스를 만들어서 구현했을까?

* - 인터페이스를 상속 받아 구현하면

* 모든 자식 클래스가 똑같은 기능을 가지게되어

* 비슷하게 생김!

*

* -> 언제든지 서로 다른 자식 클래스로 대체 가능!!

* ==> 유지보수성 증가

*/

 

// MemberService를 상속 받아 구현

public class MemberServiceImpl implements MemberService{

 

// dao 객체 부모 참조 변수 선언

private MemberDao dao = null;

 

private String[] gradeArr = {"일반", "골드", "다이아"};

 

 

// 기본 생성자

// - MemberServiceImpl 객체 생성 시

// MemberDaoImpl 객체도 생성

public MemberServiceImpl() throws FileNotFoundException,

ClassNotFoundException,

IOException {

dao = new MemberDaoImpl();

}

 

 

// 회원 추가

@Override

public boolean addMember(String name, String phone) throws IOException {

 

// 1) 회원 목록을 얻어와 휴대폰 번호 중복 검사

List<Member> memberList = dao.getMemberList();

 

for(Member member : memberList) {

// 휴대폰 번호가 같은 경우 == 중복인 경우

if( phone.equals(member.getPhone()) ) {

return false;

}

}

 

// 2) 중복이 아닌 경우

// 입력 받은 정보를 이용해 Member 객체를 생성하고

// DAO에 전달하여 파일에 저장

Member member = new Member(name, phone, 0, Member.COMMON);

 

// DAO 메서드 호출 후 결과 반환 받기

boolean result = dao.addMember(member);

return result;

}

 

 

// DAO에서 조회한 memberList를 그대로 반환

// (해당 서비스 메서드는 따로 처리할 조건/기능이 없어서

// 중간에서 전달만 해주는 역할이됨)

@Override

public List<Member> getMemberList() {

return dao.getMemberList();

}

 

 

// 이름 검색

@Override

public List<Member> selectName(String searchName) {

 

// DAO를 이용해서 회원 전체 목록 조회

List<Member> memberList = dao.getMemberList();

 

// memberList에 저장된 요소(회원) 중

// 이름이 같은 회원을 찾아서

// 검색 결과를 저장할 별도 List에 추가

List<Member> searchList = new ArrayList<Member>();

 

for(Member member : memberList) {

if(member.getName().equals(searchName)) {

searchList.add(member);

}

}

 

return searchList; // 검색 결과 반환

}

 

 

// 금액 누적

@Override

public String updateAmount(Member target, int acc) throws IOException {

 

// 이전 금액 백업 -> 출력할 문자열 만들 때 사용

int before = target.getAmount();

 

// 대상 회원의 금액 누적하기

target.setAmount(before + acc);

 

// 등급 판별

// 일반 : 0 ~ 100,000 미만

// 골드 : 100,000 이상 ~ 1,000,000 미만

// 다이아 : 1,000,000 이상

 

 

int grade = 0; // 판별된 등급 저장할 변수

 

int currentAmount = target.getAmount();

if(currentAmount < 100000) grade = Member.COMMON;

else if(currentAmount < 1000000) grade = Member.GOLD;

else grade = Member.DIAMOND;

 

// 신짱구 회원님의 누적 금액

// 2000 -> 100000

// * 골드 * 등급으로 변경 되셨습니다

StringBuilder sb = new StringBuilder();

sb.append(target.getName());

sb.append(" 회원님의 누적 금액\n");

sb.append(before + " -> " + currentAmount);

 

// 이전 회원의 등급과

// 새로 판별된 등급이 다른 경우

if(target.getGrade() != grade) {

String str

= String.format("\n* %s * 등급으로 변경 되셨습니다",

gradeArr[grade]);

sb.append(str);

 

// 회원의 등급을 판별된 등급(grade)으로 변경

target.setGrade(grade);

}

 

 

// 변경된 데이터를 저장하는 DAO 메서드 호출

dao.saveFile();

 

return sb.toString();

}

 

@Override

public String updateMember(Member target, String phone)throws IOException {

 

// 이전 번호 저장

String before = target.getPhone();

 

// 대상의 전화번호를 입력받은 새 번호로 변경

target.setPhone(phone);

 

// 출력 문자열 만들기

StringBuilder sb = new StringBuilder();

 

// 홍길동님의 전화번호가 변경 되었습니다.

// 01012341234 -> 01044445555

 

 

sb.append(target.getName());

sb.append("님의 전화번호가 변경되었습니다\n");

 

sb.append(before + " -> " + phone);

 

// 바뀌었기때문에 파일 저장을 위해

dao.saveFile();

 

return sb.toString(); // 결과 문자열 반환

}

 

// 회원탈퇴

@Override

public String deleteMember(Member target) throws IOException {

 

// 회원 목록을 얻어오기

List<Member> memberList = dao.getMemberList();

 

// 회원목록에서 target 제거(remove)하기

// boolean List.remove(Object obj)

// -> List에 저장된 요소 중 obj와 같은 요소 제거

// * 조건 : 요소 객체가

// equals() 오버라이딩 되어 있어야함

boolean result = memberList.remove(target);

 

dao.saveFile(); // 탈퇴 데이터 저장

 

return target.getName() + "회원이 탈퇴처리 되었습니다";

}

 

}

 

MemberRun

package run;

 

import view.MemberView;

 

// run : 실행용 클래스

 

public class MemberRun {

 

public static void main(String[] args) {

 

MemberView view = new MemberView();

 

view.mainMenu();

 

}

}

반응형