手写springmvc 框架1.0版

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

springmvc工作流程图

搭建项目

pom 依赖

项目启动配置jetty插件

自定义注解

核心类 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 方法 存在当前参数

不存在当前参数 报异常

add 方法

sub方法

remove方法

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值