手写模拟SpringMvc源码

news2024/11/28 7:49:53

MVC框架

MVC是一种设计模式(设计模式就是日常开发中编写代码的一种好的方法和经验的总结)。模型(model)-视图(view)-控制器(controller),三层架构的设计模式。用于实现前端页面的展现与后端业务数据处理的分离。

Spring MVC的主要组件

前端控制器 DispatcherServlet
Spring的MVC框架是围绕DispatcherServlet来设计的,它用来处理所有的HTTP请求和响应。此模块不需要程序员开发。
作用:接收请求、响应结果,相当于转发器,有了DispatcherServlet 就减少了其它组件之间的耦合度。
处理器映射器HandlerMapping
此功能不需要程序员开发。
作用:根据请求的URL来查找Handler
处理器适配器HandlerAdapter
作用:进行视图的解析,根据视图逻辑名解析成真正的视图(view)
视图View
需要程序员开发jsp。View是一个接口, 它的实现类支持不同的视图类型(jsp,freemarker,pdf等等)
用户发送请求至前端控制器DispatcherServlet;
DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle;
处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet;
DispatcherServlet 调用 HandlerAdapter处理器适配器;
HandlerAdapter 经过适配调用 具体处理器(Handler,也叫后端控制器);
Handler执行完成返回ModelAndView;
HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;
DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;
ViewResolver解析后返回具体View;
DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
DispatcherServlet响应用户。

手写模拟SpringMvc源码

spring mvc调用到Controller执行的原理

通过加载配置文件web.xml进而加载spring-mvc.xml。
根据配置文件给定的目录来扫描整个项目。
扫描所有加了@Controller注解的类。
当扫描到加了@Controller注解的类之后遍历里面所有的方法。
拿到方法对象之后 解析方法上面是否加了@RequestMapping注解。
定义一个Map集合把@RequstMapping的value 与方法对象绑定起来,即Map<String,Method>。
定义一个Map把声名该方法的类的对象绑定起来,即Map<String,Object>。
拦截到请求之后拿到请求的URI。
处理请求,例如执行指定方法,返回字符串或跳转到相应视图。

目录

导入依赖

 <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
    </dependency>
    <!--       解析xml文件-->
    <dependency>
      <groupId>dom4j</groupId>
      <artifactId>dom4j</artifactId>
      <version>1.6.1</version>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.9</version>
    </dependency>

代码

DispatcherServlet类

public class DispatcherServlet extends HttpServlet {
    private ApplicationContext applicationContext;
    private List<MyHandle> myHandleList=new ArrayList<>();

    @Override
    public void init() throws ServletException {
        String contextConfigLocation = this.getServletConfig().getInitParameter("contextConfigLocation");
        System.out.println(contextConfigLocation);
        applicationContext = new ApplicationContext(contextConfigLocation);
        applicationContext.refresh();
        initHandleMappinng(applicationContext);

    }

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

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

    }

    public void initHandleMappinng(ApplicationContext applicationContext){
        if(applicationContext.beanDefinitionConcurrentHashMap.size()==0){
            throw new RuntimeException("Spring容器为空");
        }
        for (Map.Entry<String, BeanDefinition> stringBeanDefinitionEntry : applicationContext.beanDefinitionConcurrentHashMap.entrySet()) {
            Class clazz = stringBeanDefinitionEntry.getValue().getClazz();
            for (Method declaredMethod : clazz.getDeclaredMethods()) {
                boolean annotationPresent = declaredMethod.isAnnotationPresent(RequestMapping.class);
                if(annotationPresent==true){
                    String value = declaredMethod.getAnnotation(RequestMapping.class).value();
                    MyHandle myHandle=new MyHandle(value,declaredMethod,clazz);
                    myHandleList.add(myHandle);
                }
            }
        }
    }
    public void excuteDispatch(HttpServletRequest request,HttpServletResponse response){
        MyHandle handle = getHandle(request);
        if(handle==null){
            try {
                response.getWriter().print("404");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        else {
            Method method = handle.getMethod();
            Class<?>[] parameterTypes = method.getParameterTypes();
            Object[] params=new Object[parameterTypes.length];
            Map<String, String[]> parameterMap = request.getParameterMap();
            for (Map.Entry<String, String[]> stringEntry : parameterMap.entrySet()) {
                String key = stringEntry.getKey();
                String value = stringEntry.getValue()[0];
                int i = GetRequestParams(method, key);
                if(i>=0)
                    params[i]=value;
                else {
                    //反射获取的是arg0,官方这里用的不是反射机制
                }
            }
            try {
                Object invoke = method.invoke(handle.getClazz().newInstance(), params);
                PrintWriter writer = response.getWriter();
                writer.print(invoke);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }

        }
    }

    public MyHandle getHandle(HttpServletRequest request){
        String requestURI = request.getRequestURI();
        for (MyHandle myHandle : myHandleList) {
            if(myHandle.getUrl().equals(requestURI))
                return myHandle;
        }
        return null;
    }

    public int GetRequestParams(Method method,String name){
        Parameter[] parameters = method.getParameters();
        for (int i=0;i<parameters.length;i++) {
            boolean annotationPresent = parameters[i].isAnnotationPresent(RequestParam.class);
            if(annotationPresent){
                String value = parameters[i].getAnnotation(RequestParam.class).value();
                if(value.equals(name))
                    return i;
            }
        }
        return -1;

    }


}

XmlPaser类

public class XmlPaser {
    public static String getbasePackage(String xml){
        SAXReader saxReader=new SAXReader();
        InputStream inputStream = XmlPaser.class.getClassLoader().getResourceAsStream(xml);
        try {
            Document document = saxReader.read(inputStream);
            Element rootElement = document.getRootElement();
            Element componentScan = rootElement.element("component-scan");
            Attribute attribute = componentScan.attribute("base-package");
            String text = attribute.getText();
            return text;
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return "";
    }
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <display-name>Application</display-name>

    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>com.example.demo.springmvc.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

代码下载地址:https://download.csdn.net/download/qq_43649937/87558006

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/402362.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

无公网IP快解析实现移动app访问内网应用

随着移动化的发展&#xff0c;国内各大管理软件厂商纷纷推出相应的移动应用服务。移动端为企业提供了不一样的办公方式&#xff0c;从碎片化应用到一体化&#xff0c;同时也为企业办公提供了更高效便捷办公体验。 移动办公和传统pc端在服务器端部署时并没有太大的区别。企业为了…

数据、数据资源及数据资产管理的区别

整理不易&#xff0c;转发请注明出处&#xff0c;请勿直接剽窃&#xff01; 点赞、关注、不迷路&#xff01; 摘要&#xff1a;数据、数据资源、数据资产 数据、数据资源及数据资产的区别 举例 CRM系统建设完成后会有很多数据&#xff0c;这些数据就是原始数据&#xff0c;业务…

线程(操作系统408)

基本概念 我们说引入进程的目的是更好的使用多道程序并发执行&#xff0c;提高资源的利用率和系统吞吐量&#xff1b;而引入线程的目的则是减小程序在并发执行的时候所付出的时间开销&#xff0c;提高操作系统的并发性能。 线程可以理解成"轻量级进程"&#xff0c;…

Request和Response的概述

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;输出优质文章⭐作者主页&#xff1a;︶ㄣ释然⭐如果觉得文章写的不错&#xff0c;欢迎点个关注&#x1f609;有写的不好的地方也欢迎指正&#xff0c;一同进步&#x1f601;Request和Respo…

Flink之Source

Flink 可以从各种来源获取数据&#xff0c;然后构建 DataStream 进行转换处理。一般将数据的输入来源称为数据源&#xff0c;而读取数据的算子就是源算子&#xff08;Source&#xff09;。所以&#xff0c;Source 就是我们整个处理程序的输入端。Flink 代码中通用的添加 Source…

【零基础入门学习Python---Python的五大数据类型之数字类型】

一.Python的五大数据类型之数字类型 在Python中,变量用于存储数据。变量名可以是任何字母、数字和下划线的组合。Python支持多种数据类型,包括数字、字符串、列表、元组和字典。这篇文章我们就来学习一下五大数据类型中的数字类型。 1.1 数字类型 Python 中的数字类型主要…

【C语言蓝桥杯每日一题】—— 单词分析

【C语言蓝桥杯每日一题】—— 单词分析&#x1f60e;前言&#x1f64c;单词分析&#x1f64c;总结撒花&#x1f49e;&#x1f60e;博客昵称&#xff1a;博客小梦 &#x1f60a;最喜欢的座右铭&#xff1a;全神贯注的上吧&#xff01;&#xff01;&#xff01; &#x1f60a;作者…

JSP电动车充电运营管理系统用myeclipse定制开发mysql数据库mvc模式java编程servlet

一、源码特点 JSP 电动车充电运营管理系统 是一套完善的系统源码&#xff0c;对理解JSP java serlvet MVC编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。 研究的基本内容是基于Web的电动车充电运营管理系统&#xf…

论文笔记 | 标准误聚类问题

关于标准误的选择&#xff0c;如是否选择稳健性标准误、是否采取聚类标准误。之前一直是困惑的&#xff0c;惯用的做法是类似主题的文献做法。所以这一次&#xff0c;借计量经济学课程之故&#xff0c;较深入学习了标准误的选择问题。 在开始之前推荐一个知乎博主。他阅读了很…

ssl/tsl 加密原理

ssl/tsl 加密原理 对称加密 对称加密&#xff1a;即加密和解密用的都是同一个秘钥&#xff0c;主要优势就是速度比非对称加密快 非对称加密 非对称加密&#xff1a; 即加密和解密用的是不同的秘钥&#xff0c;例如&#xff1a;在服务端存在一对公钥和私钥&#xff0c;服务…

JWT令牌解析及刷新令牌(十一)

写在前面&#xff1a;各位看到此博客的小伙伴&#xff0c;如有不对的地方请及时通过私信我或者评论此博客的方式指出&#xff0c;以免误人子弟。多谢&#xff01;如果我的博客对你有帮助&#xff0c;欢迎进行评论✏️✏️、点赞&#x1f44d;&#x1f44d;、收藏⭐️⭐️&#…

mmdetection3d-之(三)--FCOS3d训练waymo数据集

本内容分为两部分 1. waymo数据集转KITTI格式2. FCOS3D训练KITTI格式的waymo数据集1 waymo数据集转kitti格式 1.1 waymo数据集简介 1.1.1 waymo数据集下载 waymo数据集v1.2.0可以从这里下载。其中&#xff0c;train&#xff08;32个压缩包&#xff09;&#xff0c;test&…

零入门kubernetes网络实战-22->基于tun设备实现在用户空间可以ping通外部节点(golang版本)

《零入门kubernetes网络实战》视频专栏地址 https://www.ixigua.com/7193641905282875942 本篇文章视频地址(稍后上传) 本篇文章主要是想做一个测试&#xff1a; 实现的目的是 希望在宿主机-1上&#xff0c;在用户空间里使用ping命令发起ping请求&#xff0c;产生的icmp类型的…

从FVM上线前的测试网统计报告中看前景,Filecoin将会迎来什么变化?

FEVM将在2023/03/14主网上线&#xff01;在Calibration网络升级正式完成后&#xff0c;Filecoin V18 Hygge升级将于2023年3月14日&#xff08;π日&#xff09;正式上线&#xff01;此次升级将正式为Filecoin网络带来智能合约。基于FVM的可编程性。此次更新升级将释放数据经济的…

Spring Cloud Alibaba Sentinel 集群流量控制

为什么要进行集群流控 假设集群中有 10 台机器&#xff0c;我们给每台机器设置单机限流阈值为 10 QPS&#xff0c;理想情况下整个集群的限流阈值就为 100 QPS。不过实际情况下流量到每台机器可能会不均匀&#xff0c;会导致总量没有到的情况下某些机器就开始限流。因此仅靠单机…

因特网基础

1、因特网的概述 1-1、网络、互联网和因特网 网络&#xff08;Network&#xff09;是由若干节点&#xff08;Node&#xff09;和连接这些节点的链路&#xff08;Link&#xff09;组成。 多个网络还可以通过路由器相互连起来&#xff0c;这样就构成了一个覆盖范围更大的网络&…

【刷题笔记】--双指针--189. 轮转数组

题目&#xff1a; 思路1&#xff1a; 再设一个数组&#xff0c;通过下标的规律&#xff0c;进行更新数组。 关于这个平移的下标规律&#xff1a;%numbersize&#xff1b; 假设数组1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5&#xff0c;6&#xff0c;7 要整体…

MTK平台 Wireless Authentication Denied问题

这个问题一开始的现象是部分station无法连接某台AP。无线抓包后发现station和AP间进行了频繁的Auth认证,即station发送Auth包,ap回复Auth包出现 Expert: Wireless Authentication Denied (13: Requested authentication algorithm not supported)这样错误提示…

Lesson 9.2 随机森林回归器的参数

文章目录一、弱分类器的结构1. 分枝标准与特征重要性2. 调节树结构来控制过拟合二、弱分类器的数量三、弱分类器训练的数据1. 样本的随机抽样2. 特征的随机抽样3. 随机抽样的模式四、弱分类器的其他参数在开始学习之前&#xff0c;先导入我们需要的库。 import numpy as np im…

【项目精选】俄罗斯方块项目(视频+论文+源码)

点击下载源码 俄罗斯方块项目&#xff0c;基本功能包括&#xff1a;游戏主界面显示模块、方块及数据显示模块、方块移动控制模块、游戏界面颜色控制模块、游戏进度、等级控制模块等。本项目结构如下&#xff1a; &#xff08;1&#xff09;游戏主界面显示模块&#xff1a; 显示…