SpringBoot集成MongoDB文档存储

wen java案例 1

本文目录导读:

SpringBoot集成MongoDB文档存储

  1. 添加依赖
  2. 配置文件
  3. 实体类定义
  4. Repository 层
  5. Service 层
  6. Controller 层
  7. 索引管理
  8. 高级特性
  9. 事务支持 (MongoDB 4.0+)
  10. 注意事项

我来详细介绍 SpringBoot 集成 MongoDB 的方法和最佳实践。

添加依赖

<!-- Maven 依赖 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

配置文件

application.yml

spring:
  data:
    mongodb:
      uri: mongodb://localhost:27017/mydb
      # 或者使用详细配置
      host: localhost
      port: 27017
      database: mydb
      username: user
      password: pass
      authentication-database: admin
      # 连接池配置
      options:
        min-connections-per-host: 10
        max-connections-per-host: 50
        connect-timeout: 30000
        socket-timeout: 60000
        max-wait-time: 120000
        server-selection-timeout: 30000

application.properties

spring.data.mongodb.uri=mongodb://localhost:27017/mydb
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=mydb

实体类定义

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;
@Document(collection = "users")  // 指定集合名称
public class User {
    @Id
    private String id;
    @Indexed(unique = true)  // 创建唯一索引
    private String username;
    @Field("email_address")  // 自定义字段名
    private String email;
    private String password;
    @Indexed
    private Integer age;
    private List<String> hobbies;
    private Address address;
    @Field("created_at")
    private LocalDateTime createdAt;
    @Field("updated_at")
    private LocalDateTime updatedAt;
    // 关联引用
    @DBRef  // 引用其他文档
    private List<Order> orders;
    // getters and setters
}
// 嵌入式文档
public class Address {
    private String province;
    private String city;
    private String street;
    private String zipCode;
    // getters and setters
}

Repository 层

基础 CRUD Repository

import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
public interface UserRepository extends MongoRepository<User, String> {
    // 根据字段查询
    Optional<User> findByUsername(String username);
    List<User> findByAgeGreaterThan(int age);
    List<User> findByHobbiesContaining(String hobby);
    // 使用 @Query 自定义查询
    @Query("{ 'address.city': ?0 }")
    List<User> findByCity(String city);
    @Query("{ 'username': { $regex: ?0, $options: 'i' } }")
    List<User> findByUsernameLike(String username);
    // 分页查询
    @Query("{ 'age': { $gte: ?0, $lte: ?1 } }")
    List<User> findByAgeBetween(int min, int max, Pageable pageable);
    // 聚合查询
    @Aggregation(pipeline = {
        "{ '$group': { '_id': '$address.city', 'count': { '$sum': 1 } } }",
        "{ '$sort': { 'count': -1 } }"
    })
    List<CityCount> countUsersByCity();
}
// 聚合结果映射
public class CityCount {
    private String id;  // 城市名
    private int count;  // 用户数
    // getters and setters
}

自定义 Repository 实现

import org.springframework.beans.factory.annotation.Autowired;
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 CustomUserRepositoryImpl implements CustomUserRepository {
    @Autowired
    private MongoTemplate mongoTemplate;
    @Override
    public void updateUserEmail(String userId, String newEmail) {
        Query query = Query.query(Criteria.where("_id").is(userId));
        Update update = Update.update("email_address", newEmail);
        mongoTemplate.updateFirst(query, update, User.class);
    }
    @Override
    public List<User> findUsersByDynamicCriteria(DynamicQuery query) {
        Query mongoQuery = new Query();
        if (query.getUsername() != null) {
            mongoQuery.addCriteria(Criteria.where("username").is(query.getUsername()));
        }
        if (query.getMinAge() != null && query.getMaxAge() != null) {
            mongoQuery.addCriteria(Criteria.where("age")
                .gte(query.getMinAge())
                .lte(query.getMaxAge()));
        }
        if (query.getCity() != null) {
            mongoQuery.addCriteria(Criteria.where("address.city").is(query.getCity()));
        }
        return mongoTemplate.find(mongoQuery, User.class);
    }
}
// 动态查询条件
public class DynamicQuery {
    private String username;
    private Integer minAge;
    private Integer maxAge;
    private String city;
    // getters and setters
}
public interface CustomUserRepository {
    void updateUserEmail(String userId, String newEmail);
    List<User> findUsersByDynamicCriteria(DynamicQuery query);
}

Service 层

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
@Service
@Transactional
public class UserService {
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private CustomUserRepository customUserRepository;
    // 创建用户
    public User createUser(User user) {
        user.setCreatedAt(LocalDateTime.now());
        user.setUpdatedAt(LocalDateTime.now());
        return userRepository.save(user);
    }
    // 批量创建
    public List<User> createUsers(List<User> users) {
        users.forEach(user -> {
            user.setCreatedAt(LocalDateTime.now());
            user.setUpdatedAt(LocalDateTime.now());
        });
        return userRepository.saveAll(users);
    }
    // 查询所有用户
    public List<User> getAllUsers() {
        return userRepository.findAll();
    }
    // 分页查询
    public Page<User> getUsersByPage(int page, int size) {
        PageRequest pageRequest = PageRequest.of(page, size, Sort.by("createdAt").descending());
        return userRepository.findAll(pageRequest);
    }
    // 根据 ID 查询
    public Optional<User> getUserById(String id) {
        return userRepository.findById(id);
    }
    // 更新用户
    public User updateUser(String id, User userDetails) {
        return userRepository.findById(id)
            .map(user -> {
                user.setUsername(userDetails.getUsername());
                user.setEmail(userDetails.getEmail());
                user.setAge(userDetails.getAge());
                user.setHobbies(userDetails.getHobbies());
                user.setAddress(userDetails.getAddress());
                user.setUpdatedAt(LocalDateTime.now());
                return userRepository.save(user);
            })
            .orElseThrow(() -> new RuntimeException("User not found with id: " + id));
    }
    // 部分更新
    public void updateEmail(String userId, String newEmail) {
        customUserRepository.updateUserEmail(userId, newEmail);
    }
    // 删除用户
    public void deleteUser(String id) {
        userRepository.deleteById(id);
    }
    // 高级查询
    public List<User> findUsersByAgeRange(int min, int max) {
        return userRepository.findByAgeBetween(min, max, 
            PageRequest.of(0, 10, Sort.by("age").ascending()));
    }
}

Controller 层

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
@RestController
@RequestMapping("/api/users")
public class UserController {
    @Autowired
    private UserService userService;
    @PostMapping
    public ResponseEntity<User> createUser(@Valid @RequestBody User user) {
        User created = userService.createUser(user);
        return new ResponseEntity<>(created, HttpStatus.CREATED);
    }
    @PostMapping("/batch")
    public ResponseEntity<List<User>> createUsers(@Valid @RequestBody List<User> users) {
        List<User> created = userService.createUsers(users);
        return new ResponseEntity<>(created, HttpStatus.CREATED);
    }
    @GetMapping
    public ResponseEntity<List<User>> getAllUsers() {
        List<User> users = userService.getAllUsers();
        return ResponseEntity.ok(users);
    }
    @GetMapping("/page")
    public ResponseEntity<Page<User>> getUsersByPage(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size) {
        Page<User> userPage = userService.getUsersByPage(page, size);
        return ResponseEntity.ok(userPage);
    }
    @GetMapping("/{id}")
    public ResponseEntity<User> getUserById(@PathVariable String id) {
        return userService.getUserById(id)
            .map(ResponseEntity::ok)
            .orElse(ResponseEntity.notFound().build());
    }
    @PutMapping("/{id}")
    public ResponseEntity<User> updateUser(@PathVariable String id, @Valid @RequestBody User user) {
        User updated = userService.updateUser(id, user);
        return ResponseEntity.ok(updated);
    }
    @PatchMapping("/{id}/email")
    public ResponseEntity<Void> updateEmail(
            @PathVariable String id, 
            @RequestParam String email) {
        userService.updateEmail(id, email);
        return ResponseEntity.ok().build();
    }
    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteUser(@PathVariable String id) {
        userService.deleteUser(id);
        return ResponseEntity.noContent().build();
    }
}

索引管理

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.index.GeospatialIndex;
import org.springframework.stereotype.Component;
@Component
public class IndexInitializer implements CommandLineRunner {
    @Autowired
    private MongoTemplate mongoTemplate;
    @Override
    public void run(String... args) throws Exception {
        // 创建复合索引
        mongoTemplate.indexOps(User.class)
            .ensureIndex(new org.springframework.data.mongodb.core.index.Index()
                .on("username", Sort.Direction.ASC)
                .on("age", Sort.Direction.ASC)
                .unique());
        // 创建文本索引
        mongoTemplate.indexOps(User.class)
            .ensureIndex(new org.springframework.data.mongodb.core.index.Index()
                .on("hobbies", Sort.Direction.ASC));
        // 创建地理位置索引
        mongoTemplate.indexOps(Store.class)
            .ensureIndex(new GeospatialIndex("location"));
    }
}

高级特性

GridFS 文件存储

import com.mongodb.client.gridfs.GridFSFindIterable;
import com.mongodb.client.gridfs.model.GridFSFile;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsOperations;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.util.List;
@Service
public class FileService {
    @Autowired
    private GridFsOperations gridFsOperations;
    public String storeFile(MultipartFile file) throws Exception {
        try (InputStream inputStream = file.getInputStream()) {
            // 存储文件到 GridFS
            String fileId = gridFsOperations.store(
                inputStream, 
                file.getOriginalFilename(),
                file.getContentType()
            ).toString();
            return fileId;
        }
    }
    public GridFsResource getFile(String fileId) {
        GridFSFile gridFSFile = gridFsOperations.findOne(
            Query.query(Criteria.where("_id").is(fileId)));
        return gridFsOperations.getResource(gridFSFile);
    }
    public void deleteFile(String fileId) {
        gridFsOperations.delete(Query.query(Criteria.where("_id").is(fileId)));
    }
}

事务支持 (MongoDB 4.0+)

import org.springframework.transaction.annotation.Transactional;
@Service
public class TransactionalService {
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private OrderRepository orderRepository;
    @Transactional
    public void createUserWithOrder(User user, Order order) {
        // MongoDB 支持事务且使用副本集
        userRepository.save(user);
        orderRepository.save(order);
    }
}

注意事项

配置 MongoDB 连接池

spring:
  data:
    mongodb:
      uri: mongodb://localhost:27017/mydb
      options:
        min-connections-per-host: 10
        max-connections-per-host: 50
        connect-timeout: 30000
        read-timeout: 5000
        write-concern: ACKNOWLEDGED
        read-preference: PRIMARY_PREFERRED

性能优化建议

  1. 合理使用索引
  2. 避免频繁的关联查询
  3. 使用批量操作
  4. 合理设置连接池大小
  5. 使用投影查询减少数据传输

这样你就完成了 SpringBoot 集成 MongoDB 文档存储的完整配置和开发,记得根据实际需求调整配置和功能。

抱歉,评论功能暂时关闭!