Spring 实战(第四版)
  • Spring 实战(第 4 版)
  • 第一部分 Spring 的核心
  • 第 1 章 Spring 之旅
    • 1.1 简化 Java 开发
      • 1.1.1 激发 POJO 的潜能
      • 1.1.2 依赖注入
      • 1.1.3 应用切面
      • 1.1.4 使用模板消除样式代码
    • 1.2 容纳你的 Bean
      • 1.2.1 使用应用上下文
      • 1.2.2 bean 的生命周期
    • 1.3 俯瞰 Spring 风景线
      • 1.3.1 Spring 模块
      • 1.3.2 Spring Portfolio
    • 1.4 Spring 的新功能
      • 1.4.1 Spring 3.1 新特性
      • 1.4.2 Spring 3.2 新特性
      • 1.4.3 Spring 4.0 新特性
    • 1.5 小结
  • 第 2 章 装配 Bean
    • 2.1 Spring 配置的可选方案
    • 2.2 自动化装配 bean
      • 2.2.1 创建可被发现的 bean
      • 2.2.2 为组件扫描的 bean 命名
      • 2.2.3 设置组件扫描的基础包
      • 2.2.4 通过为 bean 添加注解实现自动装配
      • 2.2.5 验证自动装配
    • 2.3 通过 Java 代码装配 bean
      • 2.3.1 创建配置类
      • 2.3.2 声明简单的 bean
      • 2.3.3 借助 JavaConfig 实现注入
    • 2.4 通过 XML 装配 bean
      • 2.4.1 创建 XML 配置规范
      • 2.4.2 声明一个简单的 <bean>
      • 2.4.3 借助构造器注入初始化 bean
      • 2.4.4 设置属性
    • 2.5 导入和混合配置
      • 2.5.1 在 JavaConfig 中引用 XML 配置
      • 2.5.2 在 XML 配置中引用 JavaConfig
    • 2.6 小结
  • 第 3 章 高级装配
    • 3.1 环境与 profile
      • 3.1.1 配置 profile bean
      • 3.1.2 激活 profile
    • 3.2 条件化的 bean
    • 3.3 处理自动装配的歧义性
      • 3.3.1 标示首选的 bean
      • 3.3.2 限定自动装配的 bean
    • 3.4 bean 的作用域
      • 3.4.1 使用会话和请求作用域
      • 3.4.2 在 XML 中声明作用域代理
    • 3.5 运行时值注入
      • 3.5.1 注入外部的值
      • 3.5.2 使用 Spring 表达式语言进行装配
    • 3.6 小结
  • 第 4 章 面向切面的 Spring
    • 4.1 什么是面向切面编程
      • 4.1.1 定义 AOP 术语
      • 4.1.2 Spring 对 AOP 的支持
    • 4.2 通过切点来选择连接点
      • 4.2.1 编写切点
      • 4.2.2 在切点中选择 bean
    • 4.3 使用注解创建切面
      • 4.3.1 定义切面
      • 4.3.2 创建环绕通知
      • 4.3.3 处理通知中的参数
      • 4.3.4 通过注解引入新功能
    • 4.4 在 XML 中声明切面
      • 4.4.1 声明前置和后置通知
      • 4.4.2 声明环绕通知
      • 4.4.3 为通知传递参数
      • 4.4.4 通过切面引入新的功能
    • 4.5 注入 AspectJ 切面
    • 4.6 小结
  • 第二部分 Web 中的 Spring
  • 第 5 章 构建 Spring Web 应用程序
    • 5.1 Spring MVC 起步
      • 5.1.1 跟踪 Spring MVC 的请求
      • 5.1.2 搭建 Spring MVC
      • 5.1.3 Spittr 应用简介
    • 5.2 编写基本的控制器
      • 5.2.1 测试控制器
      • 5.2.2 定义类级别的请求处理
      • 5.2.3 传递模型数据到视图中
    • 5.3 接受请求的输入
      • 5.3.1 处理查询参数
      • 5.3.2 通过路径参数接受输入
    • 5.4 处理表单
      • 5.4.1 编写处理表单的控制器
      • 5.4.2 校验表单
    • 5.5 小结
  • 第 6 章 渲染 Web 视图
    • 6.1 理解视图解析
    • 6.2 创建 JSP 视图
      • 6.2.1 配置适用于 JSP 的视图解析器
      • 6.2.2 使用 Spring 的 JSP 库
    • 6.3 使用 Apache Tiles 视图定义布局
      • 6.3.1 配置 Tiles 视图解析器
    • 6.4 使用 Thymeleaf
      • 6.4.1 配置 Thymeleaf 视图解析器
      • 6.4.2 定义 Thymeleaf 模板
    • 6.5 小结
  • 第 7 章 Spring MVC 的高级技术
    • 7.1 Spring MVC 配置的替代方案
      • 7.1.1 自定义 DispatcherServlet 配置
      • 7.1.2 添加其他的 Servlet 和 Filter
      • 7.1.3 在 web.xml 中声明 DispatcherServlet
    • 7.2 处理 multipart 形式的数据
      • 7.2.1 配置 multipart 解析器
      • 7.2.2 处理 multipart 请求
    • 7.3 处理异常
      • 7.3.1 将异常映射为 HTTP 状态码
      • 7.3.2 编写异常处理的方法
    • 7.4 为控制器添加通知
    • 7.5 跨重定向请求传递数据
      • 7.5.1 通过 URL 模板进行重定向
      • 7.5.2 使用 flash 属性
    • 7.6 小结
  • 第 8 章 使用 Spring Web Flow
    • 8.1 在 Spring 中配置 Web Flow
      • 8.1.1 装配流程执行器
      • 8.1.2 配置流程注册表
      • 8.1.3 处理流程请求
    • 8.2 流程的组件
      • 8.2.1 状态
      • 8.2.2 转移
      • 8.2.3 流程数据
    • 8.3 组合起来:披萨流程
      • 8.3.1 定义基本流程
      • 8.3.2 收集顾客信息
      • 8.3.3 构建订单
      • 8.3.4 支付
    • 8.4 保护 Web 流程
    • 8.5 小结
  • 第 9 章 保护 Web 应用
    • 9.1 Spring Security 简介
      • 9.1.1 理解 Spring Security 的模块
      • 9.1.2 过滤 Web 请求
      • 9.1.3 编写简单的安全性配置
    • 9.2 选择查询用户详细信息的服务
      • 9.2.1 使用基于内存的用户存储
      • 9.2.2 基于数据库表进行认证
      • 9.2.3 基于 LDAP 进行认证
      • 9.2.4 配置自定义的用户服务
    • 9.3 拦截请求
      • 9.3.1 使用 Spring 表达式进行安全保护
      • 9.3.2 强制通道的安全性
      • 9.3.3 防止跨站请求伪造
    • 9.4 认证用户
      • 9.4.1 添加自定义的登录页
      • 9.4.2 启用 HTTP Basic 认证
      • 9.4.3 启用 Remember-me 功能
      • 9.4.4 退出
    • 9.5 保护视图
      • 9.5.1 使用 Spring Security 的 JSP 标签库
      • 9.5.2 使用 Thymeleaf 的 Spring Security 方言
    • 9.6 小结
  • 第三部分 后端中的 Spring
  • 第 10 章 通过 Spring 和 JDBC 征服数据库
    • 10.1 Spring 的数据访问哲学
      • 10.1.1 了解 Spring 的数据访问异常体系
      • 10.1.2 数据访问模板化
    • 10.2 配置数据源
      • 10.2.1 使用 JNDI 数据源
      • 10.2.2 使用数据源连接池
      • 10.2.3 基于 JDBC 驱动的数据源
      • 10.2.4 使用嵌入式的数据源
      • 10.2.5 使用 profile 选择数据源
    • 10.3 在 Spring 中使用 JDBC
      • 10.3.1 应对失控的 JDBC 代码
      • 10.3.2 使用 JDBC 模板
    • 10.4 小结
  • 第 11 章 使用对象-关系映射持久化数据
    • 11.1 在 Spring 中集成 Hibernate
      • 11.1.1 声明 Hibernate 的 Session 工厂
      • 11.1.2 构建不依赖于 Spring 的 Hibernate 代码
    • 11.2 Spring 与 Java 持久化 API
      • 11.2.1 配置实体管理器工厂
      • 11.2.2 编写基于 JPA 的 Repository
    • 11.3 借助 Spring Data 实现自动化的 JPARepository
      • 11.3.1 定义查询方法
      • 11.3.2 声明自定义查询
      • 11.3.3 混合自定义的功能
    • 11.4 小结
  • 第 12 章 使用 NoSQL 数据库
    • 12.1 使用 MongoDB 持久化文档数据
      • 12.1.1 启用 MongoDB
      • 12.1.2 为模型添加注解,实现 MongoDB 持久化
      • 12.1.3 使用 MongoTemplate 访问 MongoDB
      • 12.1.4 编写 MongoDB Repository
    • 12.2 使用 Neo4j 操作图数据
      • 12.2.1 配置 Spring Data Neo4j
      • 12.2.2 使用注解标注图实体
      • 12.2.3 使用 Neo4jTemplate
      • 12.2.4 创建自动化的 Neo4j Repository
    • 12.3 使用 Redis 操作 key-value 数据
      • 12.3.1 连接到 Redis
      • 12.3.2 使用 Redis Template
      • 12.3.3 使用 key 和 value 的序列化器
    • 12.4 小结
  • 第 13 章 缓存数据
    • 13.1 启用对缓存的支持
      • 13.1.1 配置缓存管理器
    • 13.2 为方法添加注解以支持缓存
      • 13.2.1 填充缓存
      • 13.2.2 移除缓存条目
    • 13.3 使用 XML 声明缓存
    • 13.4 小结
  • 第 14 章 保护方法应用
    • 14.1 使用注解保护方法
      • 14.1.1 使用 @Secured 注解限制方法调用
      • 14.1.2 在 Spring Security 中使用 JSR-250 的 @RolesAllowed 注解
    • 14.2 使用表达式实现方法级别的安全性
      • 14.2.1 表述方法访问规则
      • 14.2.2 过滤方法的输入和输出
    • 14.3 小结
  • 第四部分 Spring 集成
  • 第 15 章 使用远程服务
    • 15.1 Spring 远程调用概览
    • 15.2 使用 RMI
      • 15.2.1 导出 RMI 服务
      • 15.2.2 装配 RMI 服务
    • 15.3 使用 Hessian 和 Burlap 发布远程服务
      • 15.3.1 使用 Hessian 和 Burlap 导出 bean 的功能
      • 15.3.2 访问 Hessian/Burlap 服务
    • 15.4 使用 Spring 的 HttpInvoker
      • 15.4.1 将 bean 导出为 HTTP 服务
      • 15.4.2 通过 HTTP 访问服务
    • 15.5 发布和使用 Web 服务
      • 15.5.1 创建基于 Spring 的 JAX-WS 端点
      • 15.5.2 在客户端代理 JAX-WS 服务
    • 15.6 小结
  • 第 16 章 使用 Spring MVC 创建 REST API
    • 16.1 了解 REST
      • 16.1.1 REST 的基础知识
      • 16.1.2 Spring 是如何支持 REST 的
    • 16.2 创建第一个 REST 端点
      • 16.2.1 协商资源表述
      • 16.2.2 使用 HTTP 信息转换器
    • 16.3 提供资源之外的其他内容
      • 16.3.1 发送错误信息到客户端
      • 16.3.2 在响应中设置头部信息
    • 16.4 编写 REST 客户端
      • 16.4.1 了解 RestTemplate 的操作
      • 16.4.2 GET 资源
      • 16.4.3 检索资源
      • 16.4.4 抽取响应的元数据
      • 16.4.5 PUT 资源
      • 16.4.6 DELETE 资源
      • 16.4.7 POST 资源数据
      • 16.4.8 在 POST 请求中获取响应对象
      • 16.4.9 在 POST 请求后获取资源位置
      • 16.4.10 交换资源
    • 16.5 小结
  • 第 17 章 Spring 消息
    • 17.1 异步消息简介
      • 17.1.1 发送消息
      • 17.1.2 评估异步消息的优点
    • 17.2 使用 JMS 发送消息
      • 17.2.1 在 Spring 中搭建消息代理
      • 17.2.2 使用 Spring 的 JMS 模板
      • 17.2.3 创建消息驱动的 POJO
      • 17.2.4 使用基于消息的 RPC
    • 17.3 使用 AMQP 实现消息功能
      • 17.3.1 AMQP 简介
      • 17.3.2 配置 Spring 支持 AMQP 消息
      • 17.3.3 使用 RabbitTemplate 发送消息
      • 17.3.4 接收 AMQP 消息
    • 17.4 小结
  • 第 18 章 使用 WebSocket 和 STOMP 实现消息功能
    • 18.1 使用 Spring 的低层级 WebSocket API
    • 18.2 应对不支持 WebSocket 的场景
    • 18.3 使用 STOMP 消息
      • 18.3.1 启用 STOMP 消息功能
      • 18.3.2 处理来自客户端的 STOMP 消息
      • 18.3.3 发送消息到客户端
    • 18.4 为目标用户发送消息
      • 18.4.1 在控制器中处理用户的消息
      • 18.4.2 为指定用户发送消息
    • 18.5 处理消息异常
    • 18.6 小结
  • 第 19 章 使用 Spring 发送 Email
    • 19.1 配置 Spring 发送邮件
      • 19.1.1 配置邮件发送器
      • 19.1.2 装配和使用邮件发送器
    • 19.2 构建丰富内容的 Email 消息
      • 19.2.1 添加附件
      • 19.2.2 发送富文本内容的 Email
    • 19.3 使用模板生成 Email
      • 19.3.1 使用 Velocity 构建 Email 消息
      • 19.3.2 使用 Thymeleaf 构建 Email 消息
    • 19.4 小结
  • 第 20 章 使用 JMX 管理 SpringBean
    • 20.1 将 Spring bean 导出为 MBean
      • 20.1.1 通过名称暴露方法
      • 20.1.2 使用接口定义 MBean 的操作和属性
      • 20.1.3 使用注解驱动的 MBean
      • 20.1.4 处理 MBean 冲突
    • 20.2 远程 MBean
      • 20.2.1 暴露远程 MBean
      • 20.2.2 访问远程 MBean
      • 20.2.3 代理 MBean
    • 20.3 处理通知
      • 20.3.1 监听通知
    • 20.4 小结
  • 第 21 章 借助 Spring Boot 简化 Spring 开发
    • 21.1 Spring Boot 简介
      • 21.1.1 添加 Starter 依赖
      • 21.1.2 自动配置
      • 21.1.3 Spring Boot CLI
      • 21.1.4 Actuator
    • 21.2 使用 Spring Boot 构建应用
      • 21.2.1 处理请求
      • 21.2.2 创建视图
      • 21.2.3 添加静态内容
      • 21.2.4 持久化数据
      • 21.2.5 尝试运行
    • 21.3 组合使用 Groovy 与 Spring Boot CLI
      • 21.3.1 编写 Groovy 控制器
      • 21.3.2 使用 Groovy Repository 实现数据持久化
      • 21.3.3 运行 Spring Boot CLI
    • 21.4 通过 Actuator 获取了解应用内部状况
    • 21.5 小结
Powered by GitBook
On this page

Was this helpful?

  1. 第 12 章 使用 NoSQL 数据库
  2. 12.2 使用 Neo4j 操作图数据

12.2.4 创建自动化的 Neo4j Repository

大多数 Spring Data 项目都具备的最棒的一项功能就是为 Repository 接口自动生成实现。我们已经在 Spring Data JPA 和 Spring Data MongoDB 中看到了这项功能。Spring Data Neo4j 也不例外,它同样支持 Repository 自动化生成功能。

我们已经将 @EnableNeo4jRepositories 添加到了配置中,所以 Spring Data Neo4j 已经配置为支持自动化生成 Repository 的功能。我们所需要做的就是编写接口,如下的 OrderRepository 就是很好的起点:

package orders.db;

import orders.Order;
import org.springframework.data.neo4j.repository.GraphRepository;

public interface OrderRepository extends GraphRepository<Order> {
}

与其他的 Spring Data 项目一样,Spring Data Neo4j 会为扩展 Repository 接口的其他接口生成 Repository 方法实现。在本例中,OrderRepository 扩展了 GraphRepository,而后者又间接扩展了 Repository 接口。因此,Spring Data Neo4j 将会在运行时创建 OrderRepository 的实现。

注意,GraphRepository 使用 Order 进行了参数化,也就是这个 Repository 所要使用的实体类型。因为 Neo4j 要求图 ID 的类型为 Long,因此在扩展 GraphRepository 的时候,没有必要再去指定 ID 类型。

现在,我们就能够使用很多通用的 CRUD 操作,这与 JpaRepository 和 MongoRepository 所提供的功能类似。表 12.4 描述了扩展 GraphRepository 所能够得到的方法。

方法

描述

long count();

返回在数据库中,目标类型有多 少实体

void delete(Iterable<? extends T>);

删除多个实体

void delete(Long id);

根据 ID,删除一个实体

void delete(T);

删除一个实体

void deleteAll();

删除目标类型的所有实体

boolean exists(Long id);

根据指定的 ID,检查实体是否存在

EndResult<T> findAll();

获取目标类型的所有实体

Page<T> findAll(Pageable);

返回目标类型分页和排序后的实体列表

EndResult<T> findAll(Sort);

返回目标类型排序后的实体列表

EndResult<T> findAllBySchemaPropertyValue(String,Object);

返回指定属性匹配给定值的所有实体

Iterable<T> findAllByTraversal(N, TraversalDescription);

返回从某个节点开始,图遍历到达的节点

T findBySchemaPropertyValue (String,Object);

返回指定属性匹配给定值的一个 实体

T findOne(Long);

根据 ID,获得某一个实体

EndResult<T> query(String, Map<String, Object>);

返回匹配给定 Cypher 查询的所有实体

Iterable<T> save(Iterable<T>);

保存多个实体 S save(S); 保存一个实体

S save(S)

保存一个实体

我们没有足够的篇幅介绍所有的方法,但是有些方法你可能会经常用到。例如,如下的代码能够保存一个Order 实体:

Order saveOrder = orderRepository.save(order);

当实体保存之后,save() 方法将会返回被保存的实体,如果之前它使用@GraphId 注解的属性值为 null 的话,此时这个属性将会填充上值。 我们还可以使用 findOne() 方法查询某一个实体。例如,下面的这行代码将会查询图 ID 为 4 的 Order:

Order order = orderRepository.findOne(4L);

我们还可以查询所有的 Order:

EndResult<Order> allOrders = orderRepository.findAll();

当然,你可能还希望删除某一个实体。这种情况下,可以使用 delete() 方法:

delete(order);

这将会从数据库中删除给定的 Order 节点。如果你只有图 ID 的话,那可以将其传递到 delete() 方法中,而不是再使用节点类型本身:

delete(orderId);

如果你希望进行自定义的查询,那么可以使用 query() 方法对数据库执行任意的 Cypher 查询。但是这与使用 Neo4jTemplate 的 query() 方法并没有太大的差别。其实,我们还可以为 OrderRepository 添加自定义的查询方法。

添加查询方法

我们已经看过如何按照命名约定使用 Spring Data JPA 和 Spring Data MongoDB 来添加自定义的查询方法。如果 Spring Data Neo4j 没有提供相同功能的话,那我们就该失望了。

如下面的程序清单所示,其实我们完全没有必要失望:

程序清单 12.13 通过遵循命名约定来定义查询方法
package orders.db;

import java.util.List;
import orders.Order;
import org.springframework.data.neo4j.repository.GraphRepository;

public interface OrderRepository extends GraphRepository<Order> {
  List<Order> findByCustomer(String customer);
  List<Order> findByCustomerAndType(String customer, String type);
}

这里,我们添加了两个方法。其中一个会查询 customer 属性等于给定 String 值的 Order 节点。另外一个方法与之类似,但是除了匹我们之前已经讨论过查询方法的命名约定,所以这里没有必要再进行深入地讨论。可以翻看之前学习 Spring Data JPA 的章节,重新温习如何编写这些方法。

指定自定义查询

当命名约定无法满足需求时,我们还可以为方法添加 @Query 注解,为其指定自定义的查询。我们之前已经见过 @Query 注解。在 Spring Data JPA 中,我们使用它来为 Repository 方法指定 JPA 查询。在 Spring Data MongoDB 中,我们使用它来指定匹配 JSON 的查询。但是,在使用 Spring Data Neo4j 的时候,我们必须指定 Cypher 查询:

@Query("match (o:Order)-[:HAS_ITEMS]->(i:Item) " +
       "where i.product='Spring in Action' return o")
List<Order> findSiAOrders();

在这里,findSiAOrders() 方法上使用了 @Query 注解,并设置了一个 Cypher 查询,它会查找与 Item 关联并且 product 属性等于 “Spring in Action” 的所有 Order 节点。

混合自定义的 Repository 行为

当命名约定和 @Query 注解均无法满足满足需求的时候,我们还可以混合自定义的 Repository 逻辑。

例如,假设我们想自己编写 findSiAOrders() 方法的实现,而不是依赖于 @Query 注解。那么可以首先定义一个中间接口,该接口包含 findSiAOrders() 方法的定义:

package orders.db;

import java.util.List;
import oders.Order;

public interface OrderOperations {
  List<Order> findSiAOrders();
}

然后,我们修改 OrderRepository,让它扩展 OrderOperations 和 GraphRepository:

public interface OrderRepository extends GraphRepository<Order>, OrderOperations {
}

最后,我们需要自己编写实现。与 Spring Data JPA 和 Spring Data MongoDB 类似,Spring Data Neo4j 将会查找名字与 Repository 接口相同 且添加 “Impl” 后缀的实现类。因此,我们需要创建 OrderRepositoryImpl 类。如下的程序清单展示了 OrderRepositoryImpl 类,它实现了 findSiAOrders() 方法。

package orders.db;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import orders.Order;
import org.neo4j.helpers.collection.IteratorUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.neo4j.conversion.EndResult;
import org.springframework.data.neo4j.conversion.Result;
import org.springframework.data.neo4j.template.Neo4jOperations;

public class OrderRepositorylmpl implements OrderOperations {
  private final Neo4jOperations neo4j;
  
  @Autowired
  public OrderRepositorylmpl(Neo4jOperations neo4j) {
    this.neo4j = neo4j;
  }
  
  public List<Order> findSiAOrders() {
    Result<Map<String, Object>> result = neo4j.query(
      "match (o:Order)-[:HAS_ITEMS]->(i:Item) " +
      "where i.product='Spring in Action' return o",
      EndResult<Order> endResult = result.to{Order.class);
    return IteratorUtil.asList(endResult);
  }
}

OrderRepositoryImpl 中注入了一个 Neo4jOperations(具体来讲,就是 Neo4jTemplate 的实例),它会用来查询数据库。因为 query() 方法返回的是 Result<Map<String, Object>>,我们需要将其转换为 List<Order>。第一步是调用 Result 的 to() 方法,产生一个 EndResult<Order>。然后,使用 Neo4j 的 IteratorUtil.asList() 方法将 EndResult<Order> 转换为 List<Order>,然后将其返回。

对于能够表达为节点和关联关系的数据,像 Neo4j 这样的图数据库是非常合适的。如果将我们生活的世界理解为各种互相关联的事物,那么图数据库能够适用于很大的范围。就我个人而言,我非常喜欢的数据持久化。

Previous12.2.3 使用 Neo4jTemplateNext12.3 使用 Redis 操作 key-value 数据

Last updated 5 years ago

Was this helpful?