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, 分布式存储

相关推荐
一只自律的鸡29 分钟前
【MySQL】第二章 基本的SELECT语句
数据库·mysql
liliangcsdn2 小时前
如何使用python创建和维护sqlite3数据库
数据库·sqlite
TDengine (老段)8 小时前
TDengine 数学函数 DEGRESS 用户手册
大数据·数据库·sql·物联网·时序数据库·iot·tdengine
TDengine (老段)8 小时前
TDengine 数学函数 GREATEST 用户手册
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据
安当加密8 小时前
云原生时代的数据库字段加密:在微服务与 Kubernetes 中实现合规与敏捷的统一
数据库·微服务·云原生
爱喝白开水a9 小时前
LangChain 基础系列之 Prompt 工程详解:从设计原理到实战模板_langchain prompt
开发语言·数据库·人工智能·python·langchain·prompt·知识图谱
想ai抽9 小时前
深入starrocks-多列联合统计一致性探查与策略(YY一下)
java·数据库·数据仓库
武子康9 小时前
Java-152 深入浅出 MongoDB 索引详解 从 MongoDB B-树 到 MySQL B+树 索引机制、数据结构与应用场景的全面对比分析
java·开发语言·数据库·sql·mongodb·性能优化·nosql
longgyy9 小时前
5 分钟用火山引擎 DeepSeek 调用大模型生成小红书文案
java·数据库·火山引擎
ytttr87310 小时前
C# 仿QQ聊天功能实现 (SQL Server数据库)
数据库·oracle·c#