手写springmvc-dispathcherServlet

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

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;
import javassist.bytecode.annotation.AnnotationMemberValue;

@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("收到用户请求");
        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();
        }
    }

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

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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值