在本教程中,我们将学习如何为类配置 MongoDB 集合名称,并通过实际案例演示实现方法。我们将使用 Spring Data,它提供了多种轻量级配置选项。通过构建一个简单的音乐商店应用,我们将探索每种配置方式的适用场景。

2. 用例与项目设置

我们的用例包含四个核心类:MusicAlbum、Compilation、MusicTrack 和 Store。每个类将采用不同方式配置集合名称,且每个类都有对应的 MongoRepository。无需自定义查询,只需准备一个配置好的 MongoDB 实例。

2.1. 按名称列出集合内容的控制器

首先编写一个控制器验证配置是否生效。我们将通过集合名称进行查询。注意使用 Repository 时,集合名称配置是透明的:

@RestController
@RequestMapping("/collection")
public class CollectionController {
    @Autowired
    private MongoTemplate mongoDb;

    @GetMapping("/{name}")
    public List<DBObject> get(@PathVariable String name) {
        return mongoDb.findAll(DBObject.class, name);
    }
}

该控制器基于 MongoTemplate,使用通用类型 DBObject,不依赖具体类和 Repository。这样能直接查看 MongoDB 内部属性,特别是 Spring Data 用于反序列化的 "_class" 属性,确保配置正确。

2.2. API 服务层

接下来构建服务层,实现对象保存和集合查询功能。Compilation 类将在第一个配置示例中创建

@Service
public class MusicStoreService {
    @Autowired
    private CompilationRepository compilationRepository;

    public Compilation add(Compilation item) {
        return compilationRepository.save(item);
    }

    public List<Compilation> getCompilationList() {
        return compilationRepository.findAll();
    }

    // 其他服务方法
}

2.3. API 接口层

最后编写控制器暴露服务接口:

@RestController
@RequestMapping("/music")
public class MusicStoreController {
    @Autowired
    private MusicStoreService service;

    @PostMapping("/compilation")
    public Compilation post(@RequestBody Compilation item) {
        return service.add(item);
    }

    @GetMapping("/compilation")
    public List<Compilation> getCompilationList() {
        return service.getCompilationList();
    }

    // 其他接口方法
}

现在开始配置各个类。

3. 使用 @Document 注解配置

Spring Data 1.9 版本引入的 @Document 注解能满足所有配置需求。它专用于 MongoDB,类似 JPA 的 @Entity 注解。目前无法为集合名称定义命名策略(仅字段名支持),下面探索可用方案。

3.1. 默认行为

默认行为将类名首字母小写作为集合名。只需添加 @Document 注解即可生效

@Document
public class Compilation {
    @Id
    private String id;

    // getters and setters
}

所有通过 Compilation Repository 插入的数据将存入 MongoDB 的 "compilation" 集合:

$ curl -X POST http://localhost:8080/music/compilation -H 'Content-Type: application/json' -d '{
    "name": "Spring Hits"
}'

{ "id": "6272e26e04a673360d926ca1" }

查询 "compilation" 集合验证配置:

$ curl http://localhost:8080/collection/compilation

[
  {
    "name": "Spring Hits",
    "_class": "com.baeldung.boot.collection.name.data.Compilation"
  }
]

这是最简洁的配置方式,缺点是若修改数据库命名规范(如改用下划线命名),需重构所有类

3.2. 覆盖 value 属性

通过 @Document 的 collection 属性可覆盖默认行为。由于 value 是其别名,可直接设置:

@Document("albums")
public class MusicAlbum {
    @Id
    private String id;

    private String name;

    private String artist;

    // getters and setters
}

现在数据将存入 "albums" 而非 "musicAlbum" 集合。这是 Spring Data 中最简单的自定义集合名方式。添加专辑测试:

$ curl -X POST 'http://localhost:8080/music/album' -H 'Content-Type: application/json' -d '{
  "name": "Album 1",
  "artist": "Artist A"
}'

{ "id": "62740de003d2452a61a75c35" }

查询 "albums" 集合验证:

$ curl 'http://localhost:8080/collection/albums'

[
  {
    "name": "Album 1",
    "artist": "Artist A",
    "_class": "com.baeldung.boot.collection.name.data.MusicAlbum"
  }
]

此方式适合适配现有数据库(集合名与类名不匹配),缺点是无法统一添加前缀

3.3. 结合配置属性与 SpEL

此组合能实现 @Document 单独无法完成的功能。首先定义应用级属性供多个类复用。

在 application.properties 添加集合名后缀属性

collection.suffix=db

通过 SpEL 引用 environment bean 创建类:

@Document("store-#{@environment.getProperty('collection.suffix')}")
public class Store {
    @Id
    private String id;

    private String name;

    // getters and setters
}

创建商店测试:

$ curl -X POST 'http://localhost:8080/music/store' -H 'Content-Type: application/json' -d '{
  "name": "Store A"
}'

{ "id": "62744c6267d3a034ec5e5719" }

数据存入 "store-db" 集合,查询验证:

$ curl 'http://localhost:8080/collection/store-db'

[
  {
    "name": "Store A",
    "_class": "com.baeldung.boot.collection.name.data.Store"
  }
]

修改后缀只需更新配置文件,缺点是模板代码较多此方式也支持多租户场景(如用租户 ID 替代后缀区分非共享集合)。

3.4. 结合 Bean 方法与 SpEL

SpEL 的另一缺点是需额外编程处理,但能调用任意 Bean 方法动态确定集合名。接下来创建 Bean 实现命名规则转换

采用下划线命名策略,借用 Spring Data 的 SnakeCaseFieldNamingStrategy 创建工具 Bean:

public class Naming {
    public String fix(String name) {
        List<String> parts = ParsingUtils.splitCamelCaseToLower(name);
        List<String> result = new ArrayList<>();

        for (String part : parts) {
            if (StringUtils.hasText(part)) {
                result.add(part);
            }
        }

        return StringUtils.collectionToDelimitedString(result, "_");
    }
}

将 Bean 添加到应用:

@SpringBootApplication
public class SpringBootCollectionNameApplication {
    
    // main method

    @Bean
    public Naming naming() {
        return new Naming();
    }
}

通过 SpEL 引用该 Bean:

@Document("#{@naming.fix('MusicTrack')}")
public class MusicTrack {
    @Id
    private String id;

    private String name;

    private String artist;

    // getters and setters
}

添加曲目测试:

$ curl -X POST 'http://localhost:8080/music/track' -H 'Content-Type: application/json' -d '{
  "name": "Track 1",
  "artist":"Artist A"
}'

{ "id": "62755987ae94c5278b9530cc" }

数据存入 "music_track" 集合:

$ curl 'http://localhost:8080/collection/music_track'

[
  {
    "name": "Track 1",
    "artist": "Artist A",
    "_class": "com.baeldung.boot.collection.name.data.MusicTrack"
  }
]

缺点是无法动态获取类名,但优势是修改命名规则时无需手动重命名所有类。

4. 总结

本文探讨了使用 Spring Data 工具配置集合名称的多种方式。我们分析了每种方案的优缺点,以便根据具体场景选择最佳方案。通过构建音乐商店用例,展示了不同配置方法的实际应用。

完整源码可在 GitHub 获取。


原始标题:Configure MongoDB Collection Name for a Class in Spring Data