# 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 com.yuanmeng.engine engine-starter-web ``` ---- ## 使用工具 ### 忽略结果封装 ```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 { 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 = (Collection) ids; Map 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 autofill() { List 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 autofillSecond() { List 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 ```