Compare commits

..

9 Commits

14 changed files with 107 additions and 26 deletions

1
.gitignore vendored
View File

@@ -4,6 +4,7 @@ build/
!gradle/wrapper/gradle-wrapper.jar !gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/ !**/src/main/**/build/
!**/src/test/**/build/ !**/src/test/**/build/
application-dev.yml
### STS ### ### STS ###
.apt_generated .apt_generated

View File

@@ -1,8 +1,8 @@
# Spring Boot + Axon Framework # Spring Boot + Axon Framework
### Concepts to implement ### Concepts to implement
- [ ] Event Sourcing - [x] Event Sourcing
- [x] CQRS System
- [ ] DDD - [ ] DDD
- [ ] CQRS System
### Contributors ### Contributors
- [x] Sambo Chea <sombochea@cubetiqs.com> - [x] Sambo Chea <sombochea@cubetiqs.com>

View File

@@ -1,11 +1,13 @@
package com.cubetiqs.demo.axon package com.cubetiqs.demo.axon
import com.cubetiqs.demo.axon.util.ExecUtils
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.http.ResponseEntity import org.springframework.http.MediaType
import org.springframework.util.FileCopyUtils
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.RestController import org.springframework.web.bind.annotation.RestController
import javax.servlet.http.HttpServletResponse
@SpringBootApplication @SpringBootApplication
class AxonApplication class AxonApplication
@@ -15,10 +17,13 @@ fun main(args: Array<String>) {
} }
@RestController @RestController
@RequestMapping class MyDumper {
class DefaultController { @GetMapping("/dump")
@GetMapping fun dumper(
fun index(): ResponseEntity<Any> { response: HttpServletResponse
return ResponseEntity.ok("ok") ) {
response.contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE
val data = ExecUtils.execMySqlDump()
FileCopyUtils.copy(data ?: ByteArray(0), response.outputStream)
} }
} }

View File

@@ -11,19 +11,21 @@ import org.axonframework.commandhandling.CommandHandler
import org.axonframework.eventsourcing.EventSourcingHandler import org.axonframework.eventsourcing.EventSourcingHandler
import org.axonframework.modelling.command.AggregateIdentifier import org.axonframework.modelling.command.AggregateIdentifier
import org.axonframework.modelling.command.AggregateLifecycle import org.axonframework.modelling.command.AggregateLifecycle
import org.axonframework.serialization.Revision
import org.axonframework.spring.stereotype.Aggregate import org.axonframework.spring.stereotype.Aggregate
import java.math.BigDecimal import java.math.BigDecimal
import java.util.UUID import java.util.UUID
@Aggregate @Aggregate
class BankAccountAggregate( @Revision("1.0")
final class BankAccountAggregate() {
@AggregateIdentifier @AggregateIdentifier
private var id: UUID? = null, private var id: UUID? = null
private var balance: BigDecimal? = null, private var balance: BigDecimal? = null
private var owner: String? = null private var owner: String? = null
) {
@CommandHandler @CommandHandler
constructor(command: CreateAccountCommand) { constructor(command: CreateAccountCommand) : this() {
AggregateLifecycle.apply( AggregateLifecycle.apply(
AccountCreatedEvent( AccountCreatedEvent(
command.accountId, command.accountId,

View File

@@ -40,7 +40,7 @@ class AccountCommandController @Autowired constructor(
fun debitMoneyFromAccount( fun debitMoneyFromAccount(
@PathVariable(value = "accountId") accountId: String, @PathVariable(value = "accountId") accountId: String,
@RequestBody moneyDebitDTO: MoneyAmountDTO @RequestBody moneyDebitDTO: MoneyAmountDTO
): CompletableFuture<String?>? { ): CompletableFuture<String?> {
return this.accountCommandService.debitMoneyFromAccount(accountId, moneyDebitDTO) return this.accountCommandService.debitMoneyFromAccount(accountId, moneyDebitDTO)
} }
} }

View File

@@ -10,6 +10,7 @@ import springfox.documentation.spi.DocumentationType
import springfox.documentation.spring.web.plugins.Docket import springfox.documentation.spring.web.plugins.Docket
import springfox.documentation.swagger2.annotations.EnableSwagger2 import springfox.documentation.swagger2.annotations.EnableSwagger2
import java.util.Collections import java.util.Collections
import java.util.concurrent.CompletableFuture
@Configuration @Configuration
@EnableSwagger2 @EnableSwagger2

View File

@@ -0,0 +1,17 @@
package com.cubetiqs.demo.axon.config
import org.springframework.context.annotation.Configuration
import org.springframework.web.servlet.config.annotation.EnableWebMvc
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
override fun addResourceHandlers(registry: ResourceHandlerRegistry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/")
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/")
}
}

View File

@@ -4,8 +4,6 @@ import java.io.Serializable
import java.math.BigDecimal import java.math.BigDecimal
import java.util.UUID import java.util.UUID
import javax.persistence.Entity import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.Id import javax.persistence.Id
import javax.persistence.Table import javax.persistence.Table
@@ -13,7 +11,6 @@ import javax.persistence.Table
@Table(name = "bank_accounts") @Table(name = "bank_accounts")
data class BankAccount( data class BankAccount(
@Id @Id
@GeneratedValue(strategy = GenerationType.AUTO)
var id: UUID? = null, var id: UUID? = null,
var owner: String? = null, var owner: String? = null,

View File

@@ -62,6 +62,6 @@ class BankAccountProjection @Autowired constructor(
@QueryHandler @QueryHandler
fun handle(query: FindBankAccountQuery): BankAccount? { fun handle(query: FindBankAccountQuery): BankAccount? {
log.debug("Handling FindBankAccountQuery query: {}", query) log.debug("Handling FindBankAccountQuery query: {}", query)
return this.bankAccountRepository.findById(query.accountId).orElse(null) return this.bankAccountRepository.findById(query.id).orElse(null)
} }
} }

View File

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

View File

@@ -44,6 +44,4 @@ class AccountCommandServiceImpl @Autowired constructor(
) )
) )
} }
} }

View File

@@ -0,0 +1,43 @@
package com.cubetiqs.demo.axon.util
import java.io.BufferedInputStream
import java.io.ByteArrayOutputStream
object ExecUtils {
private const val MYSQLDUMP_FILE = "mysqldump"
fun execMySqlDump(): ByteArray? {
var results: ByteArray?
try {
val command: MutableList<String> = mutableListOf()
command.add(MYSQLDUMP_FILE)
command.add("--databases")
command.add("orderwebapp")
command.add("--host")
command.add("192.168.0.204")
command.add("-usombochea")
command.add("-p@Csb632612")
val builder = ProcessBuilder(*command.toTypedArray())
.redirectErrorStream(false)
val process = builder.start()
BufferedInputStream(process.inputStream).use {
ByteArrayOutputStream().use { stdout ->
while (true) {
val x = it.read()
if (x == -1) {
break
}
stdout.write(x)
}
results = stdout.toByteArray()
process.waitFor()
}
}
} catch (e: Exception) {
println(e.message)
return null
}
return results
}
}

View File

@@ -2,11 +2,13 @@ server:
port: 8182 port: 8182
spring: spring:
application:
name: axon-demo
datasource: datasource:
driverClassName: org.postgresql.Driver driverClassName: org.postgresql.Driver
url: jdbc:postgresql://${POSTGRES_HOST:192.168.0.202}:${POSTGRES_PORT:5432}/${POSTGRES_DB:axon_demo} url: jdbc:postgresql://${POSTGRES_HOST:localhost}:${POSTGRES_PORT:5432}/${POSTGRES_DB:axon_demo}
username: ${POSTGRES_USERNAME:cubetiq} username: ${POSTGRES_USERNAME:root}
password: ${POSTGRES_PASSWORD:Root$} password: ${POSTGRES_PASSWORD:root}
hikari: hikari:
max-lifetime: 1800000 max-lifetime: 1800000
connection-timeout: 30000 connection-timeout: 30000
@@ -33,4 +35,9 @@ spring:
axon: axon:
serializer: serializer:
general: jackson general: jackson
axonserver:
servers: localhost
logging:
level.root: debug

View File

@@ -0,0 +1,10 @@
import com.cubetiqs.demo.axon.util.ExecUtils
import org.junit.jupiter.api.Test
class TestExecUtils {
@Test
fun dump() {
val dump = ExecUtils.execMySqlDump()
println("Dump size: ${dump?.size}")
}
}