如何处理route的数据结构 ,如何构建route
来源:互联网 发布:linux清除文件夹内容 编辑:程序博客网 时间:2024/05/22 10:38
如何处理route的数据结构 ,如何构建route
route是一个在web程序中扮演很重要的角色,我们的uri其实就是一个路由,通过路由我们可以区分不同的请求,然后分派到具体的类中去执行响应具体的操作,那么怎么知道当前的uri到底是请求的哪个呢,这个就涉及到了route的数据结构的问题,慢慢的去体会他的无穷的奥妙。
Route的数据结构
public class Route { /** * HTTP Request Method */ private HttpMethod httpMethod; /** * Route path */ private String path; /** * Logical controller object */ private Object target; /** * Controller Class Type */ private Class<?> targetType; /** * Implementation logic controller method */ private Method action; public Route() { } public Route(HttpMethod httpMethod, String path, Object target, Class<?> targetType, Method action) { super(); this.httpMethod = httpMethod; this.path = Path.fixPath(path); this.target = target; this.targetType = targetType; this.action = action; } public HttpMethod getHttpMethod() { return httpMethod; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } public Object getTarget() { return target; } public void setTarget(Object target) { this.target = target; } public Method getAction() { return action; } public Class<?> getTargetType() { return targetType; } @Override public String toString() { return httpMethod + "\t" + path; }}//修正路径的信息哦 public static String fixPath(String path) { if (path == null) { return "/"; } if (!path.startsWith("/")) { path = "/" + path; } if (path.length() > 1 && path.endsWith("/")) { path = path.substring(0, path.length() - 1); } return path;}
HttpMethod 枚举信息
public enum HttpMethod { ALL, GET, POST, PUT, PATCH, DELETE, HEAD, TRACE, CONNECT, OPTIONS, BEFORE, AFTER}
Route的数据包含
- 请求的类型
- 请求的路径
- 响应的Class
- 响应的Object
- 响应的Method
根据以上的几点,我们根本上就可以根据请求的path路径找到相应的执行的的类的信息哦!你觉得了?是不是这个道理。
如何处理自己定义的Route
比如我们在使用spring mvc的时候,肯定在Controller层处理了好多的route对吧,那么我们怎么去获取这写处理的逻辑呢,这里进行简单的说明一下子。
下面的这个是Blade的核心类,里面包含的很多,什么Ioc,全局配置信息,自然也是拥有Routers和RouterBuilder( this.routeBuilder = new RouteBuilder(this.routers)),这里的保存的都是核心的东西,Blade是一个单例,这两个类到底是有何用?慢慢的揭晓这个答案,体会别人是怎么书写,怎么去构造这么大的工程的。
/** * Blade Core Class */public final class Blade { /** * Framework Global Configuration */ private BConfig bConfig; /** * Default ioc container */ private Ioc ioc = new SimpleIoc(); /** * Default routes 这个就是route的一个集合 */ private Routers routers = new Routers(); /** * Route builder 这里估计就是为了构建工程中书写的route放置在routers中去 */ private RouteBuilder routeBuilder; /** * filters */ private Map<Class<? extends Filter>, String[]> filters = CollectionKit.newHashMap(8); /** * servlets */ private Map<Class<? extends HttpServlet>, String[]> servlets = CollectionKit.newHashMap(8); /** * embed web server e.g:jetty/tomcat */ private EmbedServer embedServer; private Blade() { this.bConfig = new BConfig(); this.plugins = CollectionKit.newHashSet(); this.routeBuilder = new RouteBuilder(this.routers); } private static final class BladeHolder { private static final Blade $ = new Blade(); } /** * @return Single case method returns Blade object */ public static Blade $() { return BladeHolder.$; } /** * @return return route manager */ public Routers routers() { return routers; } /** * Setting Ioc packages, e.g:com.bladejava.service * * @param packages All need to do into the package, can be introduced into a * number of * @return return blade */ public Blade scan(String... packages) { bConfig.addScanPackage(packages); return this; } /** * Add a route * * @param path route path * @param clazz Target object for routing * @param method The method name of the route (at the same time, the HttpMethod * is specified: post:saveUser, if not specified, HttpMethod.ALL) * @return return blade */ public Blade route(String path, Class<?> clazz, String method) { routers.route(path, clazz, method); return this; } /** * regsiter filter * * @param clazz * @param pathSpec * @return */ public Blade registerFilter(Class<? extends Filter> clazz, String... pathSpec) { filters.put(clazz, pathSpec); return this; } /** * regsiter servlet * * @param clazz * @param pathSpec * @return */ public Blade registerServlet(Class<? extends HttpServlet> clazz, String... pathSpec) { servlets.put(clazz, pathSpec); return this; } /** * Register a functional route * * @param path route url * @param clazz route processing class * @param method route processing method name * @param httpMethod HttpMethod Type, GET/POST/... * @return Blade return blade */ public Blade route(String path, Class<?> clazz, String method, HttpMethod httpMethod) { routers.route(path, clazz, method, httpMethod); return this; } /** * Register a GET request route * * @param path route path, request url * @param handler execute route Handle * @return return blade */ public Blade get(String path, RouteHandler handler) { routers.route(path, handler, HttpMethod.GET); return this; } /** * Register a POST request route * * @param path route path, request url * @param handler execute route Handle * @return return blade */ public Blade post(String path, RouteHandler handler) { routers.route(path, handler, HttpMethod.POST); return this; } /** * Register a DELETE request route * * @param path route path, request url * @param handler execute route Handle * @return return blade */ public Blade delete(String path, RouteHandler handler) { routers.route(path, handler, HttpMethod.DELETE); return this; } /** * Register a PUT request route * * @param path route path, request url * @param handler execute route Handle * @return return blade */ public Blade put(String path, RouteHandler handler) { routers.route(path, handler, HttpMethod.PUT); return this; } /** * Register for any request routing * * @param path route path, request url * @param handler execute route Handle * @return return blade */ public Blade all(String path, RouteHandler handler) { routers.route(path, handler, HttpMethod.ALL); return this; } /** * Register for any request routing * * @param path route path, request url * @param handler execute route Handle * @return return blade */ public Blade any(String path, RouteHandler handler) { routers.route(path, handler, HttpMethod.ALL); return this; } /** * Register a pre routing request interceptor * * @param path route path, request url * @param handler execute route Handle * @return return blade */ public Blade before(String path, RouteHandler handler) { routers.route(path, handler, HttpMethod.BEFORE); return this; } /** * Register a after routing request interceptor * * @param path route path, request url * @param handler execute route Handle * @return return blade */ public Blade after(String path, RouteHandler handler) { routers.route(path, handler, HttpMethod.AFTER); return this; } /** * Setting the frame static file folder * * @param statics List of directories to filter, e.g: "/public,/static,/images" * @return return blade */ public Blade addStatics(final String... statics) { bConfig.addStatic(statics); return this; } /** * add interceptor * * @param interceptor interceptor class * @return return blade obj */ public Blade addInterceptor(Class<? extends Interceptor> interceptor) { routeBuilder.addInterceptor(interceptor); return this; } /** * @return Return blade config object */ public BConfig bConfig() { return bConfig; } /** * @return Return blade config object */ public Config config() { return bConfig.config(); } /** * @return Return blade encoding, default is UTF-8 */ public String encoding() { return bConfig.getEncoding(); } /** * @return Return blade web root path */ public String webRoot() { return bConfig.webRoot(); }}
还记得之前controller注解?初始化Ioc的时候 ,Controller也是一样的不同的是需要处理route
classInfo 中为class< ?>和 className
下面的数据都是我们Blade这个核心类中的哦
this.blade = Blade.$();//单例获取哦 Ioc ioc = blade.ioc(); //RouteBuilder中的routers也是blade中的哦。 RouteBuilder routeBuilder = blade.routeBuilder();
下面的我们仅仅关注route和拦截器也是属于route的一部分哦。
classInfos.forEach(c -> { Class< ?> clazz = c.getClazz(); if (!clazz.isInterface() && !Modifier.isAbstract(clazz.getModifiers())) { Service service = clazz.getAnnotation(Service.class); Controller controller = clazz.getAnnotation(Controller.class); RestController restController = clazz.getAnnotation(RestController.class); Component component = clazz.getAnnotation(Component.class); if (null != service || null != component) { ioc.addBean(clazz); } else if (null != controller || null != restController) { ioc.addBean(clazz); routeBuilder.addRouter(clazz);//处理注解中的route } else if (clazz.getSuperclass().getName().equals("com.blade.aop.AbstractMethodInterceptor")) { aopInterceptors.add(ReflectKit.newInstance(clazz)); } else { Class< ?>[] interfaces = clazz.getInterfaces(); for (Class< ?> in : interfaces) { if (in.equals(Interceptor.class)) { ioc.addBean(clazz); routeBuilder.addInterceptor(clazz); } else if (in.equals(WebContextListener.class)) { ctxClasses.add(c); } else if (in.equals(BeanProcessor.class)) { processoers.add(c); } } } }});
routerbuilder中处理Class类中的方法的注解哦,这个也是这个类的意思
基于设计模式的核心原则,单一原则(一个类只负责一件事)
addRouter,将当前类的所有的方法进行扫描,然后看看是否有注解,然后,将这个注解增加到routers中去处理涩,就是这样的逻辑。
//Parse all routing in a controller public void addRouter(final Class< ?> router) { Method[] methods = router.getMethods();//得到当前Class的所有的方法 if (null == methods || methods.length == 0) { return; } //route的空间和后缀 String nameSpace = null, suffix = null; if (null != router.getAnnotation(Controller.class)) { nameSpace = router.getAnnotation(Controller.class).value(); suffix = router.getAnnotation(Controller.class).suffix(); } if (null != router.getAnnotation(RestController.class)) { nameSpace = router.getAnnotation(RestController.class).value(); suffix = router.getAnnotation(RestController.class).suffix(); } if (null == nameSpace) { LOGGER.warn("Route [{}] not controller annotation", router.getName()); return; } for (Method method : methods) { //是否含有route的注解啊 Route mapping = method.getAnnotation(Route.class); //route method if (null != mapping) { // build multiple route,一个方法对应多个路由哦 HttpMethod methodType = mapping.method(); String[] paths = mapping.value(); if (paths.length > 0) { for (String path : paths) { String pathV = getRoutePath(path, nameSpace, suffix); this.buildRoute(router, method, pathV, methodType); } } } } }
修正不同的书写路径的写法
private String getRoutePath(String value, String nameSpace, String suffix) { String path = value.startsWith("/") ? value : "/" + value; nameSpace = nameSpace.startsWith("/") ? nameSpace : "/" + nameSpace; path = nameSpace + path; path = path.replaceAll("[/]+", "/"); path = path.length() > 1 && path.endsWith("/") ? path.substring(0, path.length() - 1) : path; path = path + suffix; return path;}
Route的注解
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface Route { /** * @return Request url */ String[] value() default {"/"}; /** * @return Request HttpMethod */ HttpMethod method() default HttpMethod.ALL;}
将所有的route需要耳朵class,Method,path等传递过去,,routers就是处理这个的哦,里面的Map<路径对应,一个route>,将当前的route信息扔过去就好了。
/** * Build a route * * @param clazz route target execution class * @param execMethod route execution method * @param path route path * @param method route httpmethod */ private void buildRoute(Class< ?> clazz, Method execMethod, String path, HttpMethod method) { routers.buildRoute(path, clazz, execMethod, method); }
看看routerbuilder整个类的完整的信息,这里还有个处理就是处理过滤器哦,拦截器哈哈!道理是一个样子的!
public class RouteBuilder { private Routers routers; public RouteBuilder(Routers routers) { this.routers = routers; } /** * Parse Interceptor * * @param interceptor resolve the interceptor class */ public void addInterceptor(final Class<?> interceptor) { boolean hasInterface = ReflectKit.hasInterface(interceptor, Interceptor.class); if (null == interceptor || !hasInterface) { return; } Intercept intercept = interceptor.getAnnotation(Intercept.class); String partten = "/.*"; if (null != intercept) { partten = intercept.value(); } try { Method before = interceptor.getMethod("before", Request.class, Response.class); Method after = interceptor.getMethod("after", Request.class, Response.class); buildInterceptor(partten, interceptor, before, HttpMethod.BEFORE); buildInterceptor(partten, interceptor, after, HttpMethod.AFTER); } catch (Exception e) { LOGGER.error("", e); } } /** * Parse all routing in a controller * * @param router resolve the routing class */ public void addRouter(final Class<?> router) { Method[] methods = router.getMethods(); if (null == methods || methods.length == 0) { return; } String nameSpace = null, suffix = null; if (null != router.getAnnotation(Controller.class)) { nameSpace = router.getAnnotation(Controller.class).value(); suffix = router.getAnnotation(Controller.class).suffix(); } if (null != router.getAnnotation(RestController.class)) { nameSpace = router.getAnnotation(RestController.class).value(); suffix = router.getAnnotation(RestController.class).suffix(); } if (null == nameSpace) { LOGGER.warn("Route [{}] not controller annotation", router.getName()); return; } for (Method method : methods) { Route mapping = method.getAnnotation(Route.class); //route method if (null != mapping) { // build multiple route HttpMethod methodType = mapping.method(); String[] paths = mapping.value(); if (paths.length > 0) { for (String path : paths) { String pathV = getRoutePath(path, nameSpace, suffix); this.buildRoute(router, method, pathV, methodType); } } } } } private String getRoutePath(String value, String nameSpace, String suffix) { String path = value.startsWith("/") ? value : "/" + value; nameSpace = nameSpace.startsWith("/") ? nameSpace : "/" + nameSpace; path = nameSpace + path; path = path.replaceAll("[/]+", "/"); path = path.length() > 1 && path.endsWith("/") ? path.substring(0, path.length() - 1) : path; path = path + suffix; return path; } /** * Build a route * * @param clazz route target execution class * @param execMethod route execution method * @param path route path * @param method route httpmethod */ private void buildRoute(Class<?> clazz, Method execMethod, String path, HttpMethod method) { routers.buildRoute(path, clazz, execMethod, method); } /** * Build a route * * @param path route path * @param clazz route target execution class * @param execMethod route execution method * @param method route httpmethod */ private void buildInterceptor(String path, Class<?> clazz, Method execMethod, HttpMethod method) { routers.buildRoute(path, clazz, execMethod, method); }}
Routers 这个比较好理解的直接贴代码了,其实就是Map < String,Route>
我们可以自己通过函数添加,或者自动扫描添加。可以发现,routers非常的完善,可以自己随意的定义一个处理器哦!
public class Routers { private Map<String, Route> routes = null; private Map<String, Route> interceptors = null; private static final String METHOD_NAME = "handle"; public Routers() { this.routes = CollectionKit.newConcurrentHashMap(); this.interceptors = CollectionKit.newConcurrentHashMap(); } public Map<String, Route> getRoutes() { return routes; } public Map<String, Route> getInterceptors() { return interceptors; } //路径的信息=path#方法名称 public void addRoute(Route route) { String path = route.getPath(); HttpMethod httpMethod = route.getHttpMethod(); String key = path + "#" + httpMethod.toString(); // existent if (null != this.routes.get(key)) { } if (httpMethod == HttpMethod.BEFORE || httpMethod == HttpMethod.AFTER) { if (null != this.interceptors.get(key)) { } this.interceptors.put(key, route); LOGGER.debug("Add Interceptor => {}", route); } else { this.routes.put(key, route); LOGGER.debug("Add Route => {}", route); } } public void addRoutes(List<Route> routes) { Assert.notNull(routes); routes.forEach(this::addRoute); } public void addRoute(HttpMethod httpMethod, String path, RouteHandler handler, String methodName) throws NoSuchMethodException { Class<?> handleType = handler.getClass(); Method method = handleType.getMethod(methodName, Request.class, Response.class); addRoute(httpMethod, path, handler, RouteHandler.class, method); } public void addRoute(HttpMethod httpMethod, String path, Object controller, Class<?> controllerType, Method method) { Assert.notBlank(path); String key = path + "#" + httpMethod.toString(); // existent if (null != this.routes.get(key)) { } Route route = new Route(httpMethod, path, controller, controllerType, method); if (httpMethod == HttpMethod.BEFORE || httpMethod == HttpMethod.AFTER) { if (null != this.interceptors.get(key)) { } this.interceptors.put(key, route); LOGGER.info("Add Interceptor: {}", route); } else { this.routes.put(key, route); LOGGER.info("Add Route => {}", route); } } public void route(String path, RouteHandler handler, HttpMethod httpMethod) { try { addRoute(httpMethod, path, handler, METHOD_NAME); } catch (NoSuchMethodException e) { throw new BladeException(e); } } public void route(String[] paths, RouteHandler handler, HttpMethod httpMethod) { for (String path : paths) { route(path, handler, httpMethod); } } private Map<String, Method[]> classMethosPool = CollectionKit.newConcurrentHashMap(16); private Map<Class<?>, Object> controllerPool = CollectionKit.newConcurrentHashMap(16); public void route(String path, Class<?> clazz, String methodName) { Assert.notNull(methodName, "Method name not is null"); HttpMethod httpMethod = HttpMethod.ALL; if (methodName.contains(":")) { String[] methodArr = methodName.split(":"); httpMethod = HttpMethod.valueOf(methodArr[0].toUpperCase()); methodName = methodArr[1]; } this.route(path, clazz, methodName, httpMethod); } public void route(String path, Class<?> clazz, String methodName, HttpMethod httpMethod) { try { Assert.notNull(path, "Route path not is null!"); Assert.notNull(clazz, "Class Type not is null!"); Assert.notNull(methodName, "Method name not is null"); Assert.notNull(httpMethod, "Request Method not is null"); Method[] methods = classMethosPool.get(clazz.getName()); if (null == methods) { methods = clazz.getMethods(); classMethosPool.put(clazz.getName(), methods); } if (null != methods) { for (Method method : methods) { if (method.getName().equals(methodName)) { Object controller = controllerPool.get(clazz); if (null == controller) { controller = ReflectKit.newInstance(clazz); controllerPool.put(clazz, controller); } addRoute(httpMethod, path, controller, clazz, method); } } } } catch (Exception e) { LOGGER.error("", e); } } public void buildRoute(String path, Class<?> clazz, Method method, HttpMethod httpMethod) { addRoute(httpMethod, path, null, clazz, method); }}
public interface RouteHandler { void handle(Request request, Response response);}
- 如何处理route的数据结构 ,如何构建route
- route IP 地址的处理
- Route
- Route
- route
- route
- Route
- ROUTE
- route
- route
- route
- ROUTE
- route
- route
- route
- Route
- route
- allegro 如何设置route keepin,package keepin
- nginx+tomcat+redis/memcached完成session共享
- 新闻推荐实例调研@今日头条@搜狐新闻
- leetCode刷题归纳-List(148 Sort List)
- SkLearn学习笔记
- 机器学习基石笔记(3-6)——机器学习的类型及机器学习有效性证明
- 如何处理route的数据结构 ,如何构建route
- 北大 C++ 8.4 list and deque
- 学以致用
- Netease
- Spring源码分析3----SpringMVC的设计与实现和视图的呈现
- Python中time模块详解
- pku1088
- 第3题:Longest Substring Without Repeating Characters
- js与jq处理盒子模型&&定位