在控制台输出nosql的日志
#打印mongodb日志
logging.level.org.springframework.data.mongodb.core= DEBUG
查询抛ConverterNotFoundException异常
org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [java.util.Date] to type [java.sql.Timestamp]
解决方法
- 自定义转换器
package com.zx.mongoconfig;
import org.springframework.core.convert.converter.Converter;
import java.sql.Timestamp;
import java.util.Date;
public class TimestampConverter implements Converter<Date, Timestamp> {
@Override
public Timestamp convert(Date date) {
if (date != null) {
return new Timestamp(date.getTime());
}
return null;
}
}
- 配置MongoTemplate
@Bean
@Primary
public MongoTemplate template(MappingMongoConverter mappingMongoConverter) {
return new MongoTemplate(factory(), mappingMongoConverter);
}
@Bean
public MappingMongoConverter mappingMongoConverter(MongoDbFactory mongoDbFactory, BeanFactory beanFactory, CustomConversions customConversions) {
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory);
MongoMappingContext mongoMappingContext = new MongoMappingContext();
MappingMongoConverter mappingMongoConverter = new MappingMongoConverter(dbRefResolver, mongoMappingContext);
mappingMongoConverter.setCustomConversions(beanFactory.getBean(CustomConversions.class));
mappingMongoConverter.setTypeMapper(new DefaultMongoTypeMapper(null));//去掉默认mapper添加的_class
mappingMongoConverter.setCustomConversions(customConversions);//添加自定义的转换器
return mappingMongoConverter;
}
@Bean
public CustomConversions customConversions() {
List list = new ArrayList();
list.add(new TimestampConverter());
return new CustomConversions(list);
}
CRUD操作
常用方法
mongoTemplate.findAll(Student.class): //查询Student文档的全部数据
mongoTemplate.findById(<id>, Student.class): //查询Student文档id为id的数据
mongoTemplate.find(query, Student.class);: //根据query内的查询条件查询
mongoTemplate.upsert(query, update, Student.class): //修改
mongoTemplate.remove(query, Student.class): //删除
mongoTemplate.insert(student): //新增
若字段值为null,则新增操作不会入库
Query对象
- 创建一个query对象(用来封装所有条件对象),再创建一个criteria对象(用来构建条件)
- 精准条件:criteria.and(“key”).is(“条件”)
模糊条件:criteria.and(“key”).regex(“条件”) - 封装条件:query.addCriteria(criteria)
- 大于(创建新的criteria):Criteria gt = Criteria.where(“key”).gt(“条件”)
小于(创建新的criteria):Criteria lt = Criteria.where(“key”).lt(“条件”) - Query.addCriteria(new Criteria().andOperator(gt,lt));
- 一个query中只能有一个andOperator()。其参数也可以是Criteria数组。
- 排序 :query.with(new Sort(Sort.Direction.ASC, “age”). and(new Sort(Sort.Direction.DESC, “date”)))
多条件分页查询
1、使用limit和skip进行分页查询
//模糊查询
String regex = String.format("%s%s%s", "^.*", username, ".*$");
Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
Query query = new Query(Criteria.where("formid").is(formid)
.and("name").regex(pattern));
//排序
query.with(new Sort(new Sort.Order(Sort.Direction.DESC, "zxitime"), new Sort.Order(Sort.Direction.DESC, "zxscore")));
//分页
query.skip((pageNum-1)*pageSize).limit(pageSize);
List<FormDataEntity> datas = this.mongoTemplate.find(query, FormDataEntity.class, CollectionName.FORM_DATA);
通过skip和limit方法可以简单的实现分页操作,但是如果数据量特别巨大的时候,会出现性能的问题,不建议使用!
2、通过原生的方法实现条件查询、分页和排序
public Page<User> getPageByOriginalFunction(int age,int pageNUmber,int pageSize){
//查询条件,可以传递多个查询条件
User user = new User();
user.setAge(age);
Example<User> example = Example.of(user);
//分页条件
//Pageable pageable = new PageRequest(pageNUmber,pageSize);
Pageable pageable = PageRequest.of(pageNUmber,pageSize);
return userRepository.findAll(example,pageable);
}
//查询结果
{
"content": [
{
"id": "5cfb69ee4332ce07b864d12e",
"name": "lsr",
"pwd": "123456",
"age": 18
}
],
"pageable": {
"sort": {
"sorted": false,
"unsorted": true
},
"offset": 0,
"pageSize": 2,
"pageNumber": 0,
"unpaged": false,
"paged": true
},
"last": true,
"totalPages": 1,
"totalElements": 1,
"number": 0,
"size": 2,
"sort": {
"sorted": false,
"unsorted": true
},
"first": true,
"numberOfElements": 1
}
3、通过实现Pageable接口
- 创建自定义分页类,实现Pageable接口
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import javax.validation.constraints.Min;
@NoArgsConstructor
@AllArgsConstructor
public class SpringDataPageAble implements Pageable {
@Min(1)
private Integer pageNumber = 1;
@Min(1)
private Integer pageSize = 10;
private Sort sort;
public void setSort(Sort sort) {
this.sort = sort;
}
// 当前页面
@Override
public int getPageNumber() {
return this.pageNumber;
}
// 每一页显示的条数
@Override
public int getPageSize() {
return getPagesize();
}
// 第二页所需要增加的数量
@Override
public long getOffset() {
return (getPageNumber() - 1) * getPagesize();
}
@Override
public Sort getSort() {
return sort;
}
public void setPagenumber(Integer pagenumber) {
this.pageNumber = pageNumber;
}
public Integer getPagesize() {
return this.pageSize;
}
public void setPagesize(Integer pagesize) {
this.pageSize = pagesize;
}
@Override
public Pageable next() {
return null;
}
@Override
public Pageable previousOrFirst() {
return null;
}
@Override
public Pageable first() {
return null;
}
@Override
public boolean hasPrevious() {
return false;
}
}
- 在repository层定义分页方法
import com.tedu.huawei.entity.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;
@Repository //注意MongoRepository后面接的泛型<User, String>第一个为实体类,第二个为主键ID
public interface UserRepository extends MongoRepository<User,String> {
Page<User> getUserByPageAble(int age, Pageable pageAble);
}
- service层调用方法
public Page<User> getUserByPageAble(int age, int pageNumber,int pageSize){
SpringDataPageAble springDataPageAble = new SpringDataPageAble(pageNumber,pageSize,new Sort(Sort.Direction.ASC,"age"));
return userRepository.getUserByPageAble(age,springDataPageAble);
}
// 查询结果
{
"content": [
{
"id": "5cfb66114332ce07b864d12d",
"name": "lsr",
"pwd": "123456",
"age": 18
},
{
"id": "5cfb85084332ce4ffca97907",
"name": "panzi",
"pwd": "654321",
"age": 24
}
],
"pageable": {
"pageNumber": 1,
"pageSize": 2,
"sort": {
"sorted": true,
"unsorted": false
},
"offset": 0,
"pagesize": 2,
"unpaged": false,
"paged": true
},
"last": true,
"totalPages": 1,
"totalElements": 2,
"number": 1,
"size": 2,
"sort": {
"sorted": true,
"unsorted": false
},
"first": false,
"numberOfElements": 2
}
4、总结
第一种方式实现简单方便,但是不适用于大数据量。第二种分页是原生的方法,不需要做额外的处理,但是查询条件单一,不能设置大于等于或者在某某之间,以及模糊查询有很大的限制。第三种方式实现也很简单,但是更加开放和使用性能好。