웹 애플리케이션 제작
11. 웹 애플리케이션 제작
사용기술
- 뷰: Thymeleaf
- 웹: 스프링 MVC
- 데이터 저장 계층: JPA, 하이버네이트
- 기반 프레임워크: 스프링 부트
- 빌드: Gradle
11.1 프로젝트 환경설정
-
스프링 부트 프로젝트 생성(https://start.spring.io/)
-
build.gradle 설정
plugins {
id 'org.springframework.boot' version '2.5.2'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
}
group = 'jpabook'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-devtools'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-hibernate5'
implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.7.1'
implementation 'com.querydsl:querydsl-core'
implementation 'com.querydsl:querydsl-jpa'
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jpa"
annotationProcessor 'jakarta.persistence:jakarta.persistence-api'
annotationProcessor 'jakarta.annotation:jakarta.annotation-api'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
runtimeOnly 'mysql:mysql-connector-java'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
def generated='src/main/generated'
sourceSets {
main.java.srcDirs += [ generated ]
}
tasks.withType(JavaCompile) {
options.generatedSourceOutputDirectory = file(generated)
}
clean.doLast {
file(generated).deleteDir()
}
test {
useJUnitPlatform()
}
- application.yml 설정
spring:
datasource:
url: jdbc:h2:tcp://localhost/~/jpashop
username: sa
password:
driver-class-name: org.h2.Driver
jpa:
hibernate:
ddl-auto: create
properties:
hibernate:
# show_sql: true
format_sql: true
default_batch_fetch_size: 100
logging:
level:
org.hibernate.SQL: debug
# org.hibernate.type: trace
11.2 도메인 모델과 테이블 설계
11.2.1 요구사항 분석
- 회원 기능
- 회원 등록
- 회원 조회
- 상품 기능
- 상품 등록
- 상품 수정
- 상품 조회
- 주문 기능
- 상품 주문
- 주문 내역 조회
- 주문 취소
- 기타 요구사항
- 상품의 종류는 도서, 음반, 영화
- 상품 카테고리 분류
- 상품 주문시 배송 정보 입력
11.2.2 도메인 모델 설계
- 주문과 회원은 다대일 관계이다.
- 한 회원이 여러 개의 주문을 할 수 있다.
- 한 주문은 하나의 회원에 속한다.
- 주문과 상품은 다대다 관계이다.
- 한 주문은 여러 개의 상품을 가질 수 있다.
- 한 상품은 여러 개의 주문에 속할 수 있다.
- 주문과 상품은 다대다 관계이므로, 중간에 주문상품 엔티티를 추가해서 일대다, 다대일 관계로 풀어낸다.
- 주문과 배송은 일대일 관계이다.
- 상품과 카테고리는 다대다 관계이다.
11.3 애플리케이션 구현
- 다음 기능은 구현하지 않는다.
- 로그인과 권한 관리는 하지 않는다.
- 파라미터 검증과 예외 처리는 하지 않는다.
- 상품은 도서만 사용한다.
- 카테고리는 사용하지 않는다.
- 배송 정보는 사용하지 않는다.
11.3.1 개발 방법
- 컨트롤러: 웹
- 서비스: 트랜잭션, 비즈니스 로직 호출, 도메인 순서 보장
- 도메인 모델 패턴: 비즈니스 로직이 엔티티에 대부분 존재
- 트랜잭션 스크립트 패턴: 비즈니스 로직이 서비스에 대부분 존재
- 리포지토리: 데이터 접근
- 도메인: 비즈니스 로직
11.3.2 회원 기능
- 기능 목록
- 회원 등록
- 회원 목록 조회
- 코드 구현
- 회원 리포지토리
- 회원 서비스
- @Transactional(readOnly = true)
- 트랜잭션 커밋 시점에 플러시 안함(변경 감지 기능이 동작하지 않음) => 성능 최적화
- 스냅샷을 만들지 않음 => 메모리 최적화
- @Transactional(readOnly = true)
- 회원 서비스 테스트
11.3.3 상품 기능
- 기능 목록
- 상품 등록
- 상품 목록 조회
- 상품 수정
- 코드 구현
- 상품 엔티티
- 비즈니스 메서드: 재고 증가, 재고 감소
- 상품 리포지토리
- 상품 저장, 수정을 처리하는 save 메서드
- persist, merge
- merge 사용 권장하지 않음, 변경 감지를 이용한 수정 권장
- 상품 저장, 수정을 처리하는 save 메서드
- 상품 서비스
- 상품 수정시 변경 감지 사용
- 상품 수정시 DTO, 변경 메서드 사용
- 상품 엔티티
11.3.4 주문 기능
- 기능 목록
- 상품 주문
- 주문 내역 조회
- 주문 취소
- 코드 구현
- 주문 엔티티
- 주문 생성 메서드: 주문 생성 전용 메서드, 여러 파라미터를 전달하면 주문 객체를 생성해서 반환
- 비즈니스 메서드: 주문 취소, 주문 가격 조회
- 주문 상품 엔티티
- 주문 상품 생성 메서드: 주문 상품 생성 전용 메서드
- 비즈니스 메서드: 주문 취소, 주문 가격 조회
- 주문 리포지토리
- 주문 서비스
- 주문 서비스 테스트
- 주문 엔티티
11.3.5 웹 계층 구현
- 회원 가입
-
회원 목록
- 상품 등록
- 상품 목록
-
상품 수정
- 상품 주문
- 주문 내역
- 주문 취소
Leave a comment