keyfil/文档/基础组件/20250509-EngineStarterWeb使用指南.md
liuxiaohua d0545d80ff
All checks were successful
Publish to Confluence / confluence (push) Successful in 1m32s
[2025-05-23] 梳理使用文档
2025-05-23 15:49:26 +08:00

364 lines
9.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- Space: qifu -->
<!-- Parent: 后端技术&知识&规范 -->
<!-- Parent: 技术方案 -->
<!-- Parent: 基建 -->
<!-- Parent: 00-基础组件 -->
<!-- Title: 20250509-EngineStarterWeb使用指南 -->
<!-- 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)
> 去除 security 相关配置
## 功能特性
- [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] `YmSecurityUtils`: 登录用户信息获取
-------
## 快速使用
- **注意:** `qifu-saas-parent >= 1.1.0-SNAPSHOT`
- **注意:** `pom.xml``engine-starter-web` 依赖要置于 `web-core``oauth2-core` 之前
- **注意:** 启动类 `@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);
}
}
```
- **(可选操作)** 引入 `engine-starter-web` 后可以移除 `web-core` 和 `oauth2-core` 依赖。但是 `SecurityUtils` 需要改为
`YmSecurityUtils`
### 添加依赖
```xml
<dependency>
<groupId>com.yuanmeng.engine</groupId>
<artifactId>engine-starter-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
enable-result-wrapper: true
enable-exception-handler: true
filter:
enable-health-check: true
enable-thread-local: true
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
external-url-list:
- "/external/test"
i18n:
enable: true
```