springboot集成mognoDB实现各种方式的查询
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
使用注解使得实体类对应数据库里面的一个集合,这里我抽取出来了一个公共的实体类
@Data
public class BaseMongoEntity implements Serializable {
@ApiModelProperty(value = "id")
@MongoId
private ObjectId id;
@ApiModelProperty(value = "创建时间")
private Date createTime;
@ApiModelProperty(value = "更新时间")
private Date updateTime;
@ApiModelProperty(value = "逻辑删除(1:启用,0:删除)")
private Integer status;
@ApiModelProperty(value = "其他参数")
@Transient //被该注解标注的,将不会被录入到数据库中。只作为普通的javaBean属性
private Map<String,Object> param = new HashMap<>();
}
@Data
@ApiModel(description = "article")
@Document("article")
public class ArticleEntity extends BaseMongoEntity {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "文章标题")
@Field("title")
private String title;
@ApiModelProperty(value = "作者ID")
@Field("author_id")
private String authorId;
@ApiModelProperty(value = "文章简介")
@Field("summary")
private String summary;
@ApiModelProperty(value = "文章浏览数")
@Field("view_counts")
private Long viewCounts;
@ApiModelProperty(value = "文章点赞数")
@Field("star_counts")
private Long starCounts;
@ApiModelProperty(value = "文章评论数")
@Field("comment_counts")
private Long commentCounts;
@ApiModelProperty(value = "文章专栏")
@Field("category")
private String category;
@ApiModelProperty(value = "文章标签")
@Field("tag_list")
private List<String> tagList;
@ApiModelProperty(value = "文章来源")
@Field("source")
private Integer source;
@ApiModelProperty(value = "文章置顶")
@Field("up")
private Integer up;
@ApiModelProperty(value = "文章精品")
@Field("exquisite")
private Integer exquisite;
@ApiModelProperty(value = "文章内容")
@Field("content")
private String content;
@ApiModelProperty(value = "文章内容html")
@Field("content_html")
private String contentHtml;
}
注意,如果想要使用一些高级的操作,最好让我们的这个接口去继承 MongoRepository
,这个泛型里面是两个参数,第一个是实体类的类名字,第二个是主键的类型
@Repository
public interface ArticleRepository extends MongoRepository<ArticleEntity, ObjectId> {
}
@NoRepositoryBean
public interface MongoRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
@Override
<S extends T> List<S> saveAll(Iterable<S> entities);
@Override
List<T> findAll();
@Override
List<T> findAll(Sort sort);
<S extends T> S insert(S entity);
<S extends T> List<S> insert(Iterable<S> entities);
@Override
<S extends T> List<S> findAll(Example<S> example);
@Override
<S extends T> List<S> findAll(Example<S> example, Sort sort);
}
可以看到上面的这个父类有一些基本的方法, 这样写过之后,我们自己定义的ArticleRepository会默认实现一些基础的CRUD操作,在Spring容器中注入进去即可以使用。
spring-data-mongo还是可以支持一些高级的操作的,比如他可以在我们自定义的dao层对象里面自定义方法,只要是可以被自动联想到的方法,我们将他写了出来都可以使用它
当然,联想并不只是那么简单
/**
* 查询文章总数
*
* @param id id
* @return {@link Long}
*/
Long countById(String id);
/**
* 找到所有由视图状态订单数量desc计数desc置评
*
* @param status 状态
* @param pageable 可分页
* @return {@link List}
*/
@Query(fields = "{ 'content' : 0, 'content_html' : 0}")
List<ArticleEntity> findAllByStatusOrderByViewCountsDescCommentCountsDesc(Integer status, Pageable pageable);
/**
* 根据文章内容进行左前缀模糊查询
*
* @param content 内容
* @return {@link List}
*/
List<ArticleEntity> findAllByContentStartsWith(String content);
/**
* 根据作者id分页查询文章
*
* @param autherId 作者id
* @param pageable 可分页
* @return {@link IPage}
*/
@Query(fields = "{ 'content' : 0, 'content_html' : 0}")
List<ArticleShowVo> findAllByAuthorIdOrderByCreateTimeDesc(String autherId, Pageable pageable);
/**
* 根据作者id查询他的文章数量
*
* @param autherId 作者id
* @return {@link Long}
*/
Integer countByAuthorId(String autherId);
/**
* 根据标签进行查询文章
* 置顶的放在最上面
* 并且根据浏览量降序排序,
*
* @param tagName 标签名
* @return {@link List}
*/
@Query(fields = "{ 'content' : 0, 'content_html' : 0}")
List<ArticleShowVo> findAllByTagListOrderByUpDescViewCountsDesc(String tagName, Pageable pageable);
/**
* 查询某标签下的所有文章数量
*
* @param tagName 标签名
* @return {@link Integer}
*/
Integer countByTagList(String tagName);
/**
* 根据文章的标题进行左前缀匹配查询
*
* @param status 状态
* @param title 标题
* @param pageable 可分页
* @return {@link List}
*/
@Query(fields = "{ 'content' : 0, 'content_html' : 0}")
List<ArticleShowVo> findByStatusAndTitleStartsWithOrderByUpDescViewCountsDesc(Integer status, String title, Pageable pageable);
/**
* 按类别数和地位
*
* @param category 类别
* @param status 状态
* @return {@link Integer}
*/
Integer countByCategoryAndStatus(String category,Integer status);
上述操作包含了排序、过滤、模糊查询、左前缀匹配查询、传入条件查询、将查询结果转换为另外一个对象、分页查询。下面整体的找一些比较有难度的来解答一下:
附:
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.whaleal.community.model.article.ArticleEntity;
import com.whaleal.community.vo.article.ArticleShowVo;
import org.bson.types.ObjectId;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* 注释存储库
*
* @author: jy
* @Date: 2021/07/05
*/
@Repository
public interface ArticleRepository extends MongoRepository<ArticleEntity, ObjectId> {
/**
* 查询文章总数
*
* @param id id
* @return {@link Long}
*/
Long countById(String id);
/**
* 找到所有由视图状态订单数量desc计数desc置评
*
* @param status 状态
* @param pageable 可分页
* @return {@link List}
*/
@Query(fields = "{ 'content' : 0, 'content_html' : 0}")
List<ArticleEntity> findAllByStatusOrderByViewCountsDescCommentCountsDesc(Integer status, Pageable pageable);
/**
* 根据文章内容进行左前缀模糊查询
*
* @param content 内容
* @return {@link List}
*/
List<ArticleEntity> findAllByContentStartsWith(String content);
/**
* 根据作者id分页查询文章
*
* @param autherId 作者id
* @param pageable 可分页
* @return {@link IPage}
*/
@Query(fields = "{ 'content' : 0, 'content_html' : 0}")
List<ArticleShowVo> findAllByAuthorIdOrderByCreateTimeDesc(String autherId, Pageable pageable);
/**
* 根据作者id查询他的文章数量
*
* @param autherId 作者id
* @return {@link Long}
*/
Integer countByAuthorId(String autherId);
/**
* 根据标签进行查询文章
* 置顶的放在最上面
* 并且根据浏览量降序排序,
*
* @param tagName 标签名
* @return {@link List}
*/
@Query(fields = "{ 'content' : 0, 'content_html' : 0}")
List<ArticleShowVo> findAllByTagListOrderByUpDescViewCountsDesc(String tagName, Pageable pageable);
/**
* 查询某标签下的所有文章数量
*
* @param tagName 标签名
* @return {@link Integer}
*/
Integer countByTagList(String tagName);
/**
* 根据文章的标题进行左前缀匹配查询
*
* @param status 状态
* @param title 标题
* @param pageable 可分页
* @return {@link List}
*/
@Query(fields = "{ 'content' : 0, 'content_html' : 0}")
List<ArticleShowVo> findByStatusAndTitleStartsWithOrderByUpDescViewCountsDesc(Integer status, String title, Pageable pageable);
/**
* 按类别数和地位
*
* @param category 类别
* @param status 状态
* @return {@link Integer}
*/
Integer countByCategoryAndStatus(String category,Integer status);
}
@Data
public class ArticleShowVo {
@ApiModelProperty(value = "id")
@MongoId
private ObjectId id;
@ApiModelProperty(value = "文章标题")
@Field("title")
private String title;
@ApiModelProperty(value = "作者ID")
@Field("author_id")
private String authorId;
@ApiModelProperty(value = "文章简介")
@Field("summary")
private String summary;
@ApiModelProperty(value = "文章浏览数")
@Field("view_counts")
private Long viewCounts;
@ApiModelProperty(value = "文章点赞数")
@Field("star_counts")
private Long starCounts;
@ApiModelProperty(value = "文章评论数")
@Field("comment_counts")
private Long commentCounts;
@ApiModelProperty(value = "文章专栏")
@Field("category")
private String category;
@ApiModelProperty(value = "文章标签")
@Field("tag_list")
private List<String> tagList;
@ApiModelProperty(value = "文章来源")
@Field("source")
private Integer source;
@ApiModelProperty(value = "文章置顶")
@Field("up")
private Integer up;
@ApiModelProperty(value = "文章精品")
@Field("exquisite")
private Integer exquisite;
@ApiModelProperty(value = "创建时间")
private Date createTime;
}
最后,尽管目前这个CRUD操作已经很强大,但是在实际的场景中还是会有一些我们意想不到的需求,而我目前还没有找到关于MongoDB的那种类似于Mybatis一样可以直接写sql的框架,所以暂时就只能自己手写代码往query里面添加一些操作了,虽然感觉这样对于数据库可能很不友好,但是目前也只能如此了。下面举出一个例子
public Page<ArticleEntity> listArticle(Integer page, Integer limit, ArticleQueryVo articleQueryVo) {
Pageable pageable = PageRequest.of(page - 1, limit);
ExampleMatcher matcher = ExampleMatcher.matching()
.withMatcher("title", ExampleMatcher.GenericPropertyMatchers.startsWith())
.withIgnoreNullValues()
.withIgnoreCase(true);
//shopSetQueryVo转换Shop对象
ArticleEntity article = new ArticleEntity();
BeanUtils.copyProperties(articleQueryVo, article);
Example<ArticleEntity> example = Example.of(article, matcher);
DBObject dbObject = new BasicDBObject();
BasicDBObject fieldsObject = new BasicDBObject();
//指定返回的字段
fieldsObject.put("content", false);
fieldsObject.put("content_html", false);
Query query = new BasicQuery(dbObject.toString(), fieldsObject.toString())
.addCriteria(new Criteria().alike(example))
.with(pageable);
long count = mongoTemplate.count(query, ArticleEntity.class);
if (count <= 0) {
//没有查询到符合条件到结果
return null;
}
mongoTemplate.find(query, ArticleEntity.class);
//创建对象
//调用方法实现查询,然后再将结果封装成为一个page对象
List<ArticleEntity> entities = mongoTemplate.find(query, ArticleEntity.class);
Page<ArticleEntity> pages = new PageImpl<>(entities, pageable, count);
return pages;
}
这些自定义的查询因为需要具体的实现,而我们如果使用spring-data-mongo的框架来做的话,就是自己去拼凑这个Repository,然后自己写里面的方法,但是它是一个接口,里面并没有具体的实现,我们要是想写具体的实现的话,大部分的人都是在service层面去写,但是这样的话肯定会造成一些逻辑上的不清晰,基于这样的问题,我找到了一个解决的方法,
这样就可以很好的解决这个问题了,一些简单的可以写的直接在继承了Repository的接口中去写,然后一些比较复杂的需要使用到MongoTemplate去操作的就在enhance里面去写。