본문 바로가기

Database & ORM/JPA 프로젝트

4. Spring 웹 계층 및 CRUD 기능 구현

Spring 웹 계층

Web Layer

  • 흔히 사용하는 컨트롤러(Controller)와 JSP/Freemarker 등의 뷰 템플릿 영역이다.
  • 이외에도 필터(@Filter), 인터셉터, 컨트롤러 어드바이스(@ControllerAdvice) 등 외부 요청과 응답에 대한 전반적인 영역을 의미한다.

Service Layer

  • @Service에 사용되는 서비스 영역이다.
  • 일반적으로 Controller와 Dao의 중간 영역에서 사용된다.
  • @Transactional이 사용되어야 하는 영역이기도 하다.

Repository Layer

  • Database와 같이 데이터 저장소에 접근하는 영역이다.
  • Dao(Data Access Object) 영역이라고 생각하면 된다.

Dtos

  • Dto(Data Transfer Object)는 계층 간에 데이터 교환(Service -> Repository)을 위한 객체를 의미하며, Dtos는 이들의 영역을 의미한다.
  • 예를 들어 뷰 템플릿 엔진에서 사용될 객체나 Repository Layer에서 결과로 넘겨준 객체 등이 이들을 이야기한다.

Domain Model

  • 도메인이라 불리는 개발 대상을 모든 사람이 동일한 관점에서 이해할 수 있고 공유할 수 있도록 단순화시킨 것을 도메인 모델이라고 한다.
  • 배달 앱이라고 가정하면, 주문, 결제, 배달상태 등이 될 수 있다.
  • 비즈니스 로직을 처리하는 영역이다.Serivce가 아닌 Domain에서 처리한다.
    • Service는 트랜잭션을 보장해주고 Domain 내 비즈니스 로직을 필요한 순서대로 호출한다.
  • @Entity가 사용된 영역 역시 도메인 모델이라고 이해하면 된다.
  • 다만, 무조건 데이터베이스의 테이블과 관계가 있어야 하는 것은 아니다. VO처럼 값 객체들도 이 영역에 해당하기 때문이다.

CRUD 기능 구현

Member를 등록, 수정, 삭제, 조회하는 기능을 Spring과 JPA로 구현
전체 소스는 https://github.com/Minji1004/MinjiShop 에 있다.

Web Layer

Controller

  • @Controller를 선언해준다.
  • DTO 클래스에 setter가 없으면 화면으로부터 값을 가지고오지 못한다.
  • @RequiredArgsConstructor는 롬복이 제공하는 기능으로, final이 붙은 필드로 구성된 생성자를 만든다.
  • 생성자가 하나 밖에 없으면 @Autowired가 붙지 않아도, 생성자 방식으로 의존성을 주입한다.
  • return되는 String은 응답을 보낼 화면 이름이다.
    ex) members/createMemberForm -> members/createMemberForm.mustache로 보내진다.
  • Model 객체에 담긴 값은 mustache 파일로 보내진다.

아래는 API용 Controller이다. Member 정보의 수정 및 삭제는 API로 구현했다.

  • @RestController: JSON을 반환하는 컨트롤러로 만들어준다.

Dtos

Entity는 절대 뷰 템플릿(mustache)용으로 사용하면 안된다.
DB 테이블과 밀접한 관계가 있으므로, Reuqest/Response는 엔터티가 아닌 DTO를 만들어서 받아야 한다.

Service Layer

Service

  • @Service를 붙여 Service 클래스임을 설정한다.
  • @Transactional을 붙인다. 없으면 아래와 같은 에러가 난다.
  • Repository에서 사용하기 전에 DTO를 Entity로 바꿔준다. 또한 DB에서 가져온 Entity는 다시 DTO나 필요한 값만 빼서 내보낸다. (Service와 Repository Layer 간 데이터 교환)

  • JPA에서 수정, 삭제 시 우선 Entity ID로 JPA 영속 컨텍스트에서 조회해서 해당 Entity를 영속 상태로 만든다.

JPA에서 수정은 영속 상태에 있는 엔터티의 값만 변경해주면 된다.
그러면 JPA 영속 컨텍스트에서 변경 감지를 하여 DB에 flush 할 때 DB에 update SQL을 자동으로 보낸다.

Repository Layer

Repository

  • @Repository 를 붙인다.
  • @PersistenceContext는 스프링 컨테이너에 등록된 EntityManger 스프링 빈을 주입받는다.
  • JPQL은 JPA에서 제공하는 객체지향 쿼리 언어다.

Domain

  • @Entity를 붙인다.
  • DB의 테이블과 매핑된다.

아래 Member 엔티티의 자세한 내용은 Spring Data JPA 를 이용해 기본 도메인 Entity 생성을 참조한다.