웹 애플리케이션 제작

11. 웹 애플리케이션 제작

사용기술

  • 뷰: Thymeleaf
  • 웹: 스프링 MVC
  • 데이터 저장 계층: JPA, 하이버네이트
  • 기반 프레임워크: 스프링 부트
  • 빌드: Gradle

11.1 프로젝트 환경설정

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)
        • 트랜잭션 커밋 시점에 플러시 안함(변경 감지 기능이 동작하지 않음) => 성능 최적화
        • 스냅샷을 만들지 않음 => 메모리 최적화
    • 회원 서비스 테스트

11.3.3 상품 기능

  • 기능 목록
    • 상품 등록
    • 상품 목록 조회
    • 상품 수정
  • 코드 구현
    • 상품 엔티티
      • 비즈니스 메서드: 재고 증가, 재고 감소
    • 상품 리포지토리
      • 상품 저장, 수정을 처리하는 save 메서드
        • persist, merge
        • merge 사용 권장하지 않음, 변경 감지를 이용한 수정 권장
    • 상품 서비스
      • 상품 수정시 변경 감지 사용
      • 상품 수정시 DTO, 변경 메서드 사용

11.3.4 주문 기능

  • 기능 목록
    • 상품 주문
    • 주문 내역 조회
    • 주문 취소
  • 코드 구현
    • 주문 엔티티
      • 주문 생성 메서드: 주문 생성 전용 메서드, 여러 파라미터를 전달하면 주문 객체를 생성해서 반환
      • 비즈니스 메서드: 주문 취소, 주문 가격 조회
    • 주문 상품 엔티티
      • 주문 상품 생성 메서드: 주문 상품 생성 전용 메서드
      • 비즈니스 메서드: 주문 취소, 주문 가격 조회
    • 주문 리포지토리
    • 주문 서비스
    • 주문 서비스 테스트

11.3.5 웹 계층 구현

  • 회원 가입
  • 회원 목록

  • 상품 등록
  • 상품 목록
  • 상품 수정

  • 상품 주문
  • 주문 내역
  • 주문 취소

Tags:

Categories:

Updated:

Leave a comment