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

概述

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

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

不多说,开始搬砖。

创建项目

说明

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

"1.0" encoding="UTF-8"?>
"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">
    
        org.springframework.boot
        spring-boot-starter-parent
        1.3.3.RELEASE
    

    4.0.0

    dpos-repository

    
        
            org.scala-lang
            scala-library
            ${scala.version}
        

        
            com.alibaba
            fastjson
            ${fastjson.version}
        

        
            org.springframework.boot
            spring-boot-starter-data-mongodb
        
    

然后我们定义实体类User

@Document
public 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 find(Criteria criteria, Pageable pageable);
}

然后编写实现类UserRepositoryImpl

public class UserRepositoryImpl{

    @Autowired
    protected MongoTemplate mongoTemplate;

    /**
     * @param criteria
     * @param pageable
     * @return
     */
    Page find(Criteria criteria, Pageable pageable){
        Query query=new Query(criteria);
        final long total=mongoTemplate.count(query, User.class);
        final List list=mongoTemplate.find(query.with(pageable), User.class);

        return new PageImpl(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 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 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();
    }
}

运行结果:
[SpringBoot实践]spring-data-mongo自定义Repository接口及其实现_第1张图片

定义统一接口

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

/**
  * 通用的Repository
  * Created by zengxm on 2016/4/14 0014.
  */
@NoRepositoryBean
trait 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 entityInformation;

    public CommonMongoRepositoryImpl(MongoEntityInformation metadata, MongoOperations mongoOperations) {
        super(metadata, mongoOperations);

        this.mongoTemplate=mongoOperations;
        this.entityInformation = metadata;
    }

    protected Class getEntityClass(){
        return entityInformation.getJavaType();
    }

    @Override
    public Page find(Query query, Pageable p) {
        long total=mongoTemplate.count(query, getEntityClass());
        List list=mongoTemplate.find(query.with(p), getEntityClass());

        return new PageImpl(list, p, total);
    }

    @Override
    public Page 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。

你可能感兴趣的:(那年开始的java)