add projection

add dtos
Add exception for account
add repository
add account service command
This commit is contained in:
Sambo Chea 2020-08-21 11:18:15 +07:00
parent 8e9fd6935f
commit 05431bd77b
9 changed files with 168 additions and 8 deletions

View File

@ -1,15 +1,11 @@
package com.cubetiqs.demo.axon package com.cubetiqs.demo.axon
import com.cubetiqs.demo.axon.entity.BankAccount
import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication import org.springframework.boot.runApplication
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.http.ResponseEntity import org.springframework.http.ResponseEntity
import org.springframework.stereotype.Repository
import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController import org.springframework.web.bind.annotation.RestController
import java.util.UUID
@SpringBootApplication @SpringBootApplication
class AxonApplication class AxonApplication
@ -26,6 +22,3 @@ class DefaultController {
return ResponseEntity.ok("ok") return ResponseEntity.ok("ok")
} }
} }
@Repository
interface BankAccountRepository : JpaRepository<BankAccount, UUID>

View File

@ -0,0 +1,8 @@
package com.cubetiqs.demo.axon.dto
import java.math.BigDecimal
data class AccountCreationDTO(
var initialBalance: BigDecimal? = null,
var owner: String? = null
)

View File

@ -0,0 +1,7 @@
package com.cubetiqs.demo.axon.dto
import java.math.BigDecimal
data class MoneyAmountDTO(
var amount: BigDecimal? = null
)

View File

@ -0,0 +1,5 @@
package com.cubetiqs.demo.axon.exception
import java.util.UUID
class AccountNotFoundException(id: UUID?) : Throwable("Cannot found account number [$id]")

View File

@ -0,0 +1,59 @@
package com.cubetiqs.demo.axon.projection
import com.cubetiqs.demo.axon.entity.BankAccount
import com.cubetiqs.demo.axon.event.AccountCreatedEvent
import com.cubetiqs.demo.axon.event.MoneyCreditedEvent
import com.cubetiqs.demo.axon.event.MoneyDebitedEvent
import com.cubetiqs.demo.axon.exception.AccountNotFoundException
import com.cubetiqs.demo.axon.repository.BankAccountRepository
import org.axonframework.eventhandling.EventHandler
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
import java.util.Optional
@Component
class BankAccountProjection @Autowired constructor(
private val bankAccountRepository: BankAccountRepository
) {
private val log = LoggerFactory.getLogger(this.javaClass)
@EventHandler
fun on(event: AccountCreatedEvent) {
log.debug("Handling a Bank Account creation command {}", event.id)
val bankAccount = BankAccount(
event.id,
event.owner,
event.initialBalance
)
this.bankAccountRepository.save(bankAccount)
}
@EventHandler
@Throws(AccountNotFoundException::class)
fun on(event: MoneyCreditedEvent) {
log.debug("Handling an Account Credit command {}", event.accountId)
val optionalBankAccount: Optional<BankAccount> = this.bankAccountRepository.findById(event.accountId!!)
if (optionalBankAccount.isPresent) {
val bankAccount: BankAccount = optionalBankAccount.get()
bankAccount.balance = bankAccount.balance!!.add(event.creditAmount)
this.bankAccountRepository.save(bankAccount)
} else {
throw AccountNotFoundException(event.accountId)
}
}
@EventHandler
@Throws(AccountNotFoundException::class)
fun on(event: MoneyDebitedEvent) {
log.debug("Handling an Account Debit command {}", event.accountId)
val optionalBankAccount: Optional<BankAccount> = this.bankAccountRepository.findById(event.accountId!!)
if (optionalBankAccount.isPresent) {
val bankAccount: BankAccount = optionalBankAccount.get()
bankAccount.balance = bankAccount.balance!!.subtract(event.debitAmount)
this.bankAccountRepository.save(bankAccount)
} else {
throw AccountNotFoundException(event.accountId)
}
}
}

View File

@ -0,0 +1,7 @@
package com.cubetiqs.demo.axon.query
import java.util.UUID
data class FindBankAccountQuery(
val id: UUID
)

View File

@ -0,0 +1,9 @@
package com.cubetiqs.demo.axon.repository
import com.cubetiqs.demo.axon.entity.BankAccount
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository
import java.util.UUID
@Repository
interface BankAccountRepository : JpaRepository<BankAccount, UUID>

View File

@ -0,0 +1,22 @@
package com.cubetiqs.demo.axon.service
import com.cubetiqs.demo.axon.dto.AccountCreationDTO
import com.cubetiqs.demo.axon.dto.MoneyAmountDTO
import com.cubetiqs.demo.axon.entity.BankAccount
import org.springframework.stereotype.Service
import java.util.concurrent.CompletableFuture
@Service
interface AccountCommandService {
fun createAccount(creationDTO: AccountCreationDTO): CompletableFuture<BankAccount?>
fun creditMoneyToAccount(
accountId: String?,
moneyCreditDTO: MoneyAmountDTO
): CompletableFuture<String?>
fun debitMoneyFromAccount(
accountId: String?,
moneyDebitDTO: MoneyAmountDTO
): CompletableFuture<String?>
}

View File

@ -0,0 +1,50 @@
package com.cubetiqs.demo.axon.service
import com.cubetiqs.demo.axon.command.CreateAccountCommand
import com.cubetiqs.demo.axon.command.CreditMoneyCommand
import com.cubetiqs.demo.axon.command.DebitMoneyCommand
import com.cubetiqs.demo.axon.dto.AccountCreationDTO
import com.cubetiqs.demo.axon.dto.MoneyAmountDTO
import com.cubetiqs.demo.axon.entity.BankAccount
import org.axonframework.commandhandling.gateway.CommandGateway
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import java.util.UUID
import java.util.concurrent.CompletableFuture
@Service
class AccountCommandServiceImpl @Autowired constructor(
private val commandGateway: CommandGateway
) : AccountCommandService {
override fun createAccount(creationDTO: AccountCreationDTO): CompletableFuture<BankAccount?> {
return commandGateway.send(
CreateAccountCommand(
UUID.randomUUID(),
creationDTO.initialBalance,
creationDTO.owner,
)
)
}
override fun creditMoneyToAccount(accountId: String?, moneyCreditDTO: MoneyAmountDTO): CompletableFuture<String?> {
return commandGateway.send(
CreditMoneyCommand(
formatUuid(accountId),
moneyCreditDTO.amount
)
)
}
override fun debitMoneyFromAccount(accountId: String?, moneyDebitDTO: MoneyAmountDTO): CompletableFuture<String?> {
return commandGateway.send(
DebitMoneyCommand(
formatUuid(accountId),
moneyDebitDTO.amount
)
)
}
private fun formatUuid(accountId: String?): UUID {
return UUID.fromString(accountId)
}
}