[SpringBoot实践]spring-data-mongo自定义Repository接口及其实现

来源:互联网 发布:ios 可变字典添加数据 编辑:程序博客网 时间:2024/06/06 23:55

概述

通常我们使用spring-data-mongo时,会让我们的Repository(如UserRepository)继承MongoRepository接口,然后编写业务方法。碰到需要自定义实现代码的时候,就编写UserRepositoryImpl类。不管如何都是非常方便的。

但是有时候的一些方法是需要通用的,比如通过Criteria进行查询(MongoRepository没有相关的方法提供。可能是小弟没有发现,有误的话希望大家可以指出^-^)。

不多说,开始搬砖。

创建项目

说明

这里直接用Spring-boot快速创建项目,pom.xml如下:

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">    <parent>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-parent</artifactId>        <version>1.3.3.RELEASE</version>    </parent>    <modelVersion>4.0.0</modelVersion>    <artifactId>dpos-repository</artifactId>    <dependencies>        <dependency>            <groupId>org.scala-lang</groupId>            <artifactId>scala-library</artifactId>            <version>${scala.version}</version>        </dependency>        <dependency>            <groupId>com.alibaba</groupId>            <artifactId>fastjson</artifactId>            <version>${fastjson.version}</version>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-data-mongodb</artifactId>        </dependency>    </dependencies></project>

然后我们定义实体类User

@Documentpublic class User extends BaseEntity{    private String name;    private String password;    //各种setter,getter}

方案一

编写Repository接口

public interface UserRepository extends MongoRepository<User, String> {    /**     *     * @param criteria     * @param pageable     * @return     */    Page<User> find(Criteria criteria, Pageable pageable);}

然后编写实现类UserRepositoryImpl

public class UserRepositoryImpl{    @Autowired    protected MongoTemplate mongoTemplate;    /**     * @param criteria     * @param pageable     * @return     */    Page<User> find(Criteria criteria, Pageable pageable){        Query query=new Query(criteria);        final long total=mongoTemplate.count(query, User.class);        final List<User> list=mongoTemplate.find(query.with(pageable), User.class);        return new PageImpl<User>(list, pageable, total);    }}

最后写一个测试用例看看我们的代码是否正确

public class UserRepoTest extends TestOnSpring{    protected final String password="123456";    final String[] names=new String[]{"张三","李四"};    protected Pageable pageable=new PageRequest(0,10);    protected static Logger logger= LoggerFactory.getLogger(UserRepoTest.class);    @Autowired    private UserRepository userRepo;    /**     * 插入数据     */    @Before    public void init(){        inserTestData();    }    private void inserTestData(){        for(String n:names){            User u=new User();            u.setName(n).setPassword(password);            userRepo.save(u);            logger.info("插入用户:{}",u.toString());        }    }    @Test    public void select(){        List<User> users=userRepo.findAll();        assertThat(users.size(), is(2));        assertThat(users.get(0).getPassword(), is(password));        assertThat(users.get(0).getName(), is(names[0]));    }    @Test    public void findByCriteria(){        Page<User> page=userRepo.find(Criteria.where("password").is(password), pageable);        assertThat(page.getTotalElements(), is(2L));        page = userRepo.find(Criteria.where("name").is(names[0]),pageable);        assertThat(page.getTotalElements(), is(1L));        assertThat(page.getContent().get(0).getName(), is(names[0]));    }    @After    public void clear(){        logger.info("清空全部的测试数据......");        userRepo.deleteAll();    }}

运行结果:
这里写图片描述

定义统一接口

现在我想让find(Criteria criteria,Pageable pageable)作为一个统一的方法,即有新的实体需要操作时不需要重复实现。
首先,定义我们的CommonRepository(因为项目是用scala编写,这里贴出来的是scala的实现)

/**  * 通用的Repository  * Created by zengxm on 2016/4/14 0014.  */@NoRepositoryBeantrait CommonRepository[T,ID<:java.io.Serializable] extends MongoRepository[T,ID]{  def find(query:Query, p: Pageable):Page[T]  def find(criteria: Criteria, p: Pageable):Page[T]}

注意,要加上@NoRepositoryBean 注解,避免spring扫描CommonRepository。

然后编写实现类

class CommonRepositoryImpl[T, ID<:java.io.Serializable](matedata:MongoEntityInformation[T,ID],mongoOp:MongoOperations)  extends SimpleMongoRepository[T,ID](matedata, mongoOp)    with CommonRepository[T,ID]  {    override def find(query: Query, p: Pageable): Page[T] = {      val total=mongoOp.count(query, matedata.getJavaType)      val list=mongoOp.find(query.`with`(p), matedata.getJavaType)      new PageImpl[T](list, p, total)    }    override def find(criteria: Criteria, p: Pageable): Page[T] = find(new Query(criteria), p)}

附上java版本的实现代码:

public class CommonMongoRepositoryImpl<T, ID extends Serializable> extends SimpleMongoRepository<T,ID> implements CommonRepository<T,ID> {    protected final MongoOperations mongoTemplate;    protected final MongoEntityInformation<T, ID> entityInformation;    public CommonMongoRepositoryImpl(MongoEntityInformation<T, ID> metadata, MongoOperations mongoOperations) {        super(metadata, mongoOperations);        this.mongoTemplate=mongoOperations;        this.entityInformation = metadata;    }    protected Class<T> getEntityClass(){        return entityInformation.getJavaType();    }    @Override    public Page<T> find(Query query, Pageable p) {        long total=mongoTemplate.count(query, getEntityClass());        List<T> list=mongoTemplate.find(query.with(p), getEntityClass());        return new PageImpl<T>(list, p, total);    }    @Override    public Page<T> find(Criteria criteria, Pageable p) {        return find(new Query(criteria), p);    }}

最后我们需要告诉Spring使用CommonRepositoryImpl作为默认的Repository实现类。

/**  * 配置默认的Repository实现类为CommonRepositoryImpl,代替SimpleMongoRepository  *  * 同时修改默认的Repository扫描目录为 com.test  * Created by zengxm on 2016/4/14 0014.  */@Configuration@EnableMongoRepositories(repositoryBaseClass = classOf[CommonRepositoryImpl[_, _]], basePackages = Array("com.test"))class Config {}

然后UserRepository就可以继承CommonRepository了。
重新运行测试用例,结果与方案一一致。至此,功能OK。

2 0