一、什么是 api 分层
api 分层是微服务架构中对外暴露接口的一种组织策略。根据调用方是谁、安全要求有多高,将同一个服务的接口划分为不同层级,每个层级有独立的 url 前缀、认证方式和职责边界。
核心思想:同一份业务逻辑,对不同调用方暴露不同的接口视图。
二、三层划分
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 中获取当前用户信息:
@restcontroller
public 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);
}
调用方代码:
@service
public 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 实现中会调用多个服务/数据源聚合:
@restcontroller
public 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
@restcontroller
public 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);
}
@service
public 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 方法。
区别在于:
- page 版本从 jwt 中取审核人、做前端相关的校验
- inner 版本从入参中取审核信息、做系统间交互的校验
九、何时选择哪个层级
| 场景 | 选择 | 理由 |
|---|---|---|
| 用户在页面点击按钮 | page | 需要登录态,依赖当前用户 |
| a服务需要查b服务 | inner | 微服务间调用,不需要用户登录 |
| 定时任务触发 | page 或 inner | 取决于是否需要用户上下文 |
| 外部系统查询聚合数据 | composite | 需要组装多数据源,对外提供 |
| 外部系统回传结果 | inner | 系统间调用,参数自包含 |
| 开放平台对外暴露 | composite | api key 认证,聚合返回 |
到此这篇关于深入解析springboot中微服务api三层分级设计的文章就介绍到这了,更多相关springboot微服务内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论