代码拉取完成,页面将自动刷新
汇聚http的上层接口数据路由, 用于rpc数据交换, 事件模型等 到 同一个MVC逻辑处理中心
抽象一个系统所有的公共功能方法, 统一由一个MVC中心管理
不管是http请求还是, rpc跨系统调用, 事件触发等, 都由同一个MVC去派发执行
<dependency>
<groupId>cn.xnatural</groupId>
<artifactId>xchain</artifactId>
<version>1.1.2</version>
</dependency>
@Route("/a/b/{c}")
Object test(String c, String p1, Integer p2) {
Map<String, Object> resp = new HashMap();
resp.put("c", c);
resp.put("p1", p1);
resp.put("p2", p2);
return resp;
}
@Route(path = "arr")
Object arr(Integer[] ids) {
return Arrays.stream(ids).map(i -> i + 1).collect(Collectors.toList());
}
@Route(path = "map")
Object arr(Map<String, Object> data) {
return data;
}
@Route(path = "optional")
Object optional(Optional<String> kw) {
return kw.orElse("optional");
}
// 指定协议
@Route(path = "proto", protocol="test")
Object proto(){
return "xxx";
}
// 数组参数
mvc.handle("/arr?ids[]=1&ids[]=2");
// map 参数
mvc.handle("/map?data[a]=1&data[b]=2");
// Optional 参数
mvc.handle("/optional");
// 指定协议
mvc.handle("/proto", "test");
@Filter.prefix 配置需要过滤拦截的路由前缀
方法返回
- boolean, false: 则中断往下匹配执行
- 其他忽略
// 创建一个mvc
IMvc<Context> mvc = new IMvc() {
final Chain<Context> chain = new Chain(this);
@Override
public Chain<Context> chain() { return chain; }
@Override
public void render(Context ctx, Object body, Consumer<Object> afterFn) {
log.info("render: {}, {}", ctx.path, body);
}
// 异常统一处理
@Override
public void errHandle(Context ctx, Throwable ex) {
log.error("error: " + ctx.id(), ex);
}
};
// 添加路由处理
mvc.chain().route("/a/b/{c}", ctx -> {
ctx.render(ctx.param("c"));
});
// 从对象中解析路由处理器
mvc.chain().resolve(new Object() {
@Filter(prefix = "/a")
void f() {
log.info("=====filter");
}
@Route(path = "/a/b/d")
Object test() {
return "dd";
}
});
// 手动执行一个路由请求
Map<String, Object> param = new HashMap<>();
param.put("p1", "1");
// 手动执行一个路由请求
mvc.handle("/a/b/" + s + "?p=1", param);
协议名 -> 节点链
协议名: (非必须)支持哪种协议, 用于处理器分组, 不区分大小写
节点链: 按照节点处理器的优先级排序链成链
排序优先级规则: (优先级越高节点越靠前)
- 分片个数越大越优先级越高
- 单分片规则
- 分片是 / 优先级最低
- 分片字符串越明确(固定字符串)优先级越高
- 例1: a 高于 {var}
- 例2: a{var1}b 高于 a{var}
- 例3: a{var1}b{var2} 高于 a{var1}b
- 最后分片按字符串a-z顺序比较优先级
匹配执行流程
- 找到对应的请求协议, 然后从头往下节点依次匹配执行
- 跳跃匹配: 如果节点匹配结果code有对应的跳跃节点
节点匹配结果code对应
- 0: 匹配
- -1: 不匹配: 请求路径分片 少于 当前节点路径分片
- -2: 不匹配: method
- -3: 不匹配: consume
- -4: 不匹配: produce
- >0: 不匹配: 是路由的第几个分片不匹配
{
"": {
Route[/a/b],
}
"x-ap": {
Route[(GET)/key/{key}/{dataKey}]{1=Route[(POST)/dataVersion]},
Route[(GET)/key/{key}],
Route[(POST)/dataVersion],
}
"websocket": {
WS[(websocket)/test/msg],
WS[(websocket)/ws],
}
"x-cluster": {
Route[(POST)/nodeDown/{infect}]{-1=Route[(GET)/apps]},
Route[(GET)/nodes/{appName}],
Route[(GET)/apps],
Route[(GET)/group],
Route[(POST)/nodeUp],
Route[(POST)/nodeUpdate],
Route[/sync],
}
"x-piecefile": {
Route[/test/upload],
}
"http": {
Filter[(0)/],
Filter[(1)/test/],
Filter[(0)/test/]{0=Route[/test/async]},
Route[/view/policy/collector/{fName}]{-1=Route[(GET)/collector/collectResult/{id}], 1=Route[(POST)/collector/{id}/enable/{enabled}], 2=Route[/view/data/{fName}]},
Route[/view/policy/field/{fName}],
Route[(POST)/collector/{id}/enable/{enabled}],
Route[(PUT)/user/{uId}/addPrivilege/{privilegeId}]{1=Route[(GET)/collector/collectResult/{id}]},
Route[(DELETE)/user/{uId}/delPrivilege/{privilegeId}],
Route[(GET)/user/{uId}/hasPrivilege/{privilegeId}],
Route[(GET)/user/{uId}/privilegePaging/{page}],
Route[(GET)/collector/collectResult/{id}]{-1=Route[/decision/clean], 1=Route[/css/fonts/{fName}]},
Route[/collector/collectResultPaging/{page}],
Route[(GET)/collector/paging/{page}]{2=Route[/collector/{id}/test]},
Route[/css/fonts/{fName}]{1=Route[(GET)/decision/decideResult/{decideId}]},
Route[/css/lib/{fName}]{2=Route[/css/{fName}]},
Route[(GET)/decision/decideResult/{decideId}]{1=Route[(GET)/field/paging/{page}]},
Route[(GET)/decision/decideResultDetail/{decideId}],
Route[/decision/decideResultPaging/{page}],
Route[/decision/paging/{page}]{2=Route[/decision/{id}/decide]},
Route[(GET)/field/paging/{page}]{2=Route[(POST)/field/{id}/updateType]},
Route[/js/lib/{fName}]{2=Route[/js/{fName}]},
Route[(GET)/user/paging/{page}]{2=Route[(POST)/user/{uId}/changePwd]},
Route[/view/data/{fName}]{2=Route[/view/{fName}]},
Route[/collector/{id}/test],
Route[/decision/{id}/decide]{1=Route[(POST)/field/{id}/updateType]},
Route[(POST)/decision/{id}/updateApiConfig],
Route[(POST)/decision/{id}/updateDsl],
Route[(POST)/field/{id}/updateType],
Route[(POST)/user/{uId}/changePwd]{1=Route[/decision/clean]},
Route[(POST)/user/{uId}/restPassword],
Route[/decision/clean]{-1=Route[(PUT)/collector/], 1=Route[/test/async]},
Route[(GET)/decision/countDecideResult],
Route[(GET)/decision/countRuleResult]{2=Route[(DELETE)/decision/{id}]},
Route[/test/async]{1=Route[(application/json)/api-doc/{fName}.json]},
Route[/test/auth],
Route[/test/cus],
Route[/test/dao],
Route[(application/json)/test/error],
Route[(application/x-www-form-urlencoded)/test/form],
Route[(application/json)/test/json],
Route[/test/login],
Route[/test/remote],
Route[/test/string],
Route[/test/timeout],
Route[/test/upload],
Route[(application/json)/api-doc/{fName}.json]{1=Route[(POST)/collector/{id}]},
Route[/api-doc/{fName}],
Route[(POST)/collector/{id}]{1=Route[/component/{fName}]},
Route[(DELETE)/collector/{id}],
Route[/component/{fName}],
Route[/css/{fName}],
Route[(DELETE)/decision/{id}],
Route[(POST)/field/{id}]{1=Route[/file/{fName}]},
Route[(DELETE)/field/{id}],
Route[/file/{fName}],
Route[/img/{fName}],
Route[/js/{fName}],
Route[/opHistoryPaging/{page}],
Route[(DELETE)/user/{uId}],
Route[/view/{fName}],
Route[(PUT)/collector/],
Route[(GET)/currentUser],
Route[(PUT)/decision/],
Route[/favicon.ico],
Route[(PUT)/field/],
Route[/health],
Route[/index.html],
Route[/login],
Route[/logout],
Route[/test.html],
Route[(PUT)/user/],
Route[(GET)/webConfig],
Route[/],
}
"dataversion": {
Route[/collector],
Route[/decision],
Route[/field],
Route[/user],
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。