未进化的程序猿
人生最苦痛的是梦醒了无路可走。做梦的人是幸福的;倘没有看出可走的路,最要紧的是不要去惊醒他。鲁迅

前言:

SpringMVC最核心的就是DispatchServlet,所以要先对Servlet有一定的认识,然后就是反射注解ioc等相关知识

什么是MVC?

      MVC是一种架构模式 --- 程序分层,分工合作,既相互独立,又协同工作

      MVC是一种思考方式 --- 需要将什么信息展示给用户? 如何布局? 调用哪些业务逻辑? 

MVC设计思想

  MVC英文即Model-View-Controller,即把一个应用的输入、处理、输出流程按照Model、View、Controller的方式进行分离,这样一个应用被分成三个层——模型层、视图层、控制层。 

  视图(View)代表用户交互界面,对于Web应用来说,可以概括为HTML界面,但有可能为XHTML、XML和Applet。随着应用的复杂性和规模性,界面的处理也变得具有挑战性。一个应用可能有很多不同的视图,MVC设计模式对于视图的处理仅限于视图上数据的采集和处理,以及用户的请求,而不包括在视图上的业务流程的处理。业务流程的处理交予模型(Model)处理。比如一个订单的视图只接受来自模型的数据并显示给用户,以及将用户界面的输入数据和请求传递给控制和模型。 

  模型(Model):就是业务流程/状态的处理以及业务规则的制定。业务流程的处理过程对其它层来说是黑箱操作,模型接受视图请求的数据,并返回最终的处理结果。业务模型的设计可以说是MVC最主要的核心。目前流行的EJB模型就是一个典型的应用例子,它从应用技术实现的角度对模型做了进一步的划分,以便充分利用现有的组件,但它不能作为应用设计模型的框架。它仅仅告诉你按这种模型设计就可以利用某些技术组件,从而减少了技术上的困难。对一个开发者来说,就可以专注于业务模型的设计。MVC设计模式告诉我们,把应用的模型按一定的规则抽取出来,抽取的层次很重要,这也是判断开发人员是否优秀的设计依据。抽象与具体不能隔得太远,也不能太近。MVC并没有提供模型的设计方法,而只告诉你应该组织管理这些模型,以便于模型的重构和提高重用性。我们可以用对象编程来做比喻,MVC定义了一个顶级类,告诉它的子类你只能做这些,但没法限制你能做这些。这点对编程的开发人员非常重要。 

  业务模型还有一个很重要的模型那就是数据模型。数据模型主要指实体对象的数据 保存(持续化)。比如将一张订单保存到数据库,从数据库获取订单。我们可以将这个模型单独列出,所有有关数据库的操作只限制在该模型中。 

  控制(Controller)可以理解为从用户接收请求, 将模型与视图匹配在一起,共同完成用户的请求。划分控制层的作用也很明显,它清楚地告诉你,它就是一个分发器,选择什么样的模型,选择什么样的视图,可以完成什么样的用户请求。控制层并不做任何的数据处理。例如,用户点击一个连接,控制层接受请求后, 并不处理业务信息,它只把用户的信息传递给模型,告诉模型做什么,选择符合要求的视图返回给用户。因此,一个模型可能对应多个视图,一个视图可能对应多个模型。 

  MVC的优点

  大部分用过程语言比如ASP、PHP开发出来的Web应用,初始的开发模板就是混合层的数据编程。例如,直接向数据库发送请求并用HTML显示,开发速度往往比较快,但由于数据页面的分离不是很直接,因而很难体现出业务模型的样子或者模型的重用性。产品设计弹性力度很小,很难满足用户的变化性需求。MVC要求对应用分层,虽然要花费额外的工作,但产品的结构清晰,产品的应用通过模型可以得到更好地体现。 

  首先,最重要的是应该有多个视图对应一个模型的能力。在目前用户需求的快速变化下,可能有多种方式访问应用的要求。例如,订单模型可能有本系统的订单,也有网上订单,或者其他系统的订单,但对于订单的处理都是一样,也就是说订单的处理是一致的。按MVC设计模式,一个订单模型以及多个视图即可解决问题。这样减少了代码的复制,即减少了代码的维护量,一旦模型发生改变,也易于维护。 其次,由于模型返回的数据不带任何显示格式,因而这些模型也可直接应用于接口的使用。 

  再次,由于一个应用被分离为三层,因此有时改变其中的一层就能满足应用的改变。一个应用的业务流程或者业务规则的改变只需改动MVC的模型层。 

  控制层的概念也很有效,由于它把不同的模型和不同的视图组合在一起完成不同的请求,因此,控制层可以说是包含了用户请求权限的概念。 

  最后,它还有利于软件工程化管理。由于不同的层各司其职,每一层不同的应用具有某些相同的特征,有利于通过工程化、工具化产生管理程序代码。

  思想:

  MVC应用程序总是由三个部分组成.Event(事件)导致Controller改变Model或View,或者同时改变两者.只要Controller改变了Models的数据或者属性,所有依赖的View都会自动更新.类似的,只要Controller改变了View,View会从潜在的Model中获取数据来刷新自己 。

  MVC模式是一个复杂的架构模式,其实现也显得非常复杂,但多种设计模式结合在一起,使MVC模式的实现变得相对简单易行.Views可以看作一棵树,显然可以用Composite Pattern来实现.Views和Models之间的关系可以用Observer Pattern体现.Controller控制Views的显示,可以用Strategy Pattern实现.Model通常是一个调停者,可采用Mediator Pattern来实现.

SpringMVC的原理:

    1 首先用户发出请求,请求到达SpringMVC的前端控制器(DispatcherServlet),

    2 前端控制器根据用户的url,请求处理器映射器(HandlerMapping)查找匹配该url的handler,并返回一个执行链(HandlerExecutionChain),

    3 前端控制器再请求处理器适配器(HandlerAdapter)调用相应的handler进行处理并返回给前端控制器一modelAndView,  

    4 前端控制器再请求视图解析器(ViewResolver)对返回的逻辑视图进行解析,

    5 最后前端控制器将返回的视图进行渲染并把数据装入到request域,返回给用户。

 

  注:DispatcherServlet作为springMVC的前端控制器,负责接收用户的请求并根据用户的请求返回相应的视图给用户(分发调度)

  补充:

    为什么叫前端控制器?前端又是什么?

   举个例子:假如你去医院看病,通过向分诊台的医院描述自己的病情,就可以得到医生的指导具体去看外科、内科或者神经科等等,这里我们的分诊台就扮演着前端控制器(Dispatcher)的角色,也叫做调度器,而各个科室就扮演着控制器(Controller)的角色,因为分诊台是在具体各个科室之前,所以这个模式就叫做前端控制器。

思路:

主要的核心编码是在Servlet初始化里面扫描所有需要的包并将被@Controller,@Service注解修饰的对象实例化放在一个容IOC器里面管理(k-v,className as key ),属性值注入:遍历IOC里面所有的bean对象,遍历每个对象里面的属性,利用反射机制将value映射给它,同时将所有被@RequestMapping修饰的控制器或者方法也放在一个容器里面管理(k-v), Servlet拦截并截取对应的uri 根据uri这个key获取相应的控制器与方法执行invoke操作

首先是xml配置,springmvc需要读取xml里面的配置,然后放在简单的一个集合数据模型里(Map),再然后就是装载用户的配置,扫描基准包,获取用户添加的注解,获取注解信息和配置的参数,再用spring的IOC初始化配置的Bean实例,自动注入类实例(比如contoller的依赖service、dao层mappeer等,等容器启动起来,如果有请求进来,就会按照路径映射对应的controller,再选择方法进行处理完成一系列操作后返回给客户端。

1.实现几个常用的注解@Controller,@Service,@RequestMapping @Autowired @ResponseBody

项目结构图

 @Autowrite

package com.tom.annotation;

import java.lang.annotation.*;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowrite {
    String value() default "";
}

@Controller

package com.tom.annotation;

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Controller {
    String value() default "";
}

@RequestMapping

package com.tom.annotation;

import java.lang.annotation.*;

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestMapping {
    String value() default "";
}

@ResponseBody

package com.tom.annotation;

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ResponseBody {
    String value() default "";
}

@Service

package com.tom.annotation;

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Service {
    String value() default "";
}

控制器TestController

package com.tom.controller;

import com.tom.annotation.Autowrite;
import com.tom.annotation.Controller;
import com.tom.annotation.RequestMapping;
import com.tom.annotation.ResponseBody;
import com.tom.entity.User;
import com.tom.service.TestService;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Controller
@RequestMapping(value = "/hello")
public class TestController {

    @Autowrite(value = "TestService")
    private TestService testService;

    @RequestMapping(value = "/test")
    @ResponseBody
    public String test(){
        testService.test();
        return "Hello World";
    }

    @RequestMapping(value = "/test01")
    @ResponseBody
    public User test01(String username, HttpServletRequest request, HttpServletResponse response, User user){
        System.out.println("username:" + username);
        System.out.println("request:" + request);
        System.out.println("response:" + response);
        System.out.println("user:" + user);
        return user;
    }

    @RequestMapping(value = "/test02")
    public String test02(HttpServletRequest request){
        testService.test();
        request.setAttribute("msg","未进化的程序猿");
        return "index";
    }
}

spring-mvc.xml 配置需要扫描的包路径

<?xml version="1.0" encoding ="UTF-8"?>
<beans>
    <component-scan base-package="com.tom"></component-scan>
    <viewResolver prefix="/WEB-INF/jsp/" subfix=".jsp"></viewResolver>
</beans>

解析spring-mvc.xml XML文件的工具类

package com.tom.utils;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.io.Reader;
import java.net.URL;
import java.util.Iterator;

public class BeanXmlUtils {
    //读取默认xml文件的名字为ApplicationContext.xml
    private final static String config = "spring-mvc.xml";

    //获取类路径下的自定义的xml文件的Document对象
    public static Document getDocument() throws DocumentException {
        return getDocument(config);
    }

    //获取类路径下的自定义的xml文件的Document对象
    public static Document getDocument(String config) throws DocumentException {
        return new SAXReader().read(BeanXmlUtils.class.getClassLoader().getResource(config));
    }

    //获取类路径下的自定义的xml文件的Document对象
    //xml文件的URL
    public static Document getDocument(URL url) throws DocumentException {
        return new SAXReader().read(url);
    }

    //获取类路径下的自定义的xml文件的Document对象
    //xml文件的Reader
    public static Document getDocument(Reader reader) throws DocumentException {
        return new SAXReader().read(reader);
    }

    //获取类路径下的自定义的xml文件的Document对象
    //xml文件的InputStream
    public static Document getDocument(InputStream inputStream) throws DocumentException {
        return new SAXReader().read(inputStream);
    }

    //获取Xml根元素
    public static Element getRootElement(Document document){
        return document.getRootElement();
    }

    public static Element getRootElement(URL url) throws DocumentException {
        return getDocument(url).getRootElement();
    }

    public static Element getRootElement(Reader reader) throws DocumentException {
        return getDocument(reader).getRootElement();
    }

    public static Element getRootElement(InputStream inputStream) throws DocumentException {
        return getDocument(inputStream).getRootElement();
    }

    public static Element getRootElement(String config) throws DocumentException {
        return getDocument(config).getRootElement();
    }

    public static Element getRootElement() throws DocumentException {
        return getDocument(config).getRootElement();
    }

    //输出元素的所有子元素的详细信息
    public static void printElements(Element element){
        System.out.println("获取当前名称:" + element.getName());
        //获取属性信息
        Iterator<Attribute> attributeIterator = element.attributeIterator();
        while (attributeIterator.hasNext()){
            Attribute attribute = attributeIterator.next();
            System.out.println("属性:" + attribute.getName() + "---" + attribute.getText().trim());
        }
        //获取属性value
        if(attributeIterator != null){
            System.out.println("value:" + element.getTextTrim());
        }

        //使用迭代器遍历,继续遍历子元素
        Iterator<Element> elementIterator = element.elementIterator();
        while (elementIterator.hasNext()){
            Element element1 = elementIterator.next();
            printElements(element1);
        }
    }

    //输出元素的所有子元素的详细信息
    public static void printElements(String config) throws DocumentException {
        printElements(getRootElement(config));
    }

    //类路径下默认xml文件ApplicationContext.xml输出元素的所有子元素的详细信息
    public static void printElements() throws DocumentException {
        printElements(getRootElement(config));
    }
}

以上基本实现的springmvc的用法,但是他只是一个空壳,核心在下面

DispatcherServlet核心工作

package com.tom.servlet;

import com.tom.annotation.*;
import com.tom.entity.User;
import com.tom.utils.BeanXmlUtils;
import org.dom4j.DocumentException;
import org.dom4j.Element;

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.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.net.URL;
import java.net.URLDecoder;
import java.util.*;

@SuppressWarnings(value = "all")//取消黄色警告线
public class DispatcherServlet extends HttpServlet {
    //项目的根路径
    String project = this.getClass().getResource("/").getPath();
    //保存扫描到的类到缓存中
    private static List<String> classNames = new ArrayList<String>();
    //保存实例化类到缓存中
    private static Map<String,Object> instantiationClassMap = new HashMap<String, Object>();
    //保存所有的Method方法到缓存中
    private static Map<String,Method> mapping = new HashMap<String, Method>();

    //前缀
    String prefix = "";
    //后缀
    String subfix = "";

    //容器启动时,完成类扫描、实例化,自动化装配,建立映射
    //1、扫描工程路径,找到业务类
    //2、实例化类
    //3、自动装配
    //4、建立映射关系
    @Override
    public void init(ServletConfig config) throws ServletException {
        //初始化
        String initParameter = config.getInitParameter("configurationLocal");
        System.out.println("initParameter:" + initParameter);
        try {
            //URL解码 空格 会变成 %20
            project = URLDecoder.decode(project,"UTF-8");
            //1、获得XML文件,对XML文件进行解析
            //获取根路径
            Element rootElement = BeanXmlUtils.getRootElement(initParameter);
            //获取直接子节点
            Element element = rootElement.element("component-scan");
            System.out.println(element.getName());
            String packageName = element.attributeValue("base-package");
            System.out.println("value:"+packageName);

            Element viewResolver = rootElement.element("viewResolver");
            prefix = viewResolver.attributeValue("prefix");
            subfix = viewResolver.attributeValue("subfix");

            //2、扫描工程路径,找到业务类
            scanPackage(packageName);

            //测试有没有类保存到缓存中
//            for(String str : classNames){
////                System.out.println("总共:"+classNames.size());
//                System.out.println("保存Class的路径:" + str);
//                 /*
//                保存Class的路径:com.tom.annotation.Autowrite.class
//                保存Class的路径:com.tom.annotation.Controller.class
//                保存Class的路径:com.tom.annotation.RequestMapping.class
//                保存Class的路径:com.tom.annotation.ResponseBody.class
//                保存Class的路径:com.tom.annotation.Service.class
//                保存Class的路径:com.tom.controller.TestController.class
//                保存Class的路径:com.tom.entity.User.class
//                保存Class的路径:com.tom.service.TestService.class
//                保存Class的路径:com.tom.servlet.DispatcherServlet.class
//                保存Class的路径:com.tom.test.Test.class
//                保存Class的路径:com.tom.utils.BeanXmlUtils.class
//                 */
//            }
            //3、实例化类
            instantiationClass();
            //测试有没有实例化类到缓存中
            Collection<Object> values = instantiationClassMap.values();
//            for (Object value : values) {
//                System.out.println("实例化类:" + value);
//                    /*
//                    实例化类:com.tom.service.TestService@60e06f90
//                    实例化类:com.tom.controller.TestController@64f43fa7
//                     */
//            }
            //4、自动装配
            automatic_packaging();

            //5、建立映射关系
            mapping_relation();
            //测试
            Set<String> strings = mapping.keySet();
            for (String string : strings) {
                Method method = mapping.get(string);
                System.out.println(string + ":" + method.getName());
            }

        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }

    }

    //建立映射关系
    private void mapping_relation() {
        //判断保存的缓存的类是否为空
        if(classNames.isEmpty() || instantiationClassMap.isEmpty()){
            System.out.println("该缓存还没有存储值...");
            return;
        }
        //遍历集合
        Set<Map.Entry<String, Object>> entries = instantiationClassMap.entrySet();
        for (Map.Entry<String, Object> entry : entries) {
            //获取实例化对象
            Object o = entry.getValue();
            //获取Class对象
            Class<?> clazz = o.getClass();
            //判断Class对象是否有@Controller注解
            if (clazz.isAnnotationPresent(Controller.class)){
                //获取@RequestMapping注解
                RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
                //获取@RequestMapping注解的值
                String value = requestMapping.value();
//                System.out.println("@RequestMapping注解的值:" + value);

                //获取所有的方法
                Method[] methods = clazz.getDeclaredMethods();
                //遍历所有的方法
                for (Method method : methods) {
                    //判断所有的方法是否有@RequestMapping注解
                    if(method.isAnnotationPresent(RequestMapping.class)){
                        //获取@RequestMapping注解
                        RequestMapping requestMapping1 = method.getAnnotation(RequestMapping.class);
                        //获取@RequestMapping注解的值
                        String value1 = requestMapping1.value();
//                        System.out.println("@RequestMapping注解的值:" + value1);

                        //将所有的method方法放入到缓存中
                        mapping.put(value+value1,method);
                    }
                }
            }
        }
    }

    //自动装配
    private void automatic_packaging() throws IllegalAccessException {
        //判断保存的缓存的类是否为空
        if(classNames.isEmpty() || instantiationClassMap.isEmpty()){
            System.out.println("该缓存还没有存储值...");
            return;
        }

        //遍历集合
        Set<Map.Entry<String, Object>> entries = instantiationClassMap.entrySet();
        for (Map.Entry<String, Object> entry : entries) {
            //获取实例化对象
            Object o = entry.getValue();
            //获取Class对象
            Class<?> clazz = o.getClass();
            //获取所有的字段
            Field[] fields = clazz.getDeclaredFields();
            //遍历所有的字段
            for (Field field : fields) {
                //判断所有的字段是否有@Autowrite注解
                if(field.isAnnotationPresent(Autowrite.class)){
                    //获取@Autowrite注解
                    Autowrite autowrite = field.getAnnotation(Autowrite.class);
                    //获取@Autowrite注解的值
                    String value = autowrite.value();
//                    System.out.println("@Autowrite注解的值:" + value );
                    //暴力反射
                    field.setAccessible(true);
                    //自动装配
                    field.set(o,instantiationClassMap.get(value));
                }
            }
        }
    }

    //实例化类
    private void instantiationClass() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        //判断保存的缓存的类是否为空
        if(classNames.isEmpty()){
            System.out.println("该缓存还没有存储值...");
            return;
        }
        //遍历集合
        for (String className : classNames) {
            //com.tom.annotation.Controller.class
            //首先,实例化是Class.ForName("com.tom.annotation.Controller");
            //所以,要把它变成 --> com.tom.annotation.Controller
            String name = className.replaceAll(".class","");
//            System.out.println("class的实例化类:" + name);
            //效果如下:
            /*
            class的实例化类:com.tom.annotation.Autowrite
            class的实例化类:com.tom.annotation.Controller
            class的实例化类:com.tom.annotation.RequestMapping
            class的实例化类:com.tom.annotation.ResponseBody
            class的实例化类:com.tom.annotation.Service
            class的实例化类:com.tom.controller.TestController
            class的实例化类:com.tom.entity.User
            class的实例化类:com.tom.service.TestService
            class的实例化类:com.tom.servlet.DispatcherServlet
            class的实例化类:com.tom.test.Test
            class的实例化类:com.tom.utils.BeanXmlUtils
            保存Class的路径:com.tom.utils.BeanXmlUtils.class
            class的实例化类:com.tom.annotation.Autowrite
            class的实例化类:com.tom.annotation.Controller
            class的实例化类:com.tom.annotation.RequestMapping
            class的实例化类:com.tom.annotation.ResponseBody
            class的实例化类:com.tom.annotation.Service
            class的实例化类:com.tom.controller.TestController
            class的实例化类:com.tom.entity.User
            class的实例化类:com.tom.service.TestService
            class的实例化类:com.tom.servlet.DispatcherServlet
            class的实例化类:com.tom.test.Test
            class的实例化类:com.tom.utils.BeanXmlUtils
             */
            //通过反射进行实例化
            Class<?> clazz = Class.forName(name);

            //首先判断类上是否有@Controller注解和@Service注解
            //@Controller注解
            if(clazz.isAnnotationPresent(Controller.class)){
                //实例化
                Object o = clazz.newInstance();
                //获取@RequestMapping注解
                RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
                //获取@RequestMapping注解的值
                String value = requestMapping.value();
//                System.out.println("@RequestMapping注解的值:" + value);
                //将@RequestMapping注解的值存放到缓存中
                instantiationClassMap.put(value,o);
            }
            //@Service注解
            if(clazz.isAnnotationPresent(Service.class)){
                //实例化
                Object o = clazz.newInstance();
                //获取@Service注解
                Service service = clazz.getAnnotation(Service.class);
                //获取@Service注解的值
                String value = service.value();
//                System.out.println("@Service注解的值:" + value);
                //将@Service注解的值存放到缓存中
                instantiationClassMap.put(value,o);
            }
        }
    }

    //扫描工程路径,找到业务类
    private void scanPackage(String packageName) {
        //D:\Manual-implementation-springMVC\src\com\tom\controller\TestController.java
        //com.tom ---> com/tom/
        String path = packageName.replaceAll("\\.","/");
        //获取工程路径
        URL url = this.getClass().getClassLoader().getResource("/" + path);
        //获取子目录下的所有目录和类
        File file = new File(url.getFile());
        File[] files = file.listFiles();
        //遍历目录
        for(File file1 : files){
            //如果是目录,执行递归
            if(file1.isDirectory()){
                scanPackage(packageName+"."+ file1.getName());
            }else{
                //不是目录就是文件
                classNames.add(packageName+"."+file1.getName());
            }
        }
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取请求的URI地址/Manual_implementation_springMVC/hello/test
        String requestURI = request.getRequestURI();
        //获取contextPath对象 http://localhost:8080/Manual_implementation_springMVC/
        String contextPath = request.getContextPath();
        //将/Manual_implementation_springMVC/hello/test变为/hello/test
        String path = requestURI.replace(contextPath,"");
        System.out.println("path请求路径URI:" + path);
        //通过反射,动态的实现请求参数的绑定
        Method method = mapping.get(path);
        System.out.println(method.getName());
        //通过反射,获取实例化对象
        Object o = instantiationClassMap.get("/" + path.split("/")[1]);
        //执行invoke方法

        try {
//            Class<?> clazz = method.getDeclaringClass();
//            Object o = clazz.newInstance();
            Parameter[] parameters = method.getParameters();
            Object[] objects = new Object[parameters.length];

            //遍历所有的参数
            for (int i = 0; i < parameters.length; i++) {
                //获取所有参数的名字
                String name = parameters[i].getName();
//                System.out.println(name);
                //获取所有参数的类型
                Class<?> type = parameters[i].getType();
                //判断参数类型是否是String.class
                if(type.equals(String.class)){
                    objects[i] = request.getParameter(name);
                    System.out.println("name:---->" + request.getParameter(name));
                }else if(type.equals(HttpServletRequest.class)){
                    //判断参数类型是否是HttpServletRequest.class
                    objects[i] = request;
                }else if(type.equals(HttpServletResponse.class)){
                    //判断参数类型是否是HttpServletResponse.class
                    objects[i] = response;
                }else if(type.equals(User.class)){
                    Object instance = type.newInstance();
                    //获取Class对象
                    Class<?> clazz = instance.getClass();
                    //获取所有的字段
                    Field[] fields = clazz.getDeclaredFields();
                    //遍历所有的字段
                    for (Field field : fields) {
                        //获取所有字段的名字
                        String fieldName = field.getName();
                        //暴力反射
                        field.setAccessible(true);
                        field.set(instance,request.getParameter(fieldName));
                    }
                    objects[i] = instance;
                }
            }

            Object invoke = method.invoke(o, objects);
            //获取Method方法的返回值
            String value = String.valueOf(invoke);
            //判断Method方法是否有@ResponseBody注解
            if(method.isAnnotationPresent(ResponseBody.class)){
                //通过response.getWrite()方法写出去
                response.getWriter().write(value);
            }else{
                if(invoke.getClass().equals(String.class)){
                    //请求转发
                    request.getRequestDispatcher(prefix+"/"+value+subfix).forward(request,response);
                }else{
                    response.setStatus(404);
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }

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

}

手动实现SpringMVC的效果

@Autowrite(value = "TestService")
private TestService testService;

@RequestMapping(value = "/test")
@ResponseBody
public String test(){
    testService.test();
    return "Hello World";
}

 

@RequestMapping(value = "/test01")
    @ResponseBody
    public User test01(String username, HttpServletRequest request, HttpServletResponse response, User user){
        System.out.println("username:" + username);
        System.out.println("request:" + request);
        System.out.println("response:" + response);
        System.out.println("user:" + user);
        return user;
    }

@RequestMapping(value = "/test02")
    public String test02(HttpServletRequest request){
        testService.test();
        request.setAttribute("msg","未进化的程序猿");
        return "index";
    }
<%--
  Created by IntelliJ IDEA.
  User: admin
  Date: 2020/10/7
  Time: 14:20
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>${msg}&nbsp;欢迎您...</h1>
</body>
</html>
<?xml version="1.0" encoding ="UTF-8"?>
<beans>
    <component-scan base-package="com.tom"></component-scan>
    <viewResolver prefix="/WEB-INF/jsp/" subfix=".jsp"></viewResolver>
</beans>

实现思路(只是个大概)

1.应用启动初始化操作

创建一个contextLoader实现ServletContextListener接口

创建applicationContext上下文,存储在servletContext中
读取xml配置文件获取扫描bean的包路径
通过配置路径获取带有注解的类

通过反射将类实例化,以类名首字母小写或注解上的值为key,实例化的对象为value,将bean存储在上下文中

2.初始化dispatchservlet

在web.xml中配置dispatchservlet,拦截所有请求
将所有类中的@requestMapping存储在一个map中,key为url,value为class

将class(controller)反射实例化存储在dispatchservlet的上下文中
从applicationContext获取bean,为filed注入实例

3.解析请求

dispatchservlet收到请求

通过threadLocal设置request和response方便在controller中使用。

根据url匹配到对应的class,根据class在dispatchservlet上下文中获取实例。

根据注解value找到对应的方法执行,返回视图。

 

posted on 2020-10-07 15:47  甘茂旺  阅读(0)  评论(0)    收藏  举报