[r2dbc][spring-webflux][kotlin]problème de communication entre code et base données
Salut tout le monde,
code: https://github.com/cheroliv/develope...a2687305b26dec
stacktrace: https://pastebin.com/hmnJed4m
telecharger le code: archive
command: Bonjour lorsque je n'arrive pas à insérer des élément dans ma base de données.
mon entité:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| package backend
import org.springframework.data.annotation.Id
import org.springframework.data.relational.core.mapping.Table
import java.util.*
import javax.validation.constraints.NotBlank
import javax.validation.constraints.Positive
/*=================================================================================*/
@Table("`routes`")
data class RouteEntity (
@Id var id: UUID? = null,
@field:NotBlank
var origin: String,
@field:NotBlank
var destination: String,
@field:Positive
var travel_time: Int,
)
val RouteEntity.toDomain: Route
get() = Route(
origin = origin,
destination = destination,
travel_time = travel_time
)
/*=================================================================================*/ |
mon repository:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
package backend
import kotlinx.coroutines.reactor.awaitSingle
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate
import org.springframework.stereotype.Repository
/*=================================================================================*/
interface RouteRepository {
suspend fun insertAll(routes: List<Route>)
}
/*=================================================================================*/
@Repository
class RouteRepositoryR2dbc(
private val dao: R2dbcEntityTemplate
) : RouteRepository {
override suspend fun insertAll(routes: List<Route>) {
routes.map {
dao.insert<RouteEntity>(
RouteEntity(
origin = it.origin,
destination = it.destination,
travel_time = it.travel_time
)
).awaitSingle()
}
}
}
/*=================================================================================*/ |
mon service:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| package backend
import backend.Constants.SPRING_PROFILE_CLI
import com.fasterxml.jackson.databind.ObjectMapper
import kotlinx.coroutines.runBlocking
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.CommandLineRunner
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware
import org.springframework.context.annotation.Profile
import org.springframework.core.io.Resource
import org.springframework.stereotype.Component
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import javax.annotation.PostConstruct
/*=================================================================================*/
@Service
@Transactional
class RoadMapService(
@Value("classpath:millennium-falcon.json")
private val configurationFile: Resource,
private val routeRepository: RouteRepository,
private val mapper: ObjectMapper,
private val context: ApplicationContext,
) {
private suspend fun loadOnBoardComputerConfig() {
//read json on classpath read ComputerConfig
val conf: ComputerConfig = mapper.readValue(
configurationFile.file, ComputerConfig::class.java
)
listOf(
Route(origin = "Tatooine", destination = "Dagobah", travel_time = 6),
Route(origin = "Dagobah", destination = "Endor", travel_time = 4),
Route(origin = "Dagobah", destination = "Hoth", travel_time = 1),
Route(origin = "Hoth", destination = "Endor", travel_time = 1),
Route(origin = "Tatooine", destination = "Hoth", travel_time = 6),
).run { routeRepository.insertAll(this) }
}
@PostConstruct
private fun init() = runBlocking { loadOnBoardComputerConfig() }
}
/*=================================================================================*/ |
ma config database:
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
|
package backend
import io.r2dbc.spi.ConnectionFactory
import org.springframework.beans.factory.annotation.Qualifier
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.convert.converter.Converter
import org.springframework.core.io.ClassPathResource
import org.springframework.data.convert.CustomConversions.StoreConversions.of
import org.springframework.data.convert.ReadingConverter
import org.springframework.data.convert.WritingConverter
import org.springframework.data.r2dbc.convert.R2dbcCustomConversions
import org.springframework.data.r2dbc.convert.R2dbcCustomConversions.STORE_CONVERTERS
import org.springframework.data.r2dbc.dialect.DialectResolver.getDialect
import org.springframework.data.r2dbc.repository.config.EnableR2dbcRepositories
import org.springframework.r2dbc.connection.R2dbcTransactionManager
import org.springframework.r2dbc.connection.init.ConnectionFactoryInitializer
import org.springframework.r2dbc.connection.init.ResourceDatabasePopulator
import org.springframework.transaction.ReactiveTransactionManager
import org.springframework.transaction.annotation.EnableTransactionManagement
import org.springframework.transaction.reactive.TransactionalOperator
import org.springframework.transaction.reactive.TransactionalOperator.create
import java.time.Instant
import java.time.LocalDateTime
import java.time.LocalDateTime.ofInstant
import java.time.ZoneOffset.UTC
/*=================================================================================*/
@Configuration
@EnableTransactionManagement
@EnableR2dbcRepositories("backend")
class DatabaseConfiguration(
private val properties: ApplicationProperties
) {
@Bean
fun inMemoryConnectionFactory(
@Qualifier("connectionFactory")
connectionFactory: ConnectionFactory
): ConnectionFactoryInitializer =
ConnectionFactoryInitializer().apply {
setConnectionFactory(connectionFactory)
setDatabasePopulator(
ResourceDatabasePopulator(
ClassPathResource(properties.database.populatorPath)
)
)
}
@Bean
fun reactiveTransactionManager(
connectionFactory: ConnectionFactory
): ReactiveTransactionManager = R2dbcTransactionManager(connectionFactory)
@Bean
fun transactionalOperator(
reactiveTransactionManager: ReactiveTransactionManager
): TransactionalOperator = create(reactiveTransactionManager)
@WritingConverter
class InstantWriteConverter : Converter<Instant, LocalDateTime> {
override fun convert(source: Instant): LocalDateTime? = ofInstant(source, UTC)!!
}
@ReadingConverter
class InstantReadConverter : Converter<LocalDateTime, Instant> {
override fun convert(localDateTime: LocalDateTime): Instant = localDateTime.toInstant(UTC)!!
}
@Bean
fun r2dbcCustomConversions(
@Qualifier("connectionFactory")
connectionFactory: ConnectionFactory
): R2dbcCustomConversions {
getDialect(connectionFactory).apply {
return@r2dbcCustomConversions R2dbcCustomConversions(
of(
simpleTypeHolder,
converters.toMutableList().apply {
add(InstantWriteConverter())
add(InstantReadConverter())
addAll(STORE_CONVERTERS)
}
), mutableListOf<Any>()
)
}
}
}
/*=================================================================================*/ |
Merci pour vos suggestions et n’hésiter pas a cloner le code pour tester.