一. 概述
参考开源项目https://github.com/xkcoding/spring-boot-demo
此Demo简单集成mongodb,使用官方的 starter 实现增删改查。
二. 安装mongodb
三. SpringBoot工程
3.1 依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> </dependency>
3.2 application.yml
spring: data: mongodb: host: localhost port: 27017 database: monge_demo logging: level: org.springframework.data.mongodb.core: debug
3.3 启动类
@SpringBootApplication public class SpringBootDemoMongodbApplication { public static void main(String[] args) { SpringApplication.run(SpringBootDemoMongodbApplication.class, args); } }
3.4 实体类: Article.java
@Document(collection = "UserInfo") @Data @Builder @NoArgsConstructor @AllArgsConstructor public class Article { /** * 文章id */ @Id private Long id; /** * 用户ID */ private Long userId; /** * 文章标题 */ private String title; /** * 文章内容 */ private String content; /** * 创建时间 */ private Date createTime; /** * 更新时间 */ private Date updateTime; /** * 点赞数量 */ private Long thumbUp; /** * 访客数量 */ private Long visits; }
3.5 持久层: ArticleRepository.java
public interface ArticleRepository extends MongoRepository<Article, Long> { /** * 根据标题模糊查询 * * @param title 标题 * @return 满足条件的文章列表 */ List<Article> findByTitleLike(String title); }
注: 可以通过关键字声明方法, 不用写实现
下标源于文章MongoRepository的生成规则
3.6 简单的CURD
@Slf4j @RunWith(SpringRunner.class) @SpringBootTest public class ArticleRepositoryTest { @Autowired private ArticleRepository articleRepo; @Autowired private MongoTemplate mongoTemplate; private static Snowflake snowflake = IdUtil.createSnowflake(1, 1); /** * 测试新增 */ @Test public void testSave() { Article article = new Article(1L, RandomUtil.randomString(20), RandomUtil.randomString(150), DateUtil.date(), DateUtil.date(), 0L, 0L); articleRepo.save(article); // 更具ID属性进行新增或更新 mongoTemplate.save(article); log.info("【article】= {}", JSONUtil.toJsonStr(article)); } /** * 测试批量新增列表 */ @Test public void testSaveList() { List<Article> articles = Lists.newArrayList(); for (int i = 0; i < 10; i++) { articles.add(new Article(snowflake.nextId(), RandomUtil.randomString(20), RandomUtil.randomString(150), DateUtil.date(), DateUtil.date(), 0L, 0L)); } articleRepo.saveAll(articles); log.info("【articles】= {}", JSONUtil.toJsonStr(articles.stream().map(Article::getId).collect(Collectors.toList()))); } /** * 测试更新 */ @Test public void testUpdate() { articleRepo.findById(1L).ifPresent(article -> { article.setTitle(article.getTitle() + "更新之后的标题"); article.setUpdateTime(DateUtil.date()); articleRepo.save(article); log.info("【article】= {}", JSONUtil.toJsonStr(article)); }); } /** * 测试删除 */ @Test public void testDelete() { // 根据主键删除 articleRepo.deleteById(1L); // 全部删除 articleRepo.deleteAll(); } /** * 测试分页排序查询 */ @Test public void testQuery() { Sort sort = Sort.by("thumbUp", "updateTime").descending(); PageRequest pageRequest = PageRequest.of(0, 5, sort); Page<Article> all = articleRepo.findAll(pageRequest); log.info("【总页数】= {}", all.getTotalPages()); log.info("【总条数】= {}", all.getTotalElements()); log.info("【当前页数据】= {}", JSONUtil.toJsonStr(all.getContent().stream().map(article -> "文章标题:" + article.getTitle() + "点赞数:" + article.getThumbUp() + "更新时间:" + article.getUpdateTime()).collect(Collectors.toList()))); } }
3.7 更新
@Slf4j @RunWith(SpringRunner.class) @SpringBootTest public class ArticleRepositoryTest { @Autowired private ArticleRepository articleRepo; @Autowired private MongoTemplate mongoTemplate; /** * 测试点赞数、访客数,使用save方式更新点赞、访客 */ @Test public void testThumbUp() { articleRepo.findById(1L).ifPresent(article -> { article.setThumbUp(article.getThumbUp() + 1); article.setVisits(article.getVisits() + 1); articleRepo.save(article); log.info("【标题】= {}【点赞数】= {}【访客数】= {}", article.getTitle(), article.getThumbUp(), article.getVisits()); }); } /** * 测试点赞数、访客数,使用更优雅/高效的方式更新点赞、访客 */ @Test public void testThumbUp2() { Query query = new Query(); query.addCriteria(Criteria.where("_id").is(1L)); Update update = new Update(); update.inc("thumbUp", 1L); update.inc("visits", 1L); mongoTemplate.updateFirst(query, update, "article"); articleRepo.findById(1L).ifPresent(article -> log.info("【标题】= {}【点赞数】= {}【访客数】= {}", article.getTitle(), article.getThumbUp(), article.getVisits())); } }
3.8 高级查询
@Slf4j @RunWith(SpringRunner.class) @SpringBootTest public class ArticleRepositoryTest { @Autowired private ArticleRepository articleRepo; @Autowired private MongoTemplate mongoTemplate; /** * 查询,条件匹配/排序/分页, 基于继承MongoRepository实现 */ @Test public void testQuery1() { /** * 匹配条件构造 */ Article article = Article.builder() .title("ayyg6qetc2jigduentiz") .content("tx1549k4dbu05ou83tx8te0gx1") .build(); // 指定字段匹配类型 ExampleMatcher withMatcher = ExampleMatcher.matching() // 忽略大小写 .withIgnoreCase() // 指定"title"为精确匹配 .withMatcher("title", ExampleMatcher.GenericPropertyMatcher::exact) // 指定"content"为模糊匹配 .withMatcher("content", ExampleMatcher.GenericPropertyMatcher::contains); Example<Article> example = Example.of(article,withMatcher); /** * 排序规则 */ Sort sort = Sort.by("updateTime").descending(); /** * 分页 */ PageRequest pageRequest = PageRequest.of(0, 5, sort); /** * 分页查询 */ Page<Article> articleRepoAll = articleRepo.findAll(example, pageRequest); /** * 打印 */ log.info(JSONUtil.toJsonStr(articleRepoAll.getContent())); } /** * 查询,条件匹配/排序/分页, 基于MongoTemplate实现 */ @Test public void testQuery2() { /** * 查询条件 */ Criteria criteria = Criteria // 精确匹配 .where("title").is("ayyg6qetc2jigduentiz") // 模糊匹配, 用正则: .*[xxx].* .and("content").regex(".*tx1549k4dbu05ou83tx8te0gx1.*") // 匹配明细里的字段 .and("ids").elemMatch(Criteria.where("id").is(1)) // 匹配多个并行或 .andOperator( new Criteria().orOperator( Criteria.where("visits").exists(false), Criteria.where("visits").is(1) ), new Criteria().orOperator( Criteria.where("thumbUp").exists(false), Criteria.where("thumbUp").is(1) ) ); ; /** * 排序规则 */ Sort sort = Sort.by("updateTime").descending(); /** * 分页 */ PageRequest pageRequest = PageRequest.of(1, 5, sort); Query query = Query.query(criteria).with(sort).with(pageRequest); List<Article> articles = mongoTemplate.find(query, Article.class); PageImpl<Article> page = (PageImpl<Article>) PageableExecutionUtils.getPage(articles, pageRequest, () -> mongoTemplate.count(Query.query(criteria),Article.class)); // 打印 Optional.of(page.getContent()).ifPresent(articles1 -> { articles1.forEach(article -> { log.info("打印数据:{}",JSONUtil.toJsonStr(article)); }); }); } }
3.9 MongoTemplate 实现 联表/分页/排序查询
public IPage<Article> pageInfo(){ /** * 联表查询 * 参数1: 从表表名 * 参数2: 主表关联字段 * 参数3: 从表关联字段 * 参数4: 查出从表数据集合的别名 例如主表数据{"name":"wpr","age":18} , 关联从表后结果{"name":"wpr","age":18,"userInfo":[]}, 从表没数据则为[] */ LookupOperation lookup = Aggregation.lookup("user", "userId", "userId", "userInfo"); // 子集合不能为空 Criteria criteria = Criteria.where("userInfo").not().size(0); // 子集合条件 criteria.and("userInfo.six").is(1); // 主表条件 criteria.and("title").is("hello_world"); // 条件类型转换 MatchOperation matchOperation = Aggregation.match(criteria); /** * 查询总数 */ CountOperation countOperation = Aggregation.count().as("total"); // project: 表示结果只查询字段:total ProjectionOperation project = Aggregation.project("total"); // 条件一定要排好先后顺序 Aggregation aggregation = Aggregation.newAggregation(lookup, matchOperation, countOperation, project); AggregationResults<Map> aggregate = mongoTemplate.aggregate(aggregation, "article", Map.class); List<Map> aggregateMappedResults = aggregate.getMappedResults(); // 总数 Integer total = CollectionUtils.isEmpty(aggregateMappedResults) ? 0 : (int)aggregateMappedResults.get(0).get("total"); if(Objects.equals(total,0)){ return new Page<>(); } /** * 分页查询 */ // 排序条件 SortOperation sortOperation = Aggregation.sort(Sort.by("updateTime").descending()); // 过滤前n条数据 SkipOperation skipOperation = Aggregation.skip(0L); // 查询n条数据 LimitOperation limitOperation = Aggregation.limit(10); Aggregation pageAggregation = Aggregation.newAggregation(lookup, matchOperation, sortOperation,skipOperation,limitOperation); AggregationResults<Article> result = mongoTemplate.aggregate(pageAggregation,"article", Article.class); List<Article> articles = result.getMappedResults(); Page<Article> page = new Page<>(); page.setTotal(total); page.setRecords(articles); return page; }