88e030b7
王彪总
init project
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
|
# 网关调度机制介绍
## 概述
AppController.java 是 MicroCommunity 项目的统一网关入口控制器,主要负责接收所有HTTP请求并通过服务编码(service参数)将请求分发到相应的子服务。该控制器采用命令驱动架构设计,支持GET、POST、PUT、DELETE等多种HTTP方法。
## 核心入口方法
### 1. servicePost 方法
```java
@RequestMapping(path = "/{service:.+}", method = RequestMethod.POST)
public ResponseEntity<String> servicePost(@PathVariable String service,
@RequestBody String postInfo,
HttpServletRequest request)
```
### 2. serviceGet 方法
```java
@RequestMapping(path = "/{service:.+}", method = RequestMethod.GET)
public ResponseEntity<String> serviceGet(@PathVariable String service,
HttpServletRequest request)
```
## 请求处理流程
### 1. 头信息封装
- 调用 `getRequestInfo()` 方法初始化请求头信息
- 从HttpServletRequest中提取用户信息、token等
- 封装标准化的请求头信息到Map中
### 2. 服务编码解析
- `service` 参数作为服务编码放入头信息:`headers.put(CommonConstant.HTTP_SERVICE, service)`
- 请求方法标识:`headers.put(CommonConstant.HTTP_METHOD, CommonConstant.HTTP_METHOD_POST/GET)`
- 服务编码格式示例:`user.listUser`、`community.queryCommunities`
### 3. 权限校验
```java
// 通过IPrivilegeSMO进行权限校验
privilegeSMOImpl.hasPrivilege(restTemplate, pd, "/app/" + service);
```
- 校验用户是否有访问该接口的权限
- 基于菜单权限配置进行访问控制
### 4. 服务调用
```java
// POST请求调用
responseEntity = apiSMOImpl.doApi(postInfo, headers, request);
// GET请求调用
responseEntity = apiSMOImpl.doApi(JSONObject.toJSONString(getParameterStringMap(request)), headers, request);
```
## 核心组件说明
### 1. IApiSMO 接口
```java
public interface IApiSMO {
ResponseEntity<String> doApi(String body, Map<String, String> headers, HttpServletRequest request);
}
```
**作用**:服务调用入口,负责校验员工访问权限并转发请求
**实现类**:ApiSMOImpl
- 校验员工与商户的关系权限
- 重写用户ID和商户ID到请求头
- 调用IApiServiceSMO进行最终服务分发
### 2. IPrivilegeSMO 接口
```java
public interface IPrivilegeSMO {
void hasPrivilege(RestTemplate restTemplate, IPageData pd, String resource);
}
```
**作用**:权限校验,验证用户是否有访问特定资源的权限
**实现类**:BootPrivilegeSMOImpl
- 继承DefaultAbstractComponentSMO
- 调用父类的hasPrivilege方法进行权限验证
### 3. IApiServiceSMO 接口
```java
public interface IApiServiceSMO {
ResponseEntity<String> service(String reqJson, Map<String, String> headers);
}
```
**作用**:最终的服务分发核心,负责完整的请求处理流程
**实现类**:ApiServiceSMOImpl
- 解密请求报文(POST/PUT方法)
- 创建数据流对象
- 加载配置信息
- 权限校验
- 调用下游业务系统
## 服务编码解析机制
### 服务编码格式
- **标准格式**:`资源.操作`,如 `user.listUser`
- **路径格式**:`/{resource}/{action}`,如 `/user/listUser`
### 服务映射
通过 `CommonConstant.HTTP_SERVICE` 常量将服务编码传递到后端:
```java
headers.put(CommonConstant.HTTP_SERVICE, service);
```
## 异常处理机制
### 统一异常捕获
```java
try {
// 业务处理逻辑
} catch (Throwable e) {
logger.error("请求方法失败", e);
responseEntity = ResultVo.error("请求发生异常," + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);
}
```
### 异常类型
- **DecryptException**:解密异常
- **BusinessException**:业务异常
- **NoAuthorityException**:权限异常
- **InitConfigDataException**:配置初始化异常
## 架构图
```
客户端请求
↓
AppController (网关入口)
↓
servicePost/serviceGet 方法
↓
权限校验 (IPrivilegeSMO)
↓
服务调用 (IApiSMO → ApiSMOImpl)
↓
服务分发 (IApiServiceSMO → ApiServiceSMOImpl)
↓
数据流处理 (ApiDataFlow)
↓
配置加载 & 权限验证
↓
调用下游微服务 (dealCmd方法)
↓
返回响应结果
```
## 调用流程详解
### 1. 请求接收阶段
- 客户端发送请求到 `/app/{service}`
- AppController根据HTTP方法路由到对应方法
- 封装请求头信息和参数
### 2. 权限验证阶段
- 通过AOP拦截器获取IPageData对象
- 调用IPrivilegeSMO验证用户权限
- 验证通过后继续处理
### 3. 服务分发阶段
- ApiSMOImpl进行员工权限校验
- 重写用户和商户信息到请求头
- 调用ApiServiceSMOImpl进行最终分发
### 4. 业务处理阶段
- ApiServiceSMOImpl创建数据流
- 加载应用路由配置
- 根据服务编码找到对应的AppService
- 通过dealCmd方法调用微服务
### 5. 响应返回阶段
- 处理微服务返回结果
- 统一封装响应格式
- 记录事务日志和耗时
## 关键配置说明
### 1. 请求头常量
```java
public final static String HTTP_SERVICE = "SERVICE"; // 服务编码
public final static String HTTP_METHOD = "METHOD"; // 请求方法
public final static String HTTP_ACTION = "ACTION"; // 操作动作
public final static String HTTP_RESOURCE = "RESOURCE"; // 资源类型
```
### 2. 权限相关常量
```java
public final static String CONTEXT_PAGE_DATA = "pd"; // 页面数据上下文
public final static String COOKIE_AUTH_TOKEN = "_java110_token_"; // 认证token
```
## 代码示例
### 典型POST请求处理
```java
// 1. 接收请求
@RequestMapping(path = "/{service:.+}", method = RequestMethod.POST)
public ResponseEntity<String> servicePost(@PathVariable String service,
@RequestBody String postInfo,
HttpServletRequest request) {
// 2. 封装头信息
Map<String, String> headers = new HashMap<>();
this.getRequestInfo(request, headers);
headers.put(CommonConstant.HTTP_SERVICE, service);
headers.put(CommonConstant.HTTP_METHOD, CommonConstant.HTTP_METHOD_POST);
// 3. 权限校验
IPageData pd = (IPageData) request.getAttribute(CommonConstant.CONTEXT_PAGE_DATA);
privilegeSMOImpl.hasPrivilege(restTemplate, pd, "/app/" + service);
// 4. 服务调用
ResponseEntity<String> responseEntity = apiSMOImpl.doApi(postInfo, headers, request);
return responseEntity;
}
```
## 总结
AppController作为统一网关入口,通过标准化的服务编码机制实现了请求的智能分发。其核心特点包括:
1. **统一入口**:所有请求通过AppController统一处理
2. **权限控制**:多层次的权限验证机制
3. **服务发现**:基于服务编码的动态服务路由
4. **异常处理**:统一的异常捕获和错误处理
5. **日志记录**:完整的请求链路追踪和日志记录
这种设计使得系统具有良好的扩展性和维护性,新的服务只需按照规范注册服务编码即可自动接入网关调度体系。
|