본문 바로가기
프로젝트/개인 프로젝트 V2

3) 요구사항 구현 & 계층형 구조

by Thumper 2023. 6. 13.

요구사항을 구현해보자.

계층형 구조로 구현했다.

 

  • Controller : MVC의 컨트롤러가 모여 있는 곳이다. 컨트롤러는 서비스 계층을 호출하고 결과를 뷰에 전달한다.
  • Service : 비즈니스 로직이 있고 트랜잭션을 시작한다. 서비스 계층은 데이터 접근 계층인 리포지토리를 호출한다.
  • Repository : JPA를 직접 사용하는 곳은 리포지토리 계층이다.
  • Domain : 엔티티가 모여 있는 계층이다. 모든 계층에서 사용한다.

스프링 데이터 JPA로 요구사항을 구현해보자.

 

사용자 정의 리포지토리 구현

스프링 데이터 JPA에서는 필요한 메서드만 구현할 수 있는 방법을 제공한다.

Paging Query 편에 자세히 작성했다.

사용자 정의 리포지토리 구성

 

1. 직접 구현할 메서드를 위한 사용자 정의 인터페이스를 작성한다.

아래처럼 필요한 메서드를 정의했다.

ItemRepositoryCustom 코드

  • Page searchByItemName(ItemSearchCondition condition, Pageable pageable) : 상품 이름으로 검색 페이징
  • Page sortByCategoryType(String code, Pageable pageable) : 카테고리 타입별 페이징
  • Page searchByItemNameAndCategoryType(ItemSearchCondition condition, String code, Pageable pageable) : 카테고리별 상품 이름검색 페이징
  • Page sortByItemPriceASC(Pageable pageable) : 높은 가격순 페이징
  • Page sortByItemPriceDESC(Pageable pageable): 낮은 가격순 페이징
  • List sortByUser() : 유저별 등록한 상품 리스트 반환

2. 사용자 정의 구현 클래스를 작성한다.

이때 클래스 이름을 짓는 규칙이 있는데 "리포지토리 인터페이스 이름 + Impl" 로 지어야 한다.

ItemRepositoryCustomImpl 코드

3. 사용자 정의 인터페이스 상속

리포지토리 인터페이스(ItemRepository)에서 사용자 정의 인터페이스를 상속받으면 된다.

ItemRepository 코드

 

JpaRepository는 기본적인 CRUD 및 페이징 처리를 위한 메소드가 정의되어 있다.

JpaRepository를 상속받는 리포지토리를 만든다.

2개의 제네릭 타입을 사용하는데 첫 번째에는 엔티티의 타입 클래스를, 두 번째에는 기본키 타입인 Long을 넣어주면 된다.

CartRepository
OrderItemRepository
ItemRepository
UserRepository
ItemImgRepository

 

 

스프링 데이터 JPA가 쿼리 메소드 기능을 제공한다.

간단한 조회를 구현하기 위해 사용했다.

"JPA exists 쿼리 성능 개선" 글을 참고하려고 한다.

public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByLoginId(String id);
    User findById(long id);
    boolean existsByLoginIdAndPassword(String id, String password);
}

이런 식으로 리포지토리에 필요한 메서드를 작성했다.

 

 

 

 

 

 

서비스 계층

필요한 예외처리를 넣고, 설계한 리포지토리를 위임하는 식으로 작성했다.

ItemService

saveItem : 상품 등록 기능
findById : 상품ID로 해당 상품 조회
getItemDetail : 상품ID로 해당 상품 상세정보 조회
searchPageSort : 상품 이름으로 조회 페이징
categoryPageSort : 상품 카테고리별 페이징
itemPriceSort : 상품 가격순 페이징

ItemImgService

saveItemImg : 상품등록폼에 받은 이미지파일을 저장한다,  ItemService에서 호출된다.
findByImgName : 이미지 삭제
findByImgId : 이미지 ID로 조회
delete : 이미지 삭제

CartService

getWishList : 장바구니 조회
addWishList : 장바구니에 주문할 상품 넣기
deleteWishList : 장바구니 삭제

UserService

signUp : 회원가입
validateDuplicateUser : 중복아이디 검증로직, 회원가입()에서 사용할 검증로직이다.
existByLoginIdAndPassword : 테스트용 검증로직, 로그인 실패 케이스 테스트를 위해 만들었다.
signIn : 로그인
findOne : 회원ID로 회원 조회
findAllByUser : 회원이 등록한 상품조회
delete : 회원이 등록한 상품을 삭제

 

 

 

 

기능 테스트

  • 작성한 코드가 잘 동작하는지 테스트 코드를 작성해서 테스트해보자.
  • 개발한 로직이 정상 동작하는지 JUnit 으로 테스트를 작성해서 검증해보자.

테스트 케이스 설명은 주석으로 잘 달아놨다. 테스트 구현

 

@Transactional

테스트는 반복해서 실행할 수 있어야 한다. 테스트를 실행하면 DB에 데이터가 저장된다.
다시 테스트를 실행하면 이미 저장된 데이터 때문에 테스트가 실패할 수 있다. 
테스트를 시행할 때마다 트랜잭션을 시작하고 테스트가 끝나면 트랜잭션을 강제로 롤백한다. 
따라서 테스트를 진행하면서 DB에 저장한 데이터가 테스트가 끝나면 롤백되므로 반복해서 테스트를 진행할 수 있다.

후기

지금까지 스프링 프레임워크와 JPA를 사용해서 실제 웹 애플리케이션을 개발해보았다.

부족한 감이 있지만, 스프링과 JPA, MVC, QueryDSL 등등 어떻게 활용해야 할지 감이라도 잡은 느낌이다.

사실 이전에 만든 프로젝트를 리팩토링 하는 시간으로 가볍게 시작했지만, 생각보다 어설프게 만들었었구나 라고 느꼈다.

다시 코드를 읽어보니 부족하고 개선해야 할 사항이 많은 것 같아, 더 많은 시간이 필요한 듯하다.

'프로젝트 > 개인 프로젝트 V2' 카테고리의 다른 글

6) 파일 업로드  (0) 2023.06.14
5) Paging Query  (1) 2023.06.13
4) Enum 활용  (0) 2023.06.13
2) 도메인 모델과 테이블 설계  (0) 2023.06.13
1) SpringBoot & Github 프로젝트 생성하기  (0) 2023.06.13

댓글