springboot 不响应字段为空_Postgres、R2DBC、Spring Data JDBC和Spring WebFlux的响应式API简介...

想要了解更多关于响应式API的信息?看看这篇文章,我们将探索使用R2DBC,Spring Data JDBC等构建响应式Web应用程序。

c2655ac34716f5b6ab7f785e14ae5847.png

我知道 - 标题中已列出很多技术。 Spring WebFlux,作为构建响应堆栈Web应用程序的项目,已经被Spring 5和Spring Boot 2中引入。我曾在这篇文章中-Spring WebFlux和Spring Cloud的响应式微服务描述了它如何与Spring Boot和Spring Cloud来构建响应式微服务。 Spring 5还引入了支持对NoSQL数据库进行响应性访问的项目,如Cassandra,MongoDB或Couchbase。但是,仍然缺乏对访问关系型数据库的响应性的支持。这一变化将随着R2DBC(响应关系数据库连接)项目一起发生变化。该项目也由Pivotal成员开发。这似乎是一个非常有趣的行为,然而,它正处于起步阶段。无论如何,有一个与Postgres集成的模块,我们将用它来演示应用程序。

R2DBC不是本文中描述的唯一一个新的有趣解决方案。我还将向您展示如何使用Spring Data JDBC - 这是最近发布的另一个非常有趣的项目。值得一提的是Spring Data JDBC的功能。该项目已经发布,可在1.0版本下使用。它是更大的Spring Data框架的一部分。它提供了基于JDBC的存储库抽象。创建该库的主要原因是允许使用Spring Data(通过CrudRepository接口)访问关系数据库,而不将JPA库包含到应用程序依赖项中。当然,JPA仍然是用于Java应用程序的主要持久性API。 Spring Data JDBC旨在通过不实现延迟加载,缓存,脏上下文和会话等流行模式,在概念上比JPA更简单。它还为基于注释的映射提供非常有限的支持。最后,它提供了使用R2DBC访问关系数据库的反应式存储库的实现。虽然该模块仍在开发中(只有SNAPSHOT版本可用),但我们将在演示应用程序中尝试使用它。让我们继续做下去。

依赖包

我们使用Kotlin来实现。首先,我们包含一些必需的Kotlin依赖项。

org.jetbrains.kotlin

kotlin-stdlib

${kotlin.version}

com.fasterxml.jackson.module

jackson-module-kotlin

org.jetbrains.kotlin

kotlin-reflect

org.jetbrains.kotlin

kotlin-test-junit

${kotlin.version}

test

我们还应该添加kotlin-maven-plugin来支持Spring。

org.jetbrains.kotlin

kotlin-maven-plugin

${kotlin.version}

compile

compile

compile

test-compile

test-compile

test-compile

-Xjsr305=strict

spring

然后,我们继续包含演示实现所需的框架。我们需要包含专用于使用R2DBC访问数据库的Spring Data JDBC的特殊SNAPSHOT版本。我们还必须添加R2DBC库和Spring WebFlux。正如您在下面看到的,只有Spring WebFlux是稳定版本(作为Spring Boot RELEASE的一部分)。

org.springframework.boot

spring-boot-starter-webflux

org.springframework.data

spring-data-jdbc

1.0.0.r2dbc-SNAPSHOT

io.r2dbc

r2dbc-spi

1.0.0.M5

io.r2dbc

r2dbc-postgresql

1.0.0.M5

另一个重要的事是为Spring Data项目设置依赖关系管理。

org.springframework.data

spring-data-releasetrain

Lovelace-RELEASE

import

pom

Repositories(仓库)

我们使用著名的Spring Data风格的CRUD存储库实现。在这种情况下,我们需要创建一个扩展ReactiveCrudRepository接口的接口。

这是用于管理Employee对象的存储库的实现。

interface EmployeeRepository : ReactiveCrudRepository<Employee, Int< {

@Query("select id, name, salary, organization_id from employee e where e.organization_id = $1")

fun findByOrganizationId(organizationId: Int) : Flux<Employee>

}

这里是存储库的另一个实现——这次,我们使用它来管理Organization对象。

interface OrganizationRepository : ReactiveCrudRepository<Organization, Int< { }

Entities和DTOs实现

Kotlin提供了一种通过将实体类声明为数据类从而创建实体类的便捷方法。使用Spring Data JDBC时,我们必须通过使用@Id注释字段来为实体设置主键。它假定主键由数据库设置自动递增。如果未使用自动增量列,则必须使用BeforeSaveEvent侦听器,该侦听器设置实体的ID。但是,我尝试为实体设置这样的监听器,但它只是在Spring Data JDBC的响应式版本中不起作用。

这是Employee实体类的实现。值得一提的是,Spring Data JDBC会自动将类字段organizationId映射到数据库列organization_id。

data class Employee(

val name: String,

val salary: Int,

val organizationId: Int)

{ @Id var id: Int? = null }

这是Organization实体类的实现。

data class Organization(var name: String) {

@Id

var id: Int? = null

}

R2DBC不支持任何列表或集合。因为我想在其中一个API端点中返回Organization对象内的员工列表,所以我创建了一个包含这样一个列表的DTO,如下所示。

data class OrganizationDTO(var id: Int?, var name: String) {

var employees : MutableList = ArrayList()

constructor(employees: MutableList) : this(null, "") {

this.employees = employees

}

}

与创建的实体对应的SQL脚本如下所示。字段类型serial将自动创建序列并将其附加到字段ID。

CREATE TABLE employee (

name character varying NOT NULL,

salary integer NOT NULL,

id serial PRIMARY KEY,

organization_id integer

);

CREATE TABLE organization (

name character varying NOT NULL,

id serial PRIMARY KEY

);

构建示例Web应用程序

出于演示目的,我们将构建两个独立的应用程序:employee-service (员工服务)和 organization-service(组织服务)。应用程序组织服务使用WebFlux WebClient与员工服务进行通信。它获取分配给组织的员工列表,并包含它们以与组织对象一起响应。示例应用程序源代码可在GitHub上的存储库sample-spring-data-webflux下获得。

准备就绪,让我们从声明Spring Boot主类开始吧。我们需要通过使用@EnableJdbcRepositories注释主类来启用Spring Data JDBC存储库。

@SpringBootApplication

@EnableJdbcRepositories

class EmployeeApplication

fun main(args: Array<String>) {

runApplication<EmployeeApplication>(*args)

}

使用R2DBC和Postgres需要一些配置。由于早期Spring Data JDBC和R2DBC开发阶段,Postgres没有Spring Boot自动配置。我们需要在bean中用@Configuration声明连接工厂,客户端和存储库。

@Configuration

class EmployeeConfiguration {

@Bean

fun repository(factory: R2dbcRepositoryFactory): EmployeeRepository {

return factory.getRepository(EmployeeRepository::class.java)

}

@Bean

fun factory(client: DatabaseClient): R2dbcRepositoryFactory {

val context = RelationalMappingContext()

context.afterPropertiesSet()

return R2dbcRepositoryFactory(client, context)

}

@Bean

fun databaseClient(factory: ConnectionFactory): DatabaseClient {

return DatabaseClient.builder().connectionFactory(factory).build()

}

@Bean

fun connectionFactory(): PostgresqlConnectionFactory {

val config = PostgresqlConnectionConfiguration.builder() //

.host("192.168.99.100") //

.port(5432) //

.database("reactive") //

.username("reactive") //

.password("reactive123") //

.build()

return PostgresqlConnectionFactory(config)

}

}

最后,我们可以创建包含定义的响应API方法的REST控制器。使用Kotlin,它不会占用太多空间。以下控制器定义包含三种GET方法,这些方法允许我们查找所有员工,查找分配给给定组织的所有员工或根据id查找单个员工。

@RestController

@RequestMapping("/employees")

class EmployeeController {

@Autowired

lateinit var repository : EmployeeRepository

@GetMapping

fun findAll() : Flux<Employee> = repository.findAll()

@GetMapping("/{id}")

fun findById(@PathVariable id : Int) : Mono<Employee> = repository.findById(id)

@GetMapping("/organization/{organizationId}")

fun findByorganizationId(@PathVariable organizationId : Int) : Flux<Employee> = repository.findByOrganizationId(organizationId)

@PostMapping

fun add(@RequestBody employee: Employee) : Mono<Employee> = repository.save(employee)

}

内部服务交互

对于OrganizationController,实现有点复杂。由于组织服务正在与员工服务进行通信,因此我们首先需要声明响应式WebFlux WebClientbuilder。

@Bean

fun clientBuilder() : WebClient.Builder {

return WebClient.builder()

}

然后,类似于存储库bean,构建器被注入控制器。它在findByIdWithEmployees方法中用于调用employee-service公开的方法GET / employees / organization / {organizationId}。正如您在下面的代码片段中看到的,它提供了一个响应式API并返回包含已找到员工列表的Flux对象。使用zipWith Reactor方法将此列表注入到OrganizationDTO对象中。

@RequestMapping("/organizations")

class OrganizationController {

@Autowired

lateinit var repository : OrganizationRepository

@Autowired

lateinit var clientBuilder : WebClient.Builder

@GetMapping

fun findAll() : Flux<Organization> = repository.findAll()

@GetMapping("/{id}")

fun findById(@PathVariable id : Int) : Mono<Organization> = repository.findById(id)

@GetMapping("/{id}/withEmployees")

fun findByIdWithEmployees(@PathVariable id : Int) : Mono<OrganizationDTO> {

val employees : Flux<Employee> = clientBuilder.build().get().uri("http://localhost:8090/employees/organization/$id")

.retrieve().bodyToFlux(Employee::class.java)

val org : Mono = repository.findById(id)

return org.zipWith(employees.collectList())

.map { tuple -> OrganizationDTO(tuple.t1.id as Int, tuple.t1.name, tuple.t2) }

}

@PostMapping

fun add(@RequestBody employee: Organization) : Mono<Organization> = repository.save(employee)

}

它是如何工作的?

在测试运行之前,我们需要启动Postgres数据库。这是用于运行Postgres容器的Docker命令。它正在创建具有密码的用户,并设置默认数据库。

$ docker run -d --name postgres -p 5432:5432 -e POSTGRES_USER=reactive -e POSTGRES_PASSWORD=reactive123 -e POSTGRES_DB=reactive postgres

然后,我们需要创建一些测试表,因此您必须运行放置在实现实体和DTO部分中的SQL脚本。之后,您可以启动我们的测试应用程序。如果不覆盖application.yml文件中提供的默认设置,则employee-service端口8090上监听和organization-service在端口8095上监听。下图说明了我们的示例系统的体系结构。

febb9b254e6d6022e02c044a7e122af3.png

现在,让我们使用应用程序公开的响应API添加一些测试数据。

$ curl -d '{"name":"Test1"}' -H "Content-Type: application/json" -X POST http://localhost:8095/organizations

$ curl -d '{"name":"Name1", "balance":5000, "organizationId":1}' -H "Content-Type: application/json" -X POST http://localhost:8090/employees

$ curl -d '{"name":"Name2", "balance":10000, "organizationId":1}' -H "Content-Type: application/json" -X POST http://localhost:8090/employees

最后,您可以使用Web浏览器调用GET方法: / {id} / withEmployees。结果应类似于下图。

a9093c5cf83779e40054b061a1701df9.png

原文链接:https://dzone.com/articles/introduction-to-reactive-apis-with-postgres-r2dbc

作者:Piotr Mińkowski

译者:Emma

推荐: Spring Cloud Alibaba基础教程:使用Nacos实现服务注册与发现

上一篇:新时代的开发姿势

 关注公众号

a7741d2a5e5cb6c4f02e2cc6de8135e5.png

点击原文阅读更多

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值