오늘은 강사님 개인 사정으로 좀 늦으셔서 문제 풀이를 먼저 조금 하다가 수업이 시작됐다.
일단 강의가 시작하고 목표는 article list 명령어 입력시에 작성자의 이름까지 보이도록 하는 것인데, 이거는 어제 delete랑 modify를 권한이 있는 사람(작성자)만 가능하게끔 내가 만들어서 이미 구현한 내용이다. 일단 코드를 쭉 살펴 보면
package org.koreait.controller;
import org.koreait.util.Util;
import org.koreait.dto.Member;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class MemberController extends Controller {
static Scanner sc;
static List<Member> members;
static int lastMemberId = 3;
static String cmd;
static Member currentUser = null;
public MemberController(Scanner sc) {
this.sc = sc;
members = new ArrayList<>();
}
public boolean isLogined(){
return currentUser != null;
}
public void doAction(String cmd, String actionMethodName) {
this.cmd = cmd;
switch (actionMethodName) {
case "join":
doJoin();
break;
case "login":
doLogin();
break;
case "logout":
doLogout();
break;
default:
System.out.println("명령어 확인 (actionMethodName) 오류");
break;
}
}
private void doJoin() {
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 void doLogin() {
if (isLogined()) {
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님 로그인 성공\n", currentUser.getName());
}
private void doLogout() {
if (isLogined()) {
System.out.println("로그아웃.");
currentUser = null;
} else {
System.out.println("로그인 하지 않음.");
}
}
private boolean isJoinableLoginId(String loginId) {
for (Member member : members) {
if (member.getLoginId().equals(loginId)) {
return false;
}
}
return true;
}
public static void makeTestUserData() {
System.out.println("테스트 유저 데이터 생성");
members.add(new Member(1, "2023-12-12 12:12:12", "test1", "test1", "김민수"));
members.add(new Member(2, Util.getNow(), "test2", "test2", "최민희"));
members.add(new Member(3, Util.getNow(), "test3", "test3", "Ryan"));
}
private Member findMemberByLoginId(String loginId) {
for (Member member : members) {
if (member.getLoginId().equals(loginId)) {
return member;
}
}
return null;
}
}
MamberController class에 makeTestUserData 메서드에 작성자도 임의로 설정을 했고,
package org.koreait.controller;
import org.koreait.dto.Article;
import org.koreait.util.Util;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import static org.koreait.controller.MemberController.currentUser;
public class ArticleController extends Controller {
static int lastArticleId;
static Scanner sc;
static List<Article> articles;
private String cmd;
public ArticleController(Scanner sc) {
this.sc = sc;
articles = new ArrayList<>();
this.lastArticleId = 3;
}
public boolean isLogined(){
return currentUser != null;
}
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;
}
}
private void doWrite() {
if (!isLogined()) {
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, currentUser.getName());
articles.add(article);
System.out.println(id + "번 글이 생성되었습니다");
lastArticleId++;
}
private void showList() {
System.out.println("==게시글 목록==");
String[] cmdParts = cmd.split(" ");
String keyword = cmdParts.length == 3 ? cmdParts[2] : "";
List<Article> filteredArticles;
if (keyword.isEmpty()) {
System.out.println("검색어 : " + keyword);
filteredArticles = articles;
} else {
filteredArticles = new ArrayList<>();
for (Article article : articles) {
if (article.getTitle().contains(keyword)) {
filteredArticles.add(article);
}
}
}
if (filteredArticles.isEmpty()) {
System.out.println("아무것도 없어");
} else {
System.out.println(" 번호 / 날짜 / 제목 / 내용 / 작성자 ");
for (int i = filteredArticles.size() - 1; i >= 0; i--) {
Article article = filteredArticles.get(i);
if (Util.getNow().split(" ")[0].equals(article.getRegDate().split(" ")[0])) {
System.out.printf(" %d / %s / %s / %s / %s \n", article.getId(), article.getRegDate().split(" ")[1], article.getTitle(), article.getBody(), article.getWriter());
} else {
System.out.printf(" %d / %s / %s / %s / %s \n", article.getId(), article.getRegDate().split(" ")[0], article.getTitle(), article.getBody(), article.getWriter());
}
}
}
}
private void showDetail() {
System.out.println("==게시글 상세보기==");
int id = Integer.parseInt(cmd.split(" ")[2]);
Article foundArticle = getArticleById(id);
if (foundArticle == null) {
System.out.println("해당 게시글은 없습니다");
return;
}
System.out.println("번호 : " + foundArticle.getId());
System.out.println("작성날짜 : " + foundArticle.getRegDate());
System.out.println("수정날짜 : " + foundArticle.getUpdateDate());
System.out.println("제목 : " + foundArticle.getTitle());
System.out.println("내용 : " + foundArticle.getBody());
System.out.println("작성자 : " + foundArticle.getWriter());
}
private void doDelete() {
System.out.println("==게시글 삭제==");
int id = Integer.parseInt(cmd.split(" ")[2]);
Article foundArticle = getArticleById(id);
if (foundArticle == null) {
System.out.println("해당 게시글은 없습니다");
return;
}
if(!isLogined()){
System.out.println("삭제 권한이 없습니다.");
}else if(currentUser.getName().equals(foundArticle.getWriter())){
articles.remove(foundArticle);
System.out.println(id + "번 게시글이 삭제되었습니다");
}else {
System.out.println("삭제 권한이 없습니다.");
}
}
private void doModify() {
System.out.println("==게시글 수정==");
int id = Integer.parseInt(cmd.split(" ")[2]);
Article foundArticle = getArticleById(id);
if (foundArticle == null) {
System.out.println("해당 게시글은 없습니다");
return;
}
if(!isLogined()){
System.out.println("수정 권한이 없습니다.");
}else if(currentUser.getName().equals(foundArticle.getWriter())){
System.out.println("기존 제목 : " + foundArticle.getTitle());
System.out.println("기존 내용 : " + foundArticle.getBody());
System.out.print("새 제목 : ");
String newTitle = sc.nextLine();
System.out.print("새 내용 : ");
String newBody = sc.nextLine();
foundArticle.setTitle(newTitle);
foundArticle.setBody(newBody);
foundArticle.setUpdateDate(Util.getNow());
System.out.println(id + "번 게시글이 수정되었습니다.");
}else {
System.out.println("수정 권한이 없습니다.");
}
}
private Article getArticleById(int id) {
for (Article article : articles) {
if (article.getId() == id) {
return article;
}
}
return null;
}
public void makeTestData() {
System.out.println("테스트 데이터 생성");
articles.add(new Article(1, "2023-12-12 12:12:12", "2023-12-12 12:12:12", "제목1", "내용1", "김민수"));
articles.add(new Article(2, Util.getNow(), Util.getNow(), "제목2", "내용2", "최민희"));
articles.add(new Article(3, Util.getNow(), Util.getNow(), "제목3", "내용3", "Ryan"));
}
}
ArticleController class에 makeTestData 메서드에도 작성자를 넣었다. 나머지 코드에 작성자가 나오는 곳은 getWriter로 받아와서 쓴다. Member class에는 이미 name이 있고, Article class에는 작성자를 받을 공간이 없어서 새로 String writer를 선언해주고 getWriter(게터 세터)를 제너레이트 하고 사용할 수 있게끔 만들었다.
package org.koreait.dto;
public class Article extends Dto {
private String updateDate;
private String title;
private String body;
private String writer;
public Article(int id, String regDate, String updateDate, String title, String body, String writer) {
this.id = id;
this.regDate = regDate;
this.updateDate = updateDate;
this.title = title;
this.body = body;
this.writer = writer;
}
public String getRegDate() {
return regDate;
}
public String getUpdateDate() {
return updateDate;
}
public void setUpdateDate(String updateDate) {
this.updateDate = updateDate;
}
public void setRegDate(String regDate) {
this.regDate = regDate;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getWriter() {
return writer;
}
public void setWriter(String writer) {
this.writer = writer;
}
@Override
public String toString() {
return "Article{" +
"updateDate='" + updateDate + '\'' +
", title='" + title + '\'' +
", body='" + body + '\'' +
", author='" + writer + '\'' +
", id=" + id +
", regDate='" + regDate + '\'' +
'}';
}
}
여기서 문제를 겪었던게
public class Article extends Dto {
private String updateDate;
private String title;
private String body;
// private String writer;
public Article(int id, String regDate, String updateDate, String title, String body, String writer) {
this.id = id;
this.regDate = regDate;
this.updateDate = updateDate;
this.title = title;
this.body = body;
// this.writer = writer;
}
이렇게 인자만 받으려고 해서 null이 계속 나왔다는거? 정도 밖에 기억이 안나는데 보시다시피 다 해결은 한 상태다.
다음으로 write에 로그인 했을 때만 할 수 있게끔 하는 것에서 강사님이 유사하긴 한데 나보다 효율적으로 사용하셨다.
나는 메서드를 오버라이드 해서 사용했는데,
public abstract class Controller {
abstract public void doAction(String cmd, String actionMethodName);
public boolean isLogined(){
return true;
}
}
그래서 나는 클래스 두개에 다 메서드를 선언해 놓은 상태인데 강사님은 그럴 필요가 없게 만드셨다.
public abstract class Controller {
protected static Member loginedMember = null;
public abstract void doAction(String cmd, String actionMethodName);
public boolean isLogined() {
return loginedMember != null;
}
public void makeTestData() {
}
}
이렇게 쓰면 굳이 메서드를 또 써 넣을 필요가 없다.
그리고는 약간의 구조 개선이 있었는데,
package org.koreait.articleManager;
import org.koreait.controller.ArticleController;
import org.koreait.controller.Controller;
import org.koreait.controller.MemberController;
import java.util.Scanner;
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);
}
System.out.println("==프로그램 종료==");
sc.close();
}
}
이걸 조금 고치셨다.
String actionMethodName = cmdBits[1];
String forLoginCheck = controllerName + "/" + actionMethodName;
switch (forLoginCheck) {
case "article/write":
case "article/delete":
case "article/modify":
case "member/logout":
if (Controller.isLogined() == false) {
System.out.println("로그인 필요");
continue;
}
break;
}
switch (forLoginCheck) {
case "member/login":
case "member/join":
if (Controller.isLogined()) {
System.out.println("로그아웃 필요");
continue;
}
break;
App에서 거를 수 있게끔.
그리고 delete 랑 modify를 수행할 때 나는 작성자 이름으로 구분을 했는데 생각해보니까 동명이인이 오면 같은 이름이라는 이유로 글에 권한을 가져버린다. member join으로 같은 이름을 만들어서 지우거나 수정하니까 되더라. 그래서 고유 번호를 갖고 있는데 이 고유번호로 아이디를 판별하게끔 할 필요가 있었다.
package org.koreait.controller;
import org.koreait.articleManager.Container;
import org.koreait.dto.Article;
import org.koreait.dto.Member;
import org.koreait.util.Util;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class ArticleController extends Controller {
static int lastArticleId;
static Scanner sc;
static List<Article> articles;
private String cmd;
List<Member> members = Container.memberDao.members;
public ArticleController(Scanner sc) {
this.sc = sc;
articles = Container.articleDao.articles;
this.lastArticleId = 3;
}
// public static boolean isLogined(){
// return currentUser != null;
// }
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;
}
}
private void doWrite() {
// if (!isLogined()) {
// 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, loginedMember.getId());
articles.add(article);
System.out.println(id + "번 글이 생성되었습니다");
lastArticleId++;
}
private void showList() {
System.out.println("==게시글 목록==");
String[] cmdParts = cmd.split(" ");
String keyword = cmdParts.length == 3 ? cmdParts[2] : "";
List<Article> filteredArticles;
if (keyword.isEmpty()) {
System.out.println("검색어 : " + keyword);
filteredArticles = articles;
} else {
filteredArticles = new ArrayList<>();
for (Article article : articles) {
if (article.getTitle().contains(keyword)) {
filteredArticles.add(article);
}
}
if (filteredArticles.size() == 0) {
System.out.println(" 번호 / 날짜 / 작성자 / 제목 / 내용 ");
System.out.println("검색 결과 없음");
return;
}
}
String writerName = null;
if (filteredArticles.isEmpty()) {
System.out.println("아무것도 없어");
}
System.out.println(" 번호 / 날짜 / 작성자 / 제목 / 내용 ");
for (int i = filteredArticles.size() - 1; i >= 0; i--) {
Article article = filteredArticles.get(i);
for (Member member : members) {
if (article.getMemberId() == member.getId()) {
writerName = member.getName();
break;
}
}
if (Util.getNow().split(" ")[0].equals(article.getRegDate().split(" ")[0])) {
System.out.printf(" %d / %s / %s / %s / %s \n", article.getId(), article.getRegDate().split(" ")[1], article.getTitle(), article.getBody(), writerName);
} else {
System.out.printf(" %d / %s / %s / %s / %s \n", article.getId(), article.getRegDate().split(" ")[0], article.getTitle(), article.getBody(), writerName);
}
}
}
private void showDetail() {
System.out.println("==게시글 상세보기==");
int id = Integer.parseInt(cmd.split(" ")[2]);
Article foundArticle = getArticleById(id);
if (foundArticle == null) {
System.out.println("해당 게시글은 없습니다");
return;
}
System.out.println("번호 : " + foundArticle.getId());
System.out.println("작성날짜 : " + foundArticle.getRegDate());
System.out.println("수정날짜 : " + foundArticle.getUpdateDate());
System.out.println("제목 : " + foundArticle.getTitle());
System.out.println("내용 : " + foundArticle.getBody());
System.out.println("작성자 : " + foundArticle.getMemberId());
}
private void doDelete() {
System.out.println("==게시글 삭제==");
int id = Integer.parseInt(cmd.split(" ")[2]);
Article foundArticle = getArticleById(id);
if (foundArticle == null) {
System.out.println("해당 게시글은 없습니다");
return;
}
if (!isLogined()) {
System.out.println("삭제 권한이 없습니다. 1");
} else if (loginedMember.getId() == foundArticle.getId()) {
articles.remove(foundArticle);
System.out.println(id + "번 게시글이 삭제되었습니다");
} else {
System.out.println("삭제 권한이 없습니다. 2");
}
}
private void doModify() {
System.out.println("==게시글 수정==");
int id = Integer.parseInt(cmd.split(" ")[2]);
Article foundArticle = getArticleById(id);
if (foundArticle == null) {
System.out.println("해당 게시글은 없습니다");
return;
}
if (!isLogined()) {
System.out.println("수정 권한이 없습니다.");
} else if (loginedMember.getId() == foundArticle.getId()) {
System.out.println("기존 제목 : " + foundArticle.getTitle());
System.out.println("기존 내용 : " + foundArticle.getBody());
System.out.print("새 제목 : ");
String newTitle = sc.nextLine();
System.out.print("새 내용 : ");
String newBody = sc.nextLine();
foundArticle.setTitle(newTitle);
foundArticle.setBody(newBody);
foundArticle.setUpdateDate(Util.getNow());
System.out.println(id + "번 게시글이 수정되었습니다.");
} else {
System.out.println("수정 권한이 없습니다.");
}
}
private Article getArticleById(int id) {
for (Article article : articles) {
if (article.getId() == id) {
return article;
}
}
return null;
}
public void makeTestData() {
System.out.println("테스트 데이터 생성");
articles.add(new Article(1, "2023-12-12 12:12:12", "2023-12-12 12:12:12", "제목1", "내용1", 1));
articles.add(new Article(2, Util.getNow(), Util.getNow(), "제목2", "내용2", 2));
articles.add(new Article(3, Util.getNow(), Util.getNow(), "제목3", "내용3", 3));
}
}
일단 최종적으론 이렇게 고쳤다. 데이터를 효율적으로 쓰려고 구조가 꽤 많이 바뀌었는데 강사님 코드를 참고해서 천천히 고쳤다(구조를 고쳤다..). 나랑 코드나 변수명이 좀 달라서 오류 나는 부분들을 고치는데 조금 애를 먹었다.
아무튼 강의 끝날 때 쯤, 강사님이 전에 했던 motivation 앱을 시험으로 보신다고 하셨다. CRUD만 구현할 줄 알면 된다고 하셔서 ArticleManager를 아예 새 프로젝트를 만들어서 구현하며 공부해볼 예정이다.
'Coding History' 카테고리의 다른 글
2024. 07. 05 쿼리문 기본 문제 풀이 (0) | 2024.07.05 |
---|---|
국비 지원 IT(웹앱개발) 취업반 강의 22일차 (DB, DBMS, RDBMS) (0) | 2024.07.05 |
2024. 07. 04 문제풀이 (0) | 2024.07.04 |
2024 07. 03 ArticleManager 공부 (0) | 2024.07.03 |
국비 지원 IT(웹앱개발) 취업반 강의 20일차 (ArticleManager) (0) | 2024.07.03 |