手寫簡單mvc框架之xuchen-mvc-v1.0

package org.mvc.framework.servlet;html

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.JarURLConnection;
import java.net.URL;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;java

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRegistration;
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.XCcomponent;
import org.mvc.framework.annotation.XCcontroller;
import org.mvc.framework.annotation.XCrequestMapping;
import org.mvc.framework.annotation.XCrequestMethod;
import org.mvc.framework.annotation.XCrequestParam;
import org.mvc.framework.annotation.XCservice;
import org.mvc.framework.constant.CommonConstant;
import org.mvc.framework.entity.InnerHandler;
import org.mvc.framework.entity.Model;
import org.mvc.framework.entity.ModelMap;
import org.mvc.framework.handler.ClassReflectHandler;
import org.mvc.framework.handler.XmlBeanHandler;
import org.mvc.framework.utils.ContextPathUtil;
import org.mvc.framework.utils.StringCaseUtil;
import org.mvc.framework.utils.XmlUtils;
import org.mvc.framework.view.XCView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;json

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;mvc

public class XCDispatcherServlet extends HttpServlet {
    private static final long serialVersionUID = -5009321460671490398L;
    private static final Logger logger = LoggerFactory.getLogger(XCDispatcherServlet.class);
    private static final String CONTEXTCOMPONENTSCAN = "//" + CommonConstant.XML_CONTEXT_SCAN_PACAKAGE;
    private Map<String, Object> iocBeanMap = new HashMap<String, Object>();
    private Map<String, InnerHandler> handlerMapper = new HashMap<String, InnerHandler>();
    private Properties contextProperties = new Properties();app

    @Override
    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }jsp

    @Override
    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        System.out.println("[INFO ] @Override doPost 收到用戶請求。。。。");
    }
    
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("[INFO ] @Override service 收到用戶請求。。。。");
        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("/+", "/");
        System.out.println("[INFO ] " + url);
        InnerHandler inner = handlerMapper.get(url);
        if (null == inner) {
            System.out.println("[INFO ] service 404 not Fund reuest path " + url);
            response.getWriter().write("404 not Fund reuest");
        } else {
            doService(request, response, inner);
        }
    }ide

    /**
     * 處理請求
     * @throws ServletException 
     */
    private void doService(HttpServletRequest request, HttpServletResponse response, 
            InnerHandler inner) throws IOException, UnsupportedEncodingException, ServletException {
        request.setCharacterEncoding("UTF-8");//客戶端網頁咱們控制爲UTF-8
        String requestMethodType = request.getMethod();
        
        Method method0 = inner.getMethod();
        if(!validateRequstMethodType(requestMethodType, method0)) {
            response.getWriter().write(requestMethodType.toUpperCase() + " method not soupport......");
            return;
        }
        
        List<Object> invokeParamVal = new ArrayList<Object>();
        List<String> methodParamNames = inner.getMethodParameterNames();
        Model model = null;
        
        if (null!=methodParamNames && !methodParamNames.isEmpty()) {
            StringBuilder body = new StringBuilder();
            Map<String, Object> postQueryParam = null;
            if (CommonConstant.REQUEST_METHOD_TYPE_POST.equals(requestMethodType)) {
                doPostRequest(request, body);
                postQueryParam = StringCaseUtil.queryParam2Map(body.toString());
            }
            for (int i = 0; i < methodParamNames.size(); i++) {
                String methodParamName = methodParamNames.get(i);
                Class<?> methodParamType = inner.getMethodParameterTypes()[i];
                if (methodParamType.isAssignableFrom(HttpServletRequest.class)) {
                    invokeParamVal.add(request);
                } else if (methodParamType.isAssignableFrom(HttpServletResponse.class)) {
                    invokeParamVal.add(response);
                } else if (methodParamType.isAssignableFrom(Model.class)) {
                    model = new ModelMap();
                    invokeParamVal.add(model);
                } else {
                    String methodParamVal = "";
                    boolean notnull = false;
                    Annotation[][] annotationParam = inner.getParameterAnnotations();
                    if (null != annotationParam[i]&& annotationParam[i].length > 0) {
                        Annotation annotation = annotationParam[i][0];
                        if (annotation instanceof XCrequestParam) {
                            notnull = true;
                            methodParamName = ((XCrequestParam) annotation).value();
                        }
                    }
                    if (CommonConstant.REQUEST_METHOD_TYPE_GET.equals(requestMethodType)) {
                        logger.info("[INFO ] GET request......");
                        methodParamVal = request.getParameter(methodParamName);
                        if (notnull && StringUtils.isEmpty(methodParamVal)) {
                            response.getWriter().write(methodParamName + " cannot be null or empty");
                            return;
                        }
                    } else {
                        System.out.println("[INFO ] POST request deal with ......");
                        if (null != postQueryParam ) { 
                            if(postQueryParam.containsKey(methodParamName)) {
                                methodParamVal = String.valueOf(postQueryParam.get(methodParamName));
                                invokeParamVal.add(ClassReflectHandler.invokeMethodParamValue(methodParamType, methodParamVal));
                            } else {
                                // 判斷請求參數不是簡單的數據類型,判斷是某個的類
                                try {
                                    Field[] fileds = methodParamType.getDeclaredFields();
                                    Object instance = null;
                                    for (Field field : fileds) {
                                        field.setAccessible(true);
                                        String fieldName = field.getName();
                                        if(postQueryParam.containsKey(fieldName)) {
                                            if (null == instance) {
                                                instance = methodParamType.newInstance();
                                            }
                                            // (反射)若是請求的字段是該類的一個屬性,那麼,就設置建立一個實例而且設置值
                                            String setMethodName = "set" + StringCaseUtil.upperFirstCase(fieldName);
                                            Method method = methodParamType.getMethod(setMethodName, new Class<?>[]{field.getType()});
                                            
                                            String fieldValue = String.valueOf(postQueryParam.get(fieldName));
                                            method.invoke(instance, ClassReflectHandler.invokeMethodParamValue(field.getType(), fieldValue));
                                        }
                                    }
                                    invokeParamVal.add(instance);
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
                } 
            }
        }
        try {
            Object methodClazz = inner.getMethodClass().newInstance();
            Object result = inner.getMethod().invoke(methodClazz, invokeParamVal.toArray());
            // 反射執行方法後 先去判斷model 中是否有值,有就放到request
            if (null != model && model instanceof ModelMap) {
                @SuppressWarnings("unchecked")
                Map<String, Object> modelMap = (Map<String, Object>) model;
                copyModel2Request(request, modelMap);
            }
            
            if (result instanceof XCView) {
                XCView view = XCView.valueOf(result);
                String path = view.getPath();
                if (StringUtils.isNotEmpty(path)) {
                    if (path.startsWith("/")) {
                        response.sendRedirect(request.getContextPath() + path);
                    } else {
                        Map<String, Object> modelMap = view.getModel();
                        copyModel2Request(request, modelMap);
                        request.getRequestDispatcher(CommonConstant.JSP_BASE_PATH + path).forward(request, response);
                    }
                }
            } else if (result instanceof JSONObject) {
                response.setContentType("application/json; charset=utf-8");  
                response.getWriter().write(JSON.toJSONString(result));
            } else if (result instanceof String) {
                String path = "";
                if (String.valueOf(result).startsWith("/")) {
                    path = request.getContextPath() + String.valueOf(result);
                    response.sendRedirect(path.replaceAll("/+", "/"));
                } else {
                    path = CommonConstant.JSP_BASE_PATH + String.valueOf(result);
                    request.getRequestDispatcher(path.replaceAll("/+", "/")).forward(request, response);
                }
            }
        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | InstantiationException e) {
            e.printStackTrace();
        }
    }post

    private boolean validateRequstMethodType(String requestMethodType, Method method0) {
        if (null == method0) {
            return false;
        }
        if (method0.isAnnotationPresent(XCrequestMapping.class)) {
            XCrequestMapping requestMapping = method0.getAnnotation(XCrequestMapping.class);
            List<XCrequestMethod> requestMethodlist = Arrays.asList(requestMapping.method());
            if (requestMethodType.toUpperCase().equals("GET")) {
                if (requestMethodlist.contains(XCrequestMethod.GET)) {
                    return true;
                }
            } else {
                if (requestMethodlist.contains(XCrequestMethod.POST)) {
                    return true;
                }
            }
        }
        return false;
    }ui

    private void copyModel2Request(HttpServletRequest request, Map<String, Object> modelMap) {
        if (null != modelMap) {
            for (Map.Entry<String, Object> entry : modelMap.entrySet()) {
                request.setAttribute(entry.getKey(), entry.getValue());
            }
        }
    }

    private void doPostRequest(HttpServletRequest request, StringBuilder body)
            throws IOException {
        Enumeration<String> contentType = request.getHeaders("Content-Type");
        System.out.println("[INFO ] POST request...contentType " + JSON.toJSONString(contentType));
        ServletInputStream servletInputStream = request.getInputStream();
        ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
        try {
            byte[] buffer = new byte[1024];
            int len;
            while ((len = servletInputStream.read(buffer))!= -1) {
                byteOutStream.write(buffer, 0, len);
            }
            byteOutStream.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
        InputStream inputStream = null;
        BufferedReader bufferedReader = null;
        try {
            inputStream = new ByteArrayInputStream(byteOutStream.toByteArray());
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));
            String line = "";
            while ((line = bufferedReader.readLine()) != null) {
                body.append(StringCaseUtil.urlChinseEncode(line));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != inputStream) {
                inputStream.close();
            }
            if (null != bufferedReader) {
                bufferedReader.close();
            }
        }
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        System.out.println("[INFO ] initailize XCDispatcherServlet start ...");

        // 初始化 context 容器
        doInitContext(config);
        // 掃描bean 初始化 IOC
        String scanPack = contextProperties.getProperty(CommonConstant.XML_CONTEXT_SCAN_PACAKAGE);
        doInitIocScanPack(scanPack);
        // DI 依賴注入
        doInitDIBean();
        // 初始化 hanldeMapping
        doInitHandlerMapping();
        handlerMapper.forEach((key, value)->{
            System.out.println("[INFO ] " + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,SSS").format(new Date())) + " XCDispatcherServlet " + key);
        });
        // 註冊servlet
        ServletContext servletContext = config.getServletContext();
        // 註冊jsp servlet
        ServletRegistration jspRegistration = servletContext.getServletRegistration("jsp");
        jspRegistration.addMapping(CommonConstant.JSP_BASE_PATH + "*");
        
        ServletRegistration defaultRegistration = servletContext.getServletRegistration("default");
        defaultRegistration.addMapping(CommonConstant.STATIC_FILE_BASE_PATH + "*");
    }

    private void doInitHandlerMapping() {
        System.out.println("[INFO ] ------------ bean init handler mapping start -------------");
        if (null == iocBeanMap || iocBeanMap.isEmpty()) {
            return;
        }
        for (Entry<String, Object> entry : iocBeanMap.entrySet()) {
            Class<?> clazz = entry.getValue().getClass();
            if (clazz.isAnnotationPresent(XCcontroller.class)) {
                ClassReflectHandler.doBeanHandlerMapping(clazz, handlerMapper);
            }
        }
    }

    private void doInitDIBean() {
        System.out.println("[INFO ] ------------ bean di start -------------");
        try {
            if (null == iocBeanMap || iocBeanMap.isEmpty()) {
                return;
            }
            for (Entry<String, Object> entry : iocBeanMap.entrySet()) {
                Class<?> claxx = entry.getValue().getClass();
                if (claxx.isAnnotationPresent(XCcontroller.class) || claxx.isAnnotationPresent(XCservice.class)
                        || claxx.isAnnotationPresent(XCcomponent.class)) {
                    ClassReflectHandler.doBeanDiInstation(entry, claxx,iocBeanMap);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 空格=%20 ; !=%21 ; "=%22 ; #=%23 ; $=%24 ; %=%25 ; & = %26 ; ' = %27 ( =%28
     * ; )=%29 ; *=%2A ; +=%2B ; ,=%2C ; -=%2D ; .=%2E ; /=%2F
     * 
     * @param scanPackPath
     */
    private void doInitIocScanPack(String scanPackPath) {
        if (StringUtils.isEmpty(scanPackPath)) {
            return;
        }
        try {
            String scanRootPath = scanPackPath.replace(".", "/");
            Enumeration<URL> rootUrl = this.getClass().getClassLoader().getResources(scanRootPath);
            while (rootUrl.hasMoreElements()) {
                URL url = rootUrl.nextElement();
                String urlProtocol = url.getProtocol();
                if (CommonConstant.PACKAGE_PROTOCOL_FILE.equals(urlProtocol)) {
                    scanCurrentFile(scanPackPath, url);
                } else {
                    // 掃描 jar 包
                    if (CommonConstant.PACKAGE_PROTOCOL_JAR.equals(urlProtocol)) {
                        JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
                        if (null != jarURLConnection) {
                            JarFile jarFile = jarURLConnection.getJarFile();
                            if (null != jarFile) {
                                Enumeration<JarEntry> jarEntries = jarFile.entries();
                                while (jarEntries.hasMoreElements()) {
                                    JarEntry jarEntry = (JarEntry) jarEntries.nextElement();
                                    String jarEntryName = jarEntry.getName();
                                    if (jarEntryName.endsWith(".class")) {
                                        String className = jarEntryName.substring(0,jarEntryName.lastIndexOf(".")).replaceAll("/", ".");
                                        iocBeanMap.put(className,ClassReflectHandler.loadClass(className, false));
                                    }
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void scanCurrentFile(String scanPackPath, URL url)
            throws ClassNotFoundException, InstantiationException,
            IllegalAccessException {
        String clazzPath = url.getPath().replaceAll("%20", "");
        File[] files = new File(clazzPath).listFiles(new FileFilter() {
            @Override
            public boolean accept(File filePath) {
                return (filePath.isFile()&& filePath.getName().endsWith(".class") 
                        || filePath.isDirectory());
            }
        });
        if (null == files || files.length <= 0) {
            return;
        }
        for (File file : files) {
            String fileName = file.getName();
            if (file.isDirectory()) {
                String subScanPackPath = scanPackPath + "." + fileName;
                doInitIocScanPack(subScanPackPath);
            } else {
                String clazzName = scanPackPath + "." + fileName.substring(0, fileName.lastIndexOf("."));
                Class<?> claxx = Class.forName(clazzName);
                String instanceName = "";
                if (claxx.isAnnotationPresent(XCcontroller.class)
                        || claxx.isAnnotationPresent(XCcomponent.class)) {
                    instanceName = StringCaseUtil.lowerFirstCase(claxx
                            .getSimpleName());
                } else if (claxx.isAnnotationPresent(XCservice.class)) {
                    XCservice xCservice = claxx.getAnnotation(XCservice.class);
                    instanceName = xCservice.value();
                    if (StringUtils.isEmpty(instanceName)) {
                        instanceName = claxx.getInterfaces()[0].getSimpleName();
                    }
                }
                if (StringUtils.isNotEmpty(instanceName)) {
                    iocBeanMap.put(instanceName, claxx.newInstance());
                }
            }
        }
    }

    private void doInitContext(ServletConfig config) {         String contextPath = config.getInitParameter("applicationLocalContext");         List<String> contextlist = ContextPathUtil.splitContextPath(contextPath);         if (null == contextlist || contextlist.isEmpty()) {             throw new RuntimeException("dispacherservlet init context exception ...");         }         contextlist.stream().forEach(destPath -> {             if (destPath.toUpperCase().endsWith("xml".toUpperCase())) {                 XmlBeanHandler.initXmlBean(XmlUtils.dealWithXml(this.getClass().getClassLoader(),                          destPath, CONTEXTCOMPONENTSCAN),iocBeanMap, contextProperties);             } else {                 InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(destPath);                 try {                     contextProperties.load(new InputStreamReader(inputStream));                 } catch (IOException e) {                     logger.error("init servletconfig exception {}",e);                     e.printStackTrace();                 }             }         });     } }  

相關文章
相關標籤/搜索