手寫springmvc-dispathcherServlet

package org.mvc.framework.servlet;html

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.InvocationTargetException;
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.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Pattern;java

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

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;json

import com.alibaba.fastjson.JSON;mvc

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

@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);
    }ide

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("收到用戶請求");
        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 == HttpServletRequest.class) {
                invokeMethod.add(request);
            } else if (paramType == 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");
                        }
                    }
                } else {
                    paramValue = new String(request.getParameter(paramName).getBytes("ISO-8859-1"), "UTF-8");
                }
                Object val = invokeMethodParamValue(request, response, paramType, paramValue);
                invokeMethod.add(val);
            }
        }
        try {
            Object result = inner.getMethod().invoke(object, invokeMethod.toArray());
            String ret = new String(JSON.toJSONString(result).getBytes("UTF-8"));
            response.getWriter().write(ret);
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }ui

    private Object invokeMethodParamValue(HttpServletRequest request , HttpServletResponse response,
            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;
    }this

    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();
        }
        return nameParams;
    }url

    @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("contextConfigLocation");
            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);     }          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;         }     } }  

相關文章
相關標籤/搜索