SpringBoot3.x入门到精通系列:4.1 整合 MongoDB 详解

SpringBoot 3.x 整合 MongoDB 详解

🎯 MongoDB简介

MongoDB是一个基于分布式文件存储的NoSQL数据库,由C++语言编写。它是一个面向文档的数据库,具有高性能、高可用性和易扩展性的特点。

核心特性

  • 文档存储: 使用BSON格式存储数据
  • 动态模式: 无需预定义表结构
  • 高性能: 支持索引和内存映射
  • 高可用: 支持副本集和分片
  • 水平扩展: 支持自动分片
  • 丰富查询: 支持复杂查询和聚合操作

核心概念

  • Database: 数据库,类似于关系型数据库的数据库
  • Collection: 集合,类似于关系型数据库的表
  • Document: 文档,类似于关系型数据库的行
  • Field: 字段,类似于关系型数据库的列
  • Index: 索引,提高查询性能
  • Replica Set: 副本集,提供高可用性
  • Sharding: 分片,提供水平扩展

🚀 快速开始

1. 添加依赖

xml 复制代码
<dependencies>
    <!-- SpringBoot Starter Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- SpringBoot MongoDB Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>
    
    <!-- 数据验证 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-validation</artifactId>
    </dependency>
    
    <!-- JSON处理 -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>
    
    <!-- 测试依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

2. MongoDB配置

yaml 复制代码
spring:
  # MongoDB配置
  data:
    mongodb:
      # MongoDB连接URI
      uri: mongodb://localhost:27017/demo_db
      # 或者分别配置
      # host: localhost
      # port: 27017
      # database: demo_db
      # username: admin
      # password: password
      # authentication-database: admin
      
      # 连接池配置
      options:
        # 最大连接数
        max-pool-size: 100
        # 最小连接数
        min-pool-size: 10
        # 连接超时时间
        connect-timeout: 10000
        # 读取超时时间
        socket-timeout: 0
        # 服务器选择超时时间
        server-selection-timeout: 30000
        # 最大等待时间
        max-wait-time: 120000
        # 最大连接空闲时间
        max-connection-idle-time: 0
        # 最大连接生存时间
        max-connection-life-time: 0

# 日志配置
logging:
  level:
    org.springframework.data.mongodb: DEBUG
    org.mongodb.driver: DEBUG

🔧 MongoDB配置类

java 复制代码
package com.example.demo.config;

import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.AbstractMongoClientConfiguration;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;

@Configuration
@EnableMongoRepositories(basePackages = "com.example.demo.repository")
public class MongoConfig extends AbstractMongoClientConfiguration {
    
    @Value("${spring.data.mongodb.database}")
    private String databaseName;
    
    @Value("${spring.data.mongodb.uri}")
    private String mongoUri;
    
    @Override
    protected String getDatabaseName() {
        return databaseName;
    }
    
    @Override
    public MongoClient mongoClient() {
        return MongoClients.create(mongoUri);
    }
    
    /**
     * 自定义MongoTemplate配置
     */
    @Bean
    public MongoTemplate mongoTemplate() throws Exception {
        MongoTemplate mongoTemplate = new MongoTemplate(mongoClient(), getDatabaseName());
        
        // 移除_class字段
        MappingMongoConverter converter = (MappingMongoConverter) mongoTemplate.getConverter();
        converter.setTypeMapper(new DefaultMongoTypeMapper(null));
        
        return mongoTemplate;
    }
}

📊 文档实体类

1. 用户文档

java 复制代码
package com.example.demo.document;

import com.fasterxml.jackson.annotation.JsonFormat;
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 jakarta.validation.constraints.*;
import java.time.LocalDateTime;
import java.util.List;

@Document(collection = "users")
public class UserDocument {
    
    @Id
    private String id;
    
    @Field("username")
    @Indexed(unique = true)
    @NotBlank(message = "用户名不能为空")
    @Size(min = 2, max = 50, message = "用户名长度必须在2-50个字符之间")
    private String username;
    
    @Field("email")
    @Indexed(unique = true)
    @NotBlank(message = "邮箱不能为空")
    @Email(message = "邮箱格式不正确")
    private String email;
    
    @Field("password")
    @NotBlank(message = "密码不能为空")
    @Size(min = 6, message = "密码长度不能少于6位")
    private String password;
    
    @Field("age")
    @Min(value = 0, message = "年龄不能小于0")
    @Max(value = 150, message = "年龄不能大于150")
    private Integer age;
    
    @Field("phone")
    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
    private String phone;
    
    @Field("address")
    private Address address;
    
    @Field("hobbies")
    private List<String> hobbies;
    
    @Field("profile")
    private UserProfile profile;
    
    @Field("status")
    private Integer status = 1; // 0-禁用 1-启用
    
    @Field("create_time")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;
    
    @Field("update_time")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;
    
    // 内嵌文档:地址
    public static class Address {
        private String province;
        private String city;
        private String district;
        private String detail;
        
        // 构造函数
        public Address() {}
        
        public Address(String province, String city, String district, String detail) {
            this.province = province;
            this.city = city;
            this.district = district;
            this.detail = detail;
        }
        
        // Getter和Setter方法
        public String getProvince() { return province; }
        public void setProvince(String province) { this.province = province; }
        
        public String getCity() { return city; }
        public void setCity(String city) { this.city = city; }
        
        public String getDistrict() { return district; }
        public void setDistrict(String district) { this.district = district; }
        
        public String getDetail() { return detail; }
        public void setDetail(String detail) { this.detail = detail; }
    }
    
    // 内嵌文档:用户档案
    public static class UserProfile {
        private String avatar;
        private String nickname;
        private String bio;
        private String website;
        
        // 构造函数
        public UserProfile() {}
        
        // Getter和Setter方法
        public String getAvatar() { return avatar; }
        public void setAvatar(String avatar) { this.avatar = avatar; }
        
        public String getNickname() { return nickname; }
        public void setNickname(String nickname) { this.nickname = nickname; }
        
        public String getBio() { return bio; }
        public void setBio(String bio) { this.bio = bio; }
        
        public String getWebsite() { return website; }
        public void setWebsite(String website) { this.website = website; }
    }
    
    // 构造函数
    public UserDocument() {
        this.createTime = LocalDateTime.now();
        this.updateTime = LocalDateTime.now();
    }
    
    public UserDocument(String username, String email, String password) {
        this();
        this.username = username;
        this.email = email;
        this.password = password;
    }
    
    // Getter和Setter方法
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }
    
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    
    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }
    
    public Integer getAge() { return age; }
    public void setAge(Integer age) { this.age = age; }
    
    public String getPhone() { return phone; }
    public void setPhone(String phone) { this.phone = phone; }
    
    public Address getAddress() { return address; }
    public void setAddress(Address address) { this.address = address; }
    
    public List<String> getHobbies() { return hobbies; }
    public void setHobbies(List<String> hobbies) { this.hobbies = hobbies; }
    
    public UserProfile getProfile() { return profile; }
    public void setProfile(UserProfile profile) { this.profile = profile; }
    
    public Integer getStatus() { return status; }
    public void setStatus(Integer status) { this.status = status; }
    
    public LocalDateTime getCreateTime() { return createTime; }
    public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; }
    
    public LocalDateTime getUpdateTime() { return updateTime; }
    public void setUpdateTime(LocalDateTime updateTime) { this.updateTime = updateTime; }
    
    @Override
    public String toString() {
        return "UserDocument{" +
                "id='" + id + '\'' +
                ", username='" + username + '\'' +
                ", email='" + email + '\'' +
                ", age=" + age +
                ", phone='" + phone + '\'' +
                ", status=" + status +
                ", createTime=" + createTime +
                '}';
    }
}

2. 博客文档

java 复制代码
package com.example.demo.document;

import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.CompoundIndex;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.index.TextIndexed;
import org.springframework.data.mongodb.core.mapping.DBRef;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import java.time.LocalDateTime;
import java.util.List;

@Document(collection = "blogs")
@CompoundIndex(def = "{'author': 1, 'create_time': -1}")
public class BlogDocument {
    
    @Id
    private String id;
    
    @Field("title")
    @TextIndexed(weight = 3)
    @NotBlank(message = "标题不能为空")
    @Size(max = 200, message = "标题长度不能超过200个字符")
    private String title;
    
    @Field("content")
    @TextIndexed(weight = 1)
    @NotBlank(message = "内容不能为空")
    private String content;
    
    @Field("summary")
    @Size(max = 500, message = "摘要长度不能超过500个字符")
    private String summary;
    
    @Field("author")
    @Indexed
    private String author;
    
    @Field("category")
    @Indexed
    private String category;
    
    @Field("tags")
    private List<String> tags;
    
    @Field("view_count")
    private Long viewCount = 0L;
    
    @Field("like_count")
    private Long likeCount = 0L;
    
    @Field("comment_count")
    private Long commentCount = 0L;
    
    @Field("published")
    @Indexed
    private Boolean published = false;
    
    @Field("featured")
    private Boolean featured = false;
    
    @Field("create_time")
    @Indexed
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;
    
    @Field("update_time")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;
    
    @Field("publish_time")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime publishTime;
    
    // 引用用户文档
    @DBRef
    private UserDocument authorRef;
    
    // 评论列表(内嵌文档)
    @Field("comments")
    private List<Comment> comments;
    
    // 内嵌文档:评论
    public static class Comment {
        private String id;
        private String content;
        private String author;
        private LocalDateTime createTime;
        private List<Comment> replies; // 回复评论
        
        // 构造函数
        public Comment() {
            this.createTime = LocalDateTime.now();
        }
        
        public Comment(String content, String author) {
            this();
            this.content = content;
            this.author = author;
        }
        
        // Getter和Setter方法
        public String getId() { return id; }
        public void setId(String id) { this.id = id; }
        
        public String getContent() { return content; }
        public void setContent(String content) { this.content = content; }
        
        public String getAuthor() { return author; }
        public void setAuthor(String author) { this.author = author; }
        
        public LocalDateTime getCreateTime() { return createTime; }
        public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; }
        
        public List<Comment> getReplies() { return replies; }
        public void setReplies(List<Comment> replies) { this.replies = replies; }
    }
    
    // 构造函数
    public BlogDocument() {
        this.createTime = LocalDateTime.now();
        this.updateTime = LocalDateTime.now();
    }
    
    public BlogDocument(String title, String content, String author, String category) {
        this();
        this.title = title;
        this.content = content;
        this.author = author;
        this.category = category;
    }
    
    // Getter和Setter方法
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }
    
    public String getTitle() { return title; }
    public void setTitle(String title) { this.title = title; }
    
    public String getContent() { return content; }
    public void setContent(String content) { this.content = content; }
    
    public String getSummary() { return summary; }
    public void setSummary(String summary) { this.summary = summary; }
    
    public String getAuthor() { return author; }
    public void setAuthor(String author) { this.author = author; }
    
    public String getCategory() { return category; }
    public void setCategory(String category) { this.category = category; }
    
    public List<String> getTags() { return tags; }
    public void setTags(List<String> tags) { this.tags = tags; }
    
    public Long getViewCount() { return viewCount; }
    public void setViewCount(Long viewCount) { this.viewCount = viewCount; }
    
    public Long getLikeCount() { return likeCount; }
    public void setLikeCount(Long likeCount) { this.likeCount = likeCount; }
    
    public Long getCommentCount() { return commentCount; }
    public void setCommentCount(Long commentCount) { this.commentCount = commentCount; }
    
    public Boolean getPublished() { return published; }
    public void setPublished(Boolean published) { this.published = published; }
    
    public Boolean getFeatured() { return featured; }
    public void setFeatured(Boolean featured) { this.featured = featured; }
    
    public LocalDateTime getCreateTime() { return createTime; }
    public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; }
    
    public LocalDateTime getUpdateTime() { return updateTime; }
    public void setUpdateTime(LocalDateTime updateTime) { this.updateTime = updateTime; }
    
    public LocalDateTime getPublishTime() { return publishTime; }
    public void setPublishTime(LocalDateTime publishTime) { this.publishTime = publishTime; }
    
    public UserDocument getAuthorRef() { return authorRef; }
    public void setAuthorRef(UserDocument authorRef) { this.authorRef = authorRef; }
    
    public List<Comment> getComments() { return comments; }
    public void setComments(List<Comment> comments) { this.comments = comments; }
}

🔍 Repository接口

1. 用户Repository

java 复制代码
package com.example.demo.repository;

import com.example.demo.document.UserDocument;
import org.springframework.data.domain.Page;
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.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

@Repository
public interface UserRepository extends MongoRepository<UserDocument, String> {
    
    // 根据用户名查找用户
    Optional<UserDocument> findByUsername(String username);
    
    // 根据邮箱查找用户
    Optional<UserDocument> findByEmail(String email);
    
    // 根据用户名或邮箱查找用户
    Optional<UserDocument> findByUsernameOrEmail(String username, String email);
    
    // 根据年龄范围查找用户
    List<UserDocument> findByAgeBetween(Integer minAge, Integer maxAge);
    
    // 根据状态查找用户
    List<UserDocument> findByStatus(Integer status);
    
    // 根据爱好查找用户
    List<UserDocument> findByHobbiesContaining(String hobby);
    
    // 根据城市查找用户
    @Query("{'address.city': ?0}")
    List<UserDocument> findByCity(String city);
    
    // 根据省份查找用户
    @Query("{'address.province': ?0}")
    List<UserDocument> findByProvince(String province);
    
    // 根据创建时间范围查找用户
    List<UserDocument> findByCreateTimeBetween(LocalDateTime startTime, LocalDateTime endTime);
    
    // 分页查询用户
    Page<UserDocument> findByStatus(Integer status, Pageable pageable);
    
    // 统计用户数量
    long countByStatus(Integer status);
    
    // 自定义查询:根据多个条件查找用户
    @Query("{'$and': [{'age': {'$gte': ?0}}, {'status': ?1}, {'address.city': {'$regex': ?2, '$options': 'i'}}]}")
    List<UserDocument> findByComplexConditions(Integer minAge, Integer status, String cityPattern);
    
    // 查找最近注册的用户
    @Query(value = "{}", sort = "{'create_time': -1}")
    List<UserDocument> findRecentUsers(Pageable pageable);
}

2. 博客Repository

java 复制代码
package com.example.demo.repository;

import com.example.demo.document.BlogDocument;
import org.springframework.data.domain.Page;
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.time.LocalDateTime;
import java.util.List;

@Repository
public interface BlogRepository extends MongoRepository<BlogDocument, String> {
    
    // 根据作者查找博客
    List<BlogDocument> findByAuthor(String author);
    
    // 根据分类查找博客
    List<BlogDocument> findByCategory(String category);
    
    // 根据发布状态查找博客
    List<BlogDocument> findByPublished(Boolean published);
    
    // 根据标题模糊查找博客
    List<BlogDocument> findByTitleContainingIgnoreCase(String title);
    
    // 根据标签查找博客
    List<BlogDocument> findByTagsContaining(String tag);
    
    // 根据作者和发布状态查找博客
    List<BlogDocument> findByAuthorAndPublished(String author, Boolean published);
    
    // 根据分类和发布状态分页查找博客
    Page<BlogDocument> findByCategoryAndPublished(String category, Boolean published, Pageable pageable);
    
    // 查找热门博客(根据浏览量)
    @Query(value = "{'published': true}", sort = "{'view_count': -1}")
    List<BlogDocument> findPopularBlogs(Pageable pageable);
    
    // 查找推荐博客
    List<BlogDocument> findByFeaturedAndPublished(Boolean featured, Boolean published);
    
    // 根据创建时间范围查找博客
    List<BlogDocument> findByCreateTimeBetween(LocalDateTime startTime, LocalDateTime endTime);
    
    // 全文搜索
    @Query("{'$text': {'$search': ?0}}")
    List<BlogDocument> findByTextSearch(String searchText);
    
    // 复合查询:根据多个条件查找博客
    @Query("{'$and': [{'published': true}, {'view_count': {'$gte': ?0}}, {'like_count': {'$gte': ?1}}]}")
    List<BlogDocument> findPopularPublishedBlogs(Long minViews, Long minLikes);
    
    // 统计博客数量
    long countByAuthorAndPublished(String author, Boolean published);
    
    // 聚合查询:按分类统计博客数量
    @Query(value = "{}", fields = "{'category': 1}")
    List<BlogDocument> findAllCategories();
}

🏗️ Service层实现

1. 用户服务

java 复制代码
package com.example.demo.service;

import com.example.demo.document.UserDocument;
import com.example.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
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.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

@Service
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    @Autowired
    private MongoTemplate mongoTemplate;
    
    /**
     * 保存用户
     */
    public UserDocument save(UserDocument user) {
        user.setUpdateTime(LocalDateTime.now());
        return userRepository.save(user);
    }
    
    /**
     * 根据ID查找用户
     */
    public Optional<UserDocument> findById(String id) {
        return userRepository.findById(id);
    }
    
    /**
     * 根据用户名查找用户
     */
    public Optional<UserDocument> findByUsername(String username) {
        return userRepository.findByUsername(username);
    }
    
    /**
     * 根据邮箱查找用户
     */
    public Optional<UserDocument> findByEmail(String email) {
        return userRepository.findByEmail(email);
    }
    
    /**
     * 查找所有用户
     */
    public List<UserDocument> findAll() {
        return userRepository.findAll();
    }
    
    /**
     * 分页查找用户
     */
    public Page<UserDocument> findByPage(int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by("createTime").descending());
        return userRepository.findByStatus(1, pageable);
    }
    
    /**
     * 根据年龄范围查找用户
     */
    public List<UserDocument> findByAgeRange(Integer minAge, Integer maxAge) {
        return userRepository.findByAgeBetween(minAge, maxAge);
    }
    
    /**
     * 根据城市查找用户
     */
    public List<UserDocument> findByCity(String city) {
        return userRepository.findByCity(city);
    }
    
    /**
     * 更新用户信息
     */
    public UserDocument updateUser(String id, UserDocument userUpdate) {
        Optional<UserDocument> existingUser = userRepository.findById(id);
        if (existingUser.isPresent()) {
            UserDocument user = existingUser.get();
            user.setUsername(userUpdate.getUsername());
            user.setEmail(userUpdate.getEmail());
            user.setAge(userUpdate.getAge());
            user.setPhone(userUpdate.getPhone());
            user.setAddress(userUpdate.getAddress());
            user.setHobbies(userUpdate.getHobbies());
            user.setProfile(userUpdate.getProfile());
            user.setUpdateTime(LocalDateTime.now());
            return userRepository.save(user);
        }
        throw new RuntimeException("用户不存在: " + id);
    }
    
    /**
     * 使用MongoTemplate进行复杂更新
     */
    public void updateUserStatus(String id, Integer status) {
        Query query = new Query(Criteria.where("id").is(id));
        Update update = new Update()
                .set("status", status)
                .set("updateTime", LocalDateTime.now());
        
        mongoTemplate.updateFirst(query, update, UserDocument.class);
    }
    
    /**
     * 批量更新用户状态
     */
    public void batchUpdateUserStatus(List<String> userIds, Integer status) {
        Query query = new Query(Criteria.where("id").in(userIds));
        Update update = new Update()
                .set("status", status)
                .set("updateTime", LocalDateTime.now());
        
        mongoTemplate.updateMulti(query, update, UserDocument.class);
    }
    
    /**
     * 删除用户
     */
    public void deleteUser(String id) {
        userRepository.deleteById(id);
    }
    
    /**
     * 统计用户数量
     */
    public long countActiveUsers() {
        return userRepository.countByStatus(1);
    }
    
    /**
     * 复杂查询示例
     */
    public List<UserDocument> complexSearch(Integer minAge, String city) {
        return userRepository.findByComplexConditions(minAge, 1, city);
    }
    
    /**
     * 使用MongoTemplate进行聚合查询
     */
    public List<UserDocument> findUsersByComplexCriteria(String province, List<String> hobbies) {
        Query query = new Query();
        
        // 添加省份条件
        if (province != null && !province.isEmpty()) {
            query.addCriteria(Criteria.where("address.province").is(province));
        }
        
        // 添加爱好条件
        if (hobbies != null && !hobbies.isEmpty()) {
            query.addCriteria(Criteria.where("hobbies").in(hobbies));
        }
        
        // 只查询启用的用户
        query.addCriteria(Criteria.where("status").is(1));
        
        // 按创建时间降序排列
        query.with(Sort.by(Sort.Direction.DESC, "createTime"));
        
        return mongoTemplate.find(query, UserDocument.class);
    }
}

🎮 Controller层

java 复制代码
package com.example.demo.controller;

import com.example.demo.document.UserDocument;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@RestController
@RequestMapping("/api/mongo")
@CrossOrigin(origins = "*")
public class MongoController {
    
    @Autowired
    private UserService userService;
    
    /**
     * 创建用户
     */
    @PostMapping("/users")
    public ResponseEntity<UserDocument> createUser(@RequestBody @Valid UserDocument user) {
        UserDocument savedUser = userService.save(user);
        return ResponseEntity.ok(savedUser);
    }
    
    /**
     * 根据ID获取用户
     */
    @GetMapping("/users/{id}")
    public ResponseEntity<UserDocument> getUserById(@PathVariable String id) {
        Optional<UserDocument> user = userService.findById(id);
        return user.map(ResponseEntity::ok).orElse(ResponseEntity.notFound().build());
    }
    
    /**
     * 获取所有用户
     */
    @GetMapping("/users")
    public ResponseEntity<List<UserDocument>> getAllUsers() {
        List<UserDocument> users = userService.findAll();
        return ResponseEntity.ok(users);
    }
    
    /**
     * 分页获取用户
     */
    @GetMapping("/users/page")
    public ResponseEntity<Page<UserDocument>> getUsersByPage(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size) {
        
        Page<UserDocument> users = userService.findByPage(page, size);
        return ResponseEntity.ok(users);
    }
    
    /**
     * 根据用户名查找用户
     */
    @GetMapping("/users/username/{username}")
    public ResponseEntity<UserDocument> getUserByUsername(@PathVariable String username) {
        Optional<UserDocument> user = userService.findByUsername(username);
        return user.map(ResponseEntity::ok).orElse(ResponseEntity.notFound().build());
    }
    
    /**
     * 根据年龄范围查找用户
     */
    @GetMapping("/users/age")
    public ResponseEntity<List<UserDocument>> getUsersByAgeRange(
            @RequestParam Integer minAge,
            @RequestParam Integer maxAge) {
        
        List<UserDocument> users = userService.findByAgeRange(minAge, maxAge);
        return ResponseEntity.ok(users);
    }
    
    /**
     * 根据城市查找用户
     */
    @GetMapping("/users/city/{city}")
    public ResponseEntity<List<UserDocument>> getUsersByCity(@PathVariable String city) {
        List<UserDocument> users = userService.findByCity(city);
        return ResponseEntity.ok(users);
    }
    
    /**
     * 更新用户
     */
    @PutMapping("/users/{id}")
    public ResponseEntity<UserDocument> updateUser(
            @PathVariable String id,
            @RequestBody @Valid UserDocument user) {
        
        try {
            UserDocument updatedUser = userService.updateUser(id, user);
            return ResponseEntity.ok(updatedUser);
        } catch (RuntimeException e) {
            return ResponseEntity.notFound().build();
        }
    }
    
    /**
     * 更新用户状态
     */
    @PatchMapping("/users/{id}/status")
    public ResponseEntity<Map<String, String>> updateUserStatus(
            @PathVariable String id,
            @RequestBody Map<String, Integer> request) {
        
        Integer status = request.get("status");
        userService.updateUserStatus(id, status);
        
        Map<String, String> response = new HashMap<>();
        response.put("status", "success");
        response.put("message", "用户状态更新成功");
        return ResponseEntity.ok(response);
    }
    
    /**
     * 删除用户
     */
    @DeleteMapping("/users/{id}")
    public ResponseEntity<Map<String, String>> deleteUser(@PathVariable String id) {
        userService.deleteUser(id);
        
        Map<String, String> response = new HashMap<>();
        response.put("status", "success");
        response.put("message", "用户删除成功");
        return ResponseEntity.ok(response);
    }
    
    /**
     * 统计活跃用户数量
     */
    @GetMapping("/users/count/active")
    public ResponseEntity<Map<String, Long>> countActiveUsers() {
        long count = userService.countActiveUsers();
        
        Map<String, Long> response = new HashMap<>();
        response.put("count", count);
        return ResponseEntity.ok(response);
    }
    
    /**
     * 复杂查询示例
     */
    @GetMapping("/users/search")
    public ResponseEntity<List<UserDocument>> complexSearch(
            @RequestParam(required = false) Integer minAge,
            @RequestParam(required = false) String city) {
        
        List<UserDocument> users = userService.complexSearch(minAge, city);
        return ResponseEntity.ok(users);
    }
}

📊 最佳实践

1. 索引优化

  • 为经常查询的字段创建索引
  • 使用复合索引优化复杂查询
  • 定期分析索引使用情况
  • 避免过多索引影响写入性能

2. 文档设计

  • 合理设计文档结构
  • 避免过深的嵌套
  • 考虑数据的读写模式
  • 适当使用引用和内嵌

3. 查询优化

  • 使用投影减少数据传输
  • 合理使用分页
  • 避免全表扫描
  • 使用聚合管道优化复杂查询

本文关键词: MongoDB, NoSQL, 文档数据库, Spring Data MongoDB, 分布式存储

相关推荐
IvorySQL8 分钟前
如何使用 pg_rman 进行 PostgreSQL 的备份与恢复
数据库
Tapdata40 分钟前
一文了解增量物化视图维护(IVM):原理、演化与实践落地
数据库
码间舞1 小时前
IndexDB适用于什么场景?如何使用IndexDB?
前端·javascript·数据库
叫我:松哥1 小时前
基于Python的实习僧招聘数据采集与可视化分析,使用matplotlib进行可视化
开发语言·数据库·python·课程设计·matplotlib·文本挖掘
hzk的学习笔记2 小时前
Redis学习总结(持续更新)
数据库·redis·缓存
山茶花开时。2 小时前
[Oracle] MOD()函数
数据库·oracle
花菜会噎住2 小时前
数据库入门:从零开始构建你的第一个数据库
数据库·sql·oracle
山茶花开时。2 小时前
[Oracle] DECODE()函数
数据库·sql·oracle
5172 小时前
Scrapy爬虫集成MongoDB存储
爬虫·scrapy·mongodb