本文目录导读:

我来详细介绍 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
性能优化建议
- 合理使用索引
- 避免频繁的关联查询
- 使用批量操作
- 合理设置连接池大小
- 使用投影查询减少数据传输
这样你就完成了 SpringBoot 集成 MongoDB 文档存储的完整配置和开发,记得根据实际需求调整配置和功能。