Spring+JPA 투두리스트 만들기 ver.0

dondonee·2023년 10월 21일
0

요즘은 김영한 님의 Spring + JPA 강의를 듣고 있다. 강의만 두 달째 듣고 있어서 내가 제대로 알고 있는게 맞는지 강의 예제 코드를 응용해서 직접 무언가 만들어봐야겠다고 판단해서 간단한 투두리스트를 만들어보기로 했다.
복습이 목적이기 때문에 최대한 강의 코드를 활용해보기로 했다. 영한님 강의는 옛날에 쓰이던 코드를 점차 발전시켜나가면서 왜 지금의 형태가 되었는지 설명해주시는 것이 특징인데, 나는 아직 강의를 다 들은게 아니기 때문에 일단 구식의 코드를 사용하기로 했다. 복잡한 연관관계는 일단 패스했다.

  • 테이블 1개짜리 간단한 Todo List
  • CRUD 기능
  • Spring MVC 패턴 사용 (API는 X)
  • Spring Data JPA 사용 X
  • 화면 디자인 X

그리고 이왕 실습을 해 보는거 강의 코드 뿐 아니라 여러가지 만져보자 싶어 새로운 것들을 시도해보기로 했다.

  • Docker로 MySQL을 연결하기
  • Git Issue, Project, Milestone 적용하기
  • 커밋 메세지는 컨벤션 규칙대로 작성하기
  • Branch 용도별로 나누기
  • 단위 테스트 만들기

✔️ 요구사항

전체적인 구조는 몇달 전 부스트코스 웹 풀스택 강의를 들으면서 Servlet + JSP로 투두리스트를 만들어 본 적이 있어 이것을 참고하기로 했다. 무엇을 만들 지 고민하는 시간도 줄일 겸 Spring + JPA로 바꿔 재현해보면서 복습도 될 것 같았다.

  • 할 일을 등록하면 카드가 추가된다.
  • [Edit] 버튼을 누르면 수정 폼으로 이동한다.
    • 수정 폼에서는 현재 값을 보여준다.
    • [제출]을 누르면 수정이 완료되고 할 일 목록 페이지로 돌아간다.
  • 카드에서 [ → ] 버튼을 누르면 진행 상태가 한 단계씩 업데이트 된다.
  • 상태가 DONE인 경우 카드에 삭제 버튼 [X]가 나타나고 클릭하면 삭제된다.
  • 기타 :
    • 등록 폼에서 내용지우기를 누르면 입력한 값이 지워진다.
    • 수정 폼에서 되돌리기를 누르면 입력한 값이 지워지고 원래 값이 보여진다.
    • 등록 폼이나 수정 폼에서 [제출]을 눌렀을 때 유효성을 통과하지 못하면 안내 메세지를 보여준다.

개발환경

  • Spring Boot 2.7.17
  • Java 11
  • JUnit4
  • Gradle
  • MySQL 8.0 (Docker)
  • Thymeleaf

✔️ 공부한 것

Git

이전에도 Git을 사용해보긴 했다. 개발 과정에서 문제가 생겼을 때 롤백하기에도 좋고 완성 후 시간이 지나 내가 만든 것을 되돌아 볼 때도 커밋 기록을 보면 무엇을 했는지 파악이 쉽기 때문이었다.
그러나 이번에는 언젠가 있을(!) 협업 때 도움이 되도록, 혼자하는 프로젝트지만 최대한 Git의 여러 기능을 사용해보도록 노력했다.

  • Project, Milestone 기능을 사용해 목표를 상세하게 설정
  • Issue를 사용해 개발 내역를 구분하고 커밋을 이슈별로 그룹화
  • 커밋 메세지 컨벤션을 참고하여 직관적이고 일관적인 커밋 메세지 작성
  • 작업에 따라 Branch를 구분하고 작업이 끝나면 Pull Request를 통해 Merge

MVC의 역할

강의 예제에서는 회원이나 주문 목록을 조회할 때 전체 리스트를 한 번에 가져왔다. 그런데 나는 할 일 목록이 상태 별로 TODO, DOING, DONE 3가지 목록으로 나누어져서 어딘가에서 분류를 해야했다.
이전에 Servlet+JSP로 만들었을 때는 Servlet에서 가져와 JSP에서 분류를 했기 때문에 이번에도 View에서 타임리프로 분류를 하려고 했다. 그런데 생각해보니 View에서 분류를 하는게 적절하지 않은 것 같았다.

  • JSP가 비즈니스 로직과 뷰 코드가 섞여있어 가독성이 떨어지고 유지보수가 불편했던 점을 개선하기 위해 MVC 패턴이 등장했다고 한다.

그래서 컨트롤러에서 분류를 해서 따로따로 Model에 담아 전달하고 View는 출력만 하려고 했는데... 컨트롤러가 아니라 서비스에서 해야하는게 아닌가? 싶었다. 검색해보니 딱 맞는 영한님의 답변을 찾을 수 있었다.

  • 컨트롤러는 웹 계층을 위한 로직만 갖도록 한다. 웹 계층이 없이 콘솔에서만 동작해야되는 애플리케이션을 만든다고 했을 때 서비스 로직을 재사용 할 수 있도록 만든다.
  • 즉 컨트롤러는 폼 데이터를 처리하하거나 화면에 뿌릴 데이터를 모아서 넘겨주는 등 웹 계층을 위한 로직을 담당한다.

Form DTO

@PostMapping("/tasks/new")
public String addTask(@Valid TaskForm form, BindingResult result) {}

강의를 보면 HTML Form에서 보낸 데이터를 컨트롤러에서 파라미터로 받는 것이 아니라 새로운 Form 객체를 만들어서 데이터를 주고받았다. 이 Form 객체란 DTO의 일종인데 영한님은 컨트롤러에서 사용하는 DTO를 Form이라고 썼다고 하셨다(☞인프런 Q&A).

  • DTO(Data Transfer Object)란 데이터 전송을 위한 객체이다.
  • 검증 로직을 도메인 모델에 담으면 비즈니스 로직과 화면을 위한 로직이 뒤섞여 지저분해진다. 또한 DTO를 매개로 사용하면 원하는 정보만 선택해서 보낼 수 있기 때문에 안전하기도 하다.
  • Entity는 최대한 '순수하게' 유지하도록 하고 화면 및 검증을 위한 로직은 DTO로 분리한다.

@Valid로 유효성 검증

Form 객체에 @Valid가 지원하는 검증 애노테이션을 달면 컨트롤러에 데이터가 전달될 때 유효성을 검증한다. 그리고 오류가 있는 경우 그 정보를 BindingResult에 보관한다. View는 그 정보를 받아 에러 메세지를 출력할 수 있다.

  • 검증에 오류가 있어 컨트롤러가 BindingResult 정보를 반환하는 경우 리다이렉트가 아니라 View 이름을 반환해야 한다고 한다. 자세한 것은 MVC 2편에 소개된다고 하니 일단은 패스했다.
  • @Valid를 사용하려면 의존성을 추가해주어야 한다(Spring Boot 2.3 이상) : implementation 'org.springframework.boot:spring-boot-starter-validation'

@ModelAttribute

Form 객체를 사용하려면 컨트롤러에서 Form 객체를 생성하고 각 필드의 값을 파라미터로 받아 값을 세팅해주어야 한다. 이러한 번거로운 작업을 대신해주는 것이 @ModelAttribute이다. Form 객체를 파라미터로 받고 @ModelAttribute을 달아주면 자동으로 객체를 생성하고 프로퍼티에 값이 할당해준다.

public String modelAttributeV1(@RequestParam String username, @RequestParam int age) {

	HelloData helloData = new HelloData();
	helloData.setUsername(username);
	helloData.setAge(age);

	return "ok";
}
public String modelAttributeV1(@ModelAttribute HelloData helloData) {

	return "ok";
}
  • @ModelAttribute는 다음과 같이 생략할 수 있다 : public String modelAttributeV2(HelloData helloData) {}
  • 별도로 이름을 지정하지 않는 경우 Model에는 대상 클래스의 이름을 첫 글자만 소문자로 바뀌어서 저장된다. 이름을 지정하고 싶다면 @ModelAttribute(name = "here")으로 지정할 수 있다.
    • 이 규칙을 몰라서 엄청 헤맸다. 컨트롤러에서 분명 값을 Model에 담아 보냈는데 왜 자꾸 날아가는 건지, 왜 View에서 출력되지 않는지... 사방팔방으로 원인을 찾고 찾다 산으로 갔다왔다. 이렇게 간단했는데.

✔️ 더 공부해야 할 것

  • Git
    • 커밋을 얼마나 작은 단위로 쪼개야 하는지, 제목과 상세 내용은 어떻게 작성해야 하는지, 컨벤션 문서만으로는 알 수 없는 것들이 많았다. 협업을 해보며 다른 팀원들 입장에서 생각해 보는 경험이 필요할 것 같다. 또 팀마다 스타일이 다를테니 일단 내 수준에서 일관적으로 커밋 메세지를 작성하는 것에만 신경썼다.
  • Thymeleaf
    • 강의 예제에 나온 문법 정도만 알고 있어서 잘못된 점을 바로바로 캐치할 수 없었다.
  • 테스트
    • 강의에 나온 비슷한 테스트를 고쳐서 쓰는 정도밖에 할 줄 몰랐다. 좀 더 복잡한 앱을 만들려면 공부해야 할 것 같다.
  • 예외처리
    • 일단 앱을 완성은 했지만 예외처리를 못했다. 할 일의 이름이 중복되는 경우 예외를 발생하게 만들어놓기는 했는데 이후 처리를 하지 않아서 비정상 종료된다. 어떻게 처리해야 할지 몰라서 일단은 패스했다. 다음에 들을 강의 내용에 예외처리가 있어서 배우고 나서 수정해보고자 한다.

✔️ 후기

단일 테이블이라면 뚝딱 만들 줄 알았는데 생각보다 막힌 부분이 있었다. 강의를 듣기만 했을 땐 이해했다고 생각했는데 직접 만들어보니 제대로 이해하지 못하고 있었다. 또한 지금은 Spring + JPA만 듣고 있는데 실제로 앱을 만들어보려고 하니 알아야 하는게 정말 많았다.
모르는 게 너무 많다는 걸 실감하니 쫌 절망스럽기도 하지만. 한편 뭔가를 만들어보니 무엇을 공부해야 하는지 알 것 같다. 모든 걸 섭렵해야 무언갈 만들 수 있는게 아니라 만들면서 필요한 걸 배워가면 될 것 같다. 다음엔 좀 더 재밌는 걸 만들어보자!

0개의 댓글