dispacheservlet

package org.mvc.framework.servlet;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.mvc.framework.annotation.XCAutowired;
import org.mvc.framework.annotation.XCController;
import org.mvc.framework.annotation.XCRequestMapping;
import org.mvc.framework.annotation.XCRequestParam;
import org.mvc.framework.annotation.XCService;

import com.alibaba.fastjson.JSON;

import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;

@SuppressWarnings("serial")
public class XCDispatcherServlet extends HttpServlet {
    
    private Properties properties = new Properties();
    
    private Map<String, Object> iocBean = new HashMap<>();
    
    private Map<String, Object> handerMap = new HashMap<>();
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        this.doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("收到用户请求");
        try {
            response.setHeader("Content-type", "text/html;charset=UTF-8");  
            String reqPath = request.getRequestURL().toString(); 
            String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()
                    + request.getContextPath(); 
            String url = reqPath.replace(basePath, "").replaceAll("/+", "/");
            HanlerInner inner = (HanlerInner) handerMap.get(url);
            if (null == inner) {
                response.getWriter().write("404 not Fund reuest");
                return;
            }
            Object object = iocBean.get(inner.getBeanName());
            List<Object> invokeMethod = new ArrayList<>();
            for (int i=0; i<inner.getParametersize(); i++) {
                String paramName = inner.getParameterNames()[i];
                Class<?> paramType = inner.getParameterTypes()[i];
                if (paramType.isAssignableFrom(HttpServletRequest.class)) {
                    invokeMethod.add(request);
                } else if (paramType.isAssignableFrom(HttpServletResponse.class)) {
                    invokeMethod.add(response);
                } else {
                    String paramValue = "";
                    Annotation[][] annotationParam = inner.getMethod().getParameterAnnotations();
                    if (null != annotationParam[i] && annotationParam[i].length > 0) {
                        Annotation[] annotations =  annotationParam[i];
                        Annotation annotation = annotations[0];
                        
                        String annoParamVal = "";
                        Boolean annoParamRequire = true;
                        if (annotation instanceof XCRequestParam) {
                            annoParamVal = ((XCRequestParam) annotation).value();
                            annoParamRequire = ((XCRequestParam) annotation).required();
                            if (StringUtils.isNotBlank(annoParamVal)) {
                                paramName = annoParamVal;
                            }
                            paramValue = new String(request.getParameter(paramName).getBytes("ISO-8859-1"), "UTF-8");
                            if (annoParamRequire && StringUtils.isBlank(paramValue)) {
                                throw new RuntimeException(Thread.currentThread().getName() + " server exception parameter "
                                        + paramName + " can not empty or null.");
                            }
                            if (StringUtils.isBlank(paramValue) && annoParamRequire) {
                                throw new RuntimeException("500 exception parameter " + paramName + " is empty or null");
                            }
                        }
                        Object val = invokeMethodParamValue(paramType, paramValue);
                        invokeMethod.add(val);
                    } else {
                        Map<String, String> requestParamsMap = new HashMap<>();
                        @SuppressWarnings("unchecked")
                        Enumeration<String> paraNames = request.getParameterNames();
                        while (paraNames.hasMoreElements()) {
                            String reqParamName = (String) paraNames.nextElement();
                            String reqParamValue= new String(request.getParameter(reqParamName).getBytes("ISO-8859-1"), "UTF-8");
                            requestParamsMap.put(reqParamName, reqParamValue);
                        }
                        validateSimpleParam(invokeMethod, paramName, inner.getParameterNames(), paramType, requestParamsMap, request);
                    }
                }
            }
            
            Object result = inner.getMethod().invoke(object, invokeMethod.toArray());
            String ret = new String(JSON.toJSONString(result).getBytes("UTF-8"));
            response.getWriter().write(ret);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    private void validateSimpleParam(List<Object> invokeMethod, String methodParamName, String[] parameters,
              Class<?> paramType, Map<String, String> requestParamsMap, HttpServletRequest request) {
        if (null == parameters || parameters.length <= 0) {
            return;
        }
        try {
            if(requestParamsMap.containsKey(methodParamName)) {
                Object val = invokeMethodParamValue(paramType, requestParamsMap.get(methodParamName));
                invokeMethod.add(val);
            } else {
                Object instance = paramType.newInstance();
                for(Field field : paramType.getDeclaredFields()) {
                    field.setAccessible(true);
                    if (requestParamsMap.containsKey(field.getName())) {
                        setMethodFieldValue(field.getName(), requestParamsMap.get(field.getName()), paramType, instance);
                    }
                }
                invokeMethod.add(instance);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    private void setMethodFieldValue(String methodFieldName, String methodFieldVal, Class<?> invokeCls, Object instance) {
        String methodName = "set" + upperFirstCase(methodFieldName);
        System.out.println("===== " + methodFieldName + " " + methodFieldVal + "=====");
        try {
            for(Field field0 : invokeCls.getDeclaredFields()) {
                field0.setAccessible(true);
                Field field = invokeCls.getDeclaredField(methodFieldName);
                if (null != field) {
                    Method method = invokeCls.getMethod(methodName, new Class[]{field.getType()});
                    method.invoke(instance, invokeMethodParamValue(field.getType(), methodFieldVal));
                    return;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    private boolean validateFiled(String fildName, Class<?> invokeCls) {
        for(Field field0 : invokeCls.getDeclaredFields()) {
            field0.setAccessible(true);
            if (field0.getName().equals(fildName)) {
                return true;
            }
        }
        return false;
    }
    
    private Object invokeMethodParamValue(Class<?> paramType, String paramValue) {
        System.out.println("start convert request parameter." + JSON.toJSONString(paramType));
        try {
            if (paramType == String.class) {
                return paramValue;
            } else if (paramType == Integer.class || paramType == int.class) {
                return Integer.valueOf(paramValue);
            } else if (paramType == Long.class || paramType == long.class) {
                return Long.valueOf(paramValue);
            } else if (paramType == Boolean.class || paramType == boolean.class) {
                return Boolean.valueOf(paramValue);
            } else if (paramType == Short.class || paramType == short.class) {
                return Short.valueOf(paramValue);
            } else if (paramType == Float.class || paramType == float.class) {
                return Float.valueOf(paramValue);
            } else if (paramType == Double.class || paramType == double.class) {
                return Double.valueOf(paramValue);
            } else if (paramType == BigDecimal.class) {
                return new BigDecimal(paramValue);
            } else if (paramType == Character.class || paramType == char.class) {
                char[] cs = paramValue.toCharArray();
                if (cs.length > 1) {
                    throw new IllegalArgumentException("参数长度太大");
                }
                return paramValue;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private String[] methodParameterName(Class<?> clazz, String methodName) {
        String nameParams[] = null;
        try {
            ClassPool classPool = ClassPool.getDefault();
            classPool.insertClassPath(new ClassClassPath(clazz));
            CtClass ctClass = classPool.get(clazz.getName());
            CtMethod ctMethod = ctClass.getDeclaredMethod(methodName);
            MethodInfo methodInfo = ctMethod.getMethodInfo();
            CodeAttribute attribute = methodInfo.getCodeAttribute();
            LocalVariableAttribute lAttribute = (LocalVariableAttribute) attribute.getAttribute(LocalVariableAttribute.tag);
            if (null == lAttribute) {
                throw new RuntimeException("500 get parameter");
            }
            nameParams = new String[ctMethod.getParameterTypes().length];
            int pos = Modifier.isStatic(ctMethod.getModifiers())?0 : 1;
            for (int i=0; i< nameParams.length; i++) {
                nameParams[i] = lAttribute.variableName(i + pos);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(JSON.toJSONString(nameParams));
        return nameParams;
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        
        System.out.println("-------------- init dispatcherServlet start ------------------");
        
        // 1 加载xml 
        doinitContextConfig(config);
        
        // 2 扫描包 初始化实例化bean IOC
        String basePackage = properties.getProperty("basescan.pacakge");
        doscanPacakge(basePackage);
        
        // 4 依赖注入bean
        doInitIDBean();
        
        // 5. 初始化handlerMapping
        doInitHandlerMapping();
        
        System.out.println("-------------- init dispatcherServlet end ------------------");
        
    }

    private void doInitHandlerMapping() {
        try {
            if (iocBean.isEmpty()) {return;}
            for (Map.Entry<String, Object> bean : iocBean.entrySet()) {
                Class<?> clazz = bean.getValue().getClass();
                if (clazz.isAnnotationPresent(XCController.class)) {
                    String basePath = clazz.getAnnotation(XCRequestMapping.class).value();
                    Method[] methods = clazz.getMethods();
                    if (methods.length <= 0) {continue;}
                    for (Method method : methods) {
                        String url = "";
                        HanlerInner inner = null;
                        if (method.isAnnotationPresent(XCRequestMapping.class)) {
                            inner = new HanlerInner();
                            String methodPath = method.getAnnotation(XCRequestMapping.class).value();
                            url = (basePath + "/" + methodPath).replaceAll("/+", "/");
                            inner.setUrl(url);
                            inner.setMethod(method);
                            inner.setBeanName(bean.getKey());
                            inner.setParameterTypes(method.getParameterTypes());
                            inner.setParametersize(method.getParameterTypes().length);
                            inner.setParameterNames(methodParameterName(clazz, method.getName()));
                        }
                        handerMap.put(url, inner);
                    }
                }
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void doInitIDBean() {
        try {
            if (iocBean.isEmpty()) {return;}
            for (Map.Entry<String, Object> entry : iocBean.entrySet()) {
                Class<?> claxx = entry.getValue().getClass();
                if (claxx.isAnnotationPresent(XCController.class)) {
                    System.out.println("controller 注入");
                    Field[] fields = claxx.getDeclaredFields();
                    for (Field field : fields) {
                        field.setAccessible(true);
                        if (field.isAnnotationPresent(XCAutowired.class)) {
                            String beanName = field.getAnnotation(XCAutowired.class).value();
                            if ("".equals(beanName)) {
                                beanName = field.getName();
                            }
                            System.out.println("controller 注入 名称 " + beanName + "  " + field.getType().getName());
                            Object instatnce = iocBean.get(beanName);
                            field.set(entry.getValue(), instatnce);
                        }
                    }
                    
                } else if (claxx.isAnnotationPresent(XCService.class)) {
                    System.out.println("service 注入");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void doscanPacakge(String basePackage) {
        try {
            if ("".equals(basePackage)) {
                return;
            }
            String basePath = basePackage.replace(".", "/");
            URL url = this.getClass().getClassLoader().getResource(basePath);
            
            File file = new File(url.getFile());
            File[] files = file.listFiles();
            for (File pack : files) {
                if (pack.isDirectory()) {
                    String nextPack = basePackage + "." + pack.getName();
                    doscanPacakge(nextPack);
                } else {
                    String className = pack.getName().replace(".class", "");
                    Class<?> instance = Class.forName(basePackage + "." + className);
                    Object object = null;
                    if (instance.isAnnotationPresent(XCController.class)) {
                        object = instance.newInstance();
                        iocBean.put(lowerFirstCase(className), object);
                    } else if (instance.isAnnotationPresent(XCService.class)) {
                        object = instance.newInstance();
                        String beanName = instance.getAnnotation(XCService.class).value();
                        if ("".equals(beanName)) {
                            Class<?> instanceInter[] = instance.getInterfaces();
                            for (Class<?> inter : instanceInter) {
                                if (inter.isAssignableFrom(instance)) {
                                    beanName = lowerFirstCase(inter.getSimpleName());
                                }
                            }
                        }
                        iocBean.put(beanName, object);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void doinitContextConfig(ServletConfig config) {
        try {
            String contextPath = config.getInitParameter("applicationContextListener");
            System.out.println("==== dispatcherservlet " + contextPath);
            InputStream in = this.getClass().getClassLoader().getResourceAsStream(contextPath);
            properties.load(in);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    /**
     * 首字母小写
     * @return
     */
    private String lowerFirstCase (String claxxName) {
        char[] chars = claxxName.toCharArray();
        chars[0] = (char) (chars[0] + 32);
        return String.valueOf(chars);
    }
    
    private String upperFirstCase (String claxxName) {
        char[] chars = claxxName.toCharArray();
        chars[0] = (char) (chars[0] - 32);
        return String.valueOf(chars);
    }
    
    class HanlerInner {
        private String url;
        private String beanName;
        private Pattern pattern;
        private Method method;
        private Integer parametersize;
        private String[] parameterNames;
        private Class<?>[] parameterTypes;
        public String getUrl() {
            return url;
        }
        public void setUrl(String url) {
            this.url = url;
        }
        public String getBeanName() {
            return beanName;
        }
        public void setBeanName(String beanName) {
            this.beanName = beanName;
        }
        public Pattern getPattern() {
            return pattern;
        }
        public void setPattern(Pattern pattern) {
            this.pattern = pattern;
        }
        public Method getMethod() {
            return method;
        }
        public void setMethod(Method method) {
            this.method = method;
        }
        public String[] getParameterNames() {
            return parameterNames;
        }
        public void setParameterNames(String[] parameterNames) {
            this.parameterNames = parameterNames;
        }
        public Class<?>[] getParameterTypes() {
            return parameterTypes;
        }
        public void setParameterTypes(Class<?>[] parameterTypes) {
            this.parameterTypes = parameterTypes;
        }
        public Integer getParametersize() {
            return parametersize;
        }
        public void setParametersize(Integer parametersize) {
            this.parametersize = parametersize;
        }
    }
}
 

转载于:https://my.oschina.net/u/2510361/blog/1834249

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值