通常我们使用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();
}
}
现在我想让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。