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

9.2 KiB
Raw Blame History

engine-starter-web 使用教程

基于 web 的各种工具封装
具体使用可参考 engine-sample > engine-sample-starter-web
去除 security 相关配置

功能特性

  • @YmAutoFill@YmAutoFillResp: 结果自动填充
  • @YmIgnoreResultWrapper: 忽略 Result 结果包装
  • YmResponseAdvice: 全局结果封装
  • YmGlobalExceptionHandlerAdvice: 全局异常拦截处理
  • YmAutofillResponseAdvice: 全局返回结果填充处理
  • YmI18nResponseAdvice: I18n全局处理
  • @YmIgnoreI18n: 忽略I18n
  • YmHealthCheckFilter: 全局健康检查接口
  • YmRequestBodyWrapperFilter: request 和 response 可重复读封装
  • YmRequestPrintFilter: 请求日志打印
  • YmThreadLocalFilter: 登录用户信息解析存储(后续会迁移到网关,需要兼容)
  • YmUserLoginFilter: 用户登录校验(后续会迁移到网关,默认关闭)
  • YmSecurityUtils: 登录用户信息获取

快速使用

  • 注意: qifu-saas-parent >= 1.1.0-SNAPSHOT
  • 注意: pom.xmlengine-starter-web 依赖要置于 web-coreoauth2-core 之前
  • 注意: 启动类 @ComponentScan 需要变更为如下形式
  • @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-coreoauth2-core 依赖。但是 SecurityUtils 需要改为 YmSecurityUtils

添加依赖


<dependency>
    <groupId>com.yuanmeng.engine</groupId>
    <artifactId>engine-starter-web</artifactId>
</dependency>

使用工具

忽略结果封装

public class Usage {

    /**
     * 测试忽略包装
     *
     * @return 结果
     */
    @YmIgnoreResultWrapper
    @GetMapping("/ignore-result-wrapper")
    public String ignoreResultWrapper() {
        return "ignore-result-wrapper success";
    }

}

全局异常拦截

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"));
    }

}

国际化支持

  • 开启国际化支撑
yuanmeng:
  web:
    i18n:
      enable: true
  • 添加国际化文件
    • 默认 resources > i18n > messages_zh_CN.properties
Base\ Error=服务端错误
  • 编写代码

@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);
}
  • 自定义国际化处理类(可选)

@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);
    }

}

结果自动填充


@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;
    }

}

完整默认配置文件

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