文章目录
- 前言
- 一、微服务调用链
- 二、推荐命名
- 请求对象
- 三、Feign 接口示例
- stock-api 模块
- 请求 DTO
- 返回 DTO
- 四、微服务 DTO 不要放在哪?
- 五、不要直接暴露 Entity / DO
- 六、DTO 要分“入参”和“出参”
- 七、统一返回结构
- 八、版本兼容很重要
- 九、订单服务调用用户服务示例
- 十、推荐目录结构
- 一句话总结
前言
微服务下 DTO 设计核心原则:
对外稳定,对内隔离,禁止直接复用数据库对象。
一、微服务调用链
order-service ↓ Feign / RPC user-service stock-service coupon-service pay-service服务之间传的对象一般就是:
RequestDTO / ResponseDTO二、推荐命名
请求对象
CreateOrderRequestDeductStockRequestUserQueryRequest或者:
CreateOrderDTODeductStockDTO我更推荐微服务接口用:
XXXRequest / XXXResponse因为语义更清楚。
三、Feign 接口示例
stock-api 模块
@FeignClient(name="stock-service")publicinterfaceStockClient{@PostMapping("/api/stock/deduct")StockDeductResponsededuct(@RequestBodyStockDeductRequestrequest);}请求 DTO
publicclassStockDeductRequest{privateLongskuId;privateIntegercount;privateStringrequestId;}返回 DTO
publicclassStockDeductResponse{privateBooleansuccess;privateStringcode;privateStringmessage;}四、微服务 DTO 不要放在哪?
不要放在:
order-service 内部 domain 包 stock-service 内部 entity 包否则其他服务依赖会很乱。
推荐建独立 API 包:
stock-api ├── client │ └── StockClient.java ├── dto │ ├── StockDeductRequest.java │ └── StockDeductResponse.java然后:
order-service 依赖 stock-api stock-service 实现 stock-api五、不要直接暴露 Entity / DO
错误示例:
@PostMapping("/user/get")UserDOgetUser(@RequestBodyUserDOuser);问题:
数据库结构泄露 字段一改,调用方全炸 可能暴露敏感字段 服务边界不清晰正确:
UserQueryRequestUserResponse六、DTO 要分“入参”和“出参”
不要一个对象到处复用。
错误:
UserDTO同时用于创建、修改、查询、返回正确:
UserCreateRequestUserUpdateRequestUserQueryRequestUserResponse因为不同场景字段不一样:
创建需要 password 返回不能有 password 修改可能只传 nickname 查询可能只传 userId/mobile七、统一返回结构
微服务之间建议统一响应:
publicclassRpcResult<T>{privatebooleansuccess;privateStringcode;privateStringmessage;privateTdata;}例如:
RpcResult<UserResponse>getUser(UserQueryRequestrequest);八、版本兼容很重要
DTO 一旦被其他服务依赖,就不能随便改。
推荐规则:
新增字段:可以 删除字段:谨慎 改字段类型:禁止 改字段含义:禁止 字段重命名:基本等于破坏兼容如果必须大改:
/api/v2/user/query UserQueryV2Request UserV2Response九、订单服务调用用户服务示例
@ServicepublicclassOrderService{privatefinalUserClientuserClient;publicOrderService(UserClientuserClient){this.userClient=userClient;}publicvoidcreateOrder(LonguserId){RpcResult<UserResponse>result=userClient.getUser(newUserQueryRequest(userId));if(!result.isSuccess()){thrownewRuntimeException("查询用户失败");}UserResponseuser=result.getData();// 创建订单逻辑}}十、推荐目录结构
user-api ├── client │ └── UserClient.java ├── request │ └── UserQueryRequest.java ├── response │ └── UserResponse.java └── result └── RpcResult.java user-service ├── controller ├── service ├── domain ├── mapper └── converter order-service ├── controller ├── service └── client一句话总结
微服务 DTO 是服务契约,不是数据库对象;Feign/RPC 接口要用独立 API 模块维护 Request/Response,并注意版本兼容。