completely implementation about cqrs and event sourcing

But not testing yet
And not yet for rest too for query
This commit is contained in:
Sambo Chea 2020-08-21 11:30:40 +07:00
parent 05431bd77b
commit d3e8d63287
9 changed files with 133 additions and 7 deletions

View File

@ -0,0 +1,46 @@
package com.cubetiqs.demo.axon.api
import com.cubetiqs.demo.axon.dto.AccountCreationDTO
import com.cubetiqs.demo.axon.dto.MoneyAmountDTO
import com.cubetiqs.demo.axon.entity.BankAccount
import com.cubetiqs.demo.axon.service.AccountCommandService
import io.swagger.annotations.Api
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.http.HttpStatus
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.PutMapping
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 java.util.concurrent.CompletableFuture
@RestController
@RequestMapping(path = ["/accounts"])
@Api(value = "Bank Account Commands", description = "Bank Account Commands API")
class AccountCommandController @Autowired constructor(
private val accountCommandService: AccountCommandService
) {
@PostMapping
@ResponseStatus(value = HttpStatus.CREATED)
fun createAccount(@RequestBody creationDTO: AccountCreationDTO): CompletableFuture<BankAccount?> {
return this.accountCommandService.createAccount(creationDTO)
}
@PutMapping(value = ["/credit/{accountId}"])
fun creditMoneyToAccount(
@PathVariable(value = "accountId") accountId: String,
@RequestBody moneyCreditDTO: MoneyAmountDTO
): CompletableFuture<String?> {
return this.accountCommandService.creditMoneyToAccount(accountId, moneyCreditDTO)
}
@PutMapping(value = ["/debit/{accountId}"])
fun debitMoneyFromAccount(
@PathVariable(value = "accountId") accountId: String,
@RequestBody moneyDebitDTO: MoneyAmountDTO
): CompletableFuture<String?>? {
return this.accountCommandService.debitMoneyFromAccount(accountId, moneyDebitDTO)
}
}

View File

@ -0,0 +1,18 @@
package com.cubetiqs.demo.axon.api
import com.cubetiqs.demo.axon.entity.BankAccount
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PathVariable
import java.util.concurrent.CompletableFuture
class AccountQueryController {
@GetMapping("/{accountId}")
fun findById(@PathVariable("accountId") accountId: String?): CompletableFuture<BankAccount?>? {
return this.accountQueryService.findById(accountId)
}
@GetMapping("/{accountId}/events")
fun listEventsForAccount(@PathVariable(value = "accountId") accountId: String?): List<Any?>? {
return this.accountQueryService.listEventsForAccount(accountId)
}
}

View File

@ -5,8 +5,10 @@ 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.query.FindBankAccountQuery
import com.cubetiqs.demo.axon.repository.BankAccountRepository
import org.axonframework.eventhandling.EventHandler
import org.axonframework.queryhandling.QueryHandler
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
@ -56,4 +58,10 @@ class BankAccountProjection @Autowired constructor(
throw AccountNotFoundException(event.accountId)
}
}
@QueryHandler
fun handle(query: FindBankAccountQuery): BankAccount? {
log.debug("Handling FindBankAccountQuery query: {}", query)
return this.bankAccountRepository.findById(query.accountId).orElse(null)
}
}

View File

@ -3,5 +3,5 @@ package com.cubetiqs.demo.axon.query
import java.util.UUID
data class FindBankAccountQuery(
val id: UUID
val accountId: UUID
)

View File

@ -6,6 +6,7 @@ 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 com.cubetiqs.demo.axon.util.text.formatUuid
import org.axonframework.commandhandling.gateway.CommandGateway
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
@ -29,7 +30,7 @@ class AccountCommandServiceImpl @Autowired constructor(
override fun creditMoneyToAccount(accountId: String?, moneyCreditDTO: MoneyAmountDTO): CompletableFuture<String?> {
return commandGateway.send(
CreditMoneyCommand(
formatUuid(accountId),
accountId.formatUuid(),
moneyCreditDTO.amount
)
)
@ -38,13 +39,11 @@ class AccountCommandServiceImpl @Autowired constructor(
override fun debitMoneyFromAccount(accountId: String?, moneyDebitDTO: MoneyAmountDTO): CompletableFuture<String?> {
return commandGateway.send(
DebitMoneyCommand(
formatUuid(accountId),
accountId.formatUuid(),
moneyDebitDTO.amount
)
)
}
private fun formatUuid(accountId: String?): UUID {
return UUID.fromString(accountId)
}
}

View File

@ -0,0 +1,11 @@
package com.cubetiqs.demo.axon.service
import com.cubetiqs.demo.axon.entity.BankAccount
import org.springframework.stereotype.Service
import java.util.concurrent.CompletableFuture
@Service
interface AccountQueryService {
fun findById(accountId: String?): CompletableFuture<BankAccount?>
fun listEventsForAccount(accountId: String?): List<Any?>
}

View File

@ -0,0 +1,33 @@
package com.cubetiqs.demo.axon.service
import com.cubetiqs.demo.axon.entity.BankAccount
import com.cubetiqs.demo.axon.query.FindBankAccountQuery
import com.cubetiqs.demo.axon.util.text.formatUuid
import org.axonframework.eventsourcing.eventstore.EventStore
import org.axonframework.messaging.responsetypes.ResponseTypes
import org.axonframework.queryhandling.QueryGateway
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import java.util.concurrent.CompletableFuture
import java.util.stream.Collectors
@Service
class AccountQueryServiceImpl @Autowired constructor(
private val queryGateway: QueryGateway,
private val eventStore: EventStore
) : AccountQueryService {
override fun findById(accountId: String?): CompletableFuture<BankAccount?> {
return this.queryGateway.query(
FindBankAccountQuery(accountId.formatUuid()),
ResponseTypes.instanceOf(BankAccount::class.java)
)
}
override fun listEventsForAccount(accountId: String?): List<Any?> {
return this.eventStore
.readEvents(accountId.formatUuid().toString())
.asStream()
.map { it.payload }
.collect(Collectors.toList());
}
}

View File

@ -0,0 +1,7 @@
package com.cubetiqs.demo.axon.util.text
import java.util.UUID
fun String?.formatUuid(): UUID {
return UUID.fromString(this)
}

View File

@ -29,4 +29,8 @@ spring:
dialect: org.hibernate.dialect.PostgreSQLDialect
temp:
use_jdbc_metadata_defaults: false
open-in-view: true
open-in-view: true
axon:
serializer:
general: jackson