当前位置:   article > 正文

spring data mongodb学习以及为repository提供可扩展的自定义方法_org.springframework.data.mongodb.repository.suppor

org.springframework.data.mongodb.repository.support

Spring Data 概述

Spring Data : Spring 的一个子项目。用于简化数据库访问,支持NoSQL 和 关系数据存储。其主要目标是使数据库的访问变得方便快捷。
SpringData 项目所支持 NoSQL 存储:
MongoDB (文档数据库)
Neo4j(图形数据库)
Redis(键/值存储)
Hbase(列族数据库)
SpringData 项目所支持的关系数据存储技术:
JDBC
JPA

Spring Data mongodb 概述

Spring Data mongodb  : 致力于减少数据访问层 (DAO) 的开发量. 开发者唯一要做的,就只是声明持久层的接口,其他都交给 Spring Data mongodb 来帮你完成!
框架怎么可能代替开发者实现业务逻辑呢?比如:当有一个 customerRepository.findByNameAndAddressNumberAndAccountsAccountName(name, number,accountName)  这样一个方法声明,大致应该能判断出这是根据给定条件 查询出满足条件的 User  对象。Spring Data mongodb 做的便是规范方法的名字,根据符合规范的名字来确定方法需要实现什么样的逻辑。

使用 Spring Data JPA 进行持久层开发需要的四个步骤:

1、配置 Spring 整合 Mongodb

  1. package com.dhb.springmvc.config;
  2. import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
  3. /**
  4. * Created by ${denghb} on 2016/7/31.
  5. */
  6. public class DhbWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
  7. @Override
  8. protected Class<?>[] getRootConfigClasses() {
  9. return new Class<?>[] { RootConfig.class };
  10. }
  11. @Override
  12. protected Class<?>[] getServletConfigClasses() {
  13. // return new Class<?>[0];
  14. return new Class [] { WebConfig.class, C3P0DataSourceBuilder.class, MongodbConfig.class };
  15. }
  16. @Override
  17. protected String[] getServletMappings() {
  18. return new String[] { "/" };
  19. }
  20. }


2、让 Spring 为声明的接口创建代理对象。Spring 初始化容器时将会扫描 base-package  指定的包目录及其子目录,为继承 Repository 或其子接口的接口创建代理对象,并将代理对象注册为 Spring Bean,业务层便可以通过 Spring 自动封装的特性来直接使用该对象。

  1. package com.dhb.springmvc.config;
  2. import com.dhb.springmvc.base.support.CustomMongoRepositoryFactoryBean;
  3. import com.mongodb.Mongo;
  4. import com.mongodb.MongoClient;
  5. import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
  6. import org.springframework.data.mongodb.config.EnableMongoAuditing;
  7. import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
  8. /**
  9. * Created by ${denghb} on 2016/8/5.
  10. */
  11. @EnableMongoRepositories(
  12. basePackages = {"com.dhb.springmvc"},
  13. repositoryFactoryBeanClass = CustomMongoRepositoryFactoryBean.class
  14. )
  15. @EnableMongoAuditing
  16. public class MongodbConfig extends AbstractMongoConfiguration {
  17. @Override
  18. protected String getDatabaseName() {
  19. return "business";
  20. }
  21. @Override
  22. public Mongo mongo() throws Exception {
  23. return new MongoClient("127.0.0.1");
  24. }
  25. }
在这里没有配置MongoTemplate,但是在后续的repository里面我们却可以注入进来,原因是继承了AbstractMongoConfiguration ,该抽象类对其进行了实现。

MongoTemplate是数据库和代码之间的接口,对数据库的操作都在它里面。
注:MongoTemplate是线程安全的。
MongoTemplate实现了interface MongoOperations。

MongoDB documents和domain classes之间的映射关系是通过实现了MongoConverter这个interface的类来实现的。
MongoTemplate提供了非常多的操作MongoDB的方法。 它是线程安全的,可以在多线程的情况下使用。
MongoTemplate实现了MongoOperations接口, 此接口定义了众多的操作方法如"find", "findAndModify", "findOne", "insert", "remove", "save", "update" and "updateMulti"等。
它转换domain object为DBObject,并提供了Query, Criteria, and Update等流式API。
缺省转换类为MongoMappingConverter。
3、声明持久层的接口,该接口继承  Repository
Repository 是一个标记型接口,它不包含任何方法,如必要,Spring Data 可实现 Repository 其他子接口,其中定义了一些常用的增删改查,以及分页相关的方法。
在接口中声明需要的方法

  1. package com.dhb.springmvc.base.repository;
  2. import com.dhb.springmvc.base.entity.BaseEntity;
  3. import org.springframework.data.mongodb.repository.MongoRepository;
  4. import org.springframework.data.repository.NoRepositoryBean;
  5. import java.io.Serializable;
  6. /**
  7. * Created by ${denghb} on 2016/8/5.
  8. */
  9. @NoRepositoryBean
  10. public interface BaseRepository<T extends BaseEntity, ID extends Serializable>
  11. extends MongoRepository<T, ID>, BaseRepositoryEnhance<T, ID> {
  12. }

下面是可扩张的repository

  1. package com.dhb.springmvc.base.repository;
  2. import com.dhb.springmvc.base.entity.BaseEntity;
  3. import java.io.Serializable;
  4. /**
  5. * Created by ${denghb} on 2016/8/5.
  6. */
  7. public interface BaseRepositoryEnhance<T extends BaseEntity, ID extends Serializable> {
  8. T softDelete(ID id);
  9. }

  1. package com.dhb.springmvc.base.repository.impl;
  2. import com.dhb.springmvc.base.entity.BaseEntity;
  3. import com.dhb.springmvc.base.repository.BaseRepositoryEnhance;
  4. import org.springframework.data.mongodb.core.MongoOperations;
  5. import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
  6. import org.springframework.data.mongodb.repository.support.SimpleMongoRepository;
  7. import java.io.Serializable;
  8. /**
  9. * Created by ${denghb} on 2016/8/5.
  10. */
  11. public class BaseRepositoryImpl<T extends BaseEntity, ID extends Serializable>
  12. extends SimpleMongoRepository<T, ID>
  13. implements BaseRepositoryEnhance<T, ID> {
  14. private final MongoOperations mongoOperations;
  15. public BaseRepositoryImpl(MongoEntityInformation<T, ID> metadata, MongoOperations mongoOperations) {
  16. super(metadata, mongoOperations);
  17. this.mongoOperations = mongoOperations;
  18. }
  19. @Override
  20. public T softDelete(ID id) {
  21. return null;
  22. }
  23. }

public BaseRepositoryImpl(MongoEntityInformation<T, ID> metadata, MongoOperations mongoOperations) {
        super(metadata, mongoOperations);
        this.mongoOperations = mongoOperations;
    }

这段代码必须实现,因为父类有一个有参的构造方法,没有无参的构造方法。


父类没有无参构造函数时,子类继承时,构造函数中必须显式调用父类构造方法,并且传递对应所需要的参数。 一个类如果显式的定义了带参构造函数,那么默认无参构造函数自动失效 。

4、Spring Data 将根据给定的策略(具体策略稍后讲解)来为其生成实现代码。

  1. package com.dhb.springmvc.base.support;
  2. import com.dhb.springmvc.base.entity.BaseEntity;
  3. import com.dhb.springmvc.base.repository.impl.BaseRepositoryImpl;
  4. import org.springframework.data.mongodb.core.MongoOperations;
  5. import org.springframework.data.mongodb.repository.MongoRepository;
  6. import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
  7. import org.springframework.data.mongodb.repository.support.MongoRepositoryFactory;
  8. import org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean;
  9. import org.springframework.data.mongodb.repository.support.QueryDslMongoRepository;
  10. import org.springframework.data.querydsl.QueryDslPredicateExecutor;
  11. import org.springframework.data.repository.core.RepositoryMetadata;
  12. import org.springframework.data.repository.core.support.RepositoryFactorySupport;
  13. import java.io.Serializable;
  14. import static org.springframework.data.querydsl.QueryDslUtils.QUERY_DSL_PRESENT;
  15. /**
  16. * 用于生成自扩展的Repository方法,比如softDelete
  17. * Created by ${denghb} on 2016/8/5.
  18. */
  19. public class CustomMongoRepositoryFactoryBean<T extends MongoRepository<S, ID>, S extends BaseEntity, ID extends Serializable>
  20. extends MongoRepositoryFactoryBean<T, S, ID> {
  21. @Override
  22. protected RepositoryFactorySupport getFactoryInstance(MongoOperations operations) {
  23. return new LCRRepositoryFactory(operations);
  24. }
  25. private static class LCRRepositoryFactory<S extends BaseEntity, ID extends Serializable> extends MongoRepositoryFactory {
  26. private final MongoOperations mongoOperations;
  27. public LCRRepositoryFactory(MongoOperations mongoOperations) {
  28. super(mongoOperations);
  29. this.mongoOperations = mongoOperations;
  30. }
  31. @Override
  32. protected Object getTargetRepository(RepositoryMetadata metadata) {
  33. Class<?> repositoryInterface = metadata.getRepositoryInterface();
  34. MongoEntityInformation<?, Serializable> entityInformation = getEntityInformation(metadata.getDomainType());
  35. if (isQueryDslRepository(repositoryInterface)) {
  36. return new QueryDslMongoRepository(entityInformation, mongoOperations);
  37. } else {
  38. return new BaseRepositoryImpl<S, ID>((MongoEntityInformation<S, ID>) entityInformation, this.mongoOperations);
  39. }
  40. }
  41. private static boolean isQueryDslRepository(Class<?> repositoryInterface) {
  42. return QUERY_DSL_PRESENT && QueryDslPredicateExecutor.class.isAssignableFrom(repositoryInterface);
  43. }
  44. @Override
  45. protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
  46. return isQueryDslRepository(metadata.getRepositoryInterface()) ? QueryDslMongoRepository.class
  47. : BaseRepositoryImpl.class;
  48. }
  49. }
  50. }

Repository 接口概述
Repository 接口是 Spring Data 的一个核心接口,它不提供任何方法,开发者需要在自己定义的接口中声明需要的方法 
    public interface Repository<T, ID extends Serializable> { } 
Spring Data可以让我们只定义接口,只要遵循 Spring Data的规范,就无需写实现类。  
与继承 Repository 等价的一种方式,就是在持久层接口上使用 @RepositoryDefinition 注解,并为其指定 domainClass 和 idClass 属性。如下两种方式是完全等价的
Repository 的子接口
基础的 Repository 提供了最基本的数据访问功能,其几个子接口则扩展了一些功能。它们的继承关系如下: 
Repository: 仅仅是一个标识,表明任何继承它的均为仓库接口类
CrudRepository: 继承 Repository,实现了一组 CRUD 相关的方法 
PagingAndSortingRepository: 继承 CrudRepository,实现了一组分页排序相关的方法 
MongoRepository: 继承 PagingAndSortingRepository,实现一组 mongodb规范相关的方法 
自定义的 XxxxRepository 需要继承 MongoRepository,这样的 XxxxRepository 接口就具备了通用的数据访问控制层的能力。

entity实体类:

  1. package com.dhb.springmvc.entity;
  2. import com.dhb.springmvc.base.entity.BaseEntity;
  3. import com.dhb.springmvc.entity.support.Account;
  4. import com.dhb.springmvc.entity.support.Address;
  5. import org.springframework.data.mongodb.core.mapping.Document;
  6. import java.util.List;
  7. /**
  8. * Created by ${denghb} on 2016/8/5.
  9. */
  10. @Document
  11. public class Customer extends BaseEntity {
  12. private String name;
  13. private List<Account> accounts;
  14. private Address address;
  15. public String getName() {
  16. return name;
  17. }
  18. public void setName(String name) {
  19. this.name = name;
  20. }
  21. public List<Account> getAccounts() {
  22. return accounts;
  23. }
  24. public void setAccounts(List<Account> accounts) {
  25. this.accounts = accounts;
  26. }
  27. public Address getAddress() {
  28. return address;
  29. }
  30. public void setAddress(Address address) {
  31. this.address = address;
  32. }
  33. }

  1. package com.dhb.springmvc.entity.support;
  2. import com.dhb.springmvc.base.entity.BaseEntity;
  3. /**
  4. * Created by ${denghb} on 2016/8/5.
  5. */
  6. public class Account extends BaseEntity {
  7. private String accountName;
  8. public String getAccountName() {
  9. return accountName;
  10. }
  11. public void setAccountName(String accountName) {
  12. this.accountName = accountName;
  13. }
  14. }

  1. package com.dhb.springmvc.entity.support;
  2. import com.dhb.springmvc.base.entity.BaseEntity;
  3. /**
  4. * Created by ${denghb} on 2016/8/5.
  5. */
  6. public class Address extends BaseEntity {
  7. private String number;
  8. private String street;
  9. private String town;
  10. private String postcode;
  11. public String getNumber() {
  12. return number;
  13. }
  14. public void setNumber(String number) {
  15. this.number = number;
  16. }
  17. public String getStreet() {
  18. return street;
  19. }
  20. public void setStreet(String street) {
  21. this.street = street;
  22. }
  23. public String getTown() {
  24. return town;
  25. }
  26. public void setTown(String town) {
  27. this.town = town;
  28. }
  29. public String getPostcode() {
  30. return postcode;
  31. }
  32. public void setPostcode(String postcode) {
  33. this.postcode = postcode;
  34. }
  35. }

repository类:

  1. package com.dhb.springmvc.repository;
  2. import com.dhb.springmvc.entity.Customer;
  3. import java.util.List;
  4. /**
  5. * Created by ${denghb} on 2016/8/8.
  6. */
  7. public interface CustomerRepositoryEnhance {
  8. public List<Customer> search(String keyword, String direction, String sort, int page, int size);
  9. }

  1. package com.dhb.springmvc.repository.impl;
  2. import com.dhb.springmvc.entity.Customer;
  3. import com.dhb.springmvc.repository.CustomerRepositoryEnhance;
  4. import org.springframework.data.domain.PageRequest;
  5. import org.springframework.data.domain.Sort;
  6. import org.springframework.data.mongodb.core.MongoTemplate;
  7. import org.springframework.data.mongodb.core.query.Criteria;
  8. import org.springframework.data.mongodb.core.query.Query;
  9. import javax.annotation.Resource;
  10. import java.util.List;
  11. /**
  12. * Created by ${denghb} on 2016/8/8.
  13. */
  14. public class CustomerRepositoryImpl implements CustomerRepositoryEnhance {
  15. @Resource
  16. private MongoTemplate mongoTemplate;
  17. @Override
  18. public List<Customer> search(String keyword, String direction, String sort, int page, int size) {
  19. Query query = new Query();
  20. Criteria c = new Criteria();
  21. query.addCriteria(Criteria.where("name").is(keyword));
  22. query.with(new Sort(Sort.Direction.valueOf(direction), sort));
  23. query.with(new PageRequest(page - 1, size));
  24. return mongoTemplate.find(query, Customer.class);
  25. }
  26. }

  1. package com.dhb.springmvc.repository;
  2. import com.dhb.springmvc.base.repository.BaseRepository;
  3. import com.dhb.springmvc.entity.Customer;
  4. import org.springframework.stereotype.Repository;
  5. import java.util.List;
  6. /**
  7. * Created by ${denghb} on 2016/8/5.
  8. */
  9. @Repository
  10. public interface CustomerRepository extends BaseRepository<Customer, String>, CustomerRepositoryEnhance {
  11. List<Customer> findByNameAndAddressNumberAndAccountsAccountName(
  12. String name, String number, String accountName);
  13. }

service类:

  1. package com.dhb.springmvc.service;
  2. import com.dhb.springmvc.entity.Customer;
  3. import com.dhb.springmvc.repository.CustomerRepository;
  4. import org.springframework.stereotype.Service;
  5. import javax.annotation.Resource;
  6. import java.util.List;
  7. /**
  8. * Created by ${denghb} on 2016/8/5.
  9. */
  10. @Service
  11. public class CustomerService {
  12. @Resource
  13. private CustomerRepository customerRepository;
  14. public void insertCustomer(Customer customer) {
  15. customerRepository.save(customer);
  16. }
  17. public List<Customer> findAllCustomers() {
  18. return customerRepository.findAll();
  19. }
  20. public void dropCustomerCollection() {
  21. customerRepository.deleteAll();
  22. }
  23. public List<Customer> findByNameAndAddressNumberAndAccountsAccountName(String name, String number, String accountName) {
  24. return customerRepository.findByNameAndAddressNumberAndAccountsAccountName(name, number,accountName);
  25. }
  26. public List<Customer> search(String keyword, String direction, String sort, int page, int size) {
  27. return customerRepository.search(keyword, direction, sort, page, size);
  28. }
  29. }

restController类:

  1. package com.dhb.springmvc.controller;
  2. import com.dhb.springmvc.entity.Customer;
  3. import com.dhb.springmvc.service.CustomerService;
  4. import org.springframework.web.bind.annotation.*;
  5. import javax.annotation.Resource;
  6. import java.util.List;
  7. /**
  8. * Created by ${denghb} on 2016/8/5.
  9. */
  10. @RestController
  11. @RequestMapping(value = "/v0.1/customer")
  12. public class CustomerController {
  13. @Resource
  14. private CustomerService customerService;
  15. @RequestMapping(value = "/get_all", method = RequestMethod.GET)
  16. public Object findAllCustomerDetail() {
  17. return customerService.findAllCustomers();
  18. }
  19. @RequestMapping(value = "/get_by/{name}/{number}/{accountName}", method = RequestMethod.GET)
  20. public Object findByNameAndAddressNumberAndAccountsAccountName(@PathVariable String name, @PathVariable String number, @PathVariable String accountName) {
  21. return customerService.findByNameAndAddressNumberAndAccountsAccountName(name, number, accountName);
  22. }
  23. @RequestMapping(value = "/search_by", method = RequestMethod.GET)
  24. public List<Customer> search(@RequestParam(value= "query", defaultValue = "") String keyword,
  25. @RequestParam(value= "direction", defaultValue = "DESC") String direction,
  26. @RequestParam(value = "sort", defaultValue = "name") String sort,
  27. @RequestParam(value = "page", defaultValue = "1") int page,
  28. @RequestParam(value = "size", defaultValue = "30") int size) {
  29. return customerService.search(keyword, direction, sort, page, size);
  30. }
  31. }


1、为某一个 Repository 上添加自定义方法

1)定义一个接口: 声明要添加的自实现的方法

2)提供该接口的实现类: 类名需在要声明的 Repository 后添加 Impl, 并实现方法

3)声明 Repository 接口, 并继承 1) 声明的接口

注意: 默认情况下, Spring Data 会在 base-package 中查找 "接口名Impl" 作为实现类. 也可以通过 repository-impl-postfix 声明后缀. 


2、为所有的 Repository 都添加自实现的方法

1)声明一个接口, 在该接口中声明需要自定义的方法

2)提供 1) 所声明的接口的实现类. 且继承 SimpleJpaRepository, 并提供方法的实现

3)声明 Repository 接口, 并继承 1) 声明的接口, 且该接口需要继承 Spring Data 的 Repository.

4)定义 MongoRepositoryFactoryBean的实现类, 使其生成 1) 定义的接口实现类的对象

5)修改 mongodb repository节点的 factory-class 属性指向 3) 的全类名

注意: 全局的扩展实现类不要用 Imp 作为后缀名, 或为全局扩展接口添加 @NoRepositoryBean 注解告知  Spring Data: Spring Data 不把其作为 Repository

项目工程目录如下(部分配置适用于别的测试,可以无视):



声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/56001
推荐阅读
相关标签
  

闽ICP备14008679号