회원 도메인 모듈 만들기
Domain 모듈 생성
settings.gradle.kts에 다음과 같은 구문을 추가합니다.
include("domain")
domain이라는 이름을 가지는 Directory를 추가하고 gradle을 refresh 합니다.
domain 모듈에는 순수 Kotlin만 다루게 됩니다.
- Jpa Entity가 아닌 순수 회원 객체
- Jpa Repository가 아닌 Repository Interface 제공
member entity sample code
package com.demo.domain.member.entity
class Member(
val id: String,
val password: String,
val nickName: String,
val fullName: String,
)
member repository sample code
package com.demo.domain.member.repository
import com.demo.domain.member.entity.Member
interface MemberRepository {
fun save(member: Member): Member
}
build.gradle.kts에서도 의존성을 가지지 않습니다.
import org.springframework.boot.gradle.tasks.bundling.BootJar
val jar: Jar by tasks
val bootJar: BootJar by tasks
bootJar.enabled = false
jar.enabled = true
api 계층
@Controller와 Http 정보를 처리하며 Response, Request를 다룹니다.
SignUp Controller sample code
@RestController
@RequestMapping("/member")
class SignUpController(
val signUpUseCase: SignUpUseCase
) {
@PostMapping
fun signUp(request: SignUpRequest){
signUpUseCase.signUp(request.makeCommand())
}
}
SignUpRequest sample code
data class SignUpRequest(
val memberId: String,
val password: String,
val nickName: String,
val fullName: String,
){
fun makeCommand(): SignUpCommand{
return SignUpCommand(
memberId = this.memberId,
password = this.password,
nickName = this.nickName,
fullName = this.fullName,
)
}
}
Application 계층
인터페이스인 UseCase와 이를 구현하는 Service, 입력 모델(Command), 출력 모델(Result)을 다룹니다.
signUpCommand sample code
package com.demo.application.member.signup.command
data class SignUpCommand(
val memberId: String,
val password: String,
val nickName: String,
val fullName: String,
)
signUpService sample code
package com.demo.application.member.signup.service
import com.demo.application.member.signup.command.SignUpCommand
import com.demo.application.member.signup.usecase.SignUpUseCase
import com.demo.domain.member.entity.Member
import com.demo.domain.member.repository.MemberRepository
import org.springframework.stereotype.Service
@Service
class SignUpService(
private val memberRepository: MemberRepository
) : SignUpUseCase{
override fun signUp(command: SignUpCommand) {
val member = Member(
id = command.memberId,
password = command.password,
nickName = command.nickName,
fullName = command.fullName,
)
memberRepository.save(member)
}
}
signUpUseCase sample code
package com.demo.application.member.signup.usecase
import com.demo.application.member.signup.command.SignUpCommand
interface SignUpUseCase {
fun signUp(command: SignUpCommand)
}
Infra 계층
db 환경 설정과 jpa, mybatis, jdbctemplate 등의 실제 영속성 reposiotry, entity를 구성하고 adapter를 통해 domain 계층과 협력합니다.
member jpa entity sample code
package com.demo.infrastructure.member.signup.entity
import com.demo.domain.member.entity.Member
import javax.persistence.Column
import javax.persistence.Entity
import javax.persistence.Table
import javax.persistence.Id
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType.IDENTITY
@Entity
@Table(name = "member")
class MemberJpaEntity(
@Column
private val memberId: String,
@Column
private val password: String,
@Column
private val nickName: String,
@Column
private val fullName: String,
) {
@Id
@GeneratedValue(strategy = IDENTITY)
private val id: Long = 0L
private val _memberId: String = memberId
companion object{
fun of(member: Member): MemberJpaEntity{
return MemberJpaEntity(
memberId = member.id,
password = member.password,
nickName = member.nickName,
fullName = member.fullName,
)
}
}
fun toEntity(): Member{
return Member(
id = this.memberId,
password = this.password,
nickName = this.nickName,
fullName = this.fullName,
)
}
}
memeber jpa repository sample code
package com.demo.infrastructure.member.signup.repository
import com.demo.infrastructure.member.signup.entity.MemberJpaEntity
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository
@Repository
interface MemberJpaRepository : JpaRepository<MemberJpaEntity, Long> {
}
member persistence adapter sample code
package com.demo.infrastructure.member.signup.adapter
import com.demo.domain.member.entity.Member
import com.demo.domain.member.repository.MemberRepository
import com.demo.infrastructure.member.signup.entity.MemberJpaEntity
import com.demo.infrastructure.member.signup.repository.MemberJpaRepository
import org.springframework.stereotype.Component
@Component
class MemberPersistenceAdapter(
private val memberJpaRepository: MemberJpaRepository,
): MemberRepository {
override fun save(member: Member): Member {
val memberJpaEntity = MemberJpaEntity.of(member)
val savedMemberJpaEntity = memberJpaRepository.save(memberJpaEntity)
return savedMemberJpaEntity.toEntity()
}
}
persistenceAdapter는 memberRepository를 interface의 구현체입니다.
member entity를 받아 memberJpaEntity로 변환합니다.
이후 memberJpaRepository를 통해 save를 수행합니다.
해당 결과를 다시 member entity로 변환하여 반환합니다.
mapper 코드가 생성되지만 추후 dao 객체들의 변경에 대해 유연함을 가질 수 있습니다.