Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面。Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块。使用 Spring 可插入的 MVC 架构,从而在使用Spring进行WEB开发时,可以选择使用Spring的Spring MVC框架或集成其他MVC开发框架,如Struts1(现在一般不用),Struts 2(一般老项目使用)等。

springmvc工作流程图

手写springmvc 框架1.0版

搭建项目

手写springmvc 框架1.0版

pom 依赖

手写springmvc 框架1.0版

手写springmvc 框架1.0版

项目启动配置jetty插件

手写springmvc 框架1.0版

手写springmvc 框架1.0版

自定义注解

手写springmvc 框架1.0版

核心类 GpDispatcherServlet 

package com.gupao.servlet.mvcframework;

import com.gupao.servlet.mvcframework.annotation.*;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import javax.servlet.ServletConfig;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

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

import java.util.*;

public class GpDispatcherServlet extends HttpServlet {

private static final Loggerlogger = LoggerFactory.getLogger(GpDispatcherServlet.class);

    //保存配置文件扫描到的内容

    private Properties contextConfig = new Properties();

    //保存扫描到的类

    private List classNameList = new ArrayList();

    //ioc容器

    private Map ioc = new HashMap();

    //保存url对应的mapping

//    private Map handMapping = new HashMap();

// 为啥不用map handmapping 本身的功能url methond对应 单一职责原则

    private ListhandMapping =new ArrayList();

    @Override

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,     IOException {

    doPost(req, resp);

    }

     @Override

    protected void doPost(HttpServletRequest req, HttpServletResponse resp)throws IOException {

//调用 运行阶段

        try {

          doDispatch(req, resp);

        } catch (Exception e) {

            e.printStackTrace();

            resp.getWriter().write("500 exception " + Arrays.toString(e.getStackTrace()));

        }

}

private void doDispatch(HttpServletRequest req, HttpServletResponse response)throws Exception{

        HandMapping handMapping = getHandler(req);

        if (handMapping ==null) {

        response.getWriter().write("404 Not Found");

         return;

        }

//获得形参列表

        Class [] paramTypes = handMapping.getParamTyps();

        Object [] paramValues = new Object[paramTypes.length];

        Map stringMap = req.getParameterMap();

        for (Map.Entry param : stringMap.entrySet()) {

            String value = Arrays.toString(param.getValue()).replaceAll("\\[|\\]", "")

            .replaceAll("\\s", ",");

            if (!handMapping.paramIndexMapping.containsKey(param.getKey())) {continue;}

                int index = handMapping.paramIndexMapping.get(param.getKey());

               paramValues[index] = convert(paramTypes[index], value);

        }

        //请求参数是否有httpservletRequest httpservletResponse

        if (handMapping.paramIndexMapping.containsKey(HttpServletRequest.class.getName())) {

            int reqIndex = handMapping.paramIndexMapping.get(HttpServletRequest.class.getName());

            paramValues[reqIndex] = req;

        }

if (handMapping.paramIndexMapping.containsKey(HttpServletResponse.class.getName())) {

            int respIndex = handMapping.paramIndexMapping.get(HttpServletResponse.class.getName());

            paramValues[respIndex] = response;

        }

        Object object = handMapping.method.invoke(handMapping.controller, paramValues);

        if (object ==null) {return;}

            response.getWriter().write(object.toString());

    }

private HandMapping  getHandler (HttpServletRequest req) {

    if (handMapping.isEmpty()) {return null;}

        String url = req.getRequestURI().replaceAll("/gupaospring", "");//绝对路径这里暂时写死

        //处理成相对路径

        String contextPath = req.getContextPath();

        logger.info("contextPath : [{}]", contextPath);

        url = url.replaceAll(contextPath, "").replaceAll("/+", "/");

        for (HandMapping handMapping :this.handMapping) {

                if (handMapping.getUrl().equals(url)) {

                    return handMapping;

          }

}

            return null;

    }

    //http基于string传输

    private Object convert(Class type, String value) {

        if (Integer.class == type) {

            return Integer.valueOf(value);

        } else if (Double.class  == type) {

            return Double.valueOf(value);

        }

            return value;

    }

    //配置阶段 初始化阶段

    @Override

    public void init(ServletConfig config)throws ServletException {

            //加载配置文件 模板模式

        logger.info("access init method.......");

        doLoadConfig(config.getInitParameter("contextConfigLocation"));

        //扫描相关类

        doScanner(contextConfig.getProperty("scanPackage"));

        //初始化相关类放到Ioc容器中

        doInstance();

        //完成依赖注入

        doAutowired();

        //初始化handmapping

        initHandMapping();

        logger.info("gp srpingframework complete");

    }

private void initHandMapping() {

if (ioc.isEmpty()) {return;}

for (Map.Entry entry :ioc.entrySet()) {

            Class clazz = entry.getValue().getClass();

          if (!clazz.isAnnotationPresent(GpController.class)) {continue;}

                String baseUrl ="";

          if (clazz.isAnnotationPresent(GpRequestMapping.class)) {

                GpRequestMapping requestMapping = clazz.getAnnotation(GpRequestMapping.class);

                baseUrl = requestMapping.value().trim();//类上的url;

          }

    //默认获取所有的public方法

     for (Method method : clazz.getMethods()) {

        if (!method.isAnnotationPresent(GpRequestMapping.class)) {continue;}

                GpRequestMapping requestMapping = method.getAnnotation(GpRequestMapping.class);

                String url = (baseUrl +"/" + requestMapping.value().trim()).replaceAll("/+", "/");

//                handMapping.put(url, method);

                this.handMapping.add(new HandMapping(url, method, entry.getValue()));

                System.out.println("url:" + url +"method:" + method +"controller:" + entry.getValue());

            }

}

}

//自动注入

    private void doAutowired() {

        if (ioc.isEmpty()) {return;}

        for (Map.Entry entry :ioc.entrySet()) {

            //declared 所有的特定的 字段 包括private protected 等字段

            Field [] fields = entry.getValue().getClass().getDeclaredFields();

            for (Field field : fields) {

                if (!field.isAnnotationPresent(GpAutowried.class)) {continue;}

                GpAutowried autowried = field.getAnnotation(GpAutowried.class);

                String beanName = autowried.value().trim();

                if ("".equals(beanName)) {

                    //接口类型 作为key 到ioc容器中取值

                    beanName = field.getType().getName();

                }

                //如果是public 意外的修饰符 强制赋值

                field.setAccessible(true);

                //反射动态给字段赋值

                try {

                    field.set(entry.getValue(), ioc.get(beanName));

                } catch (IllegalAccessException e) {

                        e.printStackTrace();

                }

        }

    }

}

    //注入到ioc容器中去

    private void doInstance() {

        if (classNameList.isEmpty()) {return;}

        try {

                for (String className :classNameList) {

                        Class clazz =  Class.forName(className);

                        if (clazz.isAnnotationPresent(GpController.class)) {

                            Object instance = clazz.newInstance();

                            String beanName = toLowerFirstCase(clazz.getSimpleName());

                                ioc.put(beanName, instance);

                } else if (clazz.isAnnotationPresent(GpService.class)) {

                    GpService service = clazz.getAnnotation(GpService.class);

                    //beanName 为空

                    String beanName = service.value();

                    Object instance = clazz.newInstance();

                    if ("".equals(service.value())) {

                        beanName = toLowerFirstCase(clazz.getSimpleName());

                    }

                        ioc.put(beanName, instance);

                    //接口名称

                    for (Class i : clazz.getInterfaces()) {

                            if (ioc.containsKey(i.getName())) {

                                throw new Exception("the" + i.getName() +"is exits");

                            }

                                ioc.put(i.getName(), instance);

                    }

        } else {

                    continue;

                }

    }

} catch (Exception e) {

        e.printStackTrace();

       }

}

    private String toLowerFirstCase(String simpleName) {

            char [] chars = simpleName.toCharArray();

        //加32是因为大小写字母的ascii相差32 大写字母的asci小于小写字母的ascII

            chars[0] +=32;

        return String.valueOf(chars);

    }

private void doScanner(String scanPackage) {

            //scanPackage=com.gupao.servlet包路径 变成文件路径

        //classpath

        URL url =this.getClass().getClassLoader().getResource("/" + scanPackage.replaceAll("\\.", "/"));

        File classpath =new File(url.getFile());

        for (File file : classpath.listFiles()) {

            if (file.isDirectory()) {

                    doScanner(scanPackage +"." + file.getName());

            } else {

                    if (!file.getName().endsWith(".class")){continue;}

                    String className = (scanPackage +"." + file.getName().replace(".class", ""));

                    classNameList.add(className);

            }

    }

}

private void doLoadConfig(String contextConfigLocation) {

        //直接从类路径下 spring主配置文件的路径 读取放到properties中

        //保存到内存中scanPackage=com.gupao.servlet

        logger.info("acccess doLoadConfig method .......");

        InputStream inputStream =null;

        inputStream = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);

        try {

                contextConfig.load(inputStream);

        } catch (IOException e) {

            e.printStackTrace();

        } finally {

        if (inputStream !=null) {

            try {

                    inputStream.close();

                } catch (IOException e) {

                    e.printStackTrace();

                }

        }

    }

}

//保存一个url和method对应关系handMapping策略模式

//解决多个参数问题不然参数容易错位

    public class HandMapping {

        private Stringurl;

        private Methodmethod;

        private Objectcontroller;

        private Class []paramTyps;

        //形参列表

        private MapparamIndexMapping;

        public StringgetUrl() {

            return url;

        }

        public void setUrl(String url) {

            this.url = url;

        }

        public MethodgetMethod() {

            return method;

        }

        public void setMethod(Method method) {

            this.method = method;

        }

        public ObjectgetController() {

                return controller;

        }

    public void setController(Object controller) {

                this.controller = controller;

        }

     public Class[]getParamTyps() {

            return paramTyps;

        }

    public void setParamTyps(Class[] paramTyps) {

            this.paramTyps = paramTyps;

        }

        public HandMapping(String url, Method method, Object controller) {

                this.url = url;

                this.method = method;

                this.controller = controller;

                paramTyps = method.getParameterTypes();

                paramIndexMapping =new HashMap();

                putParamIndexMapping(method);

        }

    private void putParamIndexMapping(Method method) {

            Annotation[][] pa = method.getParameterAnnotations();

            for (int i =0; i < pa.length; i++) {

                        for (Annotation a : pa[i]) {

                            if (ainstanceof GpRequestParam) {//拿到参数注解的值

                                    String paramName = ((GpRequestParam) a).value();

                                    if (!"".equals(paramName.trim())) {//一个key对应一个数组 二维数组

                                        paramIndexMapping.put(paramName, i);

                                    }

                        }

                }

        }

            Class[] paramType =  method.getParameterTypes();

                for (int i =0; i < paramType.length; i++) {

                        Class type = paramType[i];

                        if (type == HttpServletRequest.class || type == HttpServletResponse.class) {

                            paramIndexMapping.put(type.getName(), i);

                    }

            }

    }

    }

}

看DemoAction方法


package com.gupao.servlet.action;

import com.gupao.servlet.mvcframework.annotation.GpAutowried;

import com.gupao.servlet.mvcframework.annotation.GpController;

import com.gupao.servlet.mvcframework.annotation.GpRequestMapping;

import com.gupao.servlet.mvcframework.annotation.GpRequestParam;

import com.gupao.servlet.service.IDemoService;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import java.io.IOException;

@GpController

@GpRequestMapping(value ="/demo")

public class DemoAction {

private static final Loggerlogger = LoggerFactory.getLogger(DemoAction.class);

    @GpAutowried

    private IDemoServicedemoService;

    @GpRequestMapping(value ="/query")

    public void query(HttpServletRequest request, HttpServletResponse response,

                      @GpRequestParam("name") String name) {

                        logger.info("access query query");

        try {

                response.getWriter().write(name);

        } catch (IOException e) {

                e.printStackTrace();

        }

}

@GpRequestMapping(value ="/add")

public void add(HttpServletRequest request, HttpServletResponse response,

                        @GpRequestParam("a") Integer a,

                        @GpRequestParam("b") Integer b) {

                logger.info("access add add");

        try {

                    response.getWriter().write("a + b = " +  (a + b));

        } catch (IOException e) {

                    e.printStackTrace();

        }

}

@GpRequestMapping(value ="/sub")

public void sub(HttpServletRequest request, HttpServletResponse response,

                    @GpRequestParam("a") Double a,

                    @GpRequestParam("b")  Double b) {

            logger.info("access add sub");

        try {

                response.getWriter().write("a - b = " +  (a - b));

         } catch (IOException e) {

                e.printStackTrace();

        }

}

@GpRequestMapping(value ="/remove")

public String remove(@GpRequestParam("id") Integer id) {

        logger.info("access add remove");

        return "id = " + id;

    }

}

测试:query 方法 存在当前参数

手写springmvc 框架1.0版

不存在当前参数 报异常

手写springmvc 框架1.0版

add 方法

手写springmvc 框架1.0版

sub方法

手写springmvc 框架1.0版

remove方法

手写springmvc 框架1.0版

相关文章: