多模块Maven项目中DTO类与MapStruct@Mapper的放置位置问询
模块职责导向的DTO与Mapper放置方案
先明确各模块的核心职责边界:
xxx-api/yyy-api模块:仅负责对接外部服务,包含OpenAPI生成的模型、客户端调用逻辑,本质是外部服务的"代理层",只处理与外部服务的交互逻辑。backend模块:承载业务逻辑与对外REST接口,负责聚合外部服务数据、执行业务规则,最终向前端/下游返回标准化响应。
基于职责划分,给出两种场景下的最优方案:
场景1:简化后的DTO仅为backend的REST接口服务
如果你的DTO只是为了backend控制器返回使用,优先放在backend模块,理由如下:
- 符合单一职责:
xxx-api/yyy-api只需维护与外部服务一致的模型,不用关心backend如何对外暴露数据,避免模块职责膨胀。 - 降低耦合:外部服务API模型变更时,只需调整
xxx-api/yyy-api的生成代码,以及backend内对应的Mapper和DTO,不会牵连其他模块。 - 维护直观:REST接口的DTO属于对外契约,放在负责对外接口的
backend模块,其他开发者能快速找到接口返回的模型定义。
此时的结构示例:
root ├── backend │ └── src/main/java │ └── com/yourcompany/backend │ ├── dto # 简化后的DTO,供REST控制器返回 │ ├── mapper # MapStruct的@Mapper,处理外部模型→内部DTO的转换 │ └── controller # REST端点 └── gateway ├── xxx-api │ └── src/main/java/com/yourcompany/gateway/xxxapi │ └── model # OpenAPI生成的外部服务模型 └── yyy-api └── src/main/java/com/yourcompany/gateway/yyyapi └── model # OpenAPI生成的外部服务模型
注意:需在backend模块的pom中引入xxx-api/yyy-api依赖,确保能访问外部服务的模型类。
场景2:简化后的DTO需要多模块复用
如果除backend外,还有其他模块(比如未来新增的frontend-client或其他服务)需要使用这些DTO,建议新增独立的shared-dto模块:
shared-dto模块依赖xxx-api/yyy-api,统一维护DTO和转换Mapperbackend及其他需要的模块依赖shared-dto,直接复用转换后的DTO
这种方案避免了重复定义DTO,同时保持各模块职责清晰。
不建议放在xxx-api/yyy-api模块的原因
将DTO和Mapper放在外部服务的api模块会带来两个核心问题:
- 职责混淆:
xxx-api原本只负责对接外部服务,现在额外承担为backend提供DTO的职责,违反单一职责原则。 - 耦合风险:如果
backend对DTO的需求变更(比如新增字段、调整结构),需要修改xxx-api模块,但该模块本应只跟随外部服务的API变化。
总结
- 若DTO仅服务于
backend的REST接口:放在backend模块,Mapper一同置于此处,依赖xxx-api/yyy-api完成转换。 - 若DTO需要多模块复用:新增
shared-dto模块统一维护,让依赖该DTO的模块引用此模块。
核心原则就是让每个模块只做它最核心的事情,避免跨职责的代码堆积,不用过度复杂化。
内容的提问来源于stack exchange,提问作者Marcin
相关产品推荐
相关产品推荐

