회원가입 기능을 만들어보고 있다.
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Member {
private final Scanner sc;
private int id;
private String loginId;
private String loginPw;
private String name;
static List<Member> memberList = new ArrayList<>();
public Member(Scanner sc) {
this.sc = sc;
}
public void signUp() {
System.out.println("회원가입 ");
while (true) {
System.out.print("id 입력) ");
loginId = sc.nextLine().trim();
if (isDuplicateLoginId(loginId)) {
System.out.println("이미 사용 중인 ID입니다. 다른 ID를 입력해주세요.");
} else {
break;
}
}
System.out.print("pw 입력) ");
String loginPw = sc.nextLine().trim();
this.loginId = loginId;
this.loginPw = loginPw;
memberList.add(this);
System.out.println("회원가입이 완료되었습니다.");
}
private boolean isDuplicateLoginId(String loginId) {
for (Member member : Member.memberList) {
if (member.loginId.equals(loginId)) return true;
}
return false;
}
public void setLoginId(String loginId) {
this.loginId = loginId;
}
public void setLoginPw(String loginPw) {
this.loginPw = loginPw;
}
public boolean logIn(String loginId, String loginPw) {
if (this.loginId != null && this.loginPw != null) {
if (this.loginId.equals(loginId) && this.loginPw.equals(loginPw)) {
System.out.println("로그인 성공!");
return true;
} else {
System.out.println("로그인 실패. ID 또는 비밀번호가 틀렸습니다.");
return false;
}
} else {
System.out.println("회원 정보가 없습니다. 먼저 회원가입을 해주세요.");
return false;
}
}
}
Member 클래스고
if (cmd.equals("signup")) {
member.signUp();
}
if (cmd.equals("login")) {
System.out.print("id 입력");
String id = sc.nextLine().trim();
System.out.print("pw 입력");
String pw = sc.nextLine().trim();
member.logIn(id,pw);
}
App class 에 넣은 명령어,
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Member member = new Member(sc);
member.signUp();
while (true) {
System.out.print("로그인 ID: ");
String loginId = sc.nextLine().trim();
System.out.print("로그인 비밀번호: ");
String loginPw = sc.nextLine().trim();
if (member.logIn(loginId, loginPw)) {
System.out.println("로그인 성공");
} else {
System.out.println("로그인에 실패했습니다.");
continue;
}
break;
}
new App(sc).run();
sc.close();
}
}
Main class 실행하자마자 회원가입할 수 있게 만들었는데 뭔가 대충 구색은 잡혔는데 디테일을 살리는데 애를 먹고 있다.
암튼 골머리 앓는 와중에 강사님이 하시는 것을 봤는데 원래 있던 코드들에서 변수명만 건드면서 만드시는걸 보고 감탄했다. 기존에 있는 코드를 사용한다는 생각을 왜 못했을까.
- 강사님 회원가입 코드 구현
public class Main {
static List<Article> articles = new ArrayList<>();
static List<Member> members = new ArrayList<>();
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("==프로그램 시작==");
makeTestData();
int lastArticleId = 3;
int lastMemberId = 0;
while (true) {
System.out.print("명령어) ");
String cmd = sc.nextLine().trim();
if (cmd.length() == 0) {
System.out.println("명령어를 입력하세요");
continue;
}
if (cmd.equals("exit")) {
break;
}
if (cmd.equals("member join")) {
System.out.println("==회원가입==");
int id = lastMemberId + 1;
String regDate = Util.getNow();
String loginId = null;
while (true) {
System.out.print("로그인 아이디 : ");
loginId = sc.nextLine().trim();
if (isJoinableLoginId(loginId) == false) {
System.out.println("이미 사용중이야");
continue;
}
break;
}
String loginPw = null;
while (true) {
System.out.print("비밀번호 : ");
loginPw = sc.nextLine();
System.out.print("비밀번호 확인 : ");
String loginPwConfirm = sc.nextLine();
if (loginPw.equals(loginPwConfirm) == false) {
System.out.println("비번 다시 확인해");
continue;
}
break;
}
System.out.print("이름 : ");
String name = sc.nextLine();
Member member = new Member(id, regDate, loginId, loginPw, name);
members.add(member);
System.out.println(id + "번 회원이 가입되었습니다");
lastMemberId++;
private static boolean isJoinableLoginId(String loginId) {
for (Member member : members) {
if (member.getLoginId().equals(loginId)) {
return false;
}
}
return true;
}
class Member {
private int id;
private String regDate;
private String loginId;
private String loginPw;
private String name;
public Member(int id, String regDate, String loginId, String loginPw, String name) {
this.id = id;
this.regDate = regDate;
this.loginId = loginId;
this.loginPw = loginPw;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getRegDate() {
return regDate;
}
public void setRegDate(String regDate) {
this.regDate = regDate;
}
public String getLoginId() {
return loginId;
}
public void setLoginId(String loginId) {
this.loginId = loginId;
}
public String getLoginPw() {
return loginPw;
}
public void setLoginPw(String loginPw) {
this.loginPw = loginPw;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
기존의 article 코드랑 매우 유사하다. 나는 새로 만들어서 처음부터 쌓으려고 하니까 뭔가 꼬이고 계속 문제가 생겼는데 이렇게 하니까 그냥 뚝딱 만든 다음에 변수명 약간 수정하고 로그인에 필요한 회원의 아이디 겹침 문제와 회원가입할 때 비밀번호확인 단계에서 비밀번호가 일치하는지 일치 하지 않는지만 검증하는 코드를 쓰니까 끝났다.
약간 어제 저녁부터 계속 고민하던 내가 좀 이상하다고 느껴질 정도로 쉽고 간단하게 구현하셨다. 그래도 도움은 됐던게 강사님이 쓰시는 코드가 조금씩 보이기 시작한다는 느낌이 온다는게 신기했다.
암튼 내 코드도 조금 고쳐봐야겠다.
고친 코드를 복사를 못했다.
아무튼 지금 리팩토링을 하고 있다.
Main, App, Article, ArticleController, Member, MemberController, Util 클래스로 나누었고 서로 연동되게끔 했다.
이후에 강사님이 Controller 클래스를 만드시고 App 클래스를 간소화 하셨는데 이에 대해서 분석해보라고 하셨다.
아래는 바뀌기 전의 App 클래스고
public class App {
final Scanner sc;
public App(Scanner sc) {
this.sc = sc;
}
public void run() {
System.out.println("==프로그램 시작==");
MemberController memberController = new org.koreait.MemberController(sc);
ArticleController articleController = new ArticleController(sc);
ArticleController.makeTestData();
MemberController.makeTestUserData();
while (true) {
System.out.print("명령어) ");
String cmd = sc.nextLine().trim();
if (cmd.length() == 0) {
System.out.println("명령어를 입력하세요");
continue;
}
if (cmd.equals("exit")) {
break;
}
if (cmd.equals("member join")) {
MemberController.doJoin();
} else if (cmd.equals("member login")) {
MemberController.doLogin();
} else if (cmd.equals("article write")) {
ArticleController.doWrite();
} else if (cmd.startsWith("article list")) {
ArticleController.showList(cmd);
} else if (cmd.startsWith("article detail")) {
ArticleController.showDetail();
} else if (cmd.startsWith("article delete")) {
ArticleController.doDelete(cmd);
} else if (cmd.startsWith("article modify")) {
ArticleController.doModify(cmd);
} else {
System.out.println("사용할 수 없는 명령어입니다");
}
}
System.out.println("==프로그램 종료==");
sc.close();
}
}
Controller 클래스를 추가한 뒤,
public class Controller {
public void doAction(String cmd, String actionMethodName) {
}
}
public class App {
public void run() {
Scanner sc = new Scanner(System.in);
System.out.println("==프로그램 시작==");
MemberController memberController = new MemberController(sc);
ArticleController articleController = new ArticleController(sc);
articleController.makeTestData();
memberController.makeTestUserData();
Controller controller = null;
while (true) {
System.out.print("명령어) ");
String cmd = sc.nextLine().trim();
if (cmd.length() == 0) {
System.out.println("명령어를 입력하세요");
continue;
}
if (cmd.equals("exit")) {
break;
}
String[] cmdBits = cmd.split(" ");
String controllerName = cmdBits[0];
if (cmdBits.length == 1) {
System.out.println("명령어 확인해");
continue;
}
String actionMethodName = cmdBits[1];
if (controllerName.equals("article")) {
controller = articleController;
} else if (controllerName.equals("member")) {
controller = memberController;
} else {
System.out.println("사용불가 명령어");
continue;
}
controller.doAction(cmd, actionMethodName);
// if (cmd.equals("member join")) {
// memberController.doJoin();
// } else if (cmd.equals("article write")) {
// articleController.doWrite();
// } else if (cmd.startsWith("article list")) {
// articleController.showList(cmd);
// } else if (cmd.startsWith("article detail")) {
// articleController.showDetail(cmd);
// } else if (cmd.startsWith("article delete")) {
// articleController.doDelete(cmd);
// } else if (cmd.startsWith("article modify")) {
// articleController.doModify(cmd);
// } else {
// System.out.println("사용할 수 없는 명령어입니다");
// }
}
System.out.println("==프로그램 종료==");
sc.close();
}
}
코드를 붙여넣으니까 몇가지 오류가 발생해서 해결하려고 이리저리 살피니까 Main 메서드에는 sc 인자를 받지 않게끔 하고, ArticleController와 MemberController는 Controller 에게 Extends 받게끔 했다. Controller에게 상속받고 각 클래스에 doAction 메서드를 넣었다.
public void doAction(String cmd, String actionMethodName) {
this.cmd = cmd;
switch (actionMethodName) {
case "write":
doWrite();
break;
case "list":
showList();
break;
case "detail":
showDetail();
break;
case "modify":
doModify();
break;
case "delete":
doDelete();
break;
default:
System.out.println("명령어 확인 (actionMethodName) 오류");
break;
}
}
public void doAction(String cmd, String actionMethodName) {
this.cmd = cmd;
switch (actionMethodName) {
case "join":
doJoin();
break;
default:
System.out.println("명령어 확인 (actionMethodName) 오류");
break;
}
}
그러자 ArticleController에 cmd를 받아서 Split하고 데이터를 검증하는 코드들이 모두 먹통이 나서 그 코드들 까지 죄다 수정을 거쳐야했다. 잘 살펴보니 죄다 수정은 맞는데 public void를 private void로 바꿔주니 잘 됐다. doAction에서 처리하니까 죄다 퍼블릭일 필요가 없어서 그런 것 같다.
if (controllerName.equals("article")) {
controller = articleController;
} else if (controllerName.equals("member")) {
controller = memberController;
} else {
System.out.println("사용불가 명령어");
continue;
}
controller.doAction(cmd, actionMethodName);
이제 우리가 면밀히 살펴야할 곳은 여기인데 이 코드는 우리가 명령어를 입력할 때 그걸 판별해주고 어디로 보낼지 결정하는 코드이다. 이걸 수월하게 하기 위해서 Controller라는 클래스를 만들었고 해당 메서드를 필요한 각 클래스에서 수월하게 실행하기 위해 상속을 받는다. 때문에 전면적으로 코드를 약간씩 뜯어 고치고 의도한대로 잘 돌아가게끔 만든 것이다.
이제 로그인과 로그아웃을 만드는데 집중하면 된다.
private void doLogin() {
if (currentUser != null) {
System.out.println("이미 로그인 되어있음.");
return;
}
System.out.println("==로그인==");
System.out.print("로그인 아이디 : ");
String loginId = sc.nextLine().trim();
System.out.print("로그인 비밀번호 : ");
String loginPw = sc.nextLine().trim();
Member member = findMemberByLoginId(loginId);
if (member == null) {
System.out.println("아이디 확인");
return;
} else if (!member.getLoginPw().equals(loginPw)) {
System.out.println("비밀번호 틀림");
return;
}
currentUser = member;
System.out.printf("%s님 로그인 성공", member.getName());
}
private void doLogout() {
if (currentUser != null) {
System.out.println("로그아웃.");
currentUser = null;
} else {
System.out.println("로그인 하지 않음.");
}
}
private Member findMemberByLoginId(String loginId) {
for (Member member : members) {
if (member.getLoginId().equals(loginId)) {
return member;
}
}
return null;
}
이렇게 만들었다
만들고 나니까 다음 단계인 article write가 로그인 상태에서만 작동하게 하는 것은 쉬웠다.
private void doWrite() {
if (currentUser == null) {
System.out.println("로그인 하지 않으면 글 못써.");
return;
}
System.out.println("==게시글 작성==");
int id = lastArticleId + 1;
String regDate = Util.getNow();
String updateDate = regDate;
System.out.print("제목 : ");
String title = sc.nextLine();
System.out.print("내용 : ");
String body = sc.nextLine();
Article article = new Article(id, regDate, updateDate, title, body);
articles.add(article);
System.out.println(id + "번 글이 생성되었습니다");
lastArticleId++;
}
이렇게 해결했고 다음 구현은 작성자만 수정/삭제가 가능하도록 하는 것이다.
private void doWrite() {
if (!isLogined()) {
System.out.println("로그인 하지 않으면 글 못써.");
return;
}
강사님이 원하는 답은 이거 같아서 수정해서 남긴다. 어떻게 된거냐면 isLogined라는 메서드를 MemberController에 하나 만들었다. 로그인 로그아웃 기능을 만들 때 나는 변수 자체를 사용했는데 강사님은 메서드로 만드시고 이 메서드를 ArticleController에 어떻게 적용시킬거냐는 질문을 남기고 강의가 끝이 났다. 그 때 나는 부모 클래스인 Controller 클래스에 메서드 선언해서 상속 받으면 된다는 생각을 했고 그 결과가 저렇게 나와있다. 고친 Controller 클래스를 보자.
public abstract class Controller {
abstract public void doAction(String cmd, String actionMethodName);
public boolean isLogined(){
return true;
}
}
MemberController에서 가져오는 과정에서 private가 아니라 public으로 고쳐줘서 서로 다 사용할 수 있게끔 하고 메서드 오버라이딩을 받아서 사용하는 형태로 해서 윗위의 코드 처럼 바로 메서드를 받아 쓸 수 있게끔 해결했다.
'Coding History' 카테고리의 다른 글
2024. 07. 04 문제풀이 (0) | 2024.07.04 |
---|---|
2024 07. 03 ArticleManager 공부 (0) | 2024.07.03 |
2024. 07. 02. 문제풀이 (1) | 2024.07.02 |
국비 지원 IT(웹앱개발) 취업반 강의 19일차 (ArticleManager) (0) | 2024.07.02 |
2024. 07 .01 문제풀이 (0) | 2024.07.01 |