: 자바 개발시 자주 사용되는 Getter, Setter, 기본 생성자, toString 등 어노테이션 자동 생성 제공
build.gradle에서 아래의 코드를 의존관계에 추가
implementation('org.projectlombok:lombok')
그리고 plugin에서 아래 사진 설치하고,
아래와 같이 적용까지 해주기(설치는 해두면 계속 설치된 상태이지만 새로운 프로젝트를 할 때는 항상 이렇게 체크 박스를 체크해주어야 함)
.../web/dto/HelloResponseDto.java
생성
➡️ dto 패키지는 앞으로 모든 응답 Dto가 담길 것
@Getter
: get 메소드 자동 생성
@RequiredArgsConstructor
: 선언된 모든 final 필드에 생성자를 자동 생성
final이 없는 필드는 생성자에 포함되지 않음
/test/.../web/dto/HelloResponseDtoTest.java
생성
assertThat
: 검증 메소드로 Assertions.assertThat을 static으로 변환한 것
Assertions를 import 할 때는 반드시 org.assertj.core.api.Assertions로 import 시켜줘야 함isEqualTo
: assertThat에 있는 값과 isEqualTo의 값을 비교해 일치할 때만 성공
assertThat을 import 할 때 Junit 대신 assertj를 선택한 이유는 다음 장점을 가졌기 때문이다.
📌 참고로 테스트 메소드 이름은 한글로 지어도 됨
@RequestParam
: 외부에서 API로 넘긴 파라미터를 가져오는 어노테이션
test/.../web/HelloControllerTest.java에 코드 추가하기
param
: API 테스트할 때 사용될 요청 파라미터 설정
(String 값만 허용)jsonPath
: JSON 응답값을 필드별로 검증할 수 있는 메소드
($를 기준으로 필드명을 명시)
⚠️ 잘 안된다 싶을 땐 import를 확인하기
: 자바 표준 ORM(Object Relational Mapping)
(MyBatis, iBatis는 ORM이 아님)
ORM은 객체를 매핑하는 것이고, SQL은 Mapper는 쿼리를 매핑한다.
개발자는 객체지향적으로 프로그래밍하고, JPA가 이를 관계형 데이터베이스에 맞게 SQL을 대신 생성해서 실행한다.
➡️ 더이상 SQL에 종속적이지 않게 됨
JPA: 인터페이스
Hibernate, Eclipse, Link ..: 구현체
하지만 스프링에서 JPA를 다룰 때 이 구현체들을 직접 다루진 않는다.
구현체들을 조금 더 쉽게 다루기 위해 추상화 시킨 것 ➡️ SpringData JPA라는 모듈
이들의 관계: JPA ⬅️ Hibernate ⬅️ SpringData JPA
Hibernate와 SpringData JPA는 사실 별 차이가 없음에도 불구하고 SpringData JPA가 등장한 이유는 다음과 같다.
📌 참고하기
🔗JPA에 대하여
🔗JPA vs Hibernate vs SpringData JPA
🔗SpringData JPA vs MyBatis
build.gradle에 다음 코드 추가하기
implementation('org.springframework.boot:spring-boot-starter-data-jpa')
implementation('com.h2database:h2')
딱히 설치하지 않아도 사용할 수 있지만 🔗H2를 설치하기 위해서는 링크 참고
web과 동일한 위치에 domain 패키지 생성
이제 여기에 도메인을 담을 것
(도메인: 게시글, 댓글, 회원, ... SW에 대한 요구사항 혹은 문제 영역)
domain/posts/Posts.java
생성해 코드 작성 (깃허브 참고)
@Entity
: 테이블과 링크될 클래스임을 알림@Id
: 해당 테이블의 PK 필드@GeneratedValue
: PK 생성 규칙@Column
: 테이블의 column을 나타냄
굳이 선언하지 않더라도 해당 클래스의 필드는 모두 칼럼이 되지만 굳이 사용하는 이유는 기본값 외 추가로 변경이 필요한 옵션이 있다면 추가하면 됨JPA 어노테이션:
@Entity
lombok 어노테이션(필수 어노테이션은 아님):@Getter
,@NoArgsConstructor
@Builder
: 해당 클래스의 빌더 패턴 클래스 생성
생성자 상단에 선언 시 생성자에 포함된 필드만 빌더에 포함
⚠️ Entity 클래스에 절대 Setter 금지
setter 대신 @Builder
를 통해 제공되는 빌더 클래스를 사용
(생성자나 빌더나 생성 시점 값을 채워주는 역할은 동일)
.../posts/PostsRepository.java
인터페이스 생성
→ Posts 클래스로 DB에 접근하게 해줄 인터페이스
public interface PostsRepository extends JpaRepository<Posts, Long> {
}
이렇게 Entity 클래스, PK 타입만 지정해 상속해주면 기본적인 CRUD 메소드가 자동 생성된다.
@Repository
를 추가할 필요도 없다.
⚠️ 단, Entity 클래스와 기본 Entity Repository가 함께 위치해야 한다.
(Entity 클래스는 기본 Repository 없인 제대로된 역할을 수행할 수 없기 때문)
test/.../domain/posts/PostsRepositoryTest.java
생성
@After
: Junit에서 단위 테스트가 끝날 때마다 수행되는 메소드 지정postsRepository.save
: 테이블 posts에 insert/update 쿼리 실행postsRepository.findAll
: 테이블 posts에 있는 모든 데이터를 조회해오는 메소드
아래 코드 추가하기
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
➡️ 이를 통해 MySQL 버전으로 쿼리를 확인할 수 있게 되었다.
⚠️ 꼭 Service에서 비즈니스 로직을 처리할 필요는 없음
비즈니스 로직을 담당해야 하는 곳은 Domain
Domain model은 도메인이라 불리는 개발 대상을 모든 사람이 동일한 관점에서 이해할 수 있고, 공유할 수 있도록 단순화 시킨 것 이다.
⚠️ Entity 클래스를 Request/Response 클래스로 사용하면 안됨
(Entity 클래스는 DB와 맞닿은 핵심 클래스라 이를 기준으로 테이블이 생성되고 스키마가 변경된다.
그런데 화면 변경은 아주 사소한 변화가 일어나는 부분이다. 이를 위해 Entity 클래스가 변경된다면 너무 큰 변경이 수행되기 때문이다.)
➡️ Dto는 View를 위한 클래스이기 때문에 Dto를 사용하기
스프링빈을 주입받는 방법은 세 가지가 존재한다.
1. @Autowired
➡️ 권장하지 않는 방법
2. setter
3. 생성자
이미 @RequiredArgsConstructor
로 생성자를 생성했기 때문에 @Autowired
없이도 빈을 주입받을 수 있었다.
더티 체킹 (dirty checking)때문이다.
🔗더티 체킹에 대해서 알아보기
PostsApiController.java
PostsService.java
PostsSaveRequestDto.java
PostsResponseDto.java
PostsUpdateRequestDto.java
Posts.java
PostsService.java
test/.../web/PostsApiControllerTest.java
📌 Posts_등록된다 테스트에서 자꾸 실패를 했다가 겨우 성공했다. 하루종일 찾았는데 결국
/
가 빠져있었다.오타를 주의하자
이 글은 이동욱님의 <스프링 부트와 AWS로 혼자 구현하는 웹 서비스> 를 보고 작성한 글입니다.