文档章节

手写简单mvc框架之xuchen-mvc-v1.0

 徐志
发布于 06/25 15:39
字数 1317
阅读 8
收藏 0

package org.mvc.framework.servlet;

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;

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;

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;

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

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();

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

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

    /**
     * 处理请求
     * @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();
        }
    }

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

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

© 著作权归作者所有

共有 人打赏支持
上一篇: xuchen-mvc相关类
下一篇: dispacheservlet
粉丝 1
博文 24
码字总数 22054
作品 0
崇明
私信 提问
轻量级PHP框架--DoitPHP

DoitPHP是一个简单易用,易于扩展的轻量级PHP框架。运行高效,操作灵活。基于BSD开源协议发布,适用于MVC项目开发。 自2010年5月4日正式发布TommyFramework V1.0(DoitPHP前身)以来,如今Doi...

dotiphp
2011/07/06
5.9K
1
Java程序员,最常用的30%技术有哪些?

两个月,这让我想到了我当年第一份工作,也是两个月从零学JAVA。 当时就买了3本书,强啃了6周。记住一点,时间有限,别听网上很多大牛的,他们说的太杂。你要抓重点,你只要让人家知道,你足...

2017/12/24
0
0
Java程序员,最常用的20%技术有哪些?

两个月,这让我想到了我当年第一份工作,也是两个月从零学JAVA。当时就买了3本书,强啃了6周。记住一点,时间有限,别听网上很多大牛的,他们说的太杂。你要抓重点,你只要让人家知道,你足够...

嘿你好夏天
2017/12/24
0
2
Bamboo 1.0 发布,lua MVC web开发框架

历经接近1年的开发,Bamboo v1.0终于发布了。它是一个MVC,融合了非常多的创新理念在其中。 Bamboo v1.0新特性如下: Bamboo is a MVC framework; cooperates with mongrel2, zeromq and re...

红薯
2011/11/11
1K
4
三流程序员与一流程序员之间的区别,看看你是属于哪一类?

源码系列 手写spring mvc框架 基于Spring JDBC手写ORM框架 实现自己的MyBatis Spring AOP实战之源码分析 Spring IOC高级特性应用分析 ORM框架底层实现原理剖析 手写Spring MVC框架实现 手把手...

茶轴的青春
04/17
0
0

没有更多内容

加载失败,请刷新页面

加载更多

EOS docker开发环境

使用eos docker镜像是部署本地EOS开发环境的最轻松愉快的方法。使用官方提供的eos docker镜像,你可以快速建立一个eos开发环境,可以迅速启动开发节点和钱包服务器、创建账户、编写智能合约....

汇智网教程
今天
12
0
《唐史原来超有趣》的读后感优秀范文3700字

《唐史原来超有趣》的读后感优秀范文3700字: 作者:花若离。我今天分享的内容《唐史原来超有趣》这本书的读后感,我将这本书看了一遍之后就束之高阁了,不过里面的内容一直在在脑海中回放,...

原创小博客
今天
19
0
IC-CAD Methodology知识图谱

CAD (Computer Aided Design),计算机辅助设计,指利用计算机及其图形设备帮助设计人员进行设计工作,这个定义同样可以用来近似描述IC公司CAD工程师这个岗位的工作。 早期IC公司的CAD岗位最初...

李艳青1987
今天
18
0
CompletableFuture get方法一直阻塞或抛出TimeoutException

问题描述 最近刚刚上线的服务突然抛出大量的TimeoutException,查询后发现是使用了CompletableFuture,并且在执行future.get(5, TimeUnit.SECONDS);时抛出了TimeoutException异常,导致接口响...

xiaolyuh
今天
9
0
dubbo 搭建与使用

官网:http://dubbo.apache.org/en-us/ 一,安装监控中心(可以不安装) admin管理控制台,monitor监控中心 下载 bubbo ops 这个是新版的,需要node.js环境,我没有就用老版的了...

小兵胖胖
今天
18
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部