프로젝트/선착순 쿠폰 발급 시스템

회원 도메인 모듈 만들기

Junuuu 2023. 4. 27. 00:01
반응형

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 객체들의 변경에 대해 유연함을 가질 수 있습니다.