- 백견불여일타! 스프링부트 쇼핑몰 클론코딩 후기 🛒2025년 01월 29일
- 정성인(人)
- 작성자
- 2025.01.29.오후11:36
김영한 강의(스프링 로드맵)에서 배운 내용을 종합적으로 활용하고 싶어 변구훈의 "스프링부트 쇼핑몰 프로젝트" 책을 따라 코딩했다. 예외 처리, 검증, 타임리프 등의 개념을 직접 적용해봤다. 클론코딩 후 Spring MVC 2 강의를 들으니, 내가 따라 친 내용이 나와서 더 이해가 쉬웠다.
📌 내 평점: ⭐⭐⭐⭐☆ (4/5)
🤔 왜 이렇게 평가했을까?
- 경험 순서: 김영한 스프링 로드맵 → 백견불여일타 스프링부트 쇼핑몰 프로젝트
- 김영한 강의에서 배운 내용이 실제로 이렇게 쓰이는구나 깨달음: 김영한 강의로만 뭔갈 만들기 막막했는데, 이렇게 만드는구나, 김영한 강의 속 내용이 이렇게 쓰이는구나 느낌.
- 이론보단 실습 위주: 코드에 대한 설명이 부족함. 근데 필자는 김영한 강의를 많이 들은 상태라 큰 흠은 아님.
- 버그나 deprecated되는 부분을 지속적으로 픽스해 줌: 아래 [🔗 "백견불여일타 스프링 부트 쇼핑몰 프로젝트 with JPA" Q&A] 참고
- 리팩토링이 필요할 부분이 있음: 김영한 강의와 병행하면 보완 가능.
🔗 "백견불여일타 스프링 부트 쇼핑몰 프로젝트 with JPA" 코드
🔗 "백견불여일타 스프링 부트 쇼핑몰 프로젝트 with JPA" Q&A
🔗 클론한 프로젝트
공부 흐름 📚
1️⃣ 책 코드 따라쳐보기
- DB, MVC를 종합적으로 사용해보기 위해 진행!
- 예외 처리, 검증, 타임리프 등 다양한 기능 경험 🎯
2️⃣ Spring MVC 1 복습
3️⃣ Spring MVC 2 김영한 강의 듣기
4️⃣ 다시 변구훈 쇼핑몰 코드 복기하며 이해 심화
하면서 아하! 했던 순간들 🤔
- DTO의 역할
- DTO는 "화면에서 넘어온 데이터를 처리하는 객체"로 생각하니 이해가 쉬웠다.
- 반대로 "데이터를 화면에 넘길 때도 사용"하는 느낌도 가지면 더 좋고.
- main.html에서 getContent()의 정체
<th:block th:each="item, status: ${items.getContent()}">
- user.getUsername()처럼, items.getContent()도 내부적으로 getContent() 메서드를 호출하는 것과 유사한 느낌.
- 보니까 변수 표현식 보면 되네.
${user.username}
,${user['username']}
,${user.getUsername()}
다 같은 기능이다. spring mvc 2 강의에 이 내용이 있다
- 보니까 변수 표현식 보면 되네.
- 컨트롤러에서 넘겨준 page 객체가 slice를 상속받고, slice 내부에 getContent()가 있어 리스트를 반환함. 🔍
음… 이거 고민되네? 😅
🔹
th:if
와th:errors
를 굳이 동시에 써야 하나?- 궁금했던 부분:
<p th:if="${#fields.hasErrors('price')}" th:errors="*{price}" class="fieldError">Incorrect data</p>
- th:if="${#fields.hasErrors('price')}" 없이도 정상 작동하는 것 같음.
- 굳이 필요한지 테스트해볼 필요가 있음.
🔹 @RequestBody 관련 궁금증
- @RequestBody를 쓸 때 JSON을 객체로 변경 못하면 예외가 터진다는데 -> 변구훈 코드에선 이런 처리를 안 했던 것 같은데..?
- spring mvc 2 강의 속 "Bean Validation - HTTP 메시지 컨버터" 단원에서 기인된 궁금증
🔹 DTO와 엔티티의 관계
- 김영한 강의에서는 컨트롤러에서 DTO를 엔티티로 변환 후 서비스/리포지토리로 넘김.
- 핵심 도메인(서비스, 리포지토리 등)은 form(dto)에 의존하면 안 된다고 강조함.
- 반면 변구훈 코드는 DTO를 그대로 서비스/리포지토리에서 사용함.
- ModelMapper(231p)를 활용하면 DTO ↔ 엔티티 변환이 쉬워진다고 하는데, 리팩토링을 기회 있으면 해야 하나?
🔹 템플릿을 하나로 합치는 게 최선일까?
- 등록/수정 템플릿을 하나로 합칠 경우, 분기문(th:if, th:unless)이 많아져 유지보수가 어려워질 수도 있음.
- 변구훈 코드처럼 합치는 방식이 좋은지, 따로 나누는 게 좋은지 고민해볼 필요가 있음.
🔹 비즈니스 로직 추가 고려 사항
- 현재 구현되지 않은 기능들: 배송(출발, 도착), 반품, 교환, 쿠폰 및 할인 적용 등.
- 실제 운영한다면 필요한 기능들인데, 직접 추가 구현해볼까? 🤔
내용 메모 (각 장별 포인트) 📝
2장: Spring Data JPA
- QuerydslPredicateExecutor 사용 → 실무에서는 비추천(103p) ❌
- 김영한 강의에선 실무에 쓰기 부적합하다고 한 기술임. 쓰지 말 것
3장: Thymeleaf
3.3 thymeleaf 예제 진행하기
- th:href → context-relative URL과 absolute URL의 차이 이해 ✅
- absolute url 방식은
http://, https://
로 시작함 - context-relative url은 우리가 실행하는 애플리케이션 의 서버 내부를 이동하는 방법
- 웹 애플리케이션 루트에 상대적인 url을 입력함.
<a th:href="@{/thymeleaf/ex01}">예제1 페이지 이동</a>
- 만약 애플리케이션 루트가 "/shop"으로 지정했다면 html 파일에 생성되는 이동 경로는 "/shop/thymeleaf/ex01"다.
- absolute url 방식은
3.4 thymeleaf 페이지 레이아웃
- Thymeleaf Layout Dialect → 요즘은 기본 기능으로 레이아웃 기능 지원하긴 함(133p)
- layout dialect는 사용하지 않는 편인가요 - 인프런 커뮤니티 질문&답변
- 타임리프가 기본적으로 지원하는 레이아웃 기능을 써도 되지만 이 확장 라이브러리를 써도 되고 편리한 걸 써라
4장: Spring Security 🔐
4.2 스프링 시큐리티 설정 추가하기
- WebSecurityConfigurerAdapter → deprecated됨 (150p)
4.3 회원가입 기능 구현하기
- CSRF 방어 기본 적용됨 → POST 요청마다 CSRF 토큰 필요 (162p)
- CSRF란?
- cross site request forgery란 사이트간 위조 요청으로, 해커가 의도한 대로 수정, 등록, 삭제 등을 요청해서 하는 공격을 말함
- 스프링 시큐리티는 기본적으로 이 csrf를 방어하기 위해 모든 post 방식의 데이터 전송에 csrf 토큰값이 있어야 함
- csrf 토큰은 실제 서버에서 허용한 요청이 맞는지 확인하기 위한 토큰임. 사용자의 세션에 임의의 값을 저장하여, 요청마다 그 값을 포함하여 전송한다.
- 그럼 서버에서 세션에 저장된 값과 요청이 온 값이 일치하는지 확인하여 csrf를 방어함.
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
4.4 로그인/로그아웃 구현하기
- 로그인 기능: UserDetailsService와 UserDetails 인터페이스 활용 (169p)
- UserDetailsService
- db에서 회원 정보를 가져오는 역할
- loadUserByUsername() 메서드가 존재. 회원 정보를 조회하여 사용자의 정보와 권한을 갖는 UserDetails 인터페이스를 반환함
- 스프링 시큐리티에서 UserDetailsService를 구현하고 있는 클래스를 통해 로그인 기능을 구현한다 생각하면 됨.
- UserDetails
- 회원의 정보를 담기 위해 사용하는 인터페이스
- 이 인터페이스를 직접 구현하거나 스프링 시큐리티에서 제공하는 User 클래스를 사용함.
- User 클래스는 UserDetails 인터페이스를 구현한 클래스임
- UserDetailsService
- 로그인 기능 구현은? (170p)
- 기존에 만든 MemberService가 UserDetailsService를 구현하면 됨
- UserDetailsService를 구현한 다음, loadUserByUsername() 메서드를 오버라이딩함.
- 스프링부트 2.7대에서 WebSecurityConfigurerAdapter가 deprecated되어서 코드 다름 (171p)
- Controller에 등록 안 한 url로 가네? (174p)
SecurityConfig
,FormLoginAuthenticationFailureHandler
등 때문이었다.
@AutoConfigureMockMvc
와 MockMvc (177p)@AutoConfigureMockMvc
와 MockMvc로 스프링 시큐리티 테스트를 함.- 로그인이 정상적으로 되는지 안 되는지 테스트할 때 씀
6장: 상품 등록 및 조회 🛍️
6.1 상품 등록하기
th:formaction
→th:action
과 차이점 학습 (241p)th:formaction
이 뭘까? => Working Difference between thaction and thformaction in Thymeleaf 참고<button th:formaction="@{'/admin/item/' + ${itemFormDto.id} }" type="submit" class="btn btn-primary">수정</button>
application.yml
에서 ddl-auto를 validate, create를 왔다갔다 해라는 팁이 좋았음 (242p)
- WebMvcConfigurer를 구현하는 WebMvcConfig 파일을 작성 (244p)
- addResourceHandlers 메서드를 통해, 자신의 로컬 컴퓨터에 업로드한 파일을 찾을 위치를 정함
registry.addResourceHandler("/images/**").addResourceLocations(uploadPath);
addResourceHandler("/images/**")
: 웹에서 접근할 url 경로를 적어줌addResourceLocations(uploadPath)
: 로컬 컴퓨터에 저장된 파일을 읽어올 root 경로를 설정함. "file://경로" 형식으로 적어준다. (⚠️마지막에 /를 적어주어야 디렉토리로 인식하므로 주의하자. /를 적어주지 않는경우 파일로 인식한다.)
ItemServiceTest
왜 실패했지? (252p)- local용 application.yml만 책에 나온대로 수정하고 ItemServiceTest 돌렸더니 실패했다.
- test용에도 똑같이 적용한 다음에 성공했다.
- vue.js 프레임워크? (255p)
- 상품 등록 페이지처럼 복잡한 페이지의 경우, 기존엔 js와 jquery만으로 처리했지만, vue.js를 도입 후 개발이 편해졌다고 함.
- 화면이 너무 복잡하고 서로 얽혀 있는 데이터가 많으면 이런 vue.js 프레임워크를 도입하는 것도 좋은 방법이라고 함.
6.3 상품 관리하기
- getAdminItemPage에서 fetchResults 는 deprecated됨 (269p)
6.4 메인 화면
- 메인 페이지에 사진이 로드안 되는데..? (288p)
application.yml
에 itemImgLocation이 원랜C:\shop\item
으로 되어있었음- 그걸
C:/shop/item
로 바꾼 다음 다시 실행하니 정상적으로 메인 페이지에 이미지가 로드되었음.
8장: 장바구니 🛒
- 화면에서 많은 이벤트 처리 → JS 활용 필수 (344p)
다음으로! 🚀
이번 프로젝트를 통해 Spring Boot와 JPA, 타임리프, Spring Security 등을 실전과 유사하게 활용해볼 수 있었다.
김영한 강의만 들은 나로서, 강의 내용이 이런 식으로 조립되어서 사용되구나 깨달았다.✔️ 다음 목표?
- 직접 프로젝트를 만들어 배포 & 운영까지 경험해볼까? 🤔
- 아니면 다른 실전 프로젝트 도전? 🏗️
- "점프 투 스프링부트"라고 위키독스에서 무료로 공개한 게 있음. 이건 게시판을 만드는 건데 해 보는 것도 좋을 듯
- 홈쇼핑, 게시판은 백엔드에서 전형적인 프로젝트다. 그러나 전형적이라고 안 하는 게 아니라, 빠르게 해보고 얻을 건 얻는 식으로 따라쳐보는 것도 좋을 듯하다.
어떤 방향이든, 직접 해보는 게 가장 좋은 학습 방법인 것 같다.
'BACKEND' 카테고리의 다른 글
[후기] 점프 투 스프링부트 - 게시판 개발 맛보기 (0) 2025.02.05 다음글이전글이전 글이 없습니다.댓글
스킨 업데이트 안내
현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)