一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

深入解析SpringBoot中微服务API三层分级设计

时间:2026-08-10 16:41:51 编辑:袖梨 来源:一聚教程网

深入解析SpringBoot中微服务API三层分级设计的重点在于把前置条件、操作顺序和容易误判的地方分清楚。

一、什么是 API 分层

API 分层是微服务架构中对外暴露接口的一种组织策略。根据调用方是谁安全要求有多高,将同一个服务的接口划分为不同层级,每个层级有独立的 URL 前缀、认证方式和职责边界。

深入解析SpringBoot中微服务API三层分级设计

核心思想:同一份业务逻辑,对不同调用方暴露不同的接口视图。

二、三层划分

2.1 Page API — 面向前端

项目说明
URL 前缀/api/page/{domain}/{action}
调用方前端页面(浏览器、APP)
认证方式JWT Token(用户登录后获取)
特点返回完整数据、支持分页、依赖当前登录用户上下文

适用场景: 用户在界面上点击按钮触发的操作。比如用户提交审核、查询列表。

@Tag(name = "订单管理", description = "订单管理页面接口")@RestController@RequestMapping("/api/page/order")public interface OrderPageApi {    @Operation(summary = "查询订单列表",         security = {@SecurityRequirement(name = "bearer-jwt")})    @PostMapping("/list-orders")    RestControllerResult<PageInfo<OrderListResultDto>> listOrders(        @RequestBody OrderListParamsDto paramsDto);    @Operation(summary = "取消订单")    @PostMapping("/cancel-order")    RestControllerResult<Boolean> cancelOrder(        @RequestBody CancelOrderParamsDto paramsDto);}

Controller 实现中通常会从 JWT 中获取当前用户信息:

@RestControllerpublic class OrderPageApiController implements OrderPageApi {    @Override    public RestControllerResult<PageInfo<OrderListResultDto>> listOrders(            OrderListParamsDto paramsDto) {        // 从JWT中获取当前登录用户的memberId        if (paramsDto.getMemberId() == null) {            paramsDto.setMemberId(JwtTokenUtil.getMemberId().intValue());        }        return RestControllerResult.success(orderService.listOrders(paramsDto));    }}

2.2 Inner API — 微服务间调用

项目说明
URL 前缀/api/inner/{domain}/{action}
调用方其他内部微服务(通过 Feign/HTTP)
认证方式IP 白名单 / 服务间 Token / 网关转发
特点参数完整(调用方直接传 memberId),不依赖用户登录上下文

适用场景: 服务 A 需要调用服务 B 的能力。

@Tag(name = "订单内部接口", description = "供其他微服务调用")@RestController@RequestMapping("/api/inner/order")public interface OrderInnerApi {    @Operation(summary = "根据订单号查询订单详情")    @GetMapping("/get-order-by-code")    RestControllerResult<OrderDetailDto> getOrderByCode(        @RequestParam("orderCode") String orderCode);    @Operation(summary = "生成退货单")    @PostMapping("/create-return-order")    RestControllerResult<ReturnOrderResultDto> createReturnOrder(        @RequestBody CreateReturnOrderParamsDto paramsDto);}

其他服务通过 Feign 客户端调用:

@FeignClient(    value = "${service-name.order}/api",    fallbackFactory = OrderFeignFallbackFactory.class)public interface OrderFeign {    @PostMapping("/inner/order/create-return-order")    RestControllerResult<ReturnOrderResultDto> createReturnOrder(        @RequestBody CreateReturnOrderParamsDto paramsDto);}

调用方代码:

@Servicepublic class StockServiceImpl {    @Resource    private OrderFeign orderFeign;    public void doSomething() {        CreateReturnOrderParamsDto params = new CreateReturnOrderParamsDto();        params.setMemberId(226887);        params.setOrderCode("xxx.xxx.000001");                RestControllerResult<ReturnOrderResultDto> result =             orderFeign.createReturnOrder(params);                if (!result.getSuccess()) {            throw new RuntimeException("生成退货单失败: " + result.getErrorMsg());        }    }}

2.3 Composite API — 跨服务聚合

项目说明
URL 前缀/api/composite/{domain}/{action}
调用方外部合作伙伴系统 / 需要聚合多服务数据的场景
认证方式JWT 或 API Key
特点单个接口内部可能调用多个服务,做数据组装和聚合

适用场景: 外部系统需要一个接口获取多维度的聚合数据。比如需要同时查库存异动表、商品信息、存性信息、订单类型等。

@Tag(name = "数据聚合服务", description = "跨服务聚合查询")@RestController@RequestMapping("/api/composite/stock/data-center")public interface StockDataCompositeApi {    @Operation(summary = "查询出入库汇总信息")    @PostMapping("/get-stock-transaction-summary")    RestControllerResult<StockTransactionSummaryDto> getStockTransactionSummary(        @RequestBody StockTransactionSummaryParamsDto paramsDto);}

Controller 实现中会调用多个服务/数据源聚合:

@RestControllerpublic class StockDataCompositeApiController implements StockDataCompositeApi {    @Resource    private StockMapper stockMapper;       // 本地查库存数据    @Resource    private OrderFeign orderFeign;         // 远程查订单数据    @Resource    private GoodsFeign goodsFeign;         // 远程查商品数据    @Override    public RestControllerResult<StockTransactionSummaryDto> getStockTransactionSummary(            StockTransactionSummaryParamsDto paramsDto) {        // 1. 查本地库存异动        List<StockTransactionDto> transactions = stockMapper.selectTransactions(paramsDto);                // 2. 远程调用订单服务补充订单类型名称        List<String> orderCodes = transactions.stream()            .map(StockTransactionDto::getOrderCode).collect(Collectors.toList());        Map<String, String> orderTypeMap = orderFeign.getOrderTypes(orderCodes);                // 3. 远程调用商品服务补充商品信息        List<Integer> skuIds = transactions.stream()            .map(StockTransactionDto::getItemSkuId).collect(Collectors.toList());        Map<Integer, ItemInfoDto> itemMap = goodsFeign.getItemInfoBatch(skuIds);                // 4. 组装聚合结果        transactions.forEach(t -> {            t.setOrderTypeName(orderTypeMap.get(t.getOrderCode()));            ItemInfoDto item = itemMap.get(t.getItemSkuId());            if (item != null) {                t.setItemName(item.getItemName());                t.setProductCode(item.getProductCode());            }        });                return RestControllerResult.success(new StockTransactionSummaryDto(transactions));    }}

三、三层对比

┌─────────────────────────────────────────────────────────┐

│ 网关 (Gateway) │

├──────────┬──────────────────┬───────────────────────────┤

│ │ │ │

│ 前端/APP │ 其他微服务 │ 外部合作伙伴系统 │

│ │ │ │

├──────────┼──────────────────┼───────────────────────────┤

│ ↓ ↓ ↓

│ /api/page/* /api/inner/* /api/composite/*

│ │ │ │

│ 需要登录JWT IP白名单/服务Token JWT/API Key

│ │ │ │

│ 依赖用户上下文 参数完整自包含 聚合多数据源

│ │ │ │

├──────────┴──────────────────┴───────────────────────────┤

│ Service 业务逻辑层 │

│ (三层共享同一个 Service) │

└─────────────────────────────────────────────────────────┘

关键点:三层 API 只是入口不同,最终都调用同一个 Service 层的业务逻辑。

四、URL 路径规范

格式:/api/{层级}/{领域}/{资源或模块}/{动作}

/api/page/stock/xx-xx/audit-reject-apply

│ │ │ │

│ │ │ └── 动作:审核拒收申请

│ │ └── 模块:xxx

│ └── 领域:库存

└── 层级:页面接口

/api/inner/stock/xx-xx/receive-order-center-reject-audit-result

│ │ │ │

│ │ │ └── 动作:接收xx拒收审核结果

│ │ └── 模块:xx

│ └── 领域:库存

└── 层级:内部接口

/api/composite/stock/xxx/get-union-stock-transaction-pager

│ │ │ │

│ │ │ └── 动作:查询出入库信息

│ │ └── 模块:xxx

│ └── 领域:库存

└── 层级:复合接口

五、接口定义与实现分离模式

// 第一层:接口定义(放在 api 包下)// 作用:定义契约,可以被其他服务引用@RestController@RequestMapping("/api/inner/order")public interface OrderInnerApi {    @PostMapping("/get-order-detail")    RestControllerResult<OrderDetailDto> getOrderDetail(@RequestBody OrderQueryDto dto);}// 第二层:Controller 实现(放在 controller 包下)// 作用:参数校验 + 调用 Service@RestControllerpublic class OrderInnerApiController implements OrderInnerApi {    @Resource    private OrderService orderService;    @Override    public RestControllerResult<OrderDetailDto> getOrderDetail(OrderQueryDto dto) {        if (dto.getOrderCode() == null) {            throw new JshCheckException("订单号不能为空");        }        return RestControllerResult.success(orderService.getOrderDetail(dto));    }}// 第三层:Service 接口 + 实现public interface OrderService {    OrderDetailDto getOrderDetail(OrderQueryDto dto);}@Servicepublic class OrderServiceImpl implements OrderService {    @Override    public OrderDetailDto getOrderDetail(OrderQueryDto dto) {        // 真正的业务逻辑    }}

六、统一返回包装

所有层级的接口都用 RestControllerResult<T> 包装返回值:

public class RestControllerResult<T> {    private Boolean success;      // 是否成功    private Integer code;         // 状态码(0=正常)    private String errCode;       // 错误编码    private String errorMsg;      // 错误信息    private T data;               // 业务数据    private List<String> infoMsgs;    private List<String> warningMsgs;}

调用方统一处理:

RestControllerResult<OrderDetailDto> result = orderFeign.getOrderDetail(dto);if (!result.getSuccess()) {    // 处理失败    log.error("调用失败: {}", result.getErrorMsg());    throw new RuntimeException(result.getErrorMsg());}OrderDetailDto data = result.getData();

七、安全机制对比

Page API — JWT 认证

前端登录 -> 获取 access_token -> 每次请求 Header 携带 Authorization: Bearer <token>

服务端 RSA 公钥验签 -> 解析出 userId/memberId

Inner API — 网关转发 + IP 白名单

服务A -> 通过注册中心/网关路由到服务B -> 网关层验证来源IP在白名单中

内部服务间不需要用户登录态,参数中直接传 memberId。

Composite API — 按场景选择

可以是 JWT,也可以是 API Key(如开放平台场景)。

八、同一业务不同层级暴露不同接口的例子

以"审核拒收申请"为例,三层可以暴露不同的入口:

// Page API:前端用户手动审核(从JWT获取审核人信息)@PostMapping("/api/page/stock/xxx/audit-reject-apply")RestControllerResult<Boolean> auditRejectApply(@RequestBody AuditRejectApplyParamsDto dto);// Inner API:xx系统审核(入参直接传审核信息,不依赖登录态)@PostMapping("/api/inner/stock/xxx/audit-reject-apply-by-xx")RestControllerResult<Boolean> auditRejectApplyByXx(@RequestBody AuditRejectApplyByLmParamsDto dto);

两个接口最终都调用同一个 Service 方法。

区别在于:

  1. Page 版本从 JWT 中取审核人、做前端相关的校验
  2. Inner 版本从入参中取审核信息、做系统间交互的校验

九、何时选择哪个层级

场景选择理由
用户在页面点击按钮Page需要登录态,依赖当前用户
A服务需要查B服务Inner微服务间调用,不需要用户登录
定时任务触发Page 或 Inner取决于是否需要用户上下文
外部系统查询聚合数据Composite需要组装多数据源,对外提供
外部系统回传结果Inner系统间调用,参数自包含
开放平台对外暴露CompositeAPI Key 认证,聚合返回

热门栏目