[스프링 핵심 원리 - 기본] 원리 이해1 - 예제 만들기
김영한님 스프링 핵심 원리 기본을 듣고 정리한 글입니다.
스프링 핵심 원리 - 기본편 - 인프런 | 강의
스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., - 강의 소개 | 인프런...
www.inflearn.com
start.spring.io 에서 generate를 하여 intellij로 프로젝트를 가져왔습니다.
강의에서는 11을 사용했지만 8버전으로 공부하고 싶어서 저는 8로 진행했습니다.
자바 버전이 맞지 않아서 gradle과 settings를 건드렸는데 이는 밑의 주소에서 확인하실 수 있습니다.
https://p-kyung.tistory.com/33
[프로젝트 환경 설정] 스프링 입문 - 코드로 배우는 스프링 부트
어플 개발 프로젝트를 진행하면서 프론트만 담당했던 내가 crud를 처리할 수 있는 백엔드의 지식이 필요했다. 백엔드의 'ㅂ' 조차 모르지만 인프런 강의를 시작으로 '백'을 알기 위해 공부해보려
p-kyung.tistory.com
<비지니스 요구사항과 설계>
회원
회원 가입 기능과 검색 기능이 있다
회원은 일반 회원과 vip로 나뉘어진다
회원 데이터는 자체 db구축 가능, 외부 시스템 연동 가능하다
주문 할인 정책
회원 상품 주문 가능하다
회원 등급에 따라 할인 정책 적용한다
모든 vip는 1000원 할인해주는 고정 금액 할인 적용한다
할인 정책은 변경 가능성이 높다
회사의 기본 할인 정책을 아직 정하지 못했고, 오픈 직전까지 미루고 싶다 (할인을 적용하지 않을 수도 있다)
---스프링 없는 순수한 자바로 개발을 진행한다---
<회원 도메인 설계>
회원 클래스 다이어그램
회원 객체 다이어그램
<회원 도메인 개발>
member package 안
Grade enum, Member class, MemberRepository interface, MemberService interface, MemberServiceImpl, MemoryMemberRepository class
Grade - VIP, BASIC
Member class - id, name, grade 생성자 게터 세터 생성한다 (alt + insert 단축키를 이용하면 편리하다)
MemberRepository - save, findById
MemberService - join, findMember
MemberServiceImpl - new MemoryMemberRepository
MemoryMemberRepository - HashMap<Long, Member>()
<회원 도메인 실행과 테스트>
- 순수한 자바 코드로 테스트
public class MemberApp {
public static void main(String[] args) {
MemberService memberService = new MemberServiceImpl();
Member memberA = new Member(1L, "memberA", Grade.VIP);
memberService.join(memberA);
Member member = memberService.findMember(1L);
System.out.println("new member = " + memberA.getName());
System.out.println("find member = " + member.getName());
}
}
실행 결과
new member = memberA
find member = memberA
- junit으로 테스트한 코드
테스트 할 때는 given when then 으로 무언가 주어졌을 때, 어떤 상황에 어떻게 되어야하는지를 생각하며 코드를 짠다.
public class MemberServiceTest {
MemberService memberService = new MemberServiceImpl();
@Test
void join() {
// given (이게 주어지고)
Member member = new Member(1L, "memberA", Grade.VIP);
// when (이런 상황에)
memberService.join(member);
Member findMember = memberService.findMember(1L);
// then (이렇게 된다)
Assertions.assertThat(member).isEqualTo(findMember);
}
}
실행 결과
이 코드는 설계상의 문제가있다. 이는 의존관계가 인터페이스 뿐만 아니라 구현까지 모두 의존하고 있다는 것이다.
MemberServiceImpl은 MemberRepository도 의존하고 있지만 MemoryMemberRepository 또한 의존하고 있다.
<주문과 할인 도메인 설계>
주문 도메인 다이어그램
1. 주문 생성 : 클라이언트는 주문 서비스에 주문 생성 요청
2. 회원 조회 : 할인을 위해 회원 조회
3. 할인 적용 : 회원 등급에 따른 할인 여부를 주문 서비스에서 위임
4. 주문 결과 반환 : 주문 서비스는 할인 결과를 포함한 주문 결과 반환
여기서 역할은 모두 interface이다.
역할과 구현을 분리함으로써 자유롭게 구현 객체를 조립할 수 있게 설계한다.
주문 도메인 클래스 다이어그램
<주문과 할인 도메인 개발>
discount 패키지 안
DiscountPolicy interface, FixDiscountPolicy
order 패키지 안
Order, OrderService interface, OrderServiceImpl
DiscountPolicy interface - discount(Member member, int price) [할인된 금액 반환]
FixDiscountPolicy class - 회원 등급이 VIP일 때 할인 금액 반환
Order class - memberId, itemName, itemPrice, discountPrice 생성자, 게터, 세터 생성
OrderService interface - createOrder(Long memberId, String itemName, int itemPrice) [주문 생성]
OrderServiceImpl class - MemoryMemberRepository와 DiscountPolicy 둘 다 필요함 (멤버를 찾아서 할인 정책 적용 후 주문 반환)
<주문과 할인 도메인 실행과 테스트>
자바 코드로 만든 테스트 코드
public class OrderApp {
public static void main(String[] args) {
MemberService memberService = new MemberServiceImpl();
OrderService orderService = new OrderServiceImpl();
Long memberId = 1L;
Member member = new Member(memberId, "memberA", Grade.VIP);
memberService.join(member);
Order order = orderService.createOrder(memberId, "itemA", 10000);
// 만들어 놓은 toString 적용됨
System.out.println("order = " + order);
System.out.println("order.calculatePrice = " + order.calculatePrice());
}
}
실행 결과
order = Order{memberId=1, itemName='itemA', itemPrice=10000, discountPrice=1000}
order.calculatePrice = 9000
junit으로 테스트한 코드
public class OrderServiceTest {
MemberService memberService = new MemberServiceImpl();
OrderService orderService = new OrderServiceImpl();
@Test
void createOrder() {
Long memberId = 1L;
Member member = new Member(memberId, "memberA", Grade.VIP);
memberService.join(member);
Order order = orderService.createOrder(memberId, "itemA", 10000);
Assertions.assertThat(order.getDiscountPrice()).isEqualTo(1000);
}
}
실행 결과