All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.unique.web.core.RouteMapping Maven / Gradle / Ivy

/**
 * Copyright (c) 2014-2015, biezhi 王爵 ([email protected])
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.unique.web.core;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.unique.commons.utils.CollectionUtil;
import org.unique.commons.utils.StringUtils;
import org.unique.ioc.AbstractBeanFactory;
import org.unique.ioc.impl.SingleBean;
import org.unique.web.annotation.Controller;
import org.unique.web.annotation.PathParam;
import org.unique.web.annotation.Route.HttpMethod;
import org.unique.web.render.Render;

/**
 * 路由映射器
 * @author biezhi
 * @since 1.0
 */
public final class RouteMapping {
	
	private static Logger logger = LoggerFactory.getLogger(RouteMapping.class);

	private final Map urlMapping;
	
	private final AbstractBeanFactory beanFactory;

	private RouteMapping() {
		urlMapping = CollectionUtil.newHashMap();
		beanFactory = new SingleBean();
	}

	public static RouteMapping single() {
		return SingleHoder.single;
	}

	private static class SingleHoder {
		private static final RouteMapping single = new RouteMapping();
	}

	/**
	 * 构建actionMapping映射
	 * @return action映射的map
	 */
	public Map buildRouteMapping() {
		urlMapping.clear();
		//所有控制器
		List> controllerList = beanFactory.getClassesByAnnotation(Controller.class);
		
		if(null != controllerList && controllerList.size() > 0){
			//遍历控制器
			for (Class controller : controllerList) {
				Method[] methods = controller.getMethods();
				String nameSpace = controller.getAnnotation(Controller.class).value();
				nameSpace = nameSpace.endsWith("/") ? nameSpace : nameSpace + "/";
				
				//构建路由
				buildRoute(controller, nameSpace, methods);
				
			}
		}
		logger.info("route size :" + urlMapping.size());
		return urlMapping;
	}
	
	/**
	 * 构建路由
	 * @param controller 	控制器class
	 * @param nameSpace 	控制器命名空间
	 * @param methods 		控制器方法
	 */
	private void buildRoute(Class controller, String nameSpace, Method[] methods){
		for (Method method : methods) {
			
			org.unique.web.annotation.Route mapping = method.getAnnotation(org.unique.web.annotation.Route.class);
			//route方法
			if (isLegalRoute(method) && null != mapping) {
				
				// action路径
				String path = mapping.value().equals("default") ? method.getName() : mapping.value();
				
				HttpMethod methodType = mapping.method();
				
				String viewPath = (nameSpace +  path).replaceAll("(//)+", "/");
				String viewReg = viewPath;
				
				if(!isLegalAction(viewReg)){
					warnning(controller, method, " 不合法的action!");
					continue;
				}
				
				Parameter[] parameters = method.getParameters();
				Object[] arguments = new Object[parameters.length];
				
				//URL参数构建
				viewReg = buildParam(parameters, viewReg);
				
				// 构建一个路由
				Route action = new Route(controller, method, arguments, methodType, viewPath);
				
				if (null != urlMapping.get(viewReg)) {
					warnning(controller, method, "route \"" + viewPath + "\"重复");
				}
				urlMapping.put(viewReg, action);
				logger.info("route:" + viewPath);
			}
		}
	}
	
	/**
	 * 构建参数
	 * @param parameters	参数列表
	 * @param viewReg		url正则
	 * @return
	 */
	private String buildParam(Parameter[] parameters, String viewReg){
		if (parameters.length > 0 && viewReg.indexOf(":") != -1) {
			// 遍历方法内的参数
			for (int i = 0,len=parameters.length; i < len; i++) {
				// 如果有url path参数
				PathParam pathParam = parameters[i].getDeclaredAnnotation(PathParam.class);
				if (null != pathParam) {
					// 存在该参数
					if(parameters[i].getType().equals(Integer.class)){
						viewReg = viewReg.replaceFirst("/(:\\w+)", "/(\\\\d+)");
					}
					if(parameters[i].getType().equals(String.class)){
						viewReg = viewReg.replaceFirst("/(:[\u4e00-\u9fa5_a-zA-Z0-9]+)", "/([\u4e00-\u9fa5_a-zA-Z0-9]+)");
					}
				}
			}
		}
		//return "^" + viewReg + "$";
		return viewReg;
	}
	
	
	/**
	 * 取得访问修饰符为public的方法集合
	 * @return 要过滤的方法
	 */
	private Set buildExcludedMethodName() {
		Set publicMethodNameSet = CollectionUtil.newHashSet();
		Method[] methods = Object.class.getMethods();
		for (Method method : methods) {
			publicMethodNameSet.add(method.getName());
		}
		// jrebel产生的代理方法__rebel_clinit,需要将此方法排除
		publicMethodNameSet.add("__rebel_clinit");
		return publicMethodNameSet;
	}
	
	/**
	 * 判断action上的映射是否是一个合法的
	 * @param action	方法注解的value 
	 * @return 			boolean
	 */
	private boolean isLegalAction(final String action){
		String regex = "^([\\w-_#&/:=.;%?])+$";
		Pattern p = Pattern.compile(regex);
		Matcher m = p.matcher(action);
		return m.find();
	}

	/**
	 * 判断是否是一个合法的action请求
	 * @param method		方法
	 * @return				true:合法 false:不合法
	 */
	private boolean isLegalRoute(Method method) {
		Set excludedMethod = this.buildExcludedMethodName();
		if (excludedMethod.contains(method.getName())) {
			return false;
		}
		if (Modifier.isStatic(method.getModifiers())) {
			return false;
		}
		if (Modifier.isPrivate(method.getModifiers())) {
			return false;
		}
		org.unique.web.annotation.Route mapping = method.getAnnotation(org.unique.web.annotation.Route.class);
		if (null != mapping && mapping.value().length() == 0) {
			return false;
		}
		Class returnType = method.getReturnType();
		// 支持三种返回值
		if (!returnType.equals(void.class) && !returnType.equals(String.class) && !returnType.equals(Render.class)) {
			return false;
		}
		return true;
	}
	
	private final void warnning(Class clazz, Method method, String msg) {
		logger.warn(clazz.getName() + "|" + method.getName() + "," + msg);
	}
	
	/**
	 * 根据url获取Action
	 * @param url		请求的url
	 * @return Action	对象
	 */
	public Route getRoute(String targetPath) {
		Route action = urlMapping.get(targetPath);
		if (null == action) {
			String indexTarget = targetPath.endsWith("/") ? targetPath + "index" : targetPath + "/index";
			action = urlMapping.get(indexTarget);
			if (null == action) {
				Set mappings = urlMapping.keySet();
				for (String mapping : mappings) {
					Pattern p = Pattern.compile("^" + mapping + "$");
					Matcher m = p.matcher(targetPath);
					if (m.find()) {
						action = urlMapping.get(mapping);
						Object[] args = action.getParameters();
						for (int i = 0; i < args.length; i++) {
							String param = targetPath.replaceFirst(mapping, "$" + (i + 1));
							args[i] = parseObject(param);
						}
						break;
					}
				}
			}
		}
		return action;
	}
	
	/**
	 * 字符串转对象
	 * @param param		字符串参数
	 * @return Object	对象
	 */
	private Object parseObject(final String param) {
		if (StringUtils.isNumeric(param)) {
			return Integer.valueOf(param);
		}
		return param;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy