# Spring Boot集成MongoDB实战:从连接到高级查询
MongoDB作为领先的NoSQL数据库,与Spring Boot的集成为Java开发者提供了强大的数据持久化方案。本文将详细介绍Spring Boot集成MongoDB的完整流程,涵盖基础配置、数据操作和高级特性。
## 环境准备与依赖配置
### Maven依赖配置
```xml
<dependencies>
<!-- Spring Boot Starter Data MongoDB -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<!-- Spring Boot Starter Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</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>
<!-- 验证依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
</dependencies>
<"jjqx.nbazhib.com">
<"xamx.nbazhib.com">
<"kfzf.nbazhib.com">
```
### 应用配置
```yaml
# application.yml
spring:
data:
mongodb:
# 连接字符串方式(推荐)
uri: mongodb://username:password@localhost:27017/mydatabase
# 或者使用单独参数方式
host: localhost
port: 27017
database: mydatabase
username: username
password: password
authentication-database: admin # 认证数据库
# 可选配置
jackson:
default-property-inclusion: NON_NULL # 不序列化null值
# 自定义MongoDB配置
app:
mongodb:
connection-timeout: 5000
socket-timeout: 30000
max-connection-idle-time: 60000
min-connections: 10
max-connections: 100
```
## 实体类设计与注解
### 基础实体类
```java
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Email;
import java.time.LocalDateTime;
import java.util.List;
/**
* 用户实体类
*/
@Document(collection = "users") // 指定集合名称
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
<"lfca.nbazhib.com">
<"xpmx.nbazhib.com">
<"pfyr.nbazhib.com">
public class User {
@Id
private String id; // MongoDB使用String类型的ID
@NotBlank(message = "用户名不能为空")
@Field("username") // 指定字段名称
private String username;
@Email(message = "邮箱格式不正确")
@Field("email")
private String email;
@Field("age")
private Integer age;
@Field("created_date")
private LocalDateTime createdDate;
@Field("updated_date")
private LocalDateTime updatedDate;
@Field("profile")
private Profile profile; // 嵌入文档
@Field("addresses")
private List<Address> addresses; // 数组类型
@Field("status")
private UserStatus status;
// 索引字段示例
@Field("tags")
private List<String> tags;
public enum UserStatus {
ACTIVE, INACTIVE, SUSPENDED
}
/**
* 嵌入文档 - 用户档案
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class Profile {
@Field("first_name")
private String firstName;
@Field("last_name")
private String lastName;
@Field("bio")
private String bio;
@Field("avatar_url")
private String avatarUrl;
}
/**
* 嵌入文档 - 地址
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
<"fbzj.nbazhib.com">
<"iutv.nbazhib.com">
<"qmsj.nbazhib.com">
public static class Address {
@Field("type")
private AddressType type;
@Field("street")
private String street;
@Field("city")
private String city;
@Field("country")
private String country;
@Field("postal_code")
private String postalCode;
public enum AddressType {
HOME, WORK, OTHER
}
}
/**
* 生命周期回调方法
*/
@PrePersist
protected void onCreate() {
this.createdDate = LocalDateTime.now();
this.updatedDate = LocalDateTime.now();
if (this.status == null) {
this.status = UserStatus.ACTIVE;
}
}
@PreUpdate
protected void onUpdate() {
this.updatedDate = LocalDateTime.now();
}
}
```
### 复杂实体类示例
```java
/**
* 博客文章实体类 - 展示复杂文档结构
*/
@Document(collection = "articles")
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
<"nhwd.nbazhib.com">
<"zzhe.nbazhib.com">
<"umui.nbazhib.com">
public class Article {
@Id
private String id;
@NotBlank(message = "标题不能为空")
@Field("title")
private String title;
@Field("content")
private String content;
@Field("author_id")
private String authorId;
@Field("tags")
private List<String> tags;
@Field("categories")
private List<String> categories;
@Field("metadata")
private ArticleMetadata metadata;
@Field("comments")
private List<Comment> comments;
@Field("view_count")
private Long viewCount = 0L;
@Field("like_count")
private Long likeCount = 0L;
@Field("status")
private ArticleStatus status;
@Field("created_at")
private LocalDateTime createdAt;
@Field("updated_at")
private LocalDateTime updatedAt;
@Field("published_at")
private LocalDateTime publishedAt;
public enum ArticleStatus {
DRAFT, PUBLISHED, ARCHIVED
}
/**
* 文章元数据
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class ArticleMetadata {
@Field("word_count")
private Integer wordCount;
@Field("read_time")
private Integer readTime; // 阅读时间(分钟)
@Field("featured_image")
private String featuredImage;
@Field("seo_description")
private String seoDescription;
@Field("seo_keywords")
private List<String> seoKeywords;
}
/**
* 评论嵌入文档
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
<"hzdy.nbazhib.com">
<"wltn.nbazhib.com">
<"sdar.nbazhib.com">
public static class Comment {
@Field("id")
private String id;
@Field("user_id")
private String userId;
@Field("user_name")
private String userName;
@Field("content")
private String content;
@Field("created_at")
private LocalDateTime createdAt;
@Field("like_count")
private Integer likeCount = 0;
@Field("replies")
private List<Comment> replies; // 嵌套回复
}
}
```
## Repository数据访问层
### 基础Repository接口
```java
/**
* 用户Repository - 继承MongoRepository获得基础CRUD能力
*/
@Repository
public interface UserRepository extends MongoRepository<User, String> {
// 根据用户名查询
Optional<User> findByUsername(String username);
// 根据邮箱查询
Optional<User> findByEmail(String email);
// 根据状态查询用户列表
List<User> findByStatus(User.UserStatus status);
// 根据年龄范围查询
List<User> findByAgeBetween(Integer minAge, Integer maxAge);
// 根据城市查询(嵌套文档查询)
List<User> findByAddressesCity(String city);
// 根据标签包含查询
List<User> findByTagsContaining(String tag);
// 根据用户名模糊查询
List<User> findByUsernameContainingIgnoreCase(String username);
// 统计状态为活跃的用户数量
Long countByStatus(User.UserStatus status);
// 根据状态删除用户
void deleteByStatus(User.UserStatus status);
// 根据用户名和状态查询
Optional<User> findByUsernameAndStatus(String username, User.UserStatus status);
// 根据邮箱或用户名查询
List<User> findByEmailOrUsername(String email, String username);
// 根据年龄排序查询
List<User> findByAgeGreaterThanOrderByAgeDesc(Integer age);
}
/**
* 自定义User Repository - 扩展复杂查询
*/
public interface CustomUserRepository {
List<User> findActiveUsersWithPagination(int page, int size);
List<User> searchUsers(String keyword, List<String> fields);
void updateUserStatus(String userId, User.UserStatus status);
List<User> findUsersByGeoNear(double longitude, double latitude, double maxDistance);
}
/**
* 自定义Repository实现
*/
@Slf4j
<"kpnr.nbazhib.com">
<"gqol.nbazhib.com">
<"eeeo.nbazhib.com">
public class CustomUserRepositoryImpl implements CustomUserRepository {
@Autowired
private MongoTemplate mongoTemplate;
@Override
public List<User> findActiveUsersWithPagination(int page, int size) {
Query query = new Query()
.with(Sort.by(Sort.Direction.DESC, "createdDate"))
.with(PageRequest.of(page, size));
query.addCriteria(Criteria.where("status").is(User.UserStatus.ACTIVE));
return mongoTemplate.find(query, User.class);
}
@Override
public List<User> searchUsers(String keyword, List<String> fields) {
TextCriteria criteria = TextCriteria.forDefaultLanguage()
.matchingAny(keyword);
Query query = TextQuery.queryText(criteria)
.sortByScore()
.with(Sort.by(Sort.Direction.DESC, "createdDate"));
return mongoTemplate.find(query, User.class);
}
@Override
public void updateUserStatus(String userId, User.UserStatus status) {
Query query = new Query(Criteria.where("id").is(userId));
Update update = new Update().set("status", status)
.set("updatedDate", LocalDateTime.now());
UpdateResult result = mongoTemplate.updateFirst(query, update, User.class);
log.info("更新用户状态影响记录数: {}", result.getModifiedCount());
}
@Override
public List<User> findUsersByGeoNear(double longitude, double latitude, double maxDistance) {
// 地理空间查询实现
Point location = new Point(longitude, latitude);
NearQuery nearQuery = NearQuery.near(location)
.maxDistance(new Distance(maxDistance, Metrics.KILOMETERS));
return mongoTemplate.geoNear(nearQuery, User.class).getContent()
.stream()
.map(GeoResult::getContent)
.collect(Collectors.toList());
}
}
// 扩展的Repository接口
public interface ExtendedUserRepository extends UserRepository, CustomUserRepository {
// 组合基础Repository和自定义Repository
}
```
### 文章Repository示例
```java
/**
* 文章Repository - 复杂查询示例
*/
@Repository
public interface ArticleRepository extends MongoRepository<Article, String> {
// 根据作者ID查询
List<Article> findByAuthorId(String authorId);
// 根据状态查询
List<Article> findByStatus(Article.ArticleStatus status);
// 根据标签查询
List<Article> findByTagsContaining(String tag);
// 根据分类查询并按发布时间排序
List<Article> findByCategoriesContainingOrderByPublishedAtDesc(String category);
// 统计作者的文章数量
Long countByAuthorId(String authorId);
// 根据作者ID和状态查询
List<Article> findByAuthorIdAndStatus(String authorId, Article.ArticleStatus status);
// 根据发布时间范围查询
List<Article> findByPublishedAtBetween(LocalDateTime start, LocalDateTime end);
// 根据浏览量排序查询热门文章
List<Article> findByStatusOrderByViewCountDesc(Article.ArticleStatus status, Pageable pageable);
// 使用@Query注解自定义查询
@Query("{ 'tags': { $in: ?0 }, 'status': 'PUBLISHED' }")
List<Article> findPublishedArticlesByTags(List<String> tags);
@Query("{ 'metadata.wordCount': { $gt: ?0, $lt: ?1 } }")
List<Article> findByWordCountRange(Integer minWords, Integer maxWords);
@Query(value = "{ 'authorId': ?0 }", fields = "{ 'title': 1, 'publishedAt': 1 }")
List<Article> findArticleTitlesByAuthor(String authorId);
// 聚合查询示例
@Aggregation(pipeline = {
"{ $match: { 'status': 'PUBLISHED' } }",
"{ $group: { _id: '$authorId', totalViews: { $sum: '$viewCount' } } }",
"{ $sort: { totalViews: -1 } }",
"{ $limit: 10 }"
})
List<AuthorViews> findTopAuthorsByViews();
interface AuthorViews {
String get_id(); // authorId
Long getTotalViews();
}
}
```
## Service业务逻辑层
### 用户服务实现
```java
@Service
@Slf4j
<"jtui.nbazhib.com">
<"wvks.nbazhib.com">
<"gydu.nbazhib.com">
public class UserService {
@Autowired
private ExtendedUserRepository userRepository;
@Autowired
private MongoTemplate mongoTemplate;
/**
* 创建用户
*/
public User createUser(User user) {
// 检查用户名是否已存在
if (userRepository.findByUsername(user.getUsername()).isPresent()) {
throw new BusinessException("用户名已存在");
}
// 检查邮箱是否已存在
if (user.getEmail() != null &&
userRepository.findByEmail(user.getEmail()).isPresent()) {
throw new BusinessException("邮箱已被注册");
}
User savedUser = userRepository.save(user);
log.info("用户创建成功: {}", savedUser.getUsername());
return savedUser;
}
/**
* 根据ID查询用户
*/
public User getUserById(String id) {
return userRepository.findById(id)
.orElseThrow(() -> new BusinessException("用户不存在"));
}
/**
* 更新用户信息
*/
public User updateUser(String id, UserUpdateRequest request) {
User existingUser = getUserById(id);
// 更新允许修改的字段
if (request.getEmail() != null) {
// 检查邮箱是否被其他用户使用
userRepository.findByEmail(request.getEmail())
.ifPresent(user -> {
if (!user.getId().equals(id)) {
throw new BusinessException("邮箱已被其他用户使用");
}
});
existingUser.setEmail(request.getEmail());
}
if (request.getAge() != null) {
existingUser.setAge(request.getAge());
}
if (request.getProfile() != null) {
if (existingUser.getProfile() == null) {
existingUser.setProfile(new User.Profile());
}
// 更新档案信息
if (request.getProfile().getFirstName() != null) {
existingUser.getProfile().setFirstName(request.getProfile().getFirstName());
}
if (request.getProfile().getLastName() != null) {
existingUser.getProfile().setLastName(request.getProfile().getLastName());
}
if (request.getProfile().getBio() != null) {
existingUser.getProfile().setBio(request.getProfile().getBio());
}
}
User updatedUser = userRepository.save(existingUser);
log.info("用户信息更新成功: {}", updatedUser.getUsername());
return updatedUser;
}
/**
* 分页查询用户列表
*/
public Page<User> getUsers(UserQuery query, Pageable pageable) {
Query mongoQuery = buildUserQuery(query);
long total = mongoTemplate.count(mongoQuery, User.class);
List<User> users = mongoTemplate.find(
mongoQuery.with(pageable).with(Sort.by(Sort.Direction.DESC, "createdDate")),
User.class
);
return new PageImpl<>(users, pageable, total);
}
/**
* 构建查询条件
*/
private Query buildUserQuery(UserQuery query) {
Query mongoQuery = new Query();
List<Criteria> criteriaList = new ArrayList<>();
if (StringUtils.hasText(query.getUsername())) {
criteriaList.add(Criteria.where("username").regex(query.getUsername(), "i"));
}
if (StringUtils.hasText(query.getEmail())) {
criteriaList.add(Criteria.where("email").regex(query.getEmail(), "i"));
}
if (query.getMinAge() != null) {
criteriaList.add(Criteria.where("age").gte(query.getMinAge()));
}
if (query.getMaxAge() != null) {
criteriaList.add(Criteria.where("age").lte(query.getMaxAge()));
}
if (query.getStatus() != null) {
criteriaList.add(Criteria.where("status").is(query.getStatus()));
}
if (CollectionUtils.isNotEmpty(query.getTags())) {
criteriaList.add(Criteria.where("tags").in(query.getTags()));
}
if (!criteriaList.isEmpty()) {
mongoQuery.addCriteria(new Criteria().andOperator(
criteriaList.toArray(new Criteria[0])
));
}
return mongoQuery;
}
/**
* 搜索用户
*/
public List<User> searchUsers(String keyword) {
return userRepository.searchUsers(keyword,
Arrays.asList("username", "email", "profile.firstName", "profile.lastName"));
}
/**
* 批量更新用户状态
*/
@Transactional
public void batchUpdateStatus(List<String> userIds, User.UserStatus status) {
Query query = new Query(Criteria.where("id").in(userIds));
Update update = new Update()
.set("status", status)
.set("updatedDate", LocalDateTime.now());
UpdateResult result = mongoTemplate.updateMulti(query, update, User.class);
log.info("批量更新用户状态,影响记录数: {}", result.getModifiedCount());
}
/**
* 添加用户标签
*/
<"clxe.nbazhib.com">
<"sozn.nbazhib.com">
<"qmkd.nbazhib.com">
public void addUserTag(String userId, String tag) {
Query query = new Query(Criteria.where("id").is(userId));
Update update = new Update().addToSet("tags", tag);
UpdateResult result = mongoTemplate.updateFirst(query, update, User.class);
if (result.getModifiedCount() == 0) {
throw new BusinessException("用户不存在或标签已存在");
}
}
}
@Data
class UserUpdateRequest {
private String email;
private Integer age;
private User.Profile profile;
}
@Data
class UserQuery {
private String username;
private String email;
private Integer minAge;
private Integer maxAge;
private User.UserStatus status;
private List<String> tags;
}
```
## 控制器层实现
### REST API控制器
```java
@RestController
@RequestMapping("/api/users")
@Validated
@Slf4j
public class UserController {
@Autowired
private UserService userService;
/**
* 创建用户
*/
@PostMapping
public ResponseEntity<ApiResponse<User>> createUser(@Valid @RequestBody User user) {
User createdUser = userService.createUser(user);
return ResponseEntity.status(HttpStatus.CREATED)
.body(ApiResponse.success("用户创建成功", createdUser));
}
/**
* 根据ID查询用户
*/
@GetMapping("/{id}")
public ResponseEntity<ApiResponse<User>> getUser(@PathVariable String id) {
User user = userService.getUserById(id);
return ResponseEntity.ok(ApiResponse.success(user));
}
/**
* 更新用户信息
*/
@PutMapping("/{id}")
public ResponseEntity<ApiResponse<User>> updateUser(
@PathVariable String id,
@Valid @RequestBody UserUpdateRequest request) {
User updatedUser = userService.updateUser(id, request);
return ResponseEntity.ok(ApiResponse.success("用户更新成功", updatedUser));
}
/**
* 分页查询用户列表
*/
@GetMapping
public ResponseEntity<ApiResponse<Page<User>>> getUsers(
UserQuery query,
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size) {
Pageable pageable = PageRequest.of(page, size, Sort.by("createdDate").descending());
Page<User> users = userService.getUsers(query, pageable);
return ResponseEntity.ok(ApiResponse.success(users));
}
/**
* 搜索用户
*/
@GetMapping("/search")
public ResponseEntity<ApiResponse<List<User>>> searchUsers(
@RequestParam String keyword) {
List<User> users = userService.searchUsers(keyword);
return ResponseEntity.ok(ApiResponse.success(users));
}
/**
* 添加用户标签
*/
@PostMapping("/{id}/tags")
public ResponseEntity<ApiResponse<String>> addUserTag(
@PathVariable String id,
@RequestParam String tag) {
userService.addUserTag(id, tag);
return ResponseEntity.ok(ApiResponse.success("标签添加成功"));
}
/**
* 批量更新用户状态
*/
@PostMapping("/batch-update-status")
public ResponseEntity<ApiResponse<String>> batchUpdateStatus(
@RequestBody BatchUpdateRequest request) {
userService.batchUpdateStatus(request.getUserIds(), request.getStatus());
return ResponseEntity.ok(ApiResponse.success("批量更新成功"));
}
}
@Data
class BatchUpdateRequest {
<"uftb.nbazhib.com">
<"unnv.nbazhib.com">
<"vcsh.nbazhib.com">
@NotEmpty(message = "用户ID列表不能为空")
private List<String> userIds;
@NotNull(message = "状态不能为空")
private User.UserStatus status;
}
```
## 高级特性与配置
### 自定义MongoDB配置
```java
@Configuration
@Slf4j
public class MongoConfig {
@Value("${app.mongodb.connection-timeout:5000}")
private int connectionTimeout;
@Value("${app.mongodb.socket-timeout:30000}")
private int socketTimeout;
@Bean
public MongoClient mongoClient() {
ConnectionString connectionString = new ConnectionString(
"mongodb://username:password@localhost:27017/mydatabase"
);
MongoClientSettings settings = MongoClientSettings.builder()
.applyConnectionString(connectionString)
.applyToConnectionPoolSettings(builder ->
builder.maxSize(100)
.minSize(10)
.maxWaitTime(30000, TimeUnit.MILLISECONDS))
.applyToSocketSettings(builder ->
builder.connectTimeout(connectionTimeout, TimeUnit.MILLISECONDS)
.readTimeout(socketTimeout, TimeUnit.MILLISECONDS))
.build();
return MongoClients.create(settings);
}
@Bean
public MongoTemplate mongoTemplate() {
return new MongoTemplate(mongoClient(), "mydatabase");
}
/**
* 自动创建索引
*/
@EventListener(ApplicationReadyEvent.class)
public void initIndices() {
MongoTemplate mongoTemplate = mongoTemplate();
// 为用户集合创建索引
IndexOperations indexOps = mongoTemplate.indexOps(User.class);
// 创建唯一索引
Index usernameIndex = new Index().on("username", Sort.Direction.ASC).unique();
indexOps.ensureIndex(usernameIndex);
// 创建复合索引
Index statusCreatedIndex = new Index()
.on("status", Sort.Direction.ASC)
.on("createdDate", Sort.Direction.DESC);
indexOps.ensureIndex(statusCreatedIndex);
// 创建文本索引用于搜索
Index textIndex = new Index().on("username", Sort.Direction.ASC)
.on("email", Sort.Direction.ASC)
.on("profile.firstName", Sort.Direction.ASC)
.on("profile.lastName", Sort.Direction.ASC);
indexOps.ensureIndex(textIndex);
log.info("MongoDB索引初始化完成");
}
}
```
### 事务配置(MongoDB 4.0+)
```java
@Configuration
@EnableMongoAuditing // 启用审计功能
@EnableMongoRepositories(basePackages = "com.example.repository")
public class TransactionConfig {
/**
* 配置Mongo事务管理器
* 注意:需要MongoDB副本集或分片集群支持
*/
@Bean
public MongoTransactionManager transactionManager(MongoDatabaseFactory dbFactory) {
return new MongoTransactionManager(dbFactory);
}
}
// 事务使用示例
@Service
@Slf4j
<"fmzb.nbazhib.com">
<"zmmm.nbazhib.com">
public class TransactionalUserService {
@Autowired
private UserRepository userRepository;
@Autowired
private ArticleRepository articleRepository;
/**
* 事务操作示例
*/
@Transactional
public void createUserWithInitialArticle(User user, Article article) {
try {
// 保存用户
User savedUser = userRepository.save(user);
// 设置文章作者
article.setAuthorId(savedUser.getId());
article.setStatus(Article.ArticleStatus.PUBLISHED);
// 保存文章
articleRepository.save(article);
log.info("用户和初始文章创建成功");
} catch (Exception e) {
log.error("创建用户和文章失败", e);
throw new BusinessException("创建失败");
}
}
}
```
## 测试与验证
### 集成测试
```java
@DataMongoTest
@ExtendWith(SpringExtension.class)
@Slf4j
class UserRepositoryTest {
@Autowired
private UserRepository userRepository;
@Autowired
private MongoTemplate mongoTemplate;
@BeforeEach
void setUp() {
userRepository.deleteAll();
}
@Test
void testSaveAndFindUser() {
// 准备测试数据
User user = User.builder()
.username("testuser")
.email("test@example.com")
.age(25)
.profile(User.Profile.builder()
.firstName("张")
.lastName("三")
.bio("测试用户")
.build())
.tags(Arrays.asList("vip", "tester"))
.build();
// 保存用户
User savedUser = userRepository.save(user);
// 验证保存结果
assertNotNull(savedUser.getId());
assertEquals("testuser", savedUser.getUsername());
// 查询验证
Optional<User> foundUser = userRepository.findById(savedUser.getId());
assertTrue(foundUser.isPresent());
assertEquals("test@example.com", foundUser.get().getEmail());
}
@Test
void testFindByUsername() {
// 准备测试数据
User user = User.builder()
.username("johndoe")
.email("john@example.com")
.age(30)
.build();
userRepository.save(user);
// 查询验证
Optional<User> foundUser = userRepository.findByUsername("johndoe");
assertTrue(foundUser.isPresent());
assertEquals(30, foundUser.get().getAge());
}
@Test
void testCustomQuery() {
// 准备测试数据
User user1 = User.builder()
.username("user1")
.age(25)
.status(User.UserStatus.ACTIVE)
.build();
User user2 = User.builder()
.username("user2")
.age(35)
.status(User.UserStatus.ACTIVE)
.build();
userRepository.saveAll(Arrays.asList(user1, user2));
// 测试自定义查询
List<User> activeUsers = userRepository.findByStatus(User.UserStatus.ACTIVE);
assertEquals(2, activeUsers.size());
List<User> usersInAgeRange = userRepository.findByAgeBetween(20, 30);
assertEquals(1, usersInAgeRange.size());
}
}
@SpringBootTest
class UserServiceIntegrationTest {
@Autowired
private UserService userService;
@Autowired
private UserRepository userRepository;
@BeforeEach
void setUp() {
userRepository.deleteAll();
}
@Test
void testCreateUser() {
User user = User.builder()
.username("newuser")
.email("new@example.com")
.age(28)
.build();
User createdUser = userService.createUser(user);
assertNotNull(createdUser.getId());
assertEquals("newuser", createdUser.getUsername());
assertEquals(User.UserStatus.ACTIVE, createdUser.getStatus());
}
@Test
void testCreateUserWithDuplicateUsername() {
User user1 = User.builder()
.username("duplicate")
.email("user1@example.com")
.build();
userService.createUser(user1);
User user2 = User.builder()
.username("duplicate")
.email("user2@example.com")
.build();
assertThrows(BusinessException.class, () -> userService.createUser(user2));
}
}
```
## 总结
通过本文的详细实现,我们完成了Spring Boot与MongoDB的完整集成,主要涵盖:
1. **环境配置**:依赖配置和连接字符串设置
2. **实体设计**:使用Spring Data MongoDB注解定义文档结构
3. **数据访问**:Repository模式和自定义查询实现
4. **业务逻辑**:Service层封装复杂业务操作
5. **REST API**:完整的控制器层实现
6. **高级特性**:索引管理、事务支持和自定义配置
这套方案为企业级应用提供了稳定可靠的MongoDB集成方案,具有良好的扩展性和维护性。开发者可以根据具体业务需求,在此基础上进行功能扩展和性能优化。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/19545/viewspace-3102443/ ,如需转载,请注明出处,否则将追究法律责任。