@PathVariable
在web后端框架中,路由设计是很重要的一步。
各个框架对接口设计的支持大多差不多,其中必然有
1 2
| @GET("/users/{id}/") @GET("/users/:id/")
|
这样的标准。
其中{id}
和:id
表示是一个不确定的值,这个随着rustful
的兴起也变得常用起来
比如我想要查看id = 1
的用户的信息,那么我的请求便是/users/1
如果查看id = 321
的用户信息,请求的便是/users/321
。
那么这个id便是一个不确定量。
于是对于这个方法而言这个id值便是参数,在我们调用时需要传进去。
在Spring MVC
中,完整的方法是这样
1 2 3 4
| @GetMapping("/employer/{phoneNumber}") public ResponseEntity<?> findByPhoneNumber(@PathVariable String phoneNumber) { }
|
所以这就要求我们在设计框架时还需要利用反射把请求的uri的特定路径值作为参数传进方法中。
route设计
正常我们进行反射调用时,像这样
1
| method().invoke(object(), paramters());
|
首先route
中需要有这个对应的Method
,其次对应的对象也应该在其中,然后是参数。
于是我设计为
1 2 3 4 5 6 7 8 9 10 11 12
| class Route { private String path; private Object object; private Method method; private HttpMethod httpMethod; private Object[] paramters; }
|
路由匹配
那么问题来了,对于不同的uri,我们应该怎么匹配路由呢。
我想到的是用正则
设计一个这样的Map
1
| Map<Pattern, Route> routeMap = new HashMap<>();
|
对于/users/{id}/
这样的字符串,我们需要产生一个pattern
出来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public static Pattern pathCompiler(String path, Method method) { Parameter[] parameters = method.getParameters(); for (Parameter parameter : parameters) { if (parameter.getAnnotations() == null) { continue; } Annotation annotation = parameter.getAnnotations()[0]; if (annotation instanceof PathVariable) { if (parameter.getType() == String.class) { path = path.replace("{" + parameter.getName()+"}","[0-9\\d\\D]*"); } else if (parameter.getType() == Integer.class || parameter.getType() == Long.class) { path = path.replace("{" + parameter.getName()+"}","[0-9]*"); } } } return Pattern.compile(path); }
|
键为url
的Pattern
,那么在匹配时只要遍历一下
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| Map<Pattern, Route> routeMap = new HashMap<>(); public static Route findRoute(String path, HttpMethod method) { for (Pattern pattern : routeMap.keySet()) { if (pattern.matcher(path).matches()) { if (routeMap.get(pattern).getHttpMethod().equals(method)) {
|