본문 바로가기

Backend

Springboot (3) 웹 애플리케이션 - 1

1. JPA

자바 표준 ORM(Object Relational Mapping: 객체 관계 매핑). 관계형 데이터베이스와 객체지향 프로그래밍 언어간의 패러다임 불일치를 해소해준다. 실제 동작하는 SQL은 JPA가 작성해주기 때문에 개발자는 객체지향적으로 데이터베이스를 다룰 수 있다.

 

2. Spring Data JPA

JPA는 인터페이스이며, Hibernate와 같은 별도의 구현체가 필요하다. Spring에서는 이 구현체를 한 번 더 감싼 Spring Data JPA를 사용한다(JPA ← Hibernate ← SpringDataJPA).

이렇게 구성하게 되면 구현체, 데이터베이스와의 결합도가 낮아지게 되어 추후 구현체 교체와 저장소 교체가 수월해진다.

 

3. Spring 웹 계층

  • Web Layer: 외부 요청과 응답 관련 영역
  • Service Layer: 트랜잭션, 도메인 간 순서보장 관련 영역
  • Repository Layer: 데이터 저장소에 접근하는 영역
  • DTOs: 계층 간 데이터 교환을 위한 객체 영역
  • Domain Model: 개발 대상(도메인)을 모든 사람이 동일한 관점에서 이해하고 공유할 수 있도록 단순화 시킨 것

*Service 영역에서 @Transactional 어노테이션을 사용한다.
*비즈니스 처리는 Domain 영역에서 담당한다(Service 영역이 아님).

 

4. 게시판 개발

모든 웹 애플리케이션의 가장 기본 기능인 CRUD(Create, Read, Update, Delete)를 구현한다.

 

A. Springboot 의존성

Spring Data JPA와 H2를 의존성에 추가해준다. H2는 메모리상에서 동작하는 데이터베이스이며, 애플리케이션 재구동 시 초기화 된다. 테스트용으로 자주 사용된다.

build.gradle 파일 dependencies에 아래 문장을 추가한다.

    ...
    compile('org.springframework.boot:spring-boot-starter-data-jpa')
    compile('com.h2database:h2')
    ...

 

i) H2-Console

H2 DB는 인메모리 데이터베이스이다.

http://localhost:8080/h2-console 접속 후 아래 정보를 입력하고 접속한다. Password는 없다.

 

C. domain 패키지

도메인 게시글, 회원, 정산 등 소프트웨어의 요구사항? 문제영역? 이라고 생각하면 된다고 한다.

> 자세한 내용은 추후 검색해볼 것

 

i) Entity

실제 데이터베이스 테이블과 매칭될 클래스이다. DTO/VO와 비슷하게 보이지만 용도나 기능 측면에서 확연히 다르다.

단적인 예로 Entity 객체를 수정 할 경우 실제 DB 데이터가 수정된다.

*영속성 컨텍스트: Entity를 영구 저장하는 환경. 트랜잭션 안에서 DB에서 가져온 데이터 객체를 수정하면 트랜잭션이 끝나는 시점에 변경분을 반영한다. 이를 더티 체킹(dirty checking)이라고 한다.

 

*주의사항:
 Entity 클래스에는 절대로 Setter를 만들지 않는다.
 값 변경이 필요할 경우 아래와 같이 목적/의도를 나타낼 수 있는 메소드를 추가하여 사용한다.

@Entity
public class Order {
    ...
    public void cancelOrder() {
        this.status = false;
    }
}

public void 주문서비스의_취소이벤트() {
    order.cancelOrder();
}

 

[주요 어노테이션]

Annotation Description
@Entity 테이블과 링크될 클래스임을 나타낸다.
카멜(MyClass) ↔ 언더스코어(MY_CLASS) 규칙으로 테이블과 매핑된다.
@Id PK 필드임을 나타낸다.
@GeneratedValue PK 생성규칙을 나타낸다.
@Column 칼럼임을 나타내며 생략 가능하다. 타입이나 길이와 같은 옵션 변경이 필요할 경우 사용한다. 참고로 문자열 기본 값은 VARCHAR(255)이다.

일반적으로 Entity의 PK는 Long타입의 Auto Increment가 권장된다.

> 자세한 내용은 식별자 전략, 복합키 매핑 등 추후 검색해볼 것

 

ii) Entity Repository

Dao와 유사한 데이터베이스 접근자이다. 인터페이스 생성 후 JpaRepository<Entity클래스, PK타입>을 상속받으면 기본적인 CRUD 메소드가 자동으로 생성된다. Entity 클래스와 같은 경로에 함께 위치해야 한다.

public interface PostsRepository extends JpaRepository<Posts, Long> {
    @Query("SELECT p FROM Posts p ORDER BY p.id DESC")
    List<Posts> findAllDesc();
}

+ repository의 save(...) 메소드는 파라미터 객체에 id값이 있으면 update, 없으면 insert를 수행한다.
+ @Query 어노테이션을 활용하여 실행 쿼리를 직접 지정할수도 있다.

 

C. Controller, Service, Dto

아래 두 가지 내용을 참고하여 일반적인 방식으로 생성해준다.

  • Bean 주입 시 생성자로 주입받는 방식을 권장한다. @RequiredArgsConstructor를 활용하자
  • Entity 클래스를 절대로 Dto로 사용해서는 안된다. Entity 클래스는 DB 테이블, 스키마와 연관 된 클래스로 쉽게 변경할 수 없다. Dto는 요구사항에 따라 언제나 쉽게 변경될 수 있기 때문에 Dto와 Entity는 기능과 용도면에서 명확히 분리해야 한다.

 

D. JPA Auditing

JPA Auditing을 사용하여 생성시간/수정시간 저장 로직을 자동화할 수 있다. 날짜 지정에는 Java8의 LocalDate, LocalDateTime을 활용하자(Date와 Calendar 클래스는 일부 문제가 있음).

Entity 클래스가 아래 클래스를 상속받으면 생성/수정시간 Auditing이 적용 된다

...
@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public class BaseTimeEntity {
    @CreatedDate
    private LocalDateTime createDate;

    @LastModifiedDate
    private LocalDateTime modifiedDate;
}

 

[주요 어노테이션]

Annotation Description
@MappedSuperclass 자식 Entity가 본 클래스의 필드를 칼럼으로 인식
@EntityListeners(AuditingEntityListener.class) 클래스에 Auditing 기능을 포함시킴
@CreatedDate Entity가 저장 될 때 시간을 자동 저장
@LastModifiedDate Entity가 수정 될 때 시간을 자동 저장
@EnableJpaAuditing JPA Auditing을 활성화 한다. 메인 클래스에 적용

일반적으로 Entity의 PK는 Long타입의 Auto Increment가 권장된다.

 

5. 기타

[기타 어노테이션]

Annotation Description
@PathVariable {변수명} 표현식과 함께 사용하여 URL 경로에 변수를 넣어준다.
@Transactional(readOnly = true) 클래스/메소드에 지정하여 기능의 원자성을 보장해준다
readOnly 옵션으로 조회만 하는 트랜잭션임을 명시하여 조회 속도를 개선할수 있다.
JUnit / @After JUnit에서 단위 테스트가 끝날 때 수행되는 메소드 지정
Lombok / @NoArgsConstructor 기본 생성자 자동 추가
Lombok / @Getter 모든 필드의 Getter 생성
Lombok / @Builder 해당 클래스의 빌더 클래스 생성. 생성자 대신 빌더를 사용함으로써 객체 생성 시 명시적으로 필드를 입력할 수 있다.

 

[application.properties]

Option Description
spring.jpa.show_sql=true 콘솔 로그에 쿼리 출력 활성화
spring.h2.console.enabled=true h2 콘솔 화면 활성화
→ http://localhost:8080/h2-console

 

[인텔리제이 단축키]

기능 단축키
툴팁보기(Quick Documentation) Ctrl + Q
이름 바꾸기(Rename) Shift + F6
라인 복제 Ctrl + D
라인 삭제 Ctrl + Y
라인 이동 Alt + Shift + ↑↓
전체 검색 Ctrl + Shift + F
코드 자동 정렬 Ctrl + Alt + L
파라미터 보기 Ctrl + P
창 닫기 Ctrl + F4

 

*기타 참고

  • DDD Start!(최범균 저)
  • 자바 ORM 표준 JPA 프로그래밍(김영한 저)

'Backend' 카테고리의 다른 글

iBatis 쿼리 가져오기  (0) 2020.05.07
Springboot (4) 웹 애플리케이션 - 2  (0) 2020.04.29
Springboot (2) 단위 테스트  (0) 2020.04.18
Springboot (1) 개발환경 설정  (0) 2020.04.17
Spring Batch + MyBatis 연결방법  (0) 2020.03.18