烹饪披萨机
110.73M · 2026-03-10
大家好,我是小悟。
业务场景:开发一个博客文章管理系统
技术需求:
安装MongoDB
# MacOS
brew install mongodb-community
brew services start mongodb-community
# 验证安装
mongo --version
pom.xml依赖配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="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
d">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
</parent>
<groupId>com.example</groupId>
<artifactId>mongodb-demo</artifactId>
<version>1.0.0</version>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Data MongoDB -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!-- Lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml
spring:
data:
mongodb:
host: localhost
port: 27017
database: blogdb
# 如果需要认证
# username: admin
# password: admin123
# authentication-database: admin
server:
port: 8080
logging:
level:
org.springframework.data.mongodb: DEBUG
Article.java
package com.example.mongodb.entity;
import lombok.Data;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import java.time.LocalDateTime;
import java.util.List;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "articles") // 指定集合名称
public class Article {
@Id
private String id; // MongoDB默认使用ObjectId,这里用String接收
@Indexed(unique = true) // 创建唯一索引
private String title;
@Field("content") // 指定字段名
private String content;
private String author;
private List<String> tags;
private Integer viewCount;
private List<Comment> comments;
@Field("createTime")
private LocalDateTime createTime;
@Field("updateTime")
private LocalDateTime updateTime;
private Boolean published;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class Comment {
private String username;
private String content;
private LocalDateTime commentTime;
private Integer likes;
}
}
使用MongoRepository方式
package com.example.mongodb.repository;
import com.example.mongodb.entity.Article;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface ArticleRepository extends MongoRepository<Article, String> {
// 根据作者查询
List<Article> findByAuthor(String author);
// 根据标签查询
List<Article> findByTagsIn(List<String> tags);
// 根据标题模糊查询
List<Article> findByTitleLike(String title);
// 根据发布时间范围查询
List<Article> findByCreateTimeBetween(LocalDateTime start, LocalDateTime end);
// 使用@Query注解自定义查询
@Query("{'title': {$regex: ?0}, 'published': true}")
List<Article> findPublishedArticlesByTitle(String title);
// 复杂的嵌套查询
@Query("{'comments.username': ?0}")
List<Article> findByCommentUsername(String username);
}
使用MongoTemplate方式
package com.example.mongodb.repository;
import com.example.mongodb.entity.Article;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public class ArticleTemplateRepository {
@Autowired
private MongoTemplate mongoTemplate;
// 条件查询
public List<Article> findByCondition(String keyword, String author) {
Query query = new Query();
// 添加查询条件
if (keyword != null && !keyword.isEmpty()) {
query.addCriteria(Criteria.where("title").regex(keyword)
.orOperator(Criteria.where("content").regex(keyword)));
}
if (author != null && !author.isEmpty()) {
query.addCriteria(Criteria.where("author").is(author));
}
// 只查询已发布的文章
query.addCriteria(Criteria.where("published").is(true));
// 排序
query.with(Sort.by(Sort.Direction.DESC, "createTime"));
return mongoTemplate.find(query, Article.class);
}
// 更新评论点赞数
public void updateCommentLikes(String articleId, String commentUsername, int increment) {
Query query = new Query(Criteria.where("id").is(articleId)
.and("comments.username").is(commentUsername));
Update update = new Update().inc("comments.$.likes", increment);
mongoTemplate.updateFirst(query, update, Article.class);
}
// 增加文章浏览量
public void incrementViewCount(String articleId) {
Query query = new Query(Criteria.where("id").is(articleId));
Update update = new Update().inc("viewCount", 1);
mongoTemplate.updateFirst(query, update, Article.class);
}
// 批量更新
public void updateArticlesStatusByAuthor(String author, Boolean status) {
Query query = new Query(Criteria.where("author").is(author));
Update update = new Update().set("published", status);
mongoTemplate.updateMulti(query, update, Article.class);
}
}
package com.example.mongodb.service;
import com.example.mongodb.entity.Article;
import com.example.mongodb.repository.ArticleRepository;
import com.example.mongodb.repository.ArticleTemplateRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@Service
public class ArticleService {
@Autowired
private ArticleRepository articleRepository;
@Autowired
private ArticleTemplateRepository articleTemplateRepository;
// 创建文章
public Article createArticle(Article article) {
article.setId(null); // 确保是新文章
article.setCreateTime(LocalDateTime.now());
article.setUpdateTime(LocalDateTime.now());
article.setViewCount(0);
return articleRepository.save(article);
}
// 更新文章
public Article updateArticle(String id, Article article) {
return articleRepository.findById(id)
.map(existingArticle -> {
article.setId(id);
article.setCreateTime(existingArticle.getCreateTime());
article.setUpdateTime(LocalDateTime.now());
return articleRepository.save(article);
})
.orElseThrow(() -> new RuntimeException("文章不存在"));
}
// 删除文章
public void deleteArticle(String id) {
articleRepository.deleteById(id);
}
// 查询单篇文章
public Article getArticle(String id) {
return articleRepository.findById(id)
.map(article -> {
// 阅读量+1
articleTemplateRepository.incrementViewCount(id);
article.setViewCount(article.getViewCount() + 1);
return article;
})
.orElseThrow(() -> new RuntimeException("文章不存在"));
}
// 查询所有文章
public List<Article> getAllArticles() {
return articleRepository.findAll();
}
// 根据作者查询
public List<Article> getArticlesByAuthor(String author) {
return articleRepository.findByAuthor(author);
}
// 条件搜索
public List<Article> searchArticles(String keyword, String author) {
return articleTemplateRepository.findByCondition(keyword, author);
}
// 添加评论
public Article addComment(String articleId, Article.Comment comment) {
return articleRepository.findById(articleId)
.map(article -> {
comment.setCommentTime(LocalDateTime.now());
comment.setLikes(0);
article.getComments().add(comment);
article.setUpdateTime(LocalDateTime.now());
return articleRepository.save(article);
})
.orElseThrow(() -> new RuntimeException("文章不存在"));
}
// 点赞评论
public void likeComment(String articleId, String username) {
articleTemplateRepository.updateCommentLikes(articleId, username, 1);
}
}
package com.example.mongodb.controller;
import com.example.mongodb.entity.Article;
import com.example.mongodb.service.ArticleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/articles")
public class ArticleController {
@Autowired
private ArticleService articleService;
@PostMapping
public ResponseEntity<Article> createArticle(@RequestBody Article article) {
Article created = articleService.createArticle(article);
return new ResponseEntity<>(created, HttpStatus.CREATED);
}
@PutMapping("/{id}")
public ResponseEntity<Article> updateArticle(@PathVariable String id,
@RequestBody Article article) {
Article updated = articleService.updateArticle(id, article);
return ResponseEntity.ok(updated);
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteArticle(@PathVariable String id) {
articleService.deleteArticle(id);
return ResponseEntity.noContent().build();
}
@GetMapping("/{id}")
public ResponseEntity<Article> getArticle(@PathVariable String id) {
Article article = articleService.getArticle(id);
return ResponseEntity.ok(article);
}
@GetMapping
public ResponseEntity<List<Article>> getAllArticles() {
List<Article> articles = articleService.getAllArticles();
return ResponseEntity.ok(articles);
}
@GetMapping("/search")
public ResponseEntity<List<Article>> searchArticles(
@RequestParam(required = false) String keyword,
@RequestParam(required = false) String author) {
List<Article> articles = articleService.searchArticles(keyword, author);
return ResponseEntity.ok(articles);
}
@PostMapping("/{id}/comments")
public ResponseEntity<Article> addComment(
@PathVariable String id,
@RequestBody Article.Comment comment) {
Article article = articleService.addComment(id, comment);
return ResponseEntity.ok(article);
}
@PostMapping("/{id}/comments/{username}/like")
public ResponseEntity<Void> likeComment(
@PathVariable String id,
@PathVariable String username) {
articleService.likeComment(id, username);
return ResponseEntity.ok().build();
}
}
package com.example.mongodb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.mongodb.config.EnableMongoAuditing;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
@SpringBootApplication
@EnableMongoRepositories // 启用MongoDB仓库
@EnableMongoAuditing // 启用MongoDB审计功能
public class MongodbApplication {
public static void main(String[] args) {
SpringApplication.run(MongodbApplication.class, args);
}
}
package com.example.mongodb.config;
import com.example.mongodb.entity.Article;
import com.example.mongodb.repository.ArticleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.util.Arrays;
@Component
public class DataInitializer implements CommandLineRunner {
@Autowired
private ArticleRepository articleRepository;
@Override
public void run(String... args) throws Exception {
// 清空数据
articleRepository.deleteAll();
// 创建测试文章
Article article1 = Article.builder()
.title("Spring Boot 入门教程")
.content("本文将介绍Spring Boot的基本使用方法...")
.author("张三")
.tags(Arrays.asList("Java", "Spring Boot", "教程"))
.viewCount(0)
.published(true)
.createTime(LocalDateTime.now())
.updateTime(LocalDateTime.now())
.comments(Arrays.asList(
Article.Comment.builder()
.username("李四")
.content("写的很好,学习了!")
.commentTime(LocalDateTime.now())
.likes(5)
.build()
))
.build();
Article article2 = Article.builder()
.title("MongoDB 实战技巧")
.content("分享MongoDB在实际项目中的应用经验...")
.author("王五")
.tags(Arrays.asList("数据库", "MongoDB", "实战"))
.viewCount(0)
.published(true)
.createTime(LocalDateTime.now())
.updateTime(LocalDateTime.now())
.comments(Arrays.asList())
.build();
articleRepository.saveAll(Arrays.asList(article1, article2));
System.out.println("测试数据初始化完成!");
}
}
使用curl测试API
# 创建文章
curl -X POST http://localhost:8080/api/articles
-H "Content-Type: application/json"
-d '{
"title": "MongoDB高级特性",
"content": "本文将介绍MongoDB的高级特性...",
"author": "赵六",
"tags": ["MongoDB", "数据库", "高级"],
"published": true
}'
# 查询所有文章
curl http://localhost:8080/api/articles
# 搜索文章
curl "http://localhost:8080/api/articles/search?keyword=Spring&author=张三"
# 添加评论
curl -X POST http://localhost:8080/api/articles/{id}/comments
-H "Content-Type: application/json"
-d '{
"username": "读者A",
"content": "非常实用的教程!"
}'
# 点赞评论
curl -X POST http://localhost:8080/api/articles/{id}/comments/读者A/like
| 特性 | MongoDB | MySQL |
|---|---|---|
| 数据结构 | 文档型(BSON/JSON) | 表格(行/列) |
| 关联查询 | 内嵌文档或DBRef | JOIN操作 |
| Schema | 动态schema | 固定schema |
| 扩展性 | 原生支持水平扩展 | 主从复制/分库分表 |
| 事务支持 | 4.0后支持多文档事务 | 完整ACID支持 |
| 注解 | 作用 |
|---|---|
| @Document | 映射MongoDB的集合 |
| @Id | 标识文档ID字段 |
| @Field | 指定字段名 |
| @Indexed | 声明索引 |
| @CompoundIndex | 复合索引 |
| @DBRef | 引用其他集合(谨慎使用) |
| @Transactional | 支持事务操作 |
MongoRepository的优点:
MongoTemplate的优点:
1. 索引设计
2. 性能优化
// 分页查询示例
Pageable pageable = PageRequest.of(0, 10, Sort.by("createTime").descending());
Page<Article> page = articleRepository.findAll(pageable);
// 只返回需要的字段
Query query = new Query();
query.fields().include("title").include("author");
3. 数据一致性
@Transactional
public void updateWithTransaction(String articleId, Comment comment) {
// 确保两个操作原子性
addComment(articleId, comment);
updateArticleStats(articleId);
}
4. 异常处理
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(DuplicateKeyException.class)
public ResponseEntity<String> handleDuplicateKey() {
return ResponseEntity.status(HttpStatus.CONFLICT)
.body("文章标题已存在");
}
}
1. 连接认证问题
spring:
data:
mongodb:
uri: mongodb://username:password@localhost:27017/dbname?authSource=admin
2. 大数据量处理
// 使用流式处理
@Autowired
private MongoTemplate mongoTemplate;
public void processLargeData() {
Query query = new Query();
query.cursorBatchSize(1000); // 设置批处理大小
mongoTemplate.stream(query, Article.class)
.forEach(article -> {
// 处理每条记录
});
}
3. 审计功能
@EntityListeners(AuditingEntityListener.class)
public class Article {
@CreatedDate
private LocalDateTime createTime;
@LastModifiedDate
private LocalDateTime updateTime;
}
src/main/java/com/example/mongodb/
├── config/ # 配置类
├── entity/ # 实体类
├── repository/ # 数据访问层
├── service/ # 业务逻辑层
├── controller/ # REST控制器
├── dto/ # 数据传输对象
├── exception/ # 异常处理
└── util/ # 工具类
通过本实战项目,我们完整地实现了Spring Boot与MongoDB的整合,涵盖了:
MongoDB作为NoSQL数据库的代表,特别适合以下场景:
Spring Data MongoDB提供了简洁的API,让开发者能够专注于业务逻辑,快速构建高性能的应用。通过合理使用MongoDB的特性,可以充分发挥其文档数据库的优势。
谢谢你看我的文章,既然看到这里了,如果觉得不错,随手点个赞、转发、在看三连吧,感谢感谢。那我们,下次再见。
您的一键三连,是我更新的最大动力,谢谢
山水有相逢,来日皆可期,谢谢阅读,我们再会
我手中的金箍棒,上能通天,下能探海