Chapter 13. 웹 애플리케이션 제작

Chapter 13. 웹 애플리케이션 제작

스프링 프레임워크와 JPA를 함께 사용하여 웹 애플리케이션을 구성하는 방법을 다룬다.

스프링 프레임워크와 JPA를 함께 사용한다는 것은 스프링 컨테이너 위에서 JPA를 사용한다는 의미다. 스프링 컨테이너가 제공하는 데이터베이스 커넥션과 트랜잭션 처리 기능을 활용할 수 있다.

1. 프로젝트 구조

jpashop (프로젝트 루트)
├── src
│   ├── main
│   │   ├── java        (소스 코드)
│   │   ├── resources   (리소스)
│   │   └── webapp      (웹 폴더)
│   └── test            (테스트)
├── target              (빌드 결과)
└── pom.xml             (메이븐 설정)

2. 메이븐과 라이브러리 관리

2.1 pom.xml 기본 구조

<?xml version="1.0" encoding="UTF-8"?>
<project ...>
    <modelVersion>4.0.0</modelVersion>

    <groupId>jpabook</groupId>
    <artifactId>jpashop</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <dependencies>
        <!-- 라이브러리 선언 -->
    </dependencies>

    <build>
        <!-- 빌드 설정 -->
    </build>
</project>

2.2 pom.xml 주요 태그

태그설명
<groupId>프로젝트 그룹 명 (예: org.springframework)
<artifactId>프로젝트 식별 ID (예: spring-core)
<version>프로젝트 버전
<packaging>패키징 방식 (웹: war, 라이브러리: jar)
<dependencies>사용할 라이브러리 목록

2.3 핵심 라이브러리

라이브러리artifactId역할
스프링 MVCspring-webmvc웹 MVC 기능
스프링 ORMspring-orm스프링 + JPA 연동
하이버네이트hibernate-entitymanagerJPA 구현체
  spring-webmvc
      │
      ▼ (의존성 전이)
  spring-core

  hibernate-entitymanager
      ├── hibernate-core.jar
      └── hibernate-jpa-2.1-api.jar
의존성 전이(Transitive Dependency): spring-webmvc를 선언하면 spring-core도 자동으로 내려받는다. 메이븐이 의존관계가 있는 라이브러리를 자동으로 추가하는 기능이다.

2.4 dependency scope

scope설명
compile기본값. 컴파일 시 사용
runtime실행 시에만 사용
provided외부에서 제공. 빌드에 미포함 (JSP, Servlet)
test테스트 코드에서만 사용

3. 스프링 프레임워크 설정

3.1 프로젝트 계층 구조

jpashop/src/main
├── java/jpabook/jpashop
│   ├── domain        (도메인 계층)
│   ├── repository    (데이터 저장 계층)
│   ├── service       (서비스 계층)
│   └── web           (웹 계층)
├── resources
│   ├── appConfig.xml
│   └── webAppConfig.xml
└── webapp/WEB-INF
    └── web.xml

3.2 설정 파일 역할

┌──────────────────────────┐
│       web.xml            │
│   (스프링 구동 설정)       │
├────────────┬─────────────┤
│            │             │
│            ▼             │
│  ┌────────────────────┐  │
│  │ webAppConfig.xml   │  │
│  │  웹 계층 설정        │  │
│  │  - MVC 활성화       │  │
│  │  - 컨트롤러 스캔     │  │
│  │  - 뷰 리졸버        │  │
│  └────────────────────┘  │
│            │             │
│            ▼             │
│  ┌────────────────────┐  │
│  │ appConfig.xml      │  │
│  │  비즈니스 계층 설정   │  │
│  │  - 서비스, 리포지토리 │  │
│  │  - 트랜잭션         │  │
│  │  - 데이터소스        │  │
│  │  - JPA 설정         │  │
│  └────────────────────┘  │
└──────────────────────────┘
파일담당 계층
web.xml웹 애플리케이션 환경설정 (스프링 구동)
webAppConfig.xml웹 계층 (MVC, 컨트롤러, 뷰 리졸버)
appConfig.xml비즈니스 계층 (서비스, 리포지토리, 트랜잭션, JPA)

4. webAppConfig.xml 설정

<!-- 스프링 MVC 기능 활성화 -->
<mvc:annotation-driven />

<!-- 컨트롤러 자동 스캔 -->
<context:component-scan
    base-package="jpabook.jpashop.web" />

<!-- 뷰 리졸버 등록 -->
<bean id="viewResolver"
    class="org.springframework.web.servlet
    .view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/jsp/" />
    <property name="suffix" value=".jsp" />
</bean>

component-scan 동작

base-package: jpabook.jpashop.web
         │
         ▼  스캔 대상 어노테이션
   @Controller  → 스프링 빈 등록
   @Service     → 스프링 빈 등록
   @Repository  → 스프링 빈 등록
   @Component   → 스프링 빈 등록

5. appConfig.xml 설정

5.1 트랜잭션 관리자

<!-- 어노테이션 기반 트랜잭션 활성화 -->
<tx:annotation-driven />

<!-- JPA 트랜잭션 관리자 등록 -->
<bean id="transactionManager"
    class="org.springframework.orm.jpa
    .JpaTransactionManager">
    <property name="dataSource"
        ref="dataSource" />
</bean>
트랜잭션 관리자용도
DataSourceTransactionManagerJDBC, MyBatis 전용
JpaTransactionManagerJPA 사용 시 필수
JpaTransactionManagerDataSourceTransactionManager의 역할도 수행한다. JPA와 JdbcTemplate, MyBatis를 함께 사용할 수 있다.

5.2 JPA 예외 변환 AOP

<bean class="org.springframework.dao
    .annotation
    .PersistenceExceptionTranslationPostProcessor" />

@Repository 어노테이션이 붙은 빈에 예외 변환 AOP를 적용한다.

JPA 예외 발생
    │
    ▼
PersistenceException
    │ (AOP 변환)
    ▼
스프링 추상화 예외
(DataAccessException)

5.3 엔티티 매니저 팩토리 설정

<bean id="entityManagerFactory"
    class="org.springframework.orm.jpa
    .LocalContainerEntityManagerFactoryBean">

    <property name="dataSource"
        ref="dataSource" />

    <property name="packagesToScan"
        value="jpabook.jpashop.domain" />

    <property name="jpaVendorAdapter">
        <bean class="org.springframework
            .orm.jpa.vendor
            .HibernateJpaVendorAdapter" />
    </property>

    <property name="jpaProperties">
        <!-- 하이버네이트 속성 설정 -->
    </property>
</bean>
속성설명
dataSource사용할 데이터소스
packagesToScan@Entity 클래스 검색 시작점
persistenceUnitName영속성 유닛 이름 (기본값: default)
jpaVendorAdapterJPA 구현체 지정 (HibernateJpaVendorAdapter)
LocalContainerEntityManagerFactoryBean을 사용하면 persistence.xml 없이도 필요한 설정을 모두 할 수 있다. 스프링이 J2SE 환경에서도 표준 컨테이너처럼 JPA를 사용할 수 있도록 에뮬레이션한다.

6. 하이버네이트 속성 설정

속성설명
hibernate.dialect데이터베이스 방언
hibernate.show_sql실행 SQL 콘솔 출력
hibernate.format_sqlSQL 보기 좋게 정리
hibernate.use_sql_commentsSQL 코멘트 출력
hibernate.id.new_generator_mappings새로운 ID 생성 전략 사용
hibernate.hbm2ddl.autoDDL 자동 생성

hbm2ddl.auto 옵션

옵션동작
create기존 DDL 제거 후 새로 생성
create-dropcreate + 종료 시 DDL 제거
update변경사항만 수정
validate스키마 비교만 수행 (DDL 변경 없음)
hibernate.id.new_generator_mappings항상 true로 설정해야 한다. false이면 하이버네이트 과거 버전의 키 생성 전략을 사용하게 된다.

SQL 로그 설정

콘솔 대신 로거를 통해 SQL을 출력하려면 logback.xml에 다음을 설정한다.

<!-- SQL 출력 -->
<logger name="org.hibernate.SQL"
    level="DEBUG" />

<!-- 바인딩 파라미터 출력 -->
<logger name="org.hibernate.type"
    level="TRACE" />
로거를 사용할 때는 hibernate.show_sql 옵션을 꺼야 콘솔에 로그가 중복 출력되지 않는다.

정리

┌──────────────────────────┐
│  웹 애플리케이션 구성 요약  │
├──────────────────────────┤
│                          │
│  1. 메이븐               │
│   └── pom.xml로 의존성   │
│       관리               │
│                          │
│  2. 설정 파일 분리        │
│   ├── web.xml            │
│   │   (구동 설정)         │
│   ├── webAppConfig.xml   │
│   │   (웹 계층)           │
│   └── appConfig.xml      │
│       (비즈니스 계층)      │
│                          │
│  3. JPA 핵심 설정         │
│   ├── JpaTransactionMgr  │
│   ├── EntityMgrFactory   │
│   └── 예외 변환 AOP       │
│                          │
│  4. 하이버네이트           │
│   ├── 방언(dialect)       │
│   ├── DDL 자동 생성       │
│   └── SQL 로그            │
│                          │
└──────────────────────────┘