[2025-05-27] 添加2.0.0使用教程
All checks were successful
Publish to Confluence / confluence (push) Successful in 1m2s

This commit is contained in:
liuxiaohua 2025-05-27 12:04:35 +08:00
parent dd10069c48
commit afa86cf270
8 changed files with 506 additions and 4 deletions

View File

@ -0,0 +1,103 @@
<!-- Space: qifu -->
<!-- Parent: 后端技术&知识&规范 -->
<!-- Parent: 技术方案 -->
<!-- Parent: 基建 -->
<!-- Parent: 00-基础组件 -->
<!-- Parent: 00-EngineStarterFeign使用指南 -->
<!-- Title: 20250509-engine-starter-feign-2.0.0 -->
<!-- Macro: :anchor\((.*)\):
Template: ac:anchor
Anchor: ${1} -->
<!-- Macro: \!\[.*\]\((.+)\)\<\!\-\- width=(.*) \-\-\>
Template: ac:image
Url: ${1}
Width: ${2} -->
<!-- Macro: \<\!\-\- :toc: \-\-\>
Template: ac:toc
Printable: 'false'
MinLevel: 2
MaxLevel: 4 -->
<!-- Include: 杂项/声明文件.md -->
<!-- :toc: -->
# engine-starter-feign 使用教程
> 基于 Feign 的通用封装
> 具体使用可参考 [engine-sample > engine-sample-starter-web](../engine-sample/engine-sample-starter-web)
## 功能特性
- [X] 请求头添加内部请求标识 `X-QiFu-From-In: true`
- [X] 请求头透传
- [X] 请求结果解析映射(解封装 `Result`
-------
## 快速使用
- **注意:** `qifu-saas-parent >= 2.0.0-SNAPSHOT`
- **注意:** 启动类 `@ComponentScan` 需要变更为如下形式
- ```java
@ComponentScan(value = "com.yuanmeng.*",
excludeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)
})
@SpringBootApplication
public class SampleStarterWebApplication {
public static void main(String[] args) {
SpringApplication.run(SampleStarterWebApplication.class, args);
}
}
```
### 添加依赖
```xml
<dependency>
<groupId>com.yuanmeng.engine</groupId>
<artifactId>engine-starter-feign</artifactId>
</dependency>
```
### 添加兼容包(可选)
- 项目中存在 `web-core` 时需要添加兼容包
```xml
<dependency>
<groupId>com.yuanmeng.engine</groupId>
<artifactId>engine-starter-compatible-feign</artifactId>
</dependency>
```
------
## 完整默认配置文件
```yaml
yuanmeng:
feign:
#- 开启feign自动配置
enable: true
#- 开启请求头内部标识
enable-contract: true
#- 开启旧包兼容
enable-ignore: true
#- 开启结果解析
enable-decoder: true
#- 开启请求头传递
enable-interceptor: true
#- 链接超时时间
connect-timeout: 10
connect-time-unit: seconds
#- 读取超时时间
read-timeout: 60
read-time-unit: seconds
```

View File

@ -79,6 +79,18 @@
</dependency>
```
### 添加兼容包(可选)
- 项目中存在 `data-mybatis-plus` 时需要添加兼容包
```xml
<dependency>
<groupId>com.yuanmeng.engine</groupId>
<artifactId>engine-starter-compatible-mybatis-plus</artifactId>
</dependency>
```
----
## 使用工具

View File

@ -32,8 +32,7 @@
- [X] `@YmIdempotent`: 基于 Redis 的幂等工具
- [X] `@YmRateLimit`: 基于 Redisson 的限流工具
- [X] `@Lock4j`: 基于 Lock4j 的分布式锁工具
- [X] 旧包中的 `@DistributedMultiLock` 慢慢迁移到新注解
- [X] TODO 旧包中的 `@DistributedMultiLock` 需要实现 `@Lock4jMulti`
- [X] `@Lock4jMulti`: 多锁模式
- [X] `@Cacheable`: 基于 Redis 的 SpringCache 集成
- [X] 扩展 key支持 key 中自定义时间 `abc#1000`
- [X] `YmRedisClient`: Redis 操作工具类,基于 `StringRedisTemplate`
@ -261,5 +260,5 @@ yuanmeng:
prefix: rate_limit
#- Lock4j Redisson 分布式锁配置
lock4j-redisson:
enable: false
enable: true
```

View File

@ -361,5 +361,5 @@ yuanmeng:
external-url-list:
- "/external/test"
i18n:
enable: true
enable: false
```

View File

@ -0,0 +1,388 @@
<!-- Space: qifu -->
<!-- Parent: 后端技术&知识&规范 -->
<!-- Parent: 技术方案 -->
<!-- Parent: 基建 -->
<!-- Parent: 00-基础组件 -->
<!-- Parent: 00-EngineStarterWeb使用指南 -->
<!-- Title: 20250509-engine-starter-web-2.0.0 -->
<!-- Macro: :anchor\((.*)\):
Template: ac:anchor
Anchor: ${1} -->
<!-- Macro: \!\[.*\]\((.+)\)\<\!\-\- width=(.*) \-\-\>
Template: ac:image
Url: ${1}
Width: ${2} -->
<!-- Macro: \<\!\-\- :toc: \-\-\>
Template: ac:toc
Printable: 'false'
MinLevel: 2
MaxLevel: 4 -->
<!-- Include: 杂项/声明文件.md -->
<!-- :toc: -->
# engine-starter-web 使用教程
> 基于 web 的各种工具封装
> 具体使用可参考 [engine-sample > engine-sample-starter-web](../engine-sample/engine-sample-starter-web)
## 功能特性
- [X] `@YmAutoFill``@YmAutoFillResp`: 结果自动填充
- [X] `@YmIgnoreResultWrapper`: 忽略 `Result` 结果包装
- [X] `YmResponseAdvice`: 全局结果封装
- [X] `YmGlobalExceptionHandlerAdvice`: 全局异常拦截处理
- [X] `YmAutofillResponseAdvice`: 全局返回结果填充处理
- [X] `YmI18nResponseAdvice`: I18n全局处理
- [X] `@YmIgnoreI18n`: 忽略I18n
- [X] `YmHealthCheckFilter`: 全局健康检查接口
- [X] `YmRequestBodyWrapperFilter`: request 和 response 可重复读封装
- [X] `YmRequestPrintFilter`: 请求日志打印
- [X] `YmThreadLocalFilter`: 登录用户信息解析存储(后续会迁移到网关,需要兼容)
- [X] `YmUserLoginFilter`: 用户登录校验(后续会迁移到网关,默认关闭)
- [X] `YmThreadLocalUtils`: 获取当前线程中的上下文信息
-------
## 快速使用
- **注意:** `qifu-saas-parent >= 2.0.0-SNAPSHOT`
- **注意:** 启动类 `@ComponentScan` 需要变更为如下形式
- ```java
@ComponentScan(value = "com.yuanmeng.*",
excludeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)
})
@SpringBootApplication
public class SampleStarterWebApplication {
public static void main(String[] args) {
SpringApplication.run(SampleStarterWebApplication.class, args);
}
}
```
### 添加依赖
```xml
<dependency>
<groupId>com.yuanmeng.engine</groupId>
<artifactId>engine-starter-web</artifactId>
</dependency>
```
### 添加兼容包(可选)
- 项目中存在 `web-core` 或者 `oauth2-core` 时需要添加兼容包
```xml
<dependency>
<groupId>com.yuanmeng.engine</groupId>
<artifactId>engine-starter-compatible-web</artifactId>
</dependency>
```
----
## 使用工具
### 忽略结果封装
```java
public class Usage {
/**
* 测试忽略包装
*
* @return 结果
*/
@YmIgnoreResultWrapper
@GetMapping("/ignore-result-wrapper")
public String ignoreResultWrapper() {
return "ignore-result-wrapper success";
}
}
```
### 全局异常拦截
```java
public class Usage {
@GetMapping("/exception")
public String exception() {
// 打印error日志触发告警
throw new RuntimeException("exception");
}
@GetMapping("/ym-exception")
public String ymException() {
// 打印error日志触发告警
throw new YmException("ym exception");
}
@GetMapping("/ym-biz-exception")
public String ymBizException() {
// 打印 warning 日志
throw new YmBizException(YmResultCode.BASE_ERROR);
}
@GetMapping("/ym-biz-data-exception")
public String ymBizDataException() {
// 打印 info 日志
throw new YmBizDataException(YmResultCode.BASE_ERROR,
new TestData(TestStatusEnum.SUCCESS.getCode(), "1"));
}
@YmAutofillResp
@GetMapping("/ym-biz-data-exception-fill")
public String ymBizDataExceptionFill() {
// 触发结果数据自动填充
throw new YmBizDataException(YmResultCode.BASE_ERROR,
new TestData(TestStatusEnum.SUCCESS.getCode(), "1"));
}
}
```
### 国际化支持
- 开启国际化支撑
```yaml
yuanmeng:
web:
i18n:
enable: true
```
- 添加国际化文件
- 默认 `resources > i18n > messages_zh_CN.properties`
```properties
Base\ Error=服务端错误
```
- 编写代码
```java
@GetMapping("/i18n")
public String i18n() {
return "test success";
}
@YmIgnoreI18n
@GetMapping("/i18n-ignore")
public String i18nIgnore() {
return "i18n ignore";
}
@GetMapping("/i18n-error")
public String i18nError() {
// 触发国际化配置
throw new YmBizException(YmResultCode.BASE_ERROR);
}
```
- **自定义国际化处理类(可选)**
```java
@RequiredArgsConstructor
public class CustomI18nMessageHandler implements YmI18nMessageHandler {
private final MessageSource messageSource;
@Override
public String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale) {
return messageSource.getMessage(code, args, defaultMessage, locale);
}
@Override
public String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException {
return messageSource.getMessage(code, args, locale);
}
@Override
public String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException {
return messageSource.getMessage(resolvable, locale);
}
}
@Configuration
public class YmI18nConfiguration {
public static final String I18N_MESSAGE_SOURCE = "ymI18nMessageSource";
public static final String I18N_MESSAGE_HANDLER = "ymI18nMessageHandler";
@Bean(I18N_MESSAGE_SOURCE)
@ConditionalOnMissingBean(name = I18N_MESSAGE_SOURCE)
public MessageSource messageSource() {
log.info("[WEB_STARTER_INIT]: CUSTOM I18N_MESSAGE_SOURCE init");
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("i18n/test");
messageSource.setDefaultEncoding(StandardCharsets.UTF_8.toString());
return messageSource;
}
@Bean(I18N_MESSAGE_HANDLER)
@ConditionalOnMissingBean(name = I18N_MESSAGE_HANDLER)
public YmI18nMessageHandler ymI18nMessageHandler(@Qualifier(I18N_MESSAGE_SOURCE) MessageSource messageSource) {
log.info("[WEB_STARTER_INIT]: CUSTOM YmI18nMessageHandler init");
return new CustomI18nMessageHandler(messageSource);
}
}
```
### 结果自动填充
```java
@Getter
@AllArgsConstructor
public enum TestStatusEnum implements YmBaseEnum<String> {
SUCCESS("SUCCESS", "成功"),
FAIL("FAIL", "失败"),
;
private final String code;
private final String desc;
}
@Component
public class TestAutoFillHandler implements YmAutofillHandler {
@Override
public Map<?, ?> handle(Collection<?> ids, YmAutofillInfo autofill) {
Collection<String> string = (Collection<String>) ids;
Map<String, String> result = new HashMap<>();
string.forEach(k -> result.put(k, k + "value"));
return result;
}
}
@Data
@NoArgsConstructor
public class TestData {
@YmAutofill(enumCls = TestStatusEnum.class)
private String statusName;
private String status;
private String code;
@YmAutofill(from = "code", type = YmAutofillType.BEAN, handler = TestAutoFillHandler.class)
private String msg;
public TestData(String status, String code) {
this.status = status;
this.code = code;
}
}
@Data
@NoArgsConstructor
public class TestDataSecond {
private String statusName;
private String status;
private String code;
private String msg;
public TestDataSecond(String status, String code) {
this.status = status;
this.code = code;
}
}
public class Usage {
@YmAutofillResp
@GetMapping("/autofill")
public List<TestData> autofill() {
List<TestData> list = new ArrayList<>();
list.add(new TestData(TestStatusEnum.SUCCESS.getCode(), "1"));
list.add(new TestData(TestStatusEnum.FAIL.getCode(), "2"));
return list;
}
@YmAutofillResp({
@YmAutofill(from = "status", target = "statusName", enumCls = TestStatusEnum.class),
@YmAutofill(from = "code", target = "msg", type = YmAutofillType.BEAN, handler = TestAutoFillHandler.class)
})
@GetMapping("/autofill-second")
public List<TestDataSecond> autofillSecond() {
List<TestDataSecond> list = new ArrayList<>();
list.add(new TestDataSecond(TestStatusEnum.SUCCESS.getCode(), "1"));
list.add(new TestDataSecond(TestStatusEnum.FAIL.getCode(), "2"));
return list;
}
}
```
------
## 完整默认配置文件
```yaml
yuanmeng:
web:
#- 开启starter
enable: true
#- 开启兼容排除
enable-ignore: true
#- 开启返回结果填充
enable-audit-handler: true
#- 开启返回结果自动封装 YmResult
enable-result-wrapper: true
#- 开启全局异常拦截
enable-exception-handler: true
filter:
#- 开启健康检查接口
enable-health-check: true
#- 开启上下文信息解析
enable-thread-local: true
#- 开启登录拦截器token校验
enable-user-login: false
#- 需要跳过的路径
skip-path:
- "/test"
#- 可重复读请求封装
request-body:
enable: true
filter-uris:
- "/test1"
#- 请求日志打印封装
track:
enable: true
filter-uris:
- "/test2"
sensitive-keys:
- "password"
print-type: 2
#- 打印请求体
print-request-body: true
#- 打印返回体
print-response-body: true
external-url-list:
- "/external/test"
#- i18n全局拦截
i18n:
enable: false
```