[wise_saying_app] GitHub 👇🏻
GitHub - daxx0ne/wise_saying_app
Contribute to daxx0ne/wise_saying_app development by creating an account on GitHub.
github.com
👀 기능설명
등록: 명언과 작가 이름을 등록할 수 있다.
목록: 등록되있는 명언과 작가 이름의 리스트를 확인할 수 있다.
삭제: 원하는 번호를 입력하여 명언을 삭제할 수 있다.
수정: 원하는 번호를 입력하여 명언 내용과, 작가 이름을 수정할 수 있다.
종료: 명언 앱을 종료한다.
📌 만들기 전 해야할 것!
- 새로운 Git 리포지터리 생성하기
- 프로젝트 생성하기
- gradle → IntelliJ 로 세팅
- .gitignore 추가
- 리포지터리 연결
- 단계 별 커밋해주기
- git init
- git remote add origin 깃허브주소
- git add .
- git commit -m “메세지”
- git push origin main
<1단계>
✔️ 목표: 종료 기능 구현하기
[main.java]
package com.example;
import java.util.*;
public class main { // Applicaiton이 일하도록 함
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
new Application(sc).run(); // 기본적으로 Scanner를 가지고 있는 Applicaiton
sc.close();
}
}
[Application.java]
package com.example;
import java.util.*;
import io.micronaut.runtime.Micronaut;
public class Application {
public final Scanner sc;
public Application(Scanner sc){
this.sc = sc;
}
public void run() {
System.out.println("== 명언 앱 ==");
while(true){
System.out.print("명령) ");
String command = sc.nextLine().trim();
// trim() : 혹시 있을지 모를 좌우공백제거된 버전으로 주세요!
if(command.equals("종료")) { // 종료가 입력되면 프로그램 종료
break;
}
}
}
}
<2단계>
✔️ 목표: 등록 기능 구현하기
[Application.java]
package com.example;
import java.util.*;
import io.micronaut.runtime.Micronaut;
public class Application {
public final Scanner sc;
public Application(Scanner sc){
this.sc = sc;
}
public void run() {
System.out.println("== 명언 앱 ==");
while(true){
System.out.print("명령) ");
String command = sc.nextLine().trim();
// trim() : 혹시 있을지 모를 좌우공백 제거된 버전으로 주세요!
if(command.equals("종료")) { // 종료가 입력되면 프로그램 종료
break;
}
else if (command.equals("등록")){
System.out.print("명언 : "); // #2 명언과 작가 이름을 입력받기
String content = sc.nextLine().trim();
System.out.print("작가 : ");
String authorName = sc.nextLine().trim();
}
}
}
}
<3단계>
✔️ 목표: 등록 시 생성된 명언 번호를 노출시키기
[Application.java]
package com.example;
import java.util.*;
import io.micronaut.runtime.Micronaut;
public class Application {
public final Scanner sc;
public Application(Scanner sc){
this.sc = sc;
}
public void run() {
System.out.println("== 명언 앱 ==");
while(true){
System.out.print("명령) ");
String command = sc.nextLine().trim();
// trim() : 혹시 있을지 모를 좌우공백 제거된 버전으로 주세요!
if(command.equals("종료")) { // 종료가 입력되면 프로그램 종료
break;
}
else if (command.equals("등록")){
System.out.print("명언 : "); // #2 명언과 작가 이름을 입력받기
String content = sc.nextLine().trim();
System.out.print("작가 : ");
String authorName = sc.nextLine().trim();
System.out.println("1번 명언이 등록되었습니다."); // #3 등록 문구 띄우기
}
}
}
}
<4단계>
✔️ 목표: 등록할 때마다 생성되는 명언번호가 증가하도록 구현하기
[Application.java]
package com.example;
import java.util.*;
import io.micronaut.runtime.Micronaut;
public class Application {
public final Scanner sc;
public Application(Scanner sc){
this.sc = sc;
}
public void run() {
System.out.println("== 명언 앱 ==");
long lastWiseSayingId = 1; // 제일 겉에 있는 곳에 변수를 선언해야지 장기기억!
while(true){
System.out.print("명령) ");
String command = sc.nextLine().trim();
// trim() : 혹시 있을지 모를 좌우공백 제거된 버전으로 주세요!
if(command.equals("종료")) { // 종료가 입력되면 프로그램 종료
break;
}
else if (command.equals("등록")){
System.out.print("명언 : "); // #2 명언과 작가 이름을 입력받기
String content = sc.nextLine().trim();
System.out.print("작가 : ");
String authorName = sc.nextLine().trim();
System.out.printf("%d번 명언이 등록되었습니다.\n",lastWiseSayingId); // #3 등록 문구 띄우기
lastWiseSayingId++; // #4 등록할 때마다 번호 증가
}
}
}
}
<5단계>
✔️ 목표: 목록 기능 구현하기
[Wisesaying.java]
package com.example;
public class WiseSaying { // 등록된 명언과 작가이름을 저장
private long id; // 등록 번호
private String content; // 명언
private String authorName; // 작가 이름
public WiseSaying(long id, String content, String authorName) {
this.id = id;
this.content = content;
this.authorName = authorName;
}
public long getId() {
return id;
}
public String getContent() {
return content;
}
public String getAuthorName() {
return authorName;
}
}
[Application.java]
package com.example;
import java.util.*;
import io.micronaut.runtime.Micronaut;
public class Application {
public final Scanner sc;
public Application(Scanner sc){
this.sc = sc;
}
public void run() {
System.out.println("== 명언 앱 ==");
long lastWiseSayingId = 0; // 제일 겉에 있는 곳에 변수를 선언해야지 장기기억!
List<WiseSaying> wiseSayings = new ArrayList<>(); // wiseSayings 라는 리스트를 만들어준 후 Arraylist 생성
while(true){
System.out.print("명령) ");
String command = sc.nextLine().trim();
// trim() : 혹시 있을지 모를 좌우공백 제거된 버전으로 주세요!
if(command.equals("종료")) { // 종료가 입력되면 프로그램 종료
break;
}
else if (command.equals("등록")){
long id = lastWiseSayingId + 1; // #4 등록할 때마다 번호 증가
System.out.print("명언 : "); // #2 명언과 작가 이름을 입력받기
String content = sc.nextLine().trim();
System.out.print("작가 : ");
String authorName = sc.nextLine().trim();
WiseSaying wiseSaying = new WiseSaying(id, content, authorName);
wiseSayings.add(wiseSaying); // 등록된 명언들을 WiseSaying 리스트에 저장
System.out.printf("%d번 명언이 등록되었습니다.\n", id); // #3 등록 문구 띄우기
lastWiseSayingId = id;
}
else if (command.equals("목록")) { // #5 등록된 명언의 목록 출력하기
System.out.println("번호 / 작가 / 명언");
System.out.println("-".repeat(30)); // -를 30번 반복해서 출력 -------... 랑 같음
for (int i = wiseSayings.size() - 1; i >= 0; i--){ // 입력의 역순으로 출력 (목록의 1번부터)
WiseSaying wiseSaying = wiseSayings.get(i);
// '목록번호 작가이름 명언' 을 출력
System.out.printf("%d / %s / %s\n", wiseSaying.getId(), wiseSaying.getAuthorName(), wiseSaying.getContent());
}
}
}
}
}
<6단계> + 각 모듈로 기능분리 및 구조개선
✔️ 목표: 삭제 기능 구현하기
[main.java]
package com.example;
import java.util.*;
public class main { // Applicaiton이 일하도록 함
public static void main(String[] args) {
Container.init(); // 공통적으로 사용되는 것들을 모아두는 공간(Container) 초기화
new Application().run(); // 기본적으로 Scanner를 가지고 있는 Applicaiton
Container.close();
// 공통적으로 사용되는 것들을 모아두는 공간(Container) 자원해제
}
}
[SystemController.java]
package com.example.system.controller;
public class SystemController { // #1 종료하기
public void exit() {
System.out.println("명언앱을 종료합니다.");
}
}
[WiseSayingController.java]
package com.example.wiseSaying.controller;
import com.example.Rq;
import com.example.wiseSaying.entity.WiseSaying;
import com.example.Container;
import java.util.*;
import java.util.stream.IntStream;
public class WiseSayingController {
private long lastWiseSayingId;
private final List<WiseSaying> wiseSayings;
public WiseSayingController() {
lastWiseSayingId = 0;
wiseSayings = new ArrayList<>();
}
public void write() { // #2~4 등록하기
long id = lastWiseSayingId + 1; // 등록할 때마다 번호 증가
System.out.print("명언 : "); // 명언과 작가 이름을 입력받기
String content = Container.getScanner().nextLine().trim();
System.out.print("작가 : ");
String authorName = Container.getScanner().nextLine().trim();
WiseSaying wiseSaying = new WiseSaying(id, content, authorName);
wiseSayings.add(wiseSaying); // 등록된 명언들을 WiseSaying 리스트에 저장
System.out.printf("%d번 명언이 등록되었습니다.\n", id); // 등록 문구 띄우기
lastWiseSayingId = id;
}
public void list() { // #5 등록된 명언의 목록 출력하기기
System.out.println("번호 / 작가 / 명언");
System.out.println("-".repeat(30)); // -를 30번 반복해서 출력 -------... 랑 같음
for (int i = wiseSayings.size() - 1; i >= 0; i--) { // 입력의 역순으로 출력 (목록의 1번부터)
WiseSaying wiseSaying = wiseSayings.get(i);
// '목록번호 작가이름 명언' 을 출력
System.out.printf("%d / %s / %s\n", wiseSaying.getId(), wiseSaying.getAuthorName(), wiseSaying.getContent());
}
}
public void remove(Rq rq) { // #6 명언 삭제하기
int id = rq.getIntParam("id", -1); // id 값을 정수화 해서 보내주고, 만약 실패하면 -1을 보내줘!
if (id == -1) {
System.out.println("id(정수)를 입력해주세요.");
return;
}
// 입력한 id와 일치하는 명언 객체를 찾음
WiseSaying wiseSaying = findById(id);
// 찾은 명언 객체를 리스트에서 제거함
wiseSayings.remove(wiseSaying);
System.out.printf("%d번 명언이 삭제되었습니다.\n", id);
}
private WiseSaying findById(int id) {
for (WiseSaying wiseSaying : wiseSayings) {
if (wiseSaying.getId() == id) {
return wiseSaying;
}
}
return null;
}
}
[WiseSaying.java]
package com.example.wiseSaying.entity;
public class WiseSaying { // 등록된 명언과 작가이름을 저장
private long id; // 등록 번호
private String content; // 명언
private String authorName; // 작가 이름
public WiseSaying(long id, String content, String authorName) {
this.id = id;
this.content = content;
this.authorName = authorName;
}
public long getId() {
return id;
}
public String getContent() {
return content;
}
public String getAuthorName() {
return authorName;
}
}
[Application.java]
package com.example;
import com.example.system.controller.SystemController;
import com.example.wiseSaying.controller.WiseSayingController;
import java.util.*;
public class Application {
public void run() {
System.out.println("== 명언 앱 ==");
SystemController systemController = new SystemController(); // 객체 생성
WiseSayingController wiseSayingController = new WiseSayingController();
while(true){
System.out.print("명령) "); // 입력 받기
String command = Container.getScanner().nextLine().trim();
Rq rq = new Rq(command);
switch (rq.getActionCode()) {
case "종료":
systemController.exit();
return;
case "등록":
wiseSayingController.write();
break;
case "목록":
wiseSayingController.list();
break;
case "삭제":
wiseSayingController.remove(rq);
break;
}
}
}
}
[Rq.java]
package com.example;
import java.util.HashMap;
import java.util.Map;
public class Rq {
private String actionCode;
private Map<String, String> params;
public Rq(String command) {
String[] commandBits = command.split("\\?", 2);
actionCode = commandBits[0];
params = new HashMap<>();
if (commandBits.length == 1) return;
String[] paramsBits = commandBits[1].split("&");
for (String paramStr : paramsBits) {
String[] paramStrBits = paramStr.split("=", 2);
if (paramStrBits.length == 1) continue;
String key = paramStrBits[0];
String value = paramStrBits[1];
params.put(key, value);
}
}
public String getActionCode() {
return actionCode;
}
public String getParam(String name) {
return params.get(name);
}
public int getIntParam(String name, int defaultValue) {
try {
return Integer.parseInt(getParam(name));
} catch (NumberFormatException e) {
}
return defaultValue;
}
}
[Container.java]
package com.example;
import java.util.Scanner;
public class Container {
private static Scanner sc;
public static void init() {
sc = new Scanner(System.in);
}
public static void close() {
sc.close();
}
public static Scanner getScanner() {
return sc;
}
}
<7단계>
✔️ 목표: 존재하지 않는 명언을 삭제 했을 때 예외처리하기
[WiseSayingController.java]
package com.example.wiseSaying.controller;
import com.example.Rq;
import com.example.wiseSaying.entity.WiseSaying;
import com.example.Container;
import java.util.*;
import java.util.stream.IntStream;
public class WiseSayingController {
private long lastWiseSayingId;
private final List<WiseSaying> wiseSayings;
public WiseSayingController() {
lastWiseSayingId = 0;
wiseSayings = new ArrayList<>();
}
public void write() { // #2~4 등록하기
long id = lastWiseSayingId + 1; // 등록할 때마다 번호 증가
System.out.print("명언 : "); // 명언과 작가 이름을 입력받기
String content = Container.getScanner().nextLine().trim();
System.out.print("작가 : ");
String authorName = Container.getScanner().nextLine().trim();
WiseSaying wiseSaying = new WiseSaying(id, content, authorName);
wiseSayings.add(wiseSaying); // 등록된 명언들을 WiseSaying 리스트에 저장
System.out.printf("%d번 명언이 등록되었습니다.\n", id); // 등록 문구 띄우기
lastWiseSayingId = id;
}
public void list() { // #5 등록된 명언의 목록 출력하기기
System.out.println("번호 / 작가 / 명언");
System.out.println("-".repeat(30)); // -를 30번 반복해서 출력 -------... 랑 같음
for (int i = wiseSayings.size() - 1; i >= 0; i--) { // 입력의 역순으로 출력 (목록의 1번부터)
WiseSaying wiseSaying = wiseSayings.get(i);
// '목록번호 작가이름 명언' 을 출력
System.out.printf("%d / %s / %s\n", wiseSaying.getId(), wiseSaying.getAuthorName(), wiseSaying.getContent());
}
}
public void remove(Rq rq) { // #6 명언 삭제하기
int id = rq.getIntParam("id", -1); // id 값을 정수화 해서 보내주고, 만약 실패하면 -1을 보내줘!
if (id == -1) {
System.out.println("id(정수)를 입력해주세요.");
return;
}
// 입력한 id와 일치하는 명언 객체를 찾음
WiseSaying wiseSaying = findById(id);
// 찾은 명언 객체를 리스트에서 제거함
if (wiseSaying == null) { // #7 존재하지 않는 명언삭제에 대한 예외처리
System.out.printf("%d번 명언은 존재하지 않습니다.\n", id);
return;
}
// 찾은 명언객체를 리스트에서 제거
wiseSayings.remove(wiseSaying);
System.out.printf("%d번 명언이 삭제되었습니다.\n", id);
}
private WiseSaying findById(int id) {
for (WiseSaying wiseSaying : wiseSayings) {
if (wiseSaying.getId() == id) {
return wiseSaying;
}
}
return null;
}
}
<8단계>
✔️ 목표: 수정 기능 구현하기
[Application.java]
package com.example;
import com.example.system.controller.SystemController;
import com.example.wiseSaying.controller.WiseSayingController;
import java.util.*;
public class Application {
public void run() {
System.out.println("== 명언 앱 ==");
SystemController systemController = new SystemController(); // 객체 생성
WiseSayingController wiseSayingController = new WiseSayingController();
while(true){
System.out.print("명령) "); // 입력 받기
String command = Container.getScanner().nextLine().trim();
Rq rq = new Rq(command);
switch (rq.getActionCode()) {
case "종료":
systemController.exit();
return;
case "등록":
wiseSayingController.write();
break;
case "목록":
wiseSayingController.list();
break;
case "삭제":
wiseSayingController.remove(rq);
break;
case "수정":
wiseSayingController.modify(rq);
break;
}
}
}
}
[WiseSayingController.java]
package com.example.wiseSaying.controller;
import com.example.Rq;
import com.example.wiseSaying.entity.WiseSaying;
import com.example.Container;
import java.util.*;
import java.util.stream.IntStream;
public class WiseSayingController {
private long lastWiseSayingId;
private final List<WiseSaying> wiseSayings;
public WiseSayingController() {
lastWiseSayingId = 0;
wiseSayings = new ArrayList<>();
}
private WiseSaying findById(int id) {
for (WiseSaying wiseSaying : wiseSayings) {
if (wiseSaying.getId() == id) {
return wiseSaying;
}
}
return null;
}
public void write() { // #2~4 등록하기
long id = lastWiseSayingId + 1; // 등록할 때마다 번호 증가
System.out.print("명언 : "); // 명언과 작가 이름을 입력받기
String content = Container.getScanner().nextLine().trim();
System.out.print("작가 : ");
String authorName = Container.getScanner().nextLine().trim();
WiseSaying wiseSaying = new WiseSaying(id, content, authorName);
wiseSayings.add(wiseSaying); // 등록된 명언들을 WiseSaying 리스트에 저장
System.out.printf("%d번 명언이 등록되었습니다.\n", id); // 등록 문구 띄우기
lastWiseSayingId = id;
}
public void list() { // #5 등록된 명언의 목록 출력하기기
System.out.println("번호 / 작가 / 명언");
System.out.println("-".repeat(30)); // -를 30번 반복해서 출력 -------... 랑 같음
for (int i = wiseSayings.size() - 1; i >= 0; i--) { // 입력의 역순으로 출력 (목록의 1번부터)
WiseSaying wiseSaying = wiseSayings.get(i);
// '목록번호 작가이름 명언' 을 출력
System.out.printf("%d / %s / %s\n", wiseSaying.getId(), wiseSaying.getAuthorName(), wiseSaying.getContent());
}
}
public void remove(Rq rq) { // #6 명언 삭제하기
int id = rq.getIntParam("id", -1); // id 값을 정수화 해서 보내주고, 만약 실패하면 -1을 보내줘!
if (id == -1) {
System.out.println("id(정수)를 입력해주세요.");
return;
}
// 입력한 id와 일치하는 명언 객체를 찾음
WiseSaying wiseSaying = findById(id);
if (wiseSaying == null) { // #7 존재하지 않는 명언삭제에 대한 예외처리
System.out.printf("%d번 명언은 존재하지 않습니다.\n", id);
return;
}
// 찾은 명언객체를 리스트에서 제거
wiseSayings.remove(wiseSaying);
System.out.printf("%d번 명언이 삭제되었습니다.\n", id);
}
public void modify(Rq rq) {
int id = rq.getIntParam("id", -1);
if (id == -1) {
System.out.println("id(정수)를 입력해주세요.");
return;
}
WiseSaying wiseSaying = findById(id); // 입력한 id와 일치하는 명언 객체를 찾음
if (wiseSaying == null) { // 존재하지 않는 명언삭제에 대한 예외처리 (수정할 때도)
System.out.printf("%d번 명언은 존재하지 않습니다.\n", id);
return;
}
// #8 명언 수정하기
System.out.printf("명언(기존) : %s\n", wiseSaying.getContent());
System.out.print("명언 : ");
String content = Container.getScanner().nextLine().trim();
System.out.printf("작가(기존) : %s\n", wiseSaying.getAuthorName());
System.out.print("작가 : ");
String authorName = Container.getScanner().nextLine().trim();
wiseSaying.setContent(content);
wiseSaying.setAuthorName(authorName);
System.out.printf("%d번 명언이 수정되었습니다.\n", id);
}
}
[WiseSaying.java]
package com.example.wiseSaying.entity;
public class WiseSaying { // 등록된 명언과 작가이름을 저장
private long id; // 등록 번호
private String content; // 명언
private String authorName; // 작가 이름
public WiseSaying(long id, String content, String authorName) {
this.id = id;
this.content = content;
this.authorName = authorName;
}
public long getId() {
return id;
}
public String getContent() {
return content;
}
public String getAuthorName() {
return authorName;
}
public void setContent(String content) {
this.content = content;
}
public void setAuthorName(String authorName) {
this.authorName = authorName;
}
}
🎉 결과물

🌟 복습하기
💡 리펙토링
- 소스코드는 유지보수가 쉬어야 한다.
- 큰 덩어리의 프로그램은 나중에 유지보수 하기 어려움!
- 적절한 단위로 나눠야 좋음
- 작은 프로그램의 조합으로 만들기
- 나눈 프로그램 끼리 통신을 할 때 규칙이 있음
- 안쪽에 있는 통신 채널의 개수는 적을 수록 좋다
- 명령의 흐름은 수직적이면 좋다
- 파악하기 쉽기 때문
💡 컨트롤러
- Appicaiton에서 주는 명령어를 받아서, 출력해주는 역할
- 외부에서 들어오는 입력을 담당하는 부분
💡 Rq 클래스
: request 요청
- Rq 클래스는 왜 쓰는걸까? (재밌는 예시를 통해 알아보자!)
- 가정집과 소 한 마리가 있다고 가정하자!
- 소고기를 먹고싶을 때, 우리는 소를 도축업자에게 주고 받아온 고기를 구워먹는다.
- 어느날 마을 옆에 어떤 상점이 생기면서 육류 요리사가 왔다고 가정하자!
- 이제는 소고기가 먹고 싶을 때, 소를 육류 요리사에게 건네주면 알아서 용도에 맞춰서 자르고 보관하고 요리해준다!!!
- 이때, 육류 요리사의 역할이 Rq 클래스라고 볼 수 있다.
*Rq 클래스를 전체적인 명령어에 도입하여 라우팅 코드를 깔끔하게 적을 수 있다.
*getIntPharam을 도입하여 유효성 체크 로직을 간단하게 사용할 수 있다.
“사용법을 꼭 이해하고 쓰자!”