12.3 编写反应式的MongoDB repository
12.3.1 启用Spring Data MongoDB
- 添加依赖
如果需要非反应式则添加:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
反应式则添加:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
</dependency>
添加嵌入式的MongoDB
<dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
</dependency>
如果是生产环境,则不使用嵌入式数据库,还需要配置几个属性:
spring:
data:
mongodb:
host: xxxx
port: 27018
username: xxxx
password: xxxx
database: xxxx
12.3.2 将领域对象映射为文档
- @Id: 将某个属性指明为文档的ID
- @Document: 将领域类型声明为要持久化到MongoDB中的文档
@Field: 指定某个属性持久化到文档中的字段名称
@Data
@RequiredArgsConstructor
@NoArgsConstructor(access = AccessLevel.PRIVATE, force = true)
@Document(collection = "ingredients")
public class Ingredient {
@Id
private final String id;
private final String name;
private final Type type;
public static enum Type {
WRAP, PROTEIN, VEGGIES, CHEESE, SAUCE
}
}
@Id可以用到任意Serializable类型的字段上,包括String和Long @Document(collection = “ingredients”): 如果没有特别指定,则会持久化到类名首字母小写(ingredient)的集合中,可以通过collection属性来改变这种行为
@Data
@Document
public class Taco {
@Id
private String id;
@NotNull
@Size(min = 5, message = "name must be at least 5 characters long")
private String name;
private Date createdAt = new Date();
@Size(min = 1, message = "You must choose at least 1 ingredient")
private List<Ingredient> ingredients;
}
@Data
@Document
public class Order implements Serializable {
private static final long serialVersionUID = 1L;
@Id
private String id;
private Date placedAt = new Date();
@Field("customer")
private User user;
private String deliveryName;
private String deliveryStreet;
private String deliveryCity;
private String deliveryState;
private String deliveryZip;
private String ccNumber;
private String ccExpiration;
private String ccCVV;
private List<Taco> tacos = new ArrayList<>();
public void addDesign(Taco design) {
this.tacos.add(design);
}
}
12.3.3 编写反应式的MongoDB repository接口
有两种接口选择:ReactiveCrudRepository和ReactiveMongoRepository
他们之间的区别在于:ReactiveMongoRepository提供多个特殊的insert()⽅法,它们针对新⽂档的持久化进⾏了优化,⽽ReactiveCrudRepository依赖save()⽅法来保存新⽂档和已有的⽂档
在数据库初始化完成之后,我们不会频繁地创建配料的⽂档,甚⾄有可能永远不会这样做。因此, ReactiveMongoRepository提供的优化没有太多的⽤处,我们可以让 IngredientRepository扩展ReactiveCrudRepository:
public interface IngredientRepository extends ReactiveCrudRepository<Ingredient, String> {}
为了将Taco持久化为MongoDB中的⽂档,我们定义另⼀个repository。 与配料⽂档不同,我们会频繁创建taco⽂档。因此,ReactiveMongoRepository优化过的insert()⽅法就很有价值了。
public interface TacoRepository extends ReactiveMongoRepository<Taco, String> {
Flux<Taco> findByOrderByCreatedAt();
}
public interface OrderRepository extends ReactiveMongoRepository<Order, String> {
}
public interface UserRepository extends ReactiveMongoRepository<User, String> {
Mono<User> findByUsername(String username);
}