Skip to content

Commit

Permalink
[BSVR-44] 영속성 계층 (JPA) 모듈 추가 (#6)
Browse files Browse the repository at this point in the history
* feat: infrastructure 모듈 추가

* feat: Spring Boot Configuration에 JPA 설정 추가

* test: JPA 확인용 예제 추가

* feat: datasource, jpa, h2 관련 application.yml 설정 추가

* fix: 모듈간 순환참조 해결

* build: usecase 모듈 추가

* feat: usecase 예제 추가

* fix: component scan 설정 수정
  • Loading branch information
EunjiShin authored Jul 3, 2024
1 parent 123e0e4 commit 6fcad26
Show file tree
Hide file tree
Showing 23 changed files with 296 additions and 0 deletions.
2 changes: 2 additions & 0 deletions application/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
dependencies {
implementation(project(":domain"))
implementation(project(":usecase"))
implementation(project(":infrastructure:jpa"))

// spring
implementation("org.springframework.boot:spring-boot-starter")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package org.depromeet.spot.application.config;

import org.depromeet.spot.jpa.config.JpaConfig;
import org.depromeet.spot.usecase.config.UsecaseConfig;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@ComponentScan(basePackages = {"org.depromeet.spot.application"})
@Configuration
@Import(value = {UsecaseConfig.class, JpaConfig.class})
public class SpotApplicationConfig {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package org.depromeet.spot.application.member.controller;

import org.depromeet.spot.application.member.dto.request.MemberRequest;
import org.depromeet.spot.application.member.dto.response.MemberResponse;
import org.depromeet.spot.usecase.port.in.MemberUsecase;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.val;

// FIXME: JPA 확인용 샘플 컨트롤러 입니다. 이후 실제 작업 시작할 때 삭제 예정이에요!
@RestController
@RequiredArgsConstructor
@Tag(name = "멤버")
@RequestMapping("/api/members")
public class MemberController {

private final MemberUsecase memberUsecase;

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
@Operation(summary = "Member 생성 API")
public MemberResponse create(@RequestBody MemberRequest request) {
val member = memberUsecase.create(request.name());
return MemberResponse.from(member);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package org.depromeet.spot.application.member.dto.request;

public record MemberRequest(String name) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.depromeet.spot.application.member.dto.response;

import org.depromeet.spot.domain.member.Member;

public record MemberResponse(Long id, String name) {

public static MemberResponse from(Member member) {
return new MemberResponse(member.getId(), member.getName());
}
}
3 changes: 3 additions & 0 deletions application/src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ server:
shutdown: graceful

spring:
# 서브모듈 profile
profiles:
include: jpa
# swagger를 이용해 API 명세서 생성
doc:
swagger-ui:
Expand Down
15 changes: 15 additions & 0 deletions domain/src/main/java/org/depromeet/spot/domain/member/Member.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.depromeet.spot.domain.member;

import lombok.Getter;

@Getter
public class Member {

private final Long id;
private final String name;

public Member(Long id, String name) {
this.id = id;
this.name = name;
}
}
2 changes: 2 additions & 0 deletions infrastructure/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
tasks.bootJar { enabled = false }
tasks.jar { enabled = true }
14 changes: 14 additions & 0 deletions infrastructure/jpa/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
dependencies {
implementation(project(":domain"))
implementation(project(":usecase"))

// spring
implementation("org.springframework.boot:spring-boot-starter-data-jpa:_")

// h2 - DB (또는 도커) 세팅 후 사라질 예정,,
runtimeOnly("com.h2database:h2")

}

tasks.bootJar { enabled = false }
tasks.jar { enabled = true }
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.depromeet.spot.jpa.config;

import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@Configuration
@ComponentScan(basePackages = {"org.depromeet.spot.jpa"})
@EnableJpaRepositories(basePackages = {"org.depromeet.spot.jpa"})
@EntityScan(basePackages = {"org.depromeet.spot.jpa"})
public class JpaConfig {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.depromeet.spot.jpa.member.entity;

/* JPA 설정 확인용 샘플 엔티티. 실제 피처 개발 시작할 때 삭제 예정! */

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

import org.depromeet.spot.domain.member.Member;

import lombok.NoArgsConstructor;

@Entity
@Table(name = "member")
@NoArgsConstructor
public class MemberEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private Long id;

@Column(name = "name", nullable = false)
private String name;

public MemberEntity(Long id, String name) {
this.id = id;
this.name = name;
}

public static MemberEntity from(Member member) {
return new MemberEntity(member.getId(), member.getName());
}

public Member toDomain() {
return new Member(id, name);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.depromeet.spot.jpa.member.repository;

import org.depromeet.spot.jpa.member.entity.MemberEntity;
import org.springframework.data.jpa.repository.JpaRepository;

public interface MemberJpaRepository extends JpaRepository<MemberEntity, Long> {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.depromeet.spot.jpa.member.repository;

import org.depromeet.spot.domain.member.Member;
import org.depromeet.spot.jpa.member.entity.MemberEntity;
import org.depromeet.spot.usecase.port.out.MemberRepository;
import org.springframework.stereotype.Repository;

import lombok.RequiredArgsConstructor;
import lombok.val;

@Repository
@RequiredArgsConstructor
public class MemberRepositoryImpl implements MemberRepository {

private final MemberJpaRepository memberJpaRepository;

@Override
public Member save(Member member) {
val memberEntity = memberJpaRepository.save(MemberEntity.from(member));
return memberEntity.toDomain();
}
}
19 changes: 19 additions & 0 deletions infrastructure/jpa/src/main/resources/application-jpa.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
spring:
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:spot
username: sa
password:

jpa:
database: h2
hibernate:
ddl-auto: create
database-platform: org.hibernate.dialect.H2Dialect
open-in-view: false
defer-datasource-initialization: true

h2:
console:
enabled: true
path: /h2-console
4 changes: 4 additions & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ plugins {

include("domain")
include("application")
include("infrastructure")
include("infrastructure:jpa")
findProject(":infrastructure:jpa")?.name = "jpa"
include("usecase")
42 changes: 42 additions & 0 deletions usecase/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/

### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/

### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/

### VS Code ###
.vscode/

### Mac OS ###
.DS_Store
10 changes: 10 additions & 0 deletions usecase/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
dependencies {
implementation(project(":domain"))

// spring
implementation("org.springframework.boot:spring-boot-starter")
implementation("org.springframework.boot:spring-boot-starter-web")
}

tasks.bootJar { enabled = false }
tasks.jar { enabled = true }
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.depromeet.spot.usecase.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(
basePackages = {
"org.depromeet.spot.usecase.port",
"org.depromeet.spot.usecase.service",
})
public class UsecaseConfig {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.depromeet.spot.usecase.port.in;

import org.depromeet.spot.domain.member.Member;

public interface MemberUsecase {

Member create(String name);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.depromeet.spot.usecase.port.out;

import org.depromeet.spot.domain.member.Member;

public interface MemberRepository {

Member save(Member member);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.depromeet.spot.usecase.service;

import org.depromeet.spot.domain.member.Member;
import org.depromeet.spot.usecase.port.in.MemberUsecase;
import org.depromeet.spot.usecase.port.out.MemberRepository;
import org.springframework.stereotype.Service;

import lombok.RequiredArgsConstructor;
import lombok.val;

@Service
@RequiredArgsConstructor
public class MemberService implements MemberUsecase {

private final MemberRepository memberRepository;

@Override
public Member create(final String name) {
val member = new Member(null, name);
return memberRepository.save(member);
}
}
3 changes: 3 additions & 0 deletions versions.properties
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,7 @@ version.org.projectlombok..lombok=1.18.30

version.org.springframework.boot..spring-boot-starter-test=3.0.1

version.org.springframework.boot..spring-boot-starter-data-jpa=3.0.1

version.org.springdoc..springdoc-openapi-starter-webmvc-ui=2.5.0

0 comments on commit 6fcad26

Please sign in to comment.