您的位置:首页 > 数据库 > Mongodb

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

2016-09-21 13:51 701 查看
来源:http://blog.csdn.net/victor_cindy1/article/details/52151891

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

[java] view
plain copy







package com.dhb.springmvc.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

/**

<
4000
span class="comment" style="margin:0px; padding:0px; border:none; color:rgb(0,130,0); background-color:inherit"> * Created by ${denghb} on 2016/7/31.

*/

public class DhbWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

@Override

protected Class<?>[] getRootConfigClasses() {

return new Class<?>[] { RootConfig.class };

}

@Override

protected Class<?>[] getServletConfigClasses() {

// return new Class<?>[0];

return new Class [] { WebConfig.class, C3P0DataSourceBuilder.class, MongodbConfig.class };

}

@Override

protected String[] getServletMappings() {

return new String[] { "/" };

}

}

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

[java] view
plain copy







package com.dhb.springmvc.config;

import com.dhb.springmvc.base.support.CustomMongoRepositoryFactoryBean;

import com.mongodb.Mongo;

import com.mongodb.MongoClient;

import org.springframework.data.mongodb.config.AbstractMongoConfiguration;

import org.springframework.data.mongodb.config.EnableMongoAuditing;

import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;

/**

* Created by ${denghb} on 2016/8/5.

*/

@EnableMongoRepositories(

basePackages = {"com.dhb.springmvc"},

repositoryFactoryBeanClass = CustomMongoRepositoryFactoryBean.class

)

@EnableMongoAuditing

public class MongodbConfig extends AbstractMongoConfiguration {

@Override

protected String getDatabaseName() {

return "business";

}

@Override

public Mongo mongo() throws Exception {

return new MongoClient("127.0.0.1");

}

}

在这里没有配置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 其他子接口,其中定义了一些常用的增删改查,以及分页相关的方法。

在接口中声明需要的方法

[java] view
plain copy







package com.dhb.springmvc.base.repository;

import com.dhb.springmvc.base.entity.BaseEntity;

import org.springframework.data.mongodb.repository.MongoRepository;

import org.springframework.data.repository.NoRepositoryBean;

import java.io.Serializable;

/**

* Created by ${denghb} on 2016/8/5.

*/

@NoRepositoryBean

public interface BaseRepository<T extends BaseEntity, ID extends Serializable>

extends MongoRepository<T, ID>, BaseRepositoryEnhance<T, ID> {

}

下面是可扩张的repository

[java] view
plain copy







package com.dhb.springmvc.base.repository;

import com.dhb.springmvc.base.entity.BaseEntity;

import java.io.Serializable;

/**

* Created by ${denghb} on 2016/8/5.

*/

public interface BaseRepositoryEnhance<T extends BaseEntity, ID extends Serializable> {

T softDelete(ID id);

}

[java] view
plain copy







package com.dhb.springmvc.base.repository.impl;

import com.dhb.springmvc.base.entity.BaseEntity;

import com.dhb.springmvc.base.repository.BaseRepositoryEnhance;

import org.springframework.data.mongodb.core.MongoOperations;

import org.springframework.data.mongodb.repository.query.MongoEntityInformation;

import org.springframework.data.mongodb.repository.support.SimpleMongoRepository;

import java.io.Serializable;

/**

* Created by ${denghb} on 2016/8/5.

*/

public class BaseRepositoryImpl<T extends BaseEntity, ID extends Serializable>

extends SimpleMongoRepository<T, ID>

implements BaseRepositoryEnhance<T, ID> {

private final MongoOperations mongoOperations;

public BaseRepositoryImpl(MongoEntityInformation<T, ID> metadata, MongoOperations mongoOperations) {

super(metadata, mongoOperations);

this.mongoOperations = mongoOperations;

}

@Override

public T softDelete(ID id) {

return null;

}

}

public BaseRepositoryImpl(MongoEntityInformation<T, ID> metadata, MongoOperations mongoOperations) {

super(metadata, mongoOperations);

this.mongoOperations = mongoOperations;

}

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



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

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

[java] view
plain copy







package com.dhb.springmvc.base.support;

import com.dhb.springmvc.base.entity.BaseEntity;

import com.dhb.springmvc.base.repository.impl.BaseRepositoryImpl;

import org.springframework.data.mongodb.core.MongoOperations;

import org.springframework.data.mongodb.repository.MongoRepository;

import org.springframework.data.mongodb.repository.query.MongoEntityInformation;

import org.springframework.data.mongodb.repository.support.MongoRepositoryFactory;

import org.springframework.data.mongodb.repository.support.MongoRepositoryFactoryBean;

import org.springframework.data.mongodb.repository.support.QueryDslMongoRepository;

import org.springframework.data.querydsl.QueryDslPredicateExecutor;

import org.springframework.data.repository.core.RepositoryMetadata;

import org.springframework.data.repository.core.support.RepositoryFactorySupport;

import java.io.Serializable;

import static org.springframework.data.querydsl.QueryDslUtils.QUERY_DSL_PRESENT;

/**

* 用于生成自扩展的Repository方法,比如softDelete

* Created by ${denghb} on 2016/8/5.

*/

public class CustomMongoRepositoryFactoryBean<T extends MongoRepository<S, ID>, S extends BaseEntity, ID extends Serializable>

extends MongoRepositoryFactoryBean<T, S, ID> {

@Override

protected RepositoryFactorySupport getFactoryInstance(MongoOperations operations) {

return new LCRRepositoryFactory(operations);

}

private static class LCRRepositoryFactory<S extends BaseEntity, ID extends Serializable> extends MongoRepositoryFactory {

private final MongoOperations mongoOperations;

public LCRRepositoryFactory(MongoOperations mongoOperations) {

super(mongoOperations);

this.mongoOperations = mongoOperations;

}

@Override

protected Object getTargetRepository(RepositoryMetadata metadata) {

Class<?> repositoryInterface = metadata.getRepositoryInterface();

MongoEntityInformation<?, Serializable> entityInformation = getEntityInformation(metadata.getDomainType());

if (isQueryDslRepository(repositoryInterface)) {

return new QueryDslMongoRepository(entityInformation, mongoOperations);

} else {

return new BaseRepositoryImpl<S, ID>((MongoEntityInformation<S, ID>) entityInformation, this.mongoOperations);

}

}

private static boolean isQueryDslRepository(Class<?> repositoryInterface) {

return QUERY_DSL_PRESENT && QueryDslPredicateExecutor.class.isAssignableFrom(repositoryInterface);

}

@Override

protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {

return isQueryDslRepository(metadata.getRepositoryInterface()) ? QueryDslMongoRepository.class

: BaseRepositoryImpl.class;

}

}

}

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实体类:

[java] view
plain copy







package com.dhb.springmvc.entity;

import com.dhb.springmvc.base.entity.BaseEntity;

import com.dhb.springmvc.entity.support.Account;

import com.dhb.springmvc.entity.support.Address;

import org.springframework.data.mongodb.core.mapping.Document;

import java.util.List;

/**

* Created by ${denghb} on 2016/8/5.

*/

@Document

public class Customer extends BaseEntity {

private String name;

private List<Account> accounts;

private Address address;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public List<Account> getAccounts() {

return accounts;

}

public void setAccounts(List<Account> accounts) {

this.accounts = accounts;

}

public Address getAddress() {

return address;

}

public void setAddress(Address address) {

this.address = address;

}

}

[java] view
plain copy







package com.dhb.springmvc.entity.support;

import com.dhb.springmvc.base.entity.BaseEntity;

/**

* Created by ${denghb} on 2016/8/5.

*/

public class Account extends BaseEntity {

private String accountName;

public String getAccountName() {

return accountName;

}

public void setAccountName(String accountName) {

this.accountName = accountName;

}

}

[java] view
plain copy







package com.dhb.springmvc.entity.support;

import com.dhb.springmvc.base.entity.BaseEntity;

/**

* Created by ${denghb} on 2016/8/5.

*/

public class Address extends BaseEntity {

private String number;

private String street;

private String town;

private String postcode;

public String getNumber() {

return number;

}

public void setNumber(String number) {

this.number = number;

}

public String getStreet() {

return street;

}

public void setStreet(String street) {

this.street = street;

}

public String getTown() {

return town;

}

public void setTown(String town) {

this.town = town;

}

public String getPostcode() {

return postcode;

}

public void setPostcode(String postcode) {

this.postcode = postcode;

}

}

repository类:

[java] view
plain copy







package com.dhb.springmvc.repository;

import com.dhb.springmvc.entity.Customer;

import java.util.List;

/**

* Created by ${denghb} on 2016/8/8.

*/

public interface CustomerRepositoryEnhance {

public List<Customer> search(String keyword, String direction, String sort, int page, int size);

}

[java] view
plain copy







package com.dhb.springmvc.repository.impl;

import com.dhb.springmvc.entity.Customer;

import com.dhb.springmvc.repository.CustomerRepositoryEnhance;

import org.springframework.data.domain.PageRequest;

import org.springframework.data.domain.Sort;

import org.springframework.data.mongodb.core.MongoTemplate;

import org.springframework.data.mongodb.core.query.Criteria;

import org.springframework.data.mongodb.core.query.Query;

import javax.annotation.Resource;

import java.util.List;

/**

* Created by ${denghb} on 2016/8/8.

*/

public class CustomerRepositoryImpl implements CustomerRepositoryEnhance {

@Resource

private MongoTemplate mongoTemplate;

@Override

public List<Customer> search(String keyword, String direction, String sort, int page, int size) {

Query query = new Query();

Criteria c = new Criteria();

query.addCriteria(Criteria.where("name").is(keyword));

query.with(new Sort(Sort.Direction.valueOf(direction), sort));

query.with(new PageRequest(page - 1, size));

return mongoTemplate.find(query, Customer.class);

}

}

[java] view
plain copy







package com.dhb.springmvc.repository;

import com.dhb.springmvc.base.repository.BaseRepository;

import com.dhb.springmvc.entity.Customer;

import org.springframework.stereotype.Repository;

import java.util.List;

/**

* Created by ${denghb} on 2016/8/5.

*/

@Repository

public interface CustomerRepository extends BaseRepository<Customer, String>, CustomerRepositoryEnhance {

List<Customer> findByNameAndAddressNumberAndAccountsAccountName(

String name, String number, String accountName);

}

service类:

[java] view
plain copy







package com.dhb.springmvc.service;

import com.dhb.springmvc.entity.Customer;

import com.dhb.springmvc.repository.CustomerRepository;

import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import java.util.List;

/**

* Created by ${denghb} on 2016/8/5.

*/

@Service

public class CustomerService {

@Resource

private CustomerRepository customerRepository;

public void insertCustomer(Customer customer) {

customerRepository.save(customer);

}

public List<Customer> findAllCustomers() {

return customerRepository.findAll();

}

public void dropCustomerCollection() {

customerRepository.deleteAll();

}

public List<Customer> findByNameAndAddressNumberAndAccountsAccountName(String name, String number, String accountName) {

return customerRepository.findByNameAndAddressNumberAndAccountsAccountName(name, number,accountName);

}

public List<Customer> search(String keyword, String 
13948
;direction, String sort, int page, int size) {

return customerRepository.search(keyword, direction, sort, page, size);

}

}

restController类:

[java] view
plain copy







package com.dhb.springmvc.controller;

import com.dhb.springmvc.entity.Customer;

import com.dhb.springmvc.service.CustomerService;

import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

import java.util.List;

/**

* Created by ${denghb} on 2016/8/5.

*/

@RestController

@RequestMapping(value = "/v0.1/customer")

public class CustomerController {

@Resource

private CustomerService customerService;

@RequestMapping(value = "/get_all", method = RequestMethod.GET)

public Object findAllCustomerDetail() {

return customerService.findAllCustomers();

}

@RequestMapping(value = "/get_by/{name}/{number}/{accountName}", method = RequestMethod.GET)

public Object findByNameAndAddressNumberAndAccountsAccountName(@PathVariable String name, @PathVariable String number, @PathVariable String accountName) {

return customerService.findByNameAndAddressNumberAndAccountsAccountName(name, number, accountName);

}

@RequestMapping(value = "/search_by", method = RequestMethod.GET)

public List<Customer> search(@RequestParam(value= "query", defaultValue = "") String keyword,

@RequestParam(value= "direction", defaultValue = "DESC") String direction,

@RequestParam(value = "sort", defaultValue = "name") String sort,

@RequestParam(value = "page", defaultValue = "1") int page,

@RequestParam(value = "size", defaultValue = "30") int size) {

return customerService.search(keyword, direction, sort, page, size);

}

}

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

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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: