Skip to content

Latest commit

 

History

History
195 lines (152 loc) · 4.32 KB

2.route.md

File metadata and controls

195 lines (152 loc) · 4.32 KB

路由设计

现代 Web 应用的 URL 十分优雅,易于人们辨识记忆。 路由的表现形式如下:

/resources/:resource/actions/:action
http://bladejava.com
http://bladejava.com/docs/modules/route

那么我们在java语言中将他定义一个 Route 类, 用于封装一个请求的最小单元, 在Mario中我们设计一个路由的对象如下:

/**
 * 路由
 * @author biezhi
 */
public class Route {

	/**
	 * 路由path
	 */
	private String path;

	/**
	 * 执行路由的方法
	 */
	private Method action;

	/**
	 * 路由所在的控制器
	 */
	private Object controller;

	public Route() {
	}

	public String getPath() {
		return path;
	}

	public void setPath(String path) {
		this.path = path;
	}

	public Method getAction() {
		return action;
	}

	public void setAction(Method action) {
		this.action = action;
	}

	public Object getController() {
		return controller;
	}

	public void setController(Object controller) {
		this.controller = controller;
	}

}

所有的请求在程序中是一个路由,匹配在 path 上,执行靠 action,处于 controller 中。

Mario使用一个Filter接收所有请求,因为从Filter过来的请求有无数,如何知道哪一个请求对应哪一个路由呢? 这时候需要设计一个路由匹配器去查找路由处理我们配置的请求, 有了路由匹配器还不够,这么多的路由我们如何管理呢?再来一个路由管理器吧,下面就创建路由匹配器和管理器2个类:

/**
 * 路由管理器,存放所有路由的
 * @author biezhi
 */
public class Routers {

	private static final Logger LOGGER = Logger.getLogger(Routers.class.getName());
	
	private List<Route> routes = new ArrayList<Route>();
	
	public Routers() {
	}
	
	public void addRoute(List<Route> routes){
		routes.addAll(routes);
	}
	
	public void addRoute(Route route){
		routes.add(route);
	}
	
	public void removeRoute(Route route){
		routes.remove(route);
	}
	
	public void addRoute(String path, Method action, Object controller){
		Route route = new Route();
		route.setPath(path);
		route.setAction(action);
		route.setController(controller);
		
		routes.add(route);
		LOGGER.info("Add Route:[" + path + "]");
	}

	public List<Route> getRoutes() {
		return routes;
	}

	public void setRoutes(List<Route> routes) {
		this.routes = routes;
	}
	
}

这里的代码很简单,这个管理器里用List存储所有路由,公有的 addRoute 方法是给外部调用的。

/**
 * 路由匹配器,用于匹配路由
 * @author biezhi
 */
public class RouteMatcher {

	private List<Route> routes;

	public RouteMatcher(List<Route> routes) {
		this.routes = routes;
	}
	
	public void setRoutes(List<Route> routes) {
		this.routes = routes;
	}

	/**
	 * 根据path查找路由
	 * @param path	请求地址
	 * @return		返回查询到的路由
	 */
	public Route findRoute(String path) {
		String cleanPath = parsePath(path);
		List<Route> matchRoutes = new ArrayList<Route>();
		for (Route route : this.routes) {
			if (matchesPath(route.getPath(), cleanPath)) {
				matchRoutes.add(route);
			}
		}
		// 优先匹配原则
        giveMatch(path, matchRoutes);
        
        return matchRoutes.size() > 0 ? matchRoutes.get(0) : null;
	}

	private void giveMatch(final String uri, List<Route> routes) {
		Collections.sort(routes, new Comparator<Route>() {
			@Override
			public int compare(Route o1, Route o2) {
				if (o2.getPath().equals(uri)) {
					return o2.getPath().indexOf(uri);
				}
				return -1;
			}
		});
	}
	
	private boolean matchesPath(String routePath, String pathToMatch) {
		routePath = routePath.replaceAll(PathUtil.VAR_REGEXP, PathUtil.VAR_REPLACE);
		return pathToMatch.matches("(?i)" + routePath);
	}

	private String parsePath(String path) {
		path = PathUtil.fixPath(path);
		try {
			URI uri = new URI(path);
			return uri.getPath();
		} catch (URISyntaxException e) {
			return null;
		}
	}

}

路由匹配器使用了正则去遍历路由列表,匹配合适的路由。当然我不认为这是最好的方法, 因为路由的量很大之后遍历的效率会降低,但这样是可以实现的,如果你有更好的方法可以告诉我 :)

在下一章节我们需要对请求处理做设计了~

links