요즘은 김영한 님의 Spring + JPA 강의를 듣고 있다. 강의만 두 달째 듣고 있어서 내가 제대로 알고 있는게 맞는지 강의 예제 코드를 응용해서 직접 무언가 만들어봐야겠다고 판단해서 간단한 투두리스트를 만들어보기로 했다.
복습이 목적이기 때문에 최대한 강의 코드를 활용해보기로 했다. 영한님 강의는 옛날에 쓰이던 코드를 점차 발전시켜나가면서 왜 지금의 형태가 되었는지 설명해주시는 것이 특징인데, 나는 아직 강의를 다 들은게 아니기 때문에 일단 구식의 코드를 사용하기로 했다. 복잡한 연관관계는 일단 패스했다.
그리고 이왕 실습을 해 보는거 강의 코드 뿐 아니라 여러가지 만져보자 싶어 새로운 것들을 시도해보기로 했다.
전체적인 구조는 몇달 전 부스트코스 웹 풀스택 강의를 들으면서 Servlet + JSP로 투두리스트를 만들어 본 적이 있어 이것을 참고하기로 했다. 무엇을 만들 지 고민하는 시간도 줄일 겸 Spring + JPA로 바꿔 재현해보면서 복습도 될 것 같았다.
이전에도 Git을 사용해보긴 했다. 개발 과정에서 문제가 생겼을 때 롤백하기에도 좋고 완성 후 시간이 지나 내가 만든 것을 되돌아 볼 때도 커밋 기록을 보면 무엇을 했는지 파악이 쉽기 때문이었다.
그러나 이번에는 언젠가 있을(!) 협업 때 도움이 되도록, 혼자하는 프로젝트지만 최대한 Git의 여러 기능을 사용해보도록 노력했다.
강의 예제에서는 회원이나 주문 목록을 조회할 때 전체 리스트를 한 번에 가져왔다. 그런데 나는 할 일 목록이 상태 별로 TODO, DOING, DONE 3가지 목록으로 나누어져서 어딘가에서 분류를 해야했다.
이전에 Servlet+JSP로 만들었을 때는 Servlet에서 가져와 JSP에서 분류를 했기 때문에 이번에도 View에서 타임리프로 분류를 하려고 했다. 그런데 생각해보니 View에서 분류를 하는게 적절하지 않은 것 같았다.
그래서 컨트롤러에서 분류를 해서 따로따로 Model에 담아 전달하고 View는 출력만 하려고 했는데... 컨트롤러가 아니라 서비스에서 해야하는게 아닌가? 싶었다. 검색해보니 딱 맞는 영한님의 답변을 찾을 수 있었다.
@PostMapping("/tasks/new")
public String addTask(@Valid TaskForm form, BindingResult result) {}
강의를 보면 HTML Form에서 보낸 데이터를 컨트롤러에서 파라미터로 받는 것이 아니라 새로운 Form 객체를 만들어서 데이터를 주고받았다. 이 Form 객체란 DTO의 일종인데 영한님은 컨트롤러에서 사용하는 DTO를 Form이라고 썼다고 하셨다(☞인프런 Q&A).
Form 객체에 @Valid
가 지원하는 검증 애노테이션을 달면 컨트롤러에 데이터가 전달될 때 유효성을 검증한다. 그리고 오류가 있는 경우 그 정보를 BindingResult
에 보관한다. View는 그 정보를 받아 에러 메세지를 출력할 수 있다.
BindingResult
정보를 반환하는 경우 리다이렉트가 아니라 View 이름을 반환해야 한다고 한다. 자세한 것은 MVC 2편에 소개된다고 하니 일단은 패스했다.@Valid
를 사용하려면 의존성을 추가해주어야 한다(Spring Boot 2.3 이상) : implementation 'org.springframework.boot:spring-boot-starter-validation'
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) {}
@ModelAttribute(name = "here")
으로 지정할 수 있다.단일 테이블이라면 뚝딱 만들 줄 알았는데 생각보다 막힌 부분이 있었다. 강의를 듣기만 했을 땐 이해했다고 생각했는데 직접 만들어보니 제대로 이해하지 못하고 있었다. 또한 지금은 Spring + JPA만 듣고 있는데 실제로 앱을 만들어보려고 하니 알아야 하는게 정말 많았다.
모르는 게 너무 많다는 걸 실감하니 쫌 절망스럽기도 하지만. 한편 뭔가를 만들어보니 무엇을 공부해야 하는지 알 것 같다. 모든 걸 섭렵해야 무언갈 만들 수 있는게 아니라 만들면서 필요한 걸 배워가면 될 것 같다. 다음엔 좀 더 재밌는 걸 만들어보자!