Solon v3.0.7

实战 Gateway 模式效果

</> markdown

基于网关的开发,是一种责任链模式的实践,一关一责任,互不相扰,按需组合

1、定制网关(仅供参考)

  • 增加 before 和 after 处理,以实现“线性”处理模型。相对的 filter 则为“包围”处理模型。
  • 同时,修改 render 方法,将真正的渲染处理交由 after 处理(可以方法,配置式切换)。
public abstract class UapiGateway extends Gateway {
    private List<Handler> beforeHandlers = new ArrayList<>();
    private List<Handler> afterHandlers = new ArrayList<>();

    /**
     * 语言
     */
    public Locale lang(Context c) {
        return c.getLocale();
    }

    /**
     * 前置处理
     */
    public void before(Handler handler) {
        beforeHandlers.add(handler);
    }

    /**
     * 后置处理
     */
    public void after(Handler handler) {
        afterHandlers.add(handler);
    }

    @Override
    protected void mainBefores(Context c) throws Throwable {
        for (Handler h : beforeHandlers) {
            h.handle(c);
        }
    }

    @Override
    protected void mainAfters(Context c) throws Throwable {
        for (Handler h : afterHandlers) {
            h.handle(c);
        }
    }

    /**
     * 渲染定制
     */
    @Override
    public void render(Object obj, Context c) throws Throwable {
        if (c.getRendered()) {
            return;
        }

        c.setRendered(true);

        //
        // 有可能根本没数据过来
        //
        if (obj instanceof ModelAndView) {
            //如果有模板,则直接渲染
            //
            c.result = obj;
            c.render(obj);
        } else {
            //如果没有按Result tyle 渲染
            //
            if (obj == null && c.status() == 404) {
                obj = UapiCodes.CODE_4001011;
            }

            Result result = null;
            if (obj instanceof UapiCode) {
                c.attrSet(Attrs.log_level, Level.WARN.toInt());

                //处理标准的状态码
                UapiCode err = (UapiCode) obj;
                String description = UapiCodes.CODE_note(lang(c), err);

                result = Result.failure(err.getCode(), description);
            } else if (obj instanceof Throwable) {
                c.attrSet(Attrs.log_level, Level.WARN.toInt());

                //处理未知异常
                String description = UapiCodes.CODE_note(lang(c), UapiCodes.CODE_400);
                result = Result.failure(Result.FAILURE_CODE, description);
            } else if (obj instanceof ONode) {
                //处理ONode数据(为兼容旧的)
                result = Result.succeed(((ONode) obj).toData());
            } else if (obj instanceof Result) {
                //处理Result结构
                result = (Result) obj;
            } else {
                //处理java bean数据(为扩展新的)
                result = Result.succeed(obj);
            }

            if (Utils.isEmpty(result.getDescription()) && result.getCode() > Result.SUCCEED_CODE) {
                result.setDescription(UapiCodes.CODE_note(lang(c), result.getCode()));
            }

            c.result = result;
        }
    }
}

2、效果预览

定制过的本地网关

@Mapping("/api/v3/app/**")
@Component
public class ApiGateway3x extends UapiGateway {
    @Override
    protected void register() {
        filter(new BreakerFilter()); //融断

        before(new StartHandler()); //开始计时
        before(new ParamsParseHandler()); //参数解析
        before(new ParamsSignCheckHandler(new Md5Encoder())); //参数签名较验
        before(new ParamsRebuildHandler(new AesDecoder())); //参数重构

        after(new OutputBuildHandler(new AesEncoder())); //输出构建
        after(new OutputSignHandler(new Md5Encoder())); //输出签名
        after(new OutputHandler()); //输出
        after(new EndBeforeLogHandler()); //日志
        after(new EndHandler("v3.api.app")); //结束计时

        //添加一批具体的接口处理Bean
        addBeans(bw -> "api".equals(bw.tag()));
    }
}

接口

@Component(tag = "api")
public class API_config_set extends ApiBase {
    @Inject
    ConfigService configService;

    @NotEmpty({"tag", "key"})
    @Mapping("config.set")
    public void exec(String tag, String key, String value) throws Throwable {
        configService.setConfig(tag, key, value);
    }
}

3、具体参考:

https://gitee.com/noear/marsh/tree/main/_demo/marsh-api-demo2