Spring 实战(第五版)
  • Spring 实战(第 5 版)
  • 第一部分 Spring 基础
  • 第 1 章 Spring 入门
    • 1.1 什么是 Spring?
    • 1.2 初始化 Spring 应用程序
      • 1.2.1 使用 Spring Tool Suite 初始化 Spring 项目
      • 1.2.2 检查 Spring 项目结构
    • 1.3 编写 Spring 应用程序
      • 1.3.1 处理 web 请求
      • 1.3.2 定义视图
      • 1.3.3 测试控制器
      • 1.3.4 构建并运行应用程序
      • 1.3.5 了解 Spring Boot DevTools
      • 1.3.6 回顾
    • 1.4 俯瞰 Spring 风景线
      • 1.4.1 Spring 核心框架
      • 1.4.2 Spring Boot
      • 1.4.3 Spring Data
      • 1.4.4 Spring Security
      • 1.4.5 Spring Integration 和 Spring Batch
      • 1.4.6 Spring Cloud
    • 1.5 小结
  • 第 2 章 开发 Web 应用程序
    • 2.1 展示信息
      • 2.1.1 建立域
      • 2.1.2 创建控制器类
      • 2.1.3 设计视图
    • 2.2 处理表单提交
    • 2.3 验证表单输入
      • 2.3.1 声明验证规则
      • 2.3.2 在表单绑定时执行验证
      • 2.3.3 显示验证错误
    • 2.4 使用视图控制器
    • 2.5 选择视图模板库
      • 2.5.1 缓存模板
    • 2.6 小结
  • 第 3 章 处理数据
    • 3.1 使用 JDBC 读写数据
      • 3.1.1 为域适配持久化
      • 3.1.2 使用 JdbcTemplate
      • 3.1.3 定义模式并预加载数据
      • 3.1.4 插入数据
    • 3.2 使用 Spring Data JPA 持久化数据
      • 3.2.1 添加 Spring Data JPA 到数据库中
      • 3.2.2 注解域作为实体
      • 3.2.3 声明 JPA repository
      • 3.2.4 自定义 JPA repository
    • 3.3 小结
  • 第 4 章 Spring 安全
    • 4.1 启用 Spring Security
    • 4.2 配置 Spring Security
      • 4.2.1 内存用户存储
      • 4.2.2 基于 JDBC 的用户存储
      • 4.2.3 LDAP 支持的用户存储
      • 4.2.4 自定义用户身份验证
    • 4.3 保护 web 请求
      • 4.3.1 保护请求
      • 4.3.2 创建用户登录页面
      • 4.3.3 登出
      • 4.3.4 阻止跨站请求伪造攻击
    • 4.4 了解你的用户
    • 4.5 小结
  • 第 5 章 使用配置属性
    • 5.1 微调自动配置
      • 5.1.1 理解 Spring 环境抽象
      • 5.1.2 配置数据源
      • 5.1.3 配置嵌入式服务器
      • 5.1.4 配置日志
      • 5.1.5 使用特殊的属性值
    • 5.2 创建自己的配置属性
      • 5.2.1 定义配置属性持有者
      • 5.2.2 声明配置属性元数据
    • 5.3 使用 profile 文件进行配置
      • 5.3.1 定义特定 profile 的属性
      • 5.3.2 激活 profile 文件
      • 5.3.3 有条件地使用 profile 文件创建 bean
    • 5.4 小结
  • 第二部分 集成 Spring
  • 第 6 章 创建 REST 服务
    • 6.1 编写 RESTful 控制器
      • 6.1.1 从服务器获取数据
      • 6.1.2 向服务器发送数据
      • 6.1.3 更新服务器上的资源
      • 6.1.4 从服务器删除数据
    • 6.2 启用超媒体
      • 6.2.1 添加超链接
      • 6.2.2 创建资源装配器
      • 6.2.3 嵌套命名关系
    • 6.3 启用以数据为中心的服务
      • 6.3.1 调整资源路径和关系名称
      • 6.3.2 分页和排序
      • 6.3.3 添加用户端点
      • 6.3.4 向 Spring Data 端点添加用户超链接
    • 6.4 小结
  • 第 7 章 调用 REST 服务
    • 7.1 使用 RestTemplate 调用 REST 端点
      • 7.1.1 请求 GET 资源
      • 7.1.2 请求 PUT 资源
      • 7.1.3 请求 DELETE 资源
      • 7.1.4 请求 POST 资源
    • 7.2 使用 Traverson 引导 REST API
    • 7.3 小结
  • 第 8 章 发送异步消息
    • 8.1 使用 JMS 发送消息
      • 8.1.3 接收 JMS 消息
      • 8.1.2 使用 JmsTemplate 发送消息
      • 8.1.1 设置 JMS
    • 8.2 使用 RabbitMQ 和 AMQP
      • 8.2.1 添加 RabbitMQ 到 Spring 中
      • 8.2.2 使用 RabbitTemplate 发送消息
      • 8.2.3 从 RabbitMQ 接收消息
    • 8.3 使用 Kafka 发送消息
      • 8.3.1 在 Spring 中设置 Kafka
      • 8.3.2 使用 KafkaTemplate 发送消息
      • 8.3.3 编写 Kafka 监听器
    • 8.4 小结
  • 第 9 章 集成 Spring
    • 9.1 声明简单的集成流
      • 9.1.1 使用 XML 定义集成流
      • 9.1.2 在 Java 中配置集成流
      • 9.1.3 使用 Spring Integration 的 DSL 配置
    • 9.2 探索 Spring Integration
      • 9.2.1 消息通道
      • 9.2.2 过滤器
      • 9.2.3 转换器
      • 9.2.4 路由
      • 9.2.5 分割器
      • 9.2.6 服务激活器
      • 9.2.7 网关
      • 9.2.8 通道适配器
      • 9.2.9 端点模块
    • 9.3 创建 Email 集成流
    • 9.4 总结
  • 第三部分 响应式 Spring
  • 第 10 章 Reactor 介绍
    • 10.1 理解响应式编程
      • 10.1.1 定义响应式流
    • 10.2 Reactor
      • 10.2.1 图解响应式流
      • 10.2.2 添加 Reactor 依赖
    • 10.3 通用响应式操作实战
      • 10.3.1 创建响应式类型
      • 10.3.2 响应式类型结合
      • 10.3.3 转换和过滤响应式流
      • 10.3.4 对反应类型执行逻辑操作
    • 10.4 总结
  • 第 11 章 开发响应式 API
    • 11.1 使用 Spring WebFlux
      • 11.1.1 Spring WebFlux 介绍
      • 11.1.2 编写响应式 Controller
    • 11.2 定义函数式请求处理程序
    • 11.3 测试响应式 Controller
      • 11.3.1 测试 GET 请求
      • 11.3.2 测试 POST 请求
      • 11.3.3 使用线上服务器进行测试
    • 11.4 响应式消费 REST API
      • 11.4.1 通过 GET 方式获取资源
      • 11.4.2 通过 POST 方式发送资源
      • 11.4.3 删除资源
      • 11.4.4 处理请求错误
      • 11.4.5 请求转换
    • 11.5 保护响应式 web API
      • 11.5.1 配置响应式 Web 安全
      • 11.5.2 配置响应式用户信息服务
    • 11.6 总结
  • 第 12 章 响应式持久化数据
    • 12.1 理解 Spring Data 响应式历程
      • 12.1.1 Spring Data 响应式精髓
      • 12.1.2 在响应式与非响应式之间进行转换
      • 12.1.3 开发响应式库
    • 12.2 使用响应式 Cassandra 库
      • 12.2.1 开启 Spring Data Cassandra
      • 12.2.2 理解 Cassandra 数据模型
      • 12.2.3 Cassandra 持久化实体映射
      • 12.2.4 编写响应式 Cassandra 库
    • 12.3 编写响应式 MongoDB 库
      • 12.3.1 开启Spring Data MongonDB
      • 12.3.2 MongoDB 持久化实体映射
      • 12.3.3 编写响应式 MongoDB 库
    • 12.4 总结
  • 第四部分 云原生 Spring
  • 第 13 章 服务发现
    • 13.1深入思考微服务
    • 13.2 配置服务注册
      • 13.2.1 配置 Eureka
      • 13.2.2 扩展 Eureka
    • 13.3 注册并发现服务
      • 13.3.1 配置 Eureka 客户端属性
      • 13.3.2 消费服务
    • 13.4 总结
  • 第 14 章 配置管理
    • 14.1 共享配置
    • 14.2 运行配置服务器
      • 14.2.1 启动配置服务器
      • 14.2.2 填写配置库
    • 14.3 消费共享的配置
    • 14.4 服务应用程序和特定配置文件的属性
      • 14.4.1 服务特定应用程序的属性
      • 14.4.2 服务配置文件属性
    • 14.5 为配置的属性加密
      • 14.5.1 在 Git 中加密属性
      • 14.5.2 在 Vault 中存储密码
    • 14.6 远程刷新配置属性
      • 14.6.1 手动刷新配置属性
      • 14.6.2 自动刷新配置属性
    • 14.7 总结
  • 第 15 章 处理失败和时延
    • 15.1 了解断路器
    • 15.2 定义断路器
      • 15.2.1 缓解时延
      • 15.2.2 管理断路器阈值
    • 15.3 管理失败事件
      • 15.3.1 介绍 Hystrix 面板
      • 15.3.2 了解 Hystrix 线程池
    • 15.4 聚合多个 Hystrix 流
    • 15.5 总结
  • 第五部分 部署Spring
  • 第 16 章 使用 SpringBoot Actuator
    • 16.1 介绍 Actuator
      • 16.1.1 配置 Actuator 基本路径
      • 16.1.2 启用和禁用 Actuator 端点
    • 16.2 使用 Actuator 端点
      • 16.2.1 获取重要的应用程序信息
      • 16.2.2 查看配置详细信息
      • 16.2.3 查看应用程序活动
      • 16.2.4 利用运行时指标
    • 16.3 自定义 Actuator
      • 16.3.1 向 /info 端点提供信息
      • 16.3.2 自定义健康指标
      • 16.3.3 注册自定义指标
      • 16.3.4 创建自定义端点
    • 16.4 保护 Actuator
    • 16.5 总结
  • 第 17 章 管理 Spring
    • 17.1 使用 SpringBoot Admin
      • 17.1.1 创建 Admin 服务端
      • 17.1.2 注册 Admin 客户端
    • 17.2 深入 Admin 服务端
      • 17.2.1 查看普通应用程序运行状况和信息
      • 17.2.2 观察关键指标
      • 17.2.3 检查环境属性
      • 17.2.4 查看并设置 log 级别
      • 17.2.5 监控线程
      • 17.2.6 追踪 HTTP 请求
    • 17.3 保护 Admin 服务端
      • 17.3.1 在 Admin 服务端中启用登录
      • 17.3.2 使用 Actuator 进行认证
    • 17.4 总结
  • 第 18 章 使用 JMX 监控 Spring
    • 18.1 使用 Actuator MBean
    • 18.2 创建自己的 MBean
    • 18.3 发送通知
    • 18.4 总结
  • 第 19 章 部署 Spring
    • 19.1 权衡部署选项
    • 19.2 构建并部署 WAR 文件
    • 19.3 将 JAR 文件推送到 Cloud Foundry
    • 19.4 在 Docker 容器中运行 SpringBoot
    • 19.5 终章
    • 19.6 总结
由 GitBook 提供支持
在本页

这有帮助吗?

  1. 第 12 章 响应式持久化数据
  2. 12.3 编写响应式 MongoDB 库

12.3.3 编写响应式 MongoDB 库

Spring Data MongoDB 提供了与 Spring Data JPA 和 Spring Data Cassandra 类似的,自动化的 Repository 支持。当涉及到为 MongoDB 编写响应式 Repository 时,您可以选择扩展 ReactiveCrudRepository 或 ReactiveMongoRepository。关键的区别在于,ReactiveMongoRepository 提供了为持久化新文档,优化过的 insert() 方法。而ReactiveCrudRepository 依赖 save() 方法来处理新的和已有文档。

非响应式 MongoDB Repository 怎么写呢?

本章的重点是使用 Spring Data 编写响应式 Repository。但如果出于某种原因,您希望使用非响应式的,可以通过扩展 CrudRepository 或 MongoRepository 接口,而不是扩展 ReactiveCrudRepository 或 ReactiveMongoRepository 来实现。然后,您可以让 Repository 的方法返回添加了 Mongo 注解的实体类型,以及这些类型的集合。

但并不是严格要求你必须这样做,你也可以通过改变依赖来实现。把 springboot-starter-data-mongodb-reactive 依赖改为 spring-boot-starterdata-mongodb。

您将首先定义一个 Repository,用于将 Ingredient 对象持久化为文档。这里您不需要频繁地创建 ingredient 文档,或者在数据库初化以后,根本不需要新创建 Ingredient。因此,ReactiveMongoRepository 提供的优化不会那么有用。您可以编写 IngredientRepository 来扩展 ReactiveCrudRepository:

package tacos.data;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import org.springframework.web.bind.annotation.CrossOrigin;
import tacos.Ingredient;

@CrossOrigin(origins="*")
public interface IngredientRepository
            extends ReactiveCrudRepository<Ingredient, String> {
}

等一下!它看起来与您在第 12.2.4 节,为 Cassandra 所写的 IngredientRepository 接口完全相同。实际上,确实是相同的接口,没有任何变化。这也突显了扩展 ReactiveCrudRepository 的好处,在不同的数据库类型中更具可移植性。为 Cassandra 所写的接口,对于 MongoDB 也同样适用。

因为它是一个响应式的 Repository,所以它的方法处理的是 Flux 和 Mono,而不是原始实体类型和实体类型的集合。举例来说,findAll() 方法 返回 Flux<Ingredient> 而不是 Iterable<Ingredient>。同样地,findById() 将返回 Mono<Ingredient> 而不是 Optional<Ingredient>。这个变化影响的是端到端响应流的一部分。

现在,让我们尝试定义一个用于将 Taco 对象持久化为 MongoDB 文档的 Repository,。与 ingredient 文档不同,您将频繁的创建 taco 文档。因此,优化的 insert() 方法就很有价值。这是您的新适配了 MongoDB 的 TacoRepository:

package tacos.data;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import reactor.core.publisher.Flux;
import tacos.Taco;

public interface TacoRepository
            extends ReactiveMongoRepository<Taco, String> {

    Flux<Taco> findByOrderByCreatedAtDesc();

}

使用 ReactiveMongoRepository 而不是 ReactiveCrudRepository 的唯一缺点,就是它是专用于 MongoDB 的,不能改变数据库类型。在您的项目中,你需要权衡是否值得这样做。如果并不期望在某个时候切换到另一种数据库,这样做就完全没问题。可以大胆选择 ReactiveMongoRepository 并从插入数据优化中获益。

注意,您在 TacoRepository 中引入了一个新方法。这种方法支持展示最近创建的 Taco 列表。在 JPA 版本中,您通过扩展 PagingAndSortingRepository 实现了这一点。但是在响应式 Repository 中, PagingAndSortingRepository 现在没有多大用处(尤其是分页部分)。在 Cassandra 版本中,排序由表定义中的集群键来确定,因此没有办法支持获取最近的 Taco。

但是对于 MongoDB,您希望能够获取最近创建的 tacos。尽管名称很奇怪,findByOrderByCreatedAtDesc() 方法还是遵循了,自定义查询方法命名约定。它指出您获取最近的 tacos,并且不需要指定任何参数。然后告诉它按 createdAt 属性降序排列结果。

之所以findBy 后面用空的 By 子句,是为了避免对方法名的错误解析。因为方法名中 OrderBy 里有字符 By。如果起名为 findAllOrderByCreatedAtDesc(),则名称的 AllOrder 部分将会 忽略,Spring Data 将尝试通过匹配 createdAtDesc 来查找。因为并不存在这样的属性,应用程序将无法启动,会报出一个错误来。

因为 findByOrderByCreatedAtDesc() 返回一个 Flux<Taco>,,所以您不必担心分页。相反,您只需将 take() 操作应用于 Flux 返回的数据上,选择最开始的那一部分。例如,您的 Controller 中可以这样调用 findByOrderByCreatedAtDesc() 方法,以显示最近创建的 tacos:

Flux<Taco> recents = repo.findByOrderByCreatedAtDesc()
                         .take(12);

这样返回的 Flux 将永远只有,且最多 12 个 Taco。

来看一下 OrderRepository 接口,您可以看到它非常简单:

package tacos.data;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import reactor.core.publisher.Flux;
import tacos.Order;

public interface OrderRepository
          extends ReactiveMongoRepository<Order, String> {
}

您将会经常创建 Order 文档,因此 OrderRepository 扩展了 ReactiveMongoRepository 以获得 insert() 方法所提供的优化。除此之外,就与其他 Repository 相比就没有什么特别之处了。

最后,让我们看看将 User 对象持久化为文档的 Repository:

package tacos.data;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
import reactor.core.publisher.Mono;
import tacos.User;

public interface UserRepository
            extends ReactiveMongoRepository<User, String> {

    Mono<User> findByUsername(String username);
}

到目前为止,这个 Repository 接口应该不会有什么特别令人惊讶的。与其他的一样,它扩展了 ReactiveMongoRepository 接口(尽管它也可以扩展 ReactiveCrudRepository)。唯一的不同就是里边的 findByUsername() 方法,这是您在第 4 章中,为支持身份验证而添加的。这里,它被调整为返回 Mono<User> 而不是原始 User 对象。

上一页12.3.2 MongoDB 持久化实体映射下一页12.4 总结

最后更新于4年前

这有帮助吗?