pathHandle怎么处理/a/b/:id这样的注册呢?
Opened this issue · 4 comments
很常见的一个场景是注册的uri为:/a/b/:id,最终能匹配到/a/b/523525之类的path并且将id=523525传递给handle。这样的需求只能通过regxhandle来满足吗?
目前没有这样的功能,需要在现在的基础上开发UriHandler(欢迎提PR~)。可以参考一些后台路由框架的设计,例如express.js,路由匹配用的是 path-to-regexp。当然对于客户端也要考虑下性能问题。
嗯,美团这个路由相对更侧重这种混合交互的场景,我也觉得这种需求很常见。现在我是魔改了regex相关,来满足自己的需求,可以参考下我的魔改版本;
使用上,依旧使用RouterRegex
,然后路由地址 http[s]?:/xxx.xxxx.com/video/{id} 使用{id}包裹路径参数,获取参数可以在intent.getStringExtra("{id}")。
我这种做法,就是把xxx/yyy/{id}
转换成xxx/yyy/([^/?]*)
,多个参数也行。
弊端挺明显,所以我称之为魔改,最大的缺陷就是你的路由不能带(xxxxx)这种子表达式,会影响参数顺序。
增加类:
com.sankuai.waimai.router.regex.PathRegexBean
package com.sankuai.waimai.router.regex;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
public class PathRegexBean {
private String pathRegex = "";
private List<String> params = new ArrayList<>();
private Pattern pattern;
public String getPathRegex() {
return pathRegex;
}
public void setPathRegex(String pathRegex) {
this.pathRegex = pathRegex;
pattern = Pattern.compile(pathRegex);
}
public Pattern getPattern() {
return pattern;
}
public void addParams (String paramsName){
params.add(paramsName);
}
public List<String> getParams() {
return params;
}
}
魔改以下类
com.sankuai.waimai.router.regex.RegexAnnotationHandler
public class RegexAnnotationHandler extends ChainedHandler {
// private static Pattern sPathParamsRegex = Pattern.compile("/\\{(.*?)\\}");
private static Pattern sPathParamsRegex = Pattern.compile("/\{(\D[^/?]*?)\}");
//省略一大堆
public void register(String regex, Object target, boolean exported, int priority,
UriInterceptor... interceptors) {
PathRegexBean regex2 = converPathParams(regex);
if (regex2.getPattern() != null) {
UriHandler innerHandler = UriTargetTools.parse(target, exported, interceptors);
if (innerHandler != null) {
RegexWrapperHandler handler = new RegexWrapperHandler(regex2, priority,
innerHandler);
addChildHandler(handler, priority);
}
}
}
private PathRegexBean converPathParams(String regex) {
PathRegexBean bean = new PathRegexBean();
Matcher matcher = sPathParamsRegex.matcher(regex);
while (matcher.find()){
String waitReplace = matcher.group();
bean.addParams(waitReplace.substring(1));
}
String realRegex = regex;
for (String s : bean.getParams()) {
realRegex = realRegex.replace(s,"([^/?]*)");
}
bean.setPathRegex(realRegex);
return bean;
}
}
com.sankuai.waimai.router.regex.RegexWrapperHandler
package com.sankuai.waimai.router.regex;
import android.os.Bundle;
import android.support.annotation.NonNull;
import com.sankuai.waimai.router.common.WrapperHandler;
import com.sankuai.waimai.router.components.ActivityLauncher;
import com.sankuai.waimai.router.core.UriHandler;
import com.sankuai.waimai.router.core.UriRequest;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by jzj on 2018/3/26.
*/
public class RegexWrapperHandler extends WrapperHandler {
//省略.........
@Override
protected boolean shouldHandle(@NonNull UriRequest request) {
Matcher matcher = mPathRegexBean.getPattern().matcher(request.getUri().toString());
if (matcher.matches()){
Bundle bundle = extraFill(request);
for (int i = 0; i < mPathRegexBean.getParams().size(); i++) {
String key = mPathRegexBean.getParams().get(i);
request.putField(key,matcher.group(i+1));
bundle.putString(key,request.getStringField(key));
}
return true;
}
return false;
}
private Bundle extraFill(@NonNull UriRequest request) {
Bundle extra = request.getField(Bundle.class, ActivityLauncher.FIELD_INTENT_EXTRA, null);
if (extra == null) {
extra = new Bundle();
request.putField(ActivityLauncher.FIELD_INTENT_EXTRA, extra);
}
return extra;
}
}
写的挺好的,主要问题在于你这里是直接在原有的regex字段上增加了你设定的 “{}” 这种非标准语法,和正则表达式自身语法冲突了,这样会有两个问题,一个就是你说的问题,正则表达式不能用小括号,会导致参数匹配不对;另一个问题就是正则表达式也不能用大括号,可能会被错误的识别成参数。
path-to-regexp的实现是定义了一个专用的path语法,统一转成正则,这样就不会和正则表达式自身的语法冲突了。所以还是得新增注解或者新增注解参数,自己定义语法,才能比较好的解决问题,不过实现有点费劲……