소스코드는 다음 깃허브에 있습니다 https://github.com/devYSK/study_repo/tree/main/%EC%9E%90%EB%B0%94ORM%20JPA%20%EC%8A%A4%ED%84%B0%EB%94%94/11%EC%9E%A5
[GitHub - devYSK/study_repo: 개인 공부 레포
개인 공부 레포. Contribute to devYSK/study_repo development by creating an account on GitHub.
github.com](https://github.com/devYSK/study_repo/tree/main/%EC%9E%90%EB%B0%94ORM%20JPA%20%EC%8A%A4%ED%84%B0%EB%94%94/11%EC%9E%A5)
JPA 프로그래밍 11장 정리
웹 애플리케이션 만들기
만들기 진행 순서
- 프로젝트 환경설정
- 도메인 모델과 테이블 설계
- 애플리케이션 기능 구현
사용 기술
- 뷰 :
JSP, JSTL
- 웹 계층 :
스프링 MVC
- 데이터 저장 계층 :
JPA, 하이버네이트
- 빌드 도구 :
메이븐 Maven
Spring Boot 2.7.4 + Maven을 사용하고, 의존성은 밑에 첨부하겠다.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- spring boot 환경에서 jsp 사용하기 위해서 반드시! !-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
</dependencies>
- Spring MVC는 spring-boot-starter-web 에서 지원
- JSP, JSTL 를 사용하기 위해서는 jstl, tomcat-embd-jasper를 반드시 추가해야 한다.
- 다음 설정을 하지 않으면 whitelabel 404 not found error 발생.
spring:
mvc:
view:
prefix: /WEB-INF/views/
suffix: .jsp
- 위처럼 반드시 경로를 지정해준다.
- jsp 파일들은 src/main/webapp 디렉토리 아래로 지정해놓고 사용해야 한다 반드시
- 만약 이 설정을 하더라도 안되면 껏다 켜보거나 인텔리제이 기준 invalidate cache 한 다음 restart 해야한다.
- spring-orm, jpa, hibernate는 spring-data-jpa에서 지원한다.
- 이외 라이브러리는
https://search.maven.org/
나,https://mvnrepository.com/
에서 검색하여 다운로드 받을 수 있다.
- 환경 설정 파일은 xml 대신 Config.java 파일로 대체한다
- properties 파일은 yml 파일로 변경했다.
패키지 구조
application.yml
spring:
datasource:
# url: jdbc:h2:tcp://localhost/~/h2/test # ?? url
url : jdbc:h2:mem:jpashop
driver-class-name: org.h2.Driver # JDBC Driver
username: sa # userID
password: # password
mvc:
view:
prefix: /WEB-INF/
suffix: .jsp
jpa:
database: h2
show-sql: true
properties:
hibernate:
dialect: org.hibernate.dialect.H2Dialect #Dialect, ?? ??
show_sql: true
format_sql: true
use_sql_comments: true
id:
new_generator_mappings: true
hibernate:
ddl-auto: update
- h2를 tcp로 연결하면, 로컬에서 실행하고 애플리케이션을 실행시켜야 컨넥션 에러가 없다.
- h2를 mem으로 설정하면 애플리케이션 종료시 같이 휘발된다.
- 이외에 책에 있는 다양한 설정들은 spring-boot-starter 의존성에 의해 자동으로 설정된다.
도메인 및 엔티티 설정
- 회원(Member) : 이름과 주문항 상품들, 임베디드 타입(Address)
- 주문(Order) : Order-OrderItem은 1:N, 주문한 회원, 배송 정보, 주문 날짜, 주문 상태
- 주문아이템(Order-Item) : 주문한 상품정보와 주문 금액, 주문 수량
- 상품(Item) : 이름, 가격, 재고수량
- 배송(Delevery) : 주문 시 하나의 배송 정보 생성. Order-Delivery는 1:1
- 카테고리(Category) : 상품과 N:M 관계
- 주소(Address) : 값 타입(임베디드) 회원과 배송에서 사용
애플리케이션 구현
- 요구사항에 필요한 기능을 분류해보자
- 회원 기능
- 회원 등록
- 회원 목록 조회
- 상품 기능
- 상품 등록
- 상품 목록 조회
- 상품 수정
- 주문 기능
- 상품 주문
- 주문 내역 조회
- 주문 취소
- 예제를 단순화 하기 위해 다음 기능은 구현하지 않는다.
- 로그인과 권한 관리
- 파라미터 검증과 예외 처리
- 상품은 도서만 사용
- 카테고리는 사용하지 않는다
- 배송 정보는 사용하지 않는다
개발 방법
일반적으로 많이 사용하는 Controller-Service-Repository 3-Layer 아키텍처를 사용
- Controller : MVC의 컨트롤러가 모여있는 곳. 컨트롤러는 서비스 계층을 호출하고 결과를 뷰(JSP) 에 전달
- Service : 서비스 계층에서는 비즈니스 로직이 있고 트랜잭션을 시작 및 종료. 레포지토리를 호출한다.
- Repository : JPA를 직접 사용하는 계층. 엔티티 매니저를 사용해서 엔티티를 저장하고 조회
- Domain : 엔티티가 모여있는 계층.
레포지토리에 있는 어노테이션 정리 (Repository Annotation)
- @Repository 어노테이션
- 스프링 빈으로 자동 등록
- JPA 전용 예외가 발생하면 스프링이 추상화한 예외로 예외 변환
- JPA 예외를 스프링 예외로 변경
- javax.persistence.NoResultException -> EmptyResultDataAccessException 으로 변환
- @PersistenceContext
- 컨테이너가 관리하는
엔티티 매니저
를 주입하는 어노테이션- 엔티티 매니저 팩토리를 주입하는 것이 아니다.
- 컨테이너가 관리하는
- @PersistenceUnit
- 엔티티 매니저 팩토리를 주입받을 떄 사용. 엔티티 매니저를 주입하는 것이 아니다
서비스에 있는 어노테이션 정리 (Service Annotation)
- @Service 어노테이션
- 스프링 빈으로 자동 등록
- @Transactional
- 클래스나 메서드에 트랜잭션 적용
- 이 클래스의 메소드를 호출할 때 트랜잭션을 시작하고 메소드를 종료할 때 커밋한다.
- 예외 발생시 롤백한다.
- RunTimeException과 그 자식들인 언체크(Unchecked) 예외만 롤백한다.
- 만약 체크 예외가 발생해도 롤백하고 싶다면 rollbackFor 옵션을 사용하여 롤백할 예외 지정.
TestCode
Given, When, Then(martinfowler.com/bilki/GivenWhenThen.html)
- 테스트를 이해하기 쉽게 도와준다
- Given : 테스트할 상황 설정
- When : 테스트 대상 실행
- Then : 결과 검증
통합 테스트
- Junit4에서는 RunWith를 사용하지만, JUnit5에서는 @SpringBootTest 어노테이션을 사용하면 된다.
- @Transactional 어노테이션을 테스트코드에 붙여 사용하면, 테스트가 끝나면 트랜잭션을 강제로 롤백해줘서 데이터베이스의 데이터가 변경되는 상황이 없다.
비즈니스 로직과 트랜잭션 스크립트, 도메인 모델 패턴
주문 서비스의 주문과 주문 취소 메소드를 보면 비즈니스 로직 대부분이 엔티티에 있다.
서비스 계층은 단순히 엔티티에 필요한 요청을 위임하는 역할은 한다.
이처럼 엔티티가 비즈니스 로직을 가지고 객체지향의 특성을 적극 활용하는 것을 도메인 모델 패턴(martinfowler.com/eaaCatalog/domailModel.html)
이라고 한다.
반대로 엔티티에는 비즈니스 로직이 없고 서비스 계층에서 대부분의 비즈니스 로직을 처리하는 것을 트랜잭션 스크립트 패턴(transactionScript)(martinfowler.com/eaaCatalog/transactionScript.html)
라고 한다.