web-micro 是 EasyFK 框架为微服务(网关后端服务)提供的 Web 基础设施模块。适用于经过 easyfk-gateway 网关转发后的下游微服务,提供以下核心能力:
本模块是 easyfk-web 多层模块体系中面向微服务场景的组合模块,依赖 web-simple(Web 容器 + easyfk-core)、web-common(通用配置 + 工具)、web-base(JWT + 上下文管理)。
web-micro
├── web-simple
│ ├── spring-boot-starter-web(排除 Tomcat + Logging)
│ ├── spring-boot-starter-undertow(默认容器)
│ └── easyfk-core
└── web-common
├── web-base
│ ├── easyfk-authority(用户权限管理)
│ └── easyfk-core(编译期)
├── easyfk-core(编译期)
└── spring-web(编译期)dependencies {
api project(':easyfk-web:web-simple')
api project(':easyfk-web:web-common')
}dependencies {
api('org.springframework.boot:spring-boot-starter-web') {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
}
api project(':easyfk-core')
api 'org.springframework.boot:spring-boot-starter-undertow'
}dependencies {
compileOnly project(':easyfk-core')
compileOnly('org.springframework:spring-web')
api project(':easyfk-web:web-base')
}dependencies {
compileOnly project(':easyfk-core')
api project(':easyfk-authority')
}easyfk-web/
├── web-simple/ # Web 容器层
│ └── (spring-boot-starter-web + Undertow + easyfk-core)
│
├── web-base/ # 基础管理层
│ ├── config/
│ │ └── WebBaseConfig.java # 自动配置(JwtManager + ContextDataManager)
│ ├── manager/
│ │ ├── JwtManager.java # JWT 创建与解析
│ │ └── ContextDataManager.java # 上下文数据管理器
│ ├── properties/
│ │ └── JwtProperties.java # JWT 配置
│ └── vo/
│ └── ParseJwtResult.java # JWT 解析结果
│
├── web-common/ # 通用配置层
│ ├── config/
│ │ └── WebCommonConfig.java # 注册属性配置
│ ├── properties/
│ │ ├── InterceptProperties.java # 拦截器配置
│ │ ├── SecurityProperties.java # 安全配置
│ │ └── CorsProperties.java # 跨域配置
│ ├── constant/
│ │ ├── ErrorRequest.java # 错误请求枚举(15 种错误类型)
│ │ ├── RequestConstant.java # 请求常量
│ │ └── SignConstant.java # 签名常量
│ ├── util/
│ │ ├── InterceptorExcludeUriUtil.java # URI 排除匹配工具
│ │ └── CheckIgnoreSecurityUriUtil.java # 安全忽略 URI 工具
│ ├── vo/
│ │ └── FilterChainData.java # 过滤链传递数据
│ └── resources/
│ └── i18n/
│ ├── webMessages_zh_CN.properties # 简体中文
│ ├── webMessages_zh_TW.properties # 繁体中文(台湾)
│ ├── webMessages_zh_HK.properties # 繁体中文(香港)
│ ├── webMessages_en_US.properties # 英文
│ └── webMessages_vi_VN.properties # 越南语
│
└── web-micro/ # 微服务组合层(本模块)
├── config/
│ └── MicroWebConfig.java # 自动配置
├── exception/
│ └── MicroExceptionHandler.java # 全局异常处理
└── filter/
└── RequestBaseFilter.java # 请求前置过滤器配置前缀:easyfk.config.web.jwt
| `secret` | String | 内置默认值 | JWT 签名私钥 |
|---|
配置前缀:easyfk.config.web.intercept
| `exclude-paths` | List<String> | null | 拦截器排除的 URI 列表 |
|---|---|---|---|
| `auth-type` | Integer | 0 | 权限拦截等级:0=只检测登录,1=检测登录+权限 |
| `refresh-user-auth` | boolean | false | 是否刷新用户权限缓存 |
| `verify-param` | boolean | false | 是否验证参数防篡改 |
| `custom-local-interceptor` | boolean | false | 是否使用自定义本地拦截器 |
| `custom-local-filter` | boolean | false | 是否使用自定义本地过滤器 |
| `custom-gateway-filter` | boolean | false | 是否使用自定义网关过滤器 |
配置前缀:easyfk.config.web.security
| `open` | boolean | false | 是否开启接口安全控制 |
|---|---|---|---|
| `timeout` | Duration | 150s | 防重放超时时间 |
| `sign-key` | String | `mcst_sign_reset` | 签名密钥 |
| `sign-key-dynamic` | boolean | false | 签名密钥是否动态 |
| `key-time-to-live` | Duration | 10min | 动态密钥存活时间 |
配置前缀:easyfk.config.web.cors
| `open` | boolean | false | 是否开启跨域 |
|---|---|---|---|
| `cors-domain` | String | `*` | 允许跨域的域名 |
| `allowed-header` | String | `*` | 允许的自定义头 |
| `allowed-method` | String | `*` | 允许的 HTTP Method |
| `path-pattern` | String | `/**` | 跨域路径模式 |
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
→ com.mcst.easyfk.web.micro.config.MicroWebConfig注册的 Bean:
| `microExceptionHandler` | `MicroExceptionHandler` | `@ConditionalOnMissingBean` | 全局异常处理器 |
|---|---|---|---|
| `serializingObjectMapper` | `ObjectMapper` | `@ConditionalOnMissingBean(ObjectMapper.class)` | Jackson 全局配置 |
注册的 Bean:
| `jwtManager` | `JwtManager` | JWT 创建与解析管理器 |
|---|
注册配置属性:SecurityProperties、InterceptProperties、CorsProperties
继承 OncePerRequestFilter,在每个请求开始时还原上下文:
HTTP 请求到达微服务
│
├─ 从 ThreadLocal 获取或创建 RequestHeaders
│
├─ 提取请求头信息
│ ├─ TRACE_ID → traceId 变量
│ ├─ ACCESS_TOKEN → headers.accessToken
│ └─ LANGUAGE → headers.language
│
├─ 非空字段写入 RequestHeaderContext(ThreadLocal)
│
├─ contextDataManager.doDataContext(traceId)
│ ├─ JWT 解析 AccessToken → LoginUser
│ ├─ UserDataManager 加载 UserData → UserDataContext
│ ├─ TraceId → TraceIdContext + MDC
│ └─ (可选)异步刷新用户权限缓存
│
├─ filterChain.doFilter() ← 继续后续处理
│
└─ finally: contextDataManager.clearContext()
├─ TraceIdContext.remove()
├─ MDC.clear()
├─ RequestHeaderContext.remove()
└─ UserDataContext.remove()使用 @ControllerAdvice 统一处理所有异常:
| `BindException` / `ValidationException` / `MethodArgumentNotValidException` | 500 | `RRBuilder.buildFailByException(e)` 提取校验错误信息 |
|---|---|---|
| `Exception`(兜底) | 500 | 使用 I18N 国际化消息 `SystemErrorMsg` |
国际化支持: 系统异常消息通过 I18NUtil.getMessage("SystemErrorMsg", "i18n/webMessages") 获取,支持 5 种语言:
核心管理类,负责请求上下文的全生命周期:
// 微服务场景:从请求头中的 traceId 恢复上下文
contextDataManager.doDataContext(traceId);内部流程:
1. 从 RequestHeaderContext 获取 AccessToken
2. 过滤无效 Token(空值、"undefined")
3. JwtManager.getObjectContent() 解析 JWT → LoginUser
4. UserDataManager.getUserData() 从缓存加载 UserData
5. 写入 UserDataContext(ThreadLocal)
6. 设置 TraceId → TraceIdContext + MDC
contextDataManager.clearContext();一次性清理四个 ThreadLocal:
contextDataManager.createTraceId();使用 IdUtil.randomUUID() 生成新的 TraceId,写入 TraceIdContext + MDC。(网关场景使用)
// 从字符串创建
String token = jwtManager.createJwtByString("content");
// 从对象创建(自动 JSON 序列化)
String token = jwtManager.createJwtByObject(loginUser);// 解析为对象
ParseJwtResult<LoginUser> result = jwtManager.getObjectContent(token, LoginUser.class);
if (result.isSuccess()) {
LoginUser user = result.getData();
}
// 解析为字符串
ParseJwtResult<String> result = jwtManager.getStringContent(token);| `success` | boolean | 解析是否成功 |
|---|---|---|
| `expires` | boolean | JWT 是否已过期 |
MicroWebConfig 注册全局 ObjectMapper:
| `LocalDateTime` | `yyyy-MM-dd HH:mm:ss` | `yyyy-MM-dd HH:mm:ss` |
|---|---|---|
| `LocalTime` | `HH:mm:ss` | `HH:mm:ss` |
| `Date` | `yyyy-MM-dd HH:mm:ss` | — |
其他配置:
web-common 定义了 15 种标准化错误码:
| `UNLOGIN` | 未登录或登录过期 |
|---|---|
| `HEARD_EMPTY` | 请求头为空 |
| `NONCE_EMPTY` | 随机串为空 |
| `RESET_SIGN_EMPTY` | ResetSign 为空 |
| `TIMESTAMP_EMPTY` | 时间戳为空 |
| `SIGN_ERROR` | 验签失败 |
| `EXPIRED` | 请求过期 |
| `API_AGAIN` | 接口重放 |
| `PARAM_SIGN_EMPTY` | ParamSign 为空 |
| `VERIFY_EMPTY` | 无验签数据 |
| `VERIFY_ERROR` | 参数签名失败 |
| `REQUEST_TOKEN_EMPTY` | RequestToken 为空 |
| `REQUEST_AGAIN` | 重复提交 |
| `JWT_ERROR` | JWT 无效 |
boolean excluded = InterceptorExcludeUriUtil.containsUri(requestUri, interceptProperties);检查请求 URI 是否在拦截器排除列表中。
boolean pass = CheckIgnoreSecurityUriUtil.isPass(requestUri, ignoreUris);检查请求 URI 是否应跳过安全检查:
微服务间传递的标准化数据容器:
@Data
@Accessors(chain = true)
public class FilterChainData implements Serializable {
private RequestHeaders headers;
private LoginUser loginUser;
}网关将解析后的 RequestHeaders 和 LoginUser 封装为 JSON 写入请求头,下游微服务从中还原上下文。
dependencies {
implementation project(':easyfk-web:web-micro')
}easyfk:
config:
web:
jwt:
secret: "your-custom-secret-key"@RestController
public class UserController {
@GetMapping("/user/info")
public ResponseResult<UserData> getUserInfo() {
// 自动由 RequestBaseFilter 注入
UserData userData = UserDataContext.getUserData();
String traceId = TraceIdContext.getTraceId();
return RRBuilder.buildSuccessBody(userData);
}
}easyfk-web-micro — 轻量级微服务 Web 基础设施。