# 개요

학원 다니면서 개인 프로젝트로 플래너 개발을 해보기로 했다.

처음에는 학원에서 배운 내용 + 내가 알고 있었는데 잊었던 것들 + 이번 개인 프로젝트로 새로 배우고 싶었던 것들 세 가지를 적절히 섞어 구현할 예정이다.

수업 내용을 기반으로 Front 화면 구현을 진행했다.

 


 

# 화면 설계

처음에는 내가 SPA(Single Page Application)에 대한 이해가 없었기 때문에 모든 기능에 대한 페이지가 구현되어야 한다고 생각했다. 그래서

  • User → 회원 가입 페이지, 로그인 페이지, 회원 정보 조회 페이지, 회원 정보 수정 페이지 등
  • Plan → 플랜 작성 페이지, 플랜 조회 페이지, 플랜 수정 페이지 등
  • DetailPlan → 디테일 작성 페이지, 디테일 조회 페이지, 디테일 수정 페이지 등

모든 페이지를 구현해야 한다고 생각했고 그에 따라 html 파일을 작성했다.

디자인이나 UI는 최대한 Bootstrap을 사용하려고 했다.

 

HTML 파일 추가 · JinHoooooou/Planner@d34b6e1

JinHoooooou committed Feb 28, 2024

github.com

각 화면에 대한 와이어 프레임을 그려보았다.

 

Figma

Created with FigJam

www.figma.com

 


 

# 클라이언트 - 서버 아키텍쳐 설계

서버의 데이터를 클라이언트로 어떻게 전달할까?를 생각해봤다.

  • 처음 계획은 JSP를 이용하여 서버 사이드 렌더링을 구현하려고 했다. 하지만 JSP는 내가 매우 싫어하는 구조이다. JSTL이 있다고는 하지만 그럴바에는 Thymeleaf나 Mustache같은 Template Engine을 사용하는게 더 낫겠다라는 생각이 들었다.
  • 그래서 다음 계획은 Thymeleaf를 사용하는 것이었다. 하지만 Thymeleaf를 위한 라이브러리를 추가해야 했고, 스프링 프레임워크를 사용하지 않았기 때문에 Embedded Tomcat에서 설정 추가해야하는 부분이 다소 어려웠다. 또한 팀원들도 Template Engine에 대해 모를 것이기 때문에 이를 설명하는 것도 문제가 될 것 같았다.
  • 마지막 계획은 ajax를 이용하는 것이었다. ajax는 수업 때 배우기도 했고, 서버와 클라이언트를 완전히 분리하여 클라이언트 사이드 렌더링을 구현하는 것이 내 개인 학습에도 도움이 되고 코드 관리하기도 더 편할 것 같다는 생각이 들었다.

그리하여 서버 - 클라이언트 아키텍쳐 구조를 다음과 같이 설계했다.

  1. 클라이언트에서 ajax 통신으로 서버에 요청을 보낸다.
  2. 서버에서는 클라이언트 요청에 대한 응답으로 JSON 형식의 데이터만 응답한다.
  3. 클라이언트는 서버의 응답 JSON 데이터를 통해 동적으로 html 요소를 렌더링하거나 다른 페이지로 이동한다. 

이 설계를 팀원들에게 얘기했는데 당시에는 서버 - 클라이언트 구조에 대한 이해를 잘 못하고 있었기 때문에 내 계획이 무슨 말인지 잘 이해하지 못한 상태에서 그냥 따랐던 것 같다.

 


 

# 화면 구현

3명의 팀원이서 각 User, Plan, Detail에 대한 화면 및 UI를 구현하기로 했는데, 나는 Detail 영역을 구현하기로 했다. 

Plan에 대한 화면 구현 설계가 나왔고 그에 따라 Detail 화면을 다음과 같이 구현해야겠다고 생각했다.

 

Figma

Created with FigJam

www.figma.com

구현 과정에서 Bootstrap 공식문서도 엄청 많이 찾아보고 Chat GPT에게도 엄청 많이 물어봤다.

지금 와서 생각해보면 기능 구현보다는 화면 배치 때문에 계속 찾아보고 검색한 것들이라 여기 정리할 의미가 없는 것 같다..

그래서 발표했던 최종 결과물 화면들중 메인 페이지로 대체한다.

팀원이 구현한 화면이다. 여기서 PlanList중 하나의 제목(빨간 박스 부분)을 클릭하면 Offcanvas영역이 나오며 내가 구현한 Detail 영역이 나온다.

내가 구현한 Offcanvas 영역이다. 부트스트랩의 Offcanvas Component를 사용했으며 대부분 UI 구현은 부트스트랩 docs를 참고하여 만들었다. (빨간 부분)

메인 페이지의 Plan의 정보를 담고 있으며 해당 부분은 input 요소로 이루어져 있어 수정할 수 있다. input 요소의 내용을 수정 후 저장 버튼을 누르면 수정한 내용으로 Plan 데이터가 변경된다. (파란 부분)

"디테일 추가" 버튼을 누르면 위 사진처럼 버튼 아래로 Detail Create Form이 나온다. form에 대한 input들을 입력 후 "생성" 버튼을 누르면 아래 쪽에 Detail 리스트가 추가된다.

추가한 Detail 만큼 List가 추가된다. 완료 체크를 누르면 위쪽의 달성률 bar에 반영이 된다.

List중 하나의 element를 클릭하면 위와 같이 확장되어 보여준다.

확장되어 보여주는 영역은 input 영역이라 수정할 수 있다. 수정 후 다시 눌러 확장 영역을 닫으면 수정한 내용으로 변경된다.

휴지통 아이콘을 누르면 삭제할 수 있다.

 

# 간단 회고

어쨌든 서버에 요청을 보내고 받아온 응답 데이터를 통해 화면을 렌더링하거나 다른 페이지로 이동해야하기 때문에, 화면 구현에 대한 HTML/CSS/JS 파일을 다 작성하고 나서 서블릿 코드를 작성한 것이 아니고 병행 작업 했다.

그 과정을 상세하게 작성하고 싶었지만 막상 글을 쓰려니 정리도 잘 안되고, 기억도 잘 안나고, 크게 기능적인 구현을 한 것이 없다. 그래서 결과 화면만 포스팅 했다.

서블릿 코드 작성하는 글에서는 서블릿 코드 작성하면서 생각했던 점과 구현한 화면 및 기능을 최대한 상세하게 적어볼 예정이다.

진짜 화면 구현하기 위해 부트스트랩 Docs를 많이 참고하고 삽질을 많이 한 것 치고는 정리할 내용이 없어서 아쉽다.

# 개요

학원 다니면서 개인 프로젝트로 플래너 개발을 해보기로 했다.

처음에는 학원에서 배운 내용 + 내가 알고 있었는데 잊었던 것들 + 이번 개인 프로젝트로 새로 배우고 싶었던 것들 세 가지를 적절히 섞어 구현할 예정이다.

설계 했던 테이블을 기반으로 DAO 클래스를 작성했다.

 


 

# 테이블 - VO 매핑

VO 클래스 작성을 위해 회의를 다시 진행했다. 그 때 각 테이블에 당장 사용하지 않은 속성이 많기 때문에 일단은 최소한으로 테이블을 설계하고 이후에 수정하는 방식으로 가자고 강하게 어필했다. 팀원들은 잘 이해하지 못했지만 일단 따르기로 했던것 같다. 

 

ERD | Notion

SQL

tin-digit-d17.notion.site

테이블에 따라 각자 VO 클래스들을 작성했다. 각자 작성한 VO클래스를 보며 리뷰하고 리팩토링하여 최종본을 확정짓기로 했다.

 

Planner/src/main/java/com/kh/model/vo at 6f774f66ec005fe1edfe6b89ba594cf2f1aeef70 · JinHoooooou/Planner

Mini Timer For Semi Project. Contribute to JinHoooooou/Planner development by creating an account on GitHub.

github.com

사실 VO 클래스라 리팩토링 할 것은 없었다.

 


 

# DAO클래스 작성 (CRUD)

각 Plan, User, DetailPlan에 따른 DAO 클래스 그리고 그 중 가장 기본적인 CRUD메서드는 수업시간에 다 배웠다고 생각해서 각자 하나씩 맡아서 작성해보기로 했다.

내가 User 객체를 맡고, 두명씩 짝지어서 Plan과 DetailPlan을 맡아서 작성하기로 했는데, DetailPlan 작성하기로 한 두 명 중 한 명은 나가고 한 명은 잘 따라오질 못해서 일단 User와 Plan 객체만 작성됐다.

 

Planner/src/main/java/com/kh/model/dao/UserDao.java at 78bdc96406ca17a77e06c537feb06ebc3cc75319 · JinHoooooou/Planner

Mini Timer For Semi Project. Contribute to JinHoooooou/Planner development by creating an account on GitHub.

github.com

내가 작성한 UserDao이고 Create, Read (One/All) 메서드 밖에 없는데, 이것을 참고해서 작성하라고 했다.

 

Planner/src/main/java/com/kh/model/dao/PlanDao_Minseok.java at f73a0df8af32f181ff9cbeca255b10da27584deb · JinHoooooou/Planner

Mini Timer For Semi Project. Contribute to JinHoooooou/Planner development by creating an account on GitHub.

github.com

 

 

Planner/src/main/java/com/kh/model/dao/PlanDao_Sim.java at 6e876137389f505eb6186f4f728ab7cb2b8c50b0 · JinHoooooou/Planner

Mini Timer For Semi Project. Contribute to JinHoooooou/Planner development by creating an account on GitHub.

github.com

 


 

# DAO 클래스 리팩토링

내가 작성한 UserDAO와 팀원들이 작성한 PlanDAO 클래스를 책(자바 웹 프로그래밍 Next Step)을 참고하여 리팩토링을 진행했다. DetailPlan까지 작성 후 할까 리팩토링을 진행할까 생각했지만, 먼저 리팩토링을 하면 그 구조에 맞게 DetailPlan도 작성하는게 더 편할 것 같고 코드 리뷰할 때 클린코드, 리팩토링 관련 설명을 해주고 싶어서 회의 전에 미리 했다.

 

## JDBC Template 리팩토링

  1. 기존의 JdbcTemplate에서 DB와 연결하는 클래스를 작성했었는데, 이를 ConnectionManager로 옮겼다.
  2. DAO 클래스를 잘 보면 각 메서드마다 공통적으로 작성되는 부분과 메서드마다 다르게 작성되는 부분이 있다.
    • 쿼리를 작성하고 그 쿼리에 맞게 변수들을 setting하는 부분은 메서드마다 다르게 작성되는 부분이다.
    • ConnectionManager를 통해 Connection 인스턴스를 가져오고 그 Connection 인스턴스를 통해 Statement 인스턴스를 가져오고 Statement의 executeUpdate()나 executeQuery()를 호출하는 부분은 공통적으로 작성되는 부분이다.
    • 이에 따라 JdbcTemplate에 INSERT, UPDATE, DELETE 쿼리를 담당하는 executeUpdate() 메서드와 SELECT 쿼리를 담당하는 executeQuery(), executeQueryForOne()을 작성했다.

3. SQLException 대신 RuntimeException을 상속받는 DataAccessException을 추가했다.

 

Jdbc 템플릿 추가 · JinHoooooou/Planner@3358d07

JinHoooooou committed Feb 28, 2024

github.com

 

## UserDAO, PlanDAO 리팩토링

DAO의 CRUD 메서드들을 위에서 리팩토링한 JdbcTemplate을 사용하는 것으로 리팩토링했다.

 

User 관련 코드 리팩토링 · JinHoooooou/Planner@d1943f3

JinHoooooou committed Feb 28, 2024

github.com

 

 

Plan 관련 코드 리팩토링 · JinHoooooou/Planner@fb31201

JinHoooooou committed Feb 28, 2024

github.com

 


 

# 코드 리뷰

내가 리팩토링한 코드를 토대로 코드 리뷰를 진행했다...만 다들 잘 이해를 못했던것 같다. 제네릭을 사용한 것, ResultMap을 이용해서 테이블 → VO로 파싱하는 부분을 RowMap이라는 인터페이스를 통해 해결한 것 등 어려워 했다. 그래서 "나중에 더 배우게 되면 이해할 수 있으니 지금은 테스트 코드와 리팩토링을 통해 이런식으로 더 깔끔하게 코드를 작성할 수 있고, 이전 코드보다 가독성이 더 좋아졌다고 느낀다면 오케이다." 라고 설명했다.

내가 팀원들보다 쪼오오오오금 더 안다고 "내가 작성한 코드가 옳다." 라고 설명하고 싶진 않았는데, 설명하다보니 그렇게 된 것 같아 아쉬웠다;

 


 

# DetailPlan VO, DAO 클래스 작성

리팩토링하여 구조화 된 DAO 클래스에 따라 DetailPlan에 대한 VO, DAO 클래스도 쉽게 작성할 수 있었다.

 

PlanDao 리팩토링 · JinHoooooou/Planner@316e1be

JinHoooooou committed Feb 29, 2024

github.com

커밋 메시지 잘못 작성함...

 


 

# 간단 회고

지금 블로그 글을 작성하면서 가장 크게 후회하는 것은 역시 commit 메시지 관련이다.

  • 팀원들이 git, github의 기본 flow? (코드 작성 → git add → git commit으로 커밋 메시지 작성 → git push로 remote에 push)도 이해하기 어려워 했어서 branch를 구분하여 작업하고 PR을 통해 Merge하는 방식을 알려주면 과부하가 올 것 같았다.
  • 그래서 organization에 Repo를 하나 생성하고 각 개인 Repo로 fork하게 했고, fork한 Repo에서 작업 후 push하여 main 브랜치에서 main 브랜치로의 PR을 하도록 했다.
  • 문제는 팀원들이 commit 메시지를 전혀 작성하지 않아서 팀장인 나의 입장에서는 이해하기가 매우 어려웠다. 그렇다고 팀원들한테 "commit 메시지 다시 작성해서 PR 주세요"라고 하기에도 좀 그래서 그냥 '내가 감수하자'라는 마인드로 일일이 다 보기로 했다.
  • 지금 시간이 지나고 나서 커밋들을 보는데 가관이다 ㅋㅋ... 물론 나도 이상하게 작성한게 많긴 하다. 다음 파이널 프로젝트 때는 이런것을 미리 정하고 하는게 나을 것 같다..

 

# 개요

학원 다니면서 개인 프로젝트로 플래너 개발을 해보기로 했다.

처음에는 학원에서 배운 내용 + 내가 알고 있었는데 잊었던 것들 + 이번 개인 프로젝트로 새로 배우고 싶었던 것들 세 가지를 적절히 섞어 구현할 예정이다.

세미 프로젝트 주제로 내 개인 프로젝트가 채택됐다.

 


 

# 세미 팀 프로젝트

강사님이 팀을 짜주었고, 우리 팀이 모이자마자 "그래도 해본 사람이 조장을 하는게 낫지 않겠어요?"시전으로 팀장을 맡게 되었다;

주제 의견을 회의했었는데, 내가 혼자 진행하던 플래너를 팀 프로젝트로 하는게 어떻냐는 의견을 냈는데 (사실은 주제 생각하기 귀찮아서;;) 그러기로 했다.

 


 

# 유사 어플리케이션 조사

 

Focus To-Do: 뽀모도로 타이머 + 업무 관리

⏱ 포모도로 타이머 ✅ 업무 관리자 📊타임 트래커 📅 스케쥴 플래너 🔔 알림

chromewebstore.google.com

유사 어플리케이션은 많았지만 초기에 내가 계획했던 뽀모도로 타이머를 기준으로 잡기로 했다. 가장 큰 이유는 간단하다고 생각해서.

애초에 나를 제외하고는 다들 개발이 처음이었기 때문에, 뭔가 대단한걸 만드는 것 보다는 간단한 프로젝트를 통해서 성취감을 느끼는 것이 중요하다고 생각했다.

 


 

# 팀 개발 방향성(?)

내가 팀장이고, 개발 프로세스 방향을 생각 해 봤을 때 진도에 맞춰서 진행하는게 낫겠다고 생각했다.

당연히 웹 어플리케이션을 만들 것이지만, 서블릿 및 JSP 관련 진도가 안나갔기 때문에 지금까지 배워 온 데이터베이스 연결(JDBC), Html/Css/JavaScript 부분을 다 같이 하고 서버와의 연결은 내가 맡아서 했다.

설계 및 개발 과정에서도 최대한 팀원들의 의견을 따르려고 했다.

 

## 테이블 설계 및 DDL 작성

내가 처음 계획했던 것은 간단하게 Plan과 User에 대한 테이블만 있으면 된다고 생각했는데, 회의를 하다보니 조금 확장 되었다.

회의를 통해 처음 나온 테이블 및 attribute(속성) 정보이다. 몇몇 속성은 당장 필요하지 않은 것인데도 불구하고 넣었다. 회의를 하는데 계속 당장 필요하고 필수적인 속성을 얘기하지 않고 이후의 부수적인 속성 얘기가 계속 나왔다. 지금 당장 필요한 것은 아니고 설계는 언제든지 변할 수 있으니 지금 당장 필요한 것만 기입하고 DDL을 작성하자고 얘기했는데 잘 받아들이지 못한 것 같다. 그래서 어쩔 수 없이 일단 다 넣었다.

-- ORACLE

CREATE TABLE USERS (
    USERNO NUMBER PRIMARY KEY,
    USERID VARCHAR2(20) UNIQUE NOT NULL,
    USERPW VARCHAR2(20) NOT NULL,
    USERNAME VARCHAR2(20) NOT NULL,
    NICKNAME VARCHAR2(20) NOT NULL UNIQUE,
    EMAIL VARCHAR2(30) NOT NULL,
    PHONE VARCHAR2(15),
    SSN VARCHAR2(30) UNIQUE NOT NULL,
    ADDRESS VARCHAR2(100) NOT NULL,
    INTEREST VARCHAR2(500),
    ENROLLDATE DATE);
    
CREATE SEQUENCE SEQ_USER
NOCACHE;

CREATE TABLE PLANNER (
    PLANNO NUMBER PRIMARY KEY,
    WRITERNO NUMBER REFERENCES USERS ON DELETE CASCADE,
    TITLE VARCHAR2(30) NOT NULL,
    CREATEDATE DATE,
    STARTDATE DATE,
    ENDDATE DATE,
    REMINDALARM DATE,
    REPEATTASK_YN CHAR(3) DEFAULT 'N' CHECK(REPEATTASK_YN IN ('Y', 'N')),
    COMPLETE_YN CHAR(3) CHECK(COMPLETE_YN IN ('Y', 'N'))
);

CREATE SEQUENCE SEQ_PLAN
NOCACHE;

CREATE TABLE DETAIL (
    DETAILNO NUMBER PRIMARY KEY,
    PLANNO NUMBER REFERENCES PLANNER ON DELETE CASCADE,
    DETATILNAME VARCHAR2(30),
    CONTENTS VARCHAR2(50),
    STARTTIME DATE,
    ENTTIME DATE,
    ALARM DATE,
    REPEAT_YN CHAR(3) DEFAULT 'N' CHECK(REPEATTASK_YN IN ('Y', 'N')),
    PRIORITY NUMBER DEFAULT 1 CHECK(PLAN_PRIORITY IN (1,2,3)),
    COMPLETE_YN CHAR(3) CHECK(COMPLETE_YN IN ('Y', 'N'))
);    
    
CREATE SEQUENCE SEQ_DETAIL
NOCACHE;

 


 

# git, github, gradle 알려주기

git에 대한 지식을 알고 있어야 팀 프로젝트를 원활하게 진행할 수 있기 때문에 가르치려고 했다.

또한, 빌드 및 라이브러리 관리를 gradle로 할 계획이어서 이것 또한 알려줘야했다. 그동안 학원에서 배운 것은 직접 jar파일을 설치해서 build path에 등록하는 방식으로 라이브러리를 추가했었는데, 너무 불편하다고 느꼈기 때문에 gradle를 사용하려고 했다.

하지만 문제가 있었는데, 나는 intelliJ를 쓰고 조원들은 eclipse를 썼다. 나는 eclipse가 익숙하지 않아서 가르치기가 어려웠다.

사실 처음부터 CLI로 배우면 어느 IDE를 쓰던 잘 쓸 수 있었을텐데 팀원들이 CLI랑 친하지 않았다.. 이 기회에 친해졌으면 그냥 좋았을텐데 되게 어려워해서 어쩔 수 없이 내가 eclipse에 맞춰 알려주기로 했다.

나름 정리하며 알려주려고 노력했는데, 잘 되었는지는 모르겠다 ㅋㅋ... 아래 링크는 내가 가르치기 위해 정리한 내용이다.

 

 

Task | Notion

Git

tin-digit-d17.notion.site

 

커밋, push, PR 과정이랑 -부분 +부분 어떻게 다른지, 어떻게 하면 충돌이나고 해결할 수 있는지 알려주려고 여러 테스트 커밋을 했었다 ㅋㅋ...


 

# 간단 회고

팀 프로젝트 과정 글 쓰는 시점은 팀 프로젝트가 끝난 이후인데, 역시 미리 작성하지 않으니 그 때의 기억이 잘 나지 않는다.

상세하게 까진 아니더라도 메모하는 습관을 들여야겠다 ㅜ

근데 위에 정리한 git, gradle 관련 노션 글을 보니 "열심히는 했다"라고 느껴지긴 한다 ㅋㅋ... 설명은 잘 못했지만..

 

# 개요

학원 다니면서 개인 프로젝트로 플래너 개발을 해보기로 했다.

처음에는 학원에서 배운 내용 + 내가 알고 있었는데 잊었던 것들 + 이번 개인 프로젝트로 새로 배우고 싶었던 것들 세 가지를 적절히 섞어 구현할 예정이다.

기존 직접 구현한 웹 서버를 Tomcat을 추가하고 Servlet을 추가했다.

 


 

# Embedded Tomcat 추가

책을 참고하며 Embedded Tomcat 라이브러리를 추가하고 직접 구현한 WebServer를 Tomcat Server를 실행하는 것으로 대체 했다.

Tomcat에 추가하는 Context는 주로 웹 어플리케이션의 설정과 속성을 정의하는데 사용한다.

addContext()로 브라우저를 통해 "localhost:8080/"로 요청을 보내면 WEB_APP_DIR_LOCATION 디렉토리에 있는 html 파일에 접근할 수 있도록 설정했다.

WebResourceRoot를 이용하여 Gradle 빌드 시 생성되는 클래스 파일 경로인 build/classes를 읽도록 설정했다.

 

Use Tomcat instead of WebServer · JinHoooooou/MiniTimer@4e3b3f1

JinHoooooou committed Feb 14, 2024

github.com

 


 

# Servlet 추가

Plan에 대한 create 기능 Servlet을 추가했다.

Create

 

add Servlet · JinHoooooou/MiniTimer@e424d2e

JinHoooooou committed Feb 14, 2024

github.com

 

 

 


 

# Chat GPT 질문

Embedded Tomcat을 사용하는 과정에서 계속 오류가 발생했는데 누군가에게 질문하기 애매한 내용이었다. 계속 구글링 해 봐도 내가 원하는 답이 나오지 않아서 고민하다가 Chat GPT를 이용해 봤는데 굉장히 잘 알려줘서 깜짝 놀랐다.

좀 이상하게 알려주는 경우도 가끔 있긴 한데.. 질문 내용을 조금 수정해서 다시 물어보거나 하면 잘 알려주는 것 같다.  

https://chat.openai.com/share/648da557-d0fa-4025-a88b-6d7c366e330a

위 링크는 내가 질문 하면서 해결 한 후에 해결한 내용을 기반으로 다시 질문한 내용이다. 실제로 질문할때는 더 많이 물어보고 삽질도 많이 했다

 


 

# 간단 회고

이 작업을 할 때 쯤부터 블로그에 개발 일지를 작성하기 시작했는데, 그 때 작성한 일지 보면 회고에 커밋 메시지 관련 얘기가 많이 있다. 그 때와 비교해보면 지금은 그래도 커밋 단위가 좀 작게 쪼개져 있긴하다. 그리고 한글도 그냥 사용하기로 했다 ㅋㅋ..

Embedded Tomcat 사용하려고 할 때 삽질을 엄청 많이하기도 했고, 예제 코드, 블로그, 책 등을 참고했었는데.. 문득 그냥 Spring boot 쓸까? 라는 생각을 많이 했다. 사실 Jdbc사용할 때도 메서드마다 SQL 작성하는점, 필드 추가/삭제에 유연하지 못한 점 때문에 그냥 JPA 쓸까? 라고 생각했었다.

그럼에도 불구하고 low level부터 이해하자라는 생각을 가지고 계속 삽질했다. 거기에 동반해야할 점은 코드 라인들이 무슨 일을 하는지 이해하는게 중요하다고 생각했다. Embedded Tomcat에 Context 추가하고 Class 디렉토리 설정하는 작업들은 처음에 그냥 예제 코드 복붙해서 사용했는데, 이해를 확실하게 하고 가기 위해 Chat GPT에게 이것 저것 계속 물어봤고 지금은 이해가 된다!

# 개요

학원 다니면서 개인 프로젝트로 플래너 개발을 해보기로 했다.

처음에는 학원에서 배운 내용 + 내가 알고 있었는데 잊었던 것들 + 이번 개인 프로젝트로 새로 배우고 싶었던 것들 세 가지를 공부할겸 적용하려고 했는데

과제로 개인 미니 프로젝트를 개발 해 보라고 해서 그냥 플래너 어플 개발하던 것을 과제로 써먹기로 했다.

발표할 내용 정리와 데이터베이스가 설치된 EC2에 배포까지 해봤다. 

 


 

# ERD

Plan 단 한개만 사용했다 ㅋㅋ..

 


 

# Class Diagram

 학원에서 배운 범위는 콘솔로 View 출력하는 것이었는데 HTML로 출력하도록 했다.

 


 

# Skills

배운 범위는 Jdbc(그 마저도 Oracle Jdbc...)까지였는데 뭐 이것 저것 라이브러리도 사용해보고, 빌드 도구도 Gradle를 이용했다.

 


 

# 배포

데이터베이스를 위한 EC2 인스턴스에 프로젝트를 받아서 임시 배포를 해봤다. 사실 배포라고 하기도 민망한게 그냥 클라우드 서버인 EC2에서 jar파일 실행 시키고 다른 로컬에서 ec2 hostname:8080 접속한 것을 보여주기만 했다 ㅋㅋ...

배포(?) 과정

 

[AWS] EC2에 자바 웹 서버 실행

# 개요 EC2에 자바로 구현한 웹 서버를 실행 하고 외부에서 접속이 가능한지 확인해봤다 그 과정에서 git, jdk 설치, gradle build, jar파일 실행한 내용 정리 EC2 생성 참고 [AWS] EC2 프리티어 사용 일지 #

jino-dev-diary.tistory.com

 


 

# 간단 회고

간단히 발표하는 거긴 했는데 발표 준비를 너무 안했다 ㅋㅋ..

웹서버 동작 방식 설명하려고 이미지도 따로 준비했었는데 발표하면서 말하는 걸 까먹었다.

그리고 남들은 view 처리를 콘솔로 했는데 나만 웹으로 했다고 '아 나 좀 치는데?' 같은 오만한 생각을 좀 했다. 사실 나중가면 다 배우고 알게 될 내용인데 전공자가 그거 조금 더 안다고 우쭐해 하는 마음가짐... 옳지 않다 

# 개요

학원 다니면서 개인 프로젝트로 플래너 개발을 해보기로 했다.

처음에는 타이머로 시작했다가 내가 생각했던 방향이 아닌거 같아서 플래너로 바꿨다.

처음에 타이머로 생각한 이유는 단순히 뽀모도로 타이머(https://chromewebstore.google.com/detail/focus-to-do-%EB%BD%80%EB%AA%A8%EB%8F%84%EB%A1%9C-%ED%83%80%EC%9D%B4%EB%A8%B8-+-%EC%97%85%EB%AC%B4/ngceodoilcgpmkijopinlkmohnfifjfb?pli=1)를 개발하려고 했기 때문인데.. 코드 작성하다보니 타이머가 돌아가는 로직은 프론트에서 간단하게 처리 할 수 있다고 생각했기 때문이다.

원래는 프로젝트 개발진행하면서 블로그도 같이 쓰려고했는데, 개발 중간에서야 작성하게 됐다 ㅎㅎ;

콘솔창에 View를 출력하는 것에서 Web에 출력하는 것으로 변환하는 과정

 


 

# WebServer 구현

책을 참고하며 WebServer를 구현했다. 로그 출력을 System.out.println()등으로 하는 것보다 Log 라이브러리를 사용하는 것이 더 좋다고 해서 Log 라이브러리도 추가하여 사용했다.  

WebServer가 클라이언트 접속을 기다리다가 연결이 되면 Thread를 상속받은 RequestHandler가 실행되는데, RequestHandler는 클라이언트에서 보낸 요청을 받고 요청에 맞는 응답을 보내는 역할을 한다.

RequestHandler에서 요청을 받는 부분은 HttpRequest가 담당하고 응답을 보내는 부분은 HttpResponse가 담당한다.

HttpRequest는 클라이언트가 보낸 요청을 처리하는데, 요청의 첫 라인인 request line을 RequestLine통해 method(GET, POST 등..), path, parameter를 추출하고 header와 request body를 key-value로 추출한다.

HttpResponse는 html을 구성하여 클라이언트로 응답을 보낸다.

 

temp commit · JinHoooooou/MiniTimer@b18b1a2

JinHoooooou committed Feb 8, 2024

github.com

 


 

# Path 추가에 따른 Controller와 RequestMapping 추가

각 기능이 추가 될 때마다 Path들도 추가가 되는데 그에 따라 RequestHandler에서 Path를 확인하는 if 조건문이 늘어난다. 그래서 Controller 인터페이스를 추가하고 각 기능들은 Controller를 구현하는 클래스들을 만들어 주었다. 그리고 그 기능들의 Path 매핑을 RequestMapping에 추가했다.

기존에 각 Path에 대한 Html 파일을 작성하는 부분도 HttpResponse에 작성했는데, 각 기능 Controller 클래스에 작성하는 것으로 변경했다.

 

Modify to Web and project restructure · JinHoooooou/MiniTimer@3d53313

JinHoooooou committed Feb 10, 2024

github.com

각 Controller마다 공통된 부분이 있어 AbstractController에 공통 기능을 추가했다.

 

Refactor: Use AbstractController · JinHoooooou/MiniTimer@da223f5

JinHoooooou committed Feb 12, 2024

github.com

Web으로 변환했으므로 기존 Console에 출력하던 View들은 전부 삭제했다.

 

erase command line view · JinHoooooou/MiniTimer@12b6616

JinHoooooou committed Feb 12, 2024

github.com

 


 

# 간단 회고

Modify to Web and project structure 커밋을 Modify console view to web view / Modify project structure 두 부분으로 나눴어야 했다. 지금 한참 지난 커밋을 보는 것인데... 엄청 헷갈린다... 매번 작성글 회고에서 커밋 단위가 큰 것을 체감하고 있다 ㅜㅜ

Web view로 변환하고 나니까 삭제한 console view 관련 코드들이 아깝게 느껴졌다. 특히 테스트코드 작성한게 엄청 아까웠는데 화면 구성같은 코드들은 테스트 코드를 작성하는 것보다 직접 확인하는게 낫겠다는 생각이 들었다.

# 개요

학원 다니면서 개인 프로젝트로 플래너 개발을 해보기로 했다.

처음에는 타이머로 시작했다가 내가 생각했던 방향이 아닌거 같아서 플래너로 바꿨다.

처음에 타이머로 생각한 이유는 단순히 뽀모도로 타이머(https://chromewebstore.google.com/detail/focus-to-do-%EB%BD%80%EB%AA%A8%EB%8F%84%EB%A1%9C-%ED%83%80%EC%9D%B4%EB%A8%B8-+-%EC%97%85%EB%AC%B4/ngceodoilcgpmkijopinlkmohnfifjfb?pli=1)를 개발하려고 했기 때문인데.. 코드 작성하다보니 타이머가 돌아가는 로직은 프론트에서 간단하게 처리 할 수 있다고 생각했기 때문이다.

원래는 프로젝트 개발진행하면서 블로그도 같이 쓰려고했는데, 개발 중간에서야 작성하게 됐다 ㅎㅎ;

데이터베이스(Mysql)을 추가하고 프로젝트와 연결하는 과정

 


 

# EC2에 데이터 베이스(Mysql) 설치

데이터베이스는 학원에서 오라클을 배웠지만, Mysql을 사용하기로 했다. Mysql을 선택한 이유는

  • 내 로컬(노트북)에는 데이터베이스 프로그램이 설치되어 있지 않은데 굳이 설치하고 싶지 않았다. 그렇다면 어떤 원격의 데이터베이스를 이용해야 한다.
    1. 학원 컴퓨터를 항상 켜 놓은 상태로 두고 원격 데스크톱 연결을 통해 노트북에서 학원 컴퓨터로 접속해서 개발을 진행 → 학원 공유기를 포트 포워딩 해야하는데 공유기 비밀번호를 모르기 때문에... 패스
    2. 내장 데이터베이스인 H2를 사용 → 기왕 사용하는거 데이터베이스 설치해서 사용하자라는 생각으로.. 패스
    3. 옛날에 AWS를 사용해봤으니까 복습한다는 생각으로 EC2 인스턴스에 데이터베이스를 설치하여 사용하는 것으로 결정!
  • 오라클을 설치하는 과정이 꽤나 복잡해서 Mysql을 선택했다. (근데 Mysql도 생각보다 복잡하더라..)
    • RDS라는 서비스도 있긴 했는데 사용해본적이 없어서 우선 EC2에 설치해서 사용해보다가 RDS도 사용 해보기로..

EC2에 Mysql 설치하는 과정

 

[AWS] EC2에 DB설치

# 개요 생성한 EC2에 Database(Mysql)을 설치해보자 학원에서는 Oracle을 사용하긴 했는데, 찾아보니 Linux에 Oracle설치하는게 꽤 복잡해서 그냥 Mysql로 진행하기로 했다. 근데 AWS RDS라는 데이터베이스 서

jino-dev-diary.tistory.com

 


 

# 내 프로젝트와 연결, CRUD 기능 구현

Mysql jdbc인 Mysql Connector를 통해 EC2에 설치된 Mysql과 연결했다.

그 과정에서 기존에 Controller의 List에 저장했던 Plan 객체들을 Database에 저장하도록 수정했다.

CRUD 기능에 대한 메서드를 구현했는데 Connection을 생성하는 부분이 중복되어서 JdbcTemplate에 데이터베이스와 연결하는 코드를 분리하여 작성하였다.

Connection 이후 PreparedStatement를 이용해서 Query에 객체 필드들을 매핑해주고 executeUpdate()(CUD) / executeQuery() (R)을 통해 쿼리를 실행했다.

이후 필요에 따라 데이터베이스 row를 자바 Object로 매핑 후 반환했다.

 

Add Feature: connect to Mysql Database · JinHoooooou/MiniTimer@8f53d07

JinHoooooou committed Feb 7, 2024

github.com

 


 

# 간단 회고

저 커밋 하나에 내용이 너무 많아서 여전히 읽기 힘들다 ㅜㅜ 커밋 작게하는 습관을 들여야하는데 생각보다 쉽지않다

database 연결할 때 접속 계정과 패스워드가 필요한데, Github에 올릴 때는 그걸 빼고 올려야 하는데 같이 올려버렸다... 이번 경우에는 EC2 인스턴스를 중지 후 재시작 함으로써 hostname이 변경 되었기 때문에 크게 상관 없겠지만 이런 정보는 별도의 파일로 만들어서 .gitignore에 해당 파일을 추가하거나 환경 변수로 구성하는 방법으로 보완해야겠다는 생각이 들었다.

# 개요

학원 다니면서 개인 프로젝트로 플래너 개발을 해보기로 했다.

처음에는 타이머로 시작했다가 내가 생각했던 방향이 아닌거 같아서 플래너로 바꿨다.

처음에 타이머로 생각한 이유는 단순히 뽀모도로 타이머(https://chromewebstore.google.com/detail/focus-to-do-%EB%BD%80%EB%AA%A8%EB%8F%84%EB%A1%9C-%ED%83%80%EC%9D%B4%EB%A8%B8-+-%EC%97%85%EB%AC%B4/ngceodoilcgpmkijopinlkmohnfifjfb?pli=1)를 개발하려고 했기 때문인데.. 코드 작성하다보니 타이머가 돌아가는 로직은 프론트에서 간단하게 처리 할 수 있다고 생각했기 때문이다.

원래는 프로젝트 개발진행하면서 블로그도 같이 쓰려고했는데, 개발 중간에서야 작성하게 됐다 ㅎㅎ;

 


# Gradle 빌드 툴 사용

학원에서 현재까지 진행된 프로젝트를 각자 발표한다고 했다. 발표하는 것은 문제가 아닌데, 개발 환경이 달라서 조금 문제가 됐다. 내 로컬 개발 IDE는 IntelliJ (Community)인데, 학원에서 진행하는 IDE는 Eclipse를 사용했다. 내 기억으로는 IntelliJ에서 생성한 프로젝트랑 Eclipse랑 호환이 안돼서 추가적인 세팅이 필요한 것으로 알고있다.

그래서 구글링하면서 세팅을 만져봤는데.. 내가 잘 못 한건지 계속 안되더라 ㅜㅜ 그래서 그냥 IntelliJ에서 작성한 코드들 다 복사해서 Eclipse에 새로 프로젝트 생성해서 붙여넣기 할까 생각했었는데, Git 설정도 문제가 될 것 같아서 그 방법은 관뒀다. Eclipse와 내 Remote Git을 연결해서 clone할까 생각도 했는데 그것도 내가 잘 못해서 그러는지 계속 안되더라 ㅜㅜ

그래서 "빌드 툴인 Gradle을 사용해서 jar파일로 만들고 발표할 로컬에서 Gradle을 이용해서 실행하면 되지 않을까?" 라는 생각으로 Gradle을 사용해보았다.

간단히 build.gradle파일과 settings.gradle파일 추가하면 IntelliJ가 자동으로 인식해서 Gradle Project Load할거냐고 물어본다. (역시 갓텔리제이... 똥클립스..) 

https://github.com/JinHoooooou/MiniTimer/commit/855a1daa1fa7fb098133687ff4c05e62f0008e45

 

Gradle 빌드 툴 사용관련 글

 

[Gradle] Gradle 빌드, 실행하기

# 개요 항상 Gradle을 쓸 때 IDE를 이용해서 빌드 및 실행을 했었는데 CMD로는 어떻게 할까? 그리고 IDE에서는 실행 할 때 알아서 빌드까지 진행해 주었는데 구분 동작은 어떻게 되는지 알아보자. Gradl

jino-dev-diary.tistory.com


# 자바 Linter와 Code Style 적용

학원 로컬과 노트북 설정이 달라서 그런가 계속 자동 정렬할 때마다 Git Change 요소가 발생해서 이 참에 Code Style을 적용해보기로 했다.

다른 블로그들 보면 네이버 캠퍼스 핵데이 코딩 컨벤션을 많이 맞췄던데.. 혼자하는 프로젝트기도 하고 Google Code Style이 더 범용적(?)으로 사용할테니 Google Code Style을 적용했다.

https://jino-dev-diary.tistory.com/entry/IntelliJ-LinterCheckStyle%EC%99%80-FormatterCode-Style-%EC%A0%81%EC%9A%A9

 

[IntelliJ] Linter(CheckStyle)와 Formatter(Code Style) 적용

개요 코드 스타일 통일을 위해 IntelliJ에 Linter와 Formatter를 적용해보았다 옛날에 파이썬 쓸 때, black, flake8같은 도구들이 매우 좋았는데 자바에는 없나 싶어서 찾아보니 있었다! CheckStyle 설치 Intelli

jino-dev-diary.tistory.com

 


# Conver Timer into Planner

CRUD까지 추가하고 든 생각이 Timer 자체는 View에서 처리하는 작업인데, 객체로 구현할 필요가 있을까? 라는 점이었다. 구글링을 해서 여느 플래너 어플리케이션을 봐도 서버쪽에서 Timer를 처리하지는 않았다.

그래서 Timer 객체를 Plan 객체로 수정하고 들어갈 필드들을 다시 생각해보았다. 예시 어플리케이션으로 선택한 뽀모도로 타이머를 보니 제목, 뽀모도로 수, 마감일, 프로젝트, 미리알림, 반복, 하위작업, 노트가 있었다.

여기서 하위 작업을 추가하는 건 뭔가 어려워 보이고.. 당장 쉽게 구현할 수 있는 것은 제목, 뽀모도로 수, 노트, 완료 여부 정도라고 생각하여 Timer → Plan 객체로 수정하고 hour, minute, second 필드를 삭제하고 timerCount와 clear라는 필드를 추가했다.

https://github.com/JinHoooooou/MiniTimer/commit/4ce3ffbf113a911bdef0ae360442d98f09e333d1

 


# 간단 회고

이 지점의 커밋들을 보니 학원에서 작업하다가 집에서 이어서 작성하려고 완전한 상태가 아닌데도 커밋하고 푸시한 커밋들이 있었다. 혼자 작업하다보니 이런 커밋들이 구별도 가고 크게 상관없겠지만, 협업하는 경우는 어떻게 해야하는지 궁금해졌다.

회사에서 작업하다가 완전하지 않은 상태인데 나머지는 집가서 마저 작업하려고 한다면(퇴근하고 집에가서 일을 더 한다는게 이상하게 느껴지긴 하는데;) 그 완전하지 않은 상태로 푸시하고 집에서 풀 이후에 작업하는게 맞는걸까? 아니면 다른 방법이 있을까?? 궁금해졌다.

이전에 자바로 웹 어플리케이션을 개발할 때는 바로 스프링 부트를 사용했는데, 지금 프로젝트 방향은 기본 프로젝트 Gradle 프로젝트로 바꾸게 됐다. 그러면서 프로젝트 구조에 대한 이해도 늘었고 이전에는 막연하게 IntelliJ에서 Gradle 알아서 사용해준 느낌이었는데, Gradle 명령어나 CMD에서 사용하는 법도 공부 할 수 있어서 좋았다.

# 개요

학원 다니면서 개인 프로젝트로 플래너 개발을 해보기로 했다.

처음에는 타이머로 시작했다가 내가 생각했던 방향이 아닌거 같아서 플래너로 바꿨다.

처음에 타이머로 생각한 이유는 단순히 뽀모도로 타이머(https://chromewebstore.google.com/detail/focus-to-do-%EB%BD%80%EB%AA%A8%EB%8F%84%EB%A1%9C-%ED%83%80%EC%9D%B4%EB%A8%B8-+-%EC%97%85%EB%AC%B4/ngceodoilcgpmkijopinlkmohnfifjfb?pli=1)를 개발하려고 했기 때문인데.. 코드 작성하다보니 타이머가 돌아가는 로직은 프론트에서 간단하게 처리 할 수 있다고 생각했기 때문이다.

원래는 프로젝트 개발진행하면서 블로그도 같이 쓰려고했는데, 개발 중간에서야 작성하게 됐다 ㅎㅎ;

 


# CRUD의 R(Read) 기능 추가

Read one / Read All에 대한 View 클래스 추가와 Controller에 메서드를 추가했다

Read One기능은 TimerController의 필드인 List의 Index 기반으로 했다. 나중에 데이터베이스 추가되면 Primary Key인 Id로 조회하거나 Front에 해당 객체 선택할 수 있도록 구현할 수 있겠지?

리팩토링을 위해 Create와 마찬가지로 Read기능에 대한 View와 Controller 테스트 코드를 작성했다. 

https://github.com/JinHoooooou/MiniTimer/commit/8b7c49d965d0a6cf870733550104a31537bb6650

 

TimerController의 필드인 List에 대한 캡슐화가 제대로 이루어진것 같지 않아서 isEmpty(), size()메서드를 따로 작성했다.

https://github.com/JinHoooooou/MiniTimer/commit/b104fe410aa618d69b0ed644c7780ebafd2f7aa2

 


# CRUD의 U(Update) 기능 추가

Update에 대한 View 클래스와 Controller에 메서드를 추가했다.

https://github.com/JinHoooooou/MiniTimer/commit/a03e217edf16138eedf27ccdded28b94a82d1293

 


# CRUD의 D(Delete) 기능 추가

Delete에 대한 View 클래스와 Controller에 메서드를 추가했다.

https://github.com/JinHoooooou/MiniTimer/commit/d37bd9a292c2eee7898cd19eac4b18228e77399d

https://github.com/JinHoooooou/MiniTimer/commit/e63dcb2ab82b5ef598241e522f4617fb258b5bd3

 


# 간단 회고

기능을 추가할 때 마다 테스트 코드를 작성했다. TDD로 구현한 것 까지는 아니지만, 테스트가 있어야 공격적인 리팩토링이 가능하기 때문에 작성했다.

근데 작성할 수록 View에 대한 테스트 코드를 작성하는것에 대해 회의감을 느꼈다. '이렇게 까지 View 테스트 코드를 작성해야 하나?" 라는 생각이 들었다. 그도 그럴 것이, View 부분은 비즈니스 로직 없이 단순히 콘솔에 보여주는 화면만 구성하는데 이것을 위한 테스트 코드까지 작성하는 것은 시간 낭비라는 생각이 계속 나를 지배했다. 그럼에도 불구하고 '테스트 코드 작성 연습하고 공부하자'라는 생각으로 작성했다.

Controller에서 getList()메서드로 List필드를 가져오고, 그 List에대한 메서드를 호출하는 것 보다. Controller에게 물어보는 메서드를 작성하는것이 더 올바른 캡슐화라고 생각해서 size(), isEmpty() 메서드를 작성했다. 근데 지금와서 보니 이 메서드들은 테스트 코드에서만 사용하는 메서드가 돼버려서 잘 못 작성한것 같다.

# 개요

학원 다니면서 개인 프로젝트로 플래너 개발을 해보기로 했다.

처음에는 타이머로 시작했다가 내가 생각했던 방향이 아닌거 같아서 플래너로 바꿨다.

처음에 타이머로 생각한 이유는 단순히 뽀모도로 타이머(https://chromewebstore.google.com/detail/focus-to-do-%EB%BD%80%EB%AA%A8%EB%8F%84%EB%A1%9C-%ED%83%80%EC%9D%B4%EB%A8%B8-+-%EC%97%85%EB%AC%B4/ngceodoilcgpmkijopinlkmohnfifjfb?pli=1)를 개발하려고 했기 때문인데.. 코드 작성하다보니 타이머가 돌아가는 로직은 프론트에서 간단하게 처리 할 수 있다고 생각했기 때문이다.

원래는 프로젝트 개발진행하면서 블로그도 같이 쓰려고했는데, 개발 중간에서야 작성하게 됐다 ㅎㅎ;

 


# 타이머 개발

기본적으로 학원 수업 진행 방향을 따라서 개발을 진행했고 거기에 추가적으로 내가 공부하고싶은 부분을 적용시켰다.

객체(Timer)에 대한 필드 설계를 하고 콘솔창에 View를 출력하고 사용자 입력 (Scanner)을 통해 실행되는 어플리케이션을 만드는 것으로 시작했다.

뽀모도로 타이머 어플을 보고 처음 설계한 것은 Timer 객체에 Hour, Minute, Second가 있고 Title과 Memo가 있어서 해당 요소들을 필드로 추가했다.

MainView에서 Timer 생성, 조회, 수정, 삭제 (CRUD)에 대한 View들을 사용자 입력으로 받고 그 기능들은 TimerController의 메서드로 구현했다.

처음에는 command 입력에 대한 기능들을 분기처리로 구현했다가 다형성을 이용하여 클래스를 분리하여 구현했다.

https://github.com/JinHoooooou/MiniTimer/commit/f3135fcb067d836ef2b534a3909c484dd39582e4

 

각 View에 대한 출력을 어플리케이션 실행이 아닌 단위 테스트 실행으로 확인할 수 있게 테스트 코드를 사용했다.

https://github.com/JinHoooooou/MiniTimer/commit/75d45a5b7524028afc3dc15f5a21e326c4b281ba 

 


# CRUD의 C(Create) 기능 추가

그리고 Create Timer에 대한 테스트 코드, View, Controller를 구현했다. 각 객체에 대한 저장은 아직 데이터베이스 연결을 하지 않았기 때문에 Controller에 있는 List에 저장하도록 구현했다.

https://github.com/JinHoooooou/MiniTimer/commit/eb696ee727a3b18035f14e2b03c6dbd7dfee3234

https://github.com/JinHoooooou/MiniTimer/commit/554c813326b17bd83210f36429371bdf8533ecca

 


# 간단 회고

지금 블로그에 작성하는건 커밋한지 약 1~2개월 후에 작성하는 것인데... 커밋 메시지 내용이 너무 개판이고 커밋 파일들도 중구난방이라 확인하는 것이 너무 힘들다..

아무리 혼자 하는 개발이라고 하지만 커밋 정리를 잘 하자.. 앞으로 한동안 커밋 개판인거 블로그에 옮기려니 벌써 어지럽다... ㅜㅜ

+ Recent posts