前面我们学习了spring框架源码,做了一些自己手写的学习,最近,我们开始学习springMVC框架的学习 ,springMVC框架,相信大家不陌生了,所以这里不做过多的介绍了。

SpringMVC以DispatcherServlet为核心,负责协调和组织不同组件以完成请求处理并返回响应的工作,实现了MVC模式。想要实现自己的SpringMVC框架,需要从以下几点入手:

1、了解SpringMVC运行流程及九大组件

2、梳理自己的SpringMVC的设计思路

3、实现自己的SpringMVC框架

一、SpringMVC流程图

二、SpringMVC流程

1、 用户发送请求至前端控制器DispatcherServlet。

2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。

3、 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。

4、 DispatcherServlet调用HandlerAdapter处理器适配器。

5、 HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。

6、 Controller执行完成返回ModelAndView。

7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。

8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器。

9、 ViewReslover解析后返回具体View。

10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。

11、 DispatcherServlet响应用户。

三、SpringMVC的九大组件

protected void initStrategies(ApplicationContext context) {
//用于处理上传请求。处理方法是将普通的request包装成MultipartHttpServletRequest,后者可以直接调用getFile方法获取File.
initMultipartResolver(context);
//SpringMVC主要有两个地方用到了Locale:一是ViewResolver视图解析的时候;二是用到国际化资源或者主题的时候。
initLocaleResolver(context);
//用于解析主题。SpringMVC中一个主题对应一个properties文件,里面存放着跟当前主题相关的所有资源、
//如图片、css样式等。SpringMVC的主题也支持国际化,
initThemeResolver(context);
//用来查找Handler的。
initHandlerMappings(context);
//从名字上看,它就是一个适配器。Servlet需要的处理方法的结构却是固定的,都是以request和response为参数的方法。
//如何让固定的Servlet处理方法调用灵活的Handler来进行处理呢?这就是HandlerAdapter要做的事情
initHandlerAdapters(context);
//其它组件都是用来干活的。在干活的过程中难免会出现问题,出问题后怎么办呢?
//这就需要有一个专门的角色对异常情况进行处理,在SpringMVC中就是HandlerExceptionResolver。
initHandlerExceptionResolvers(context);
//有的Handler处理完后并没有设置View也没有设置ViewName,这时就需要从request获取ViewName了,
//如何从request中获取ViewName就是RequestToViewNameTranslator要做的事情了。
initRequestToViewNameTranslator(context);
//ViewResolver用来将String类型的视图名和Locale解析为View类型的视图。
//View是用来渲染页面的,也就是将程序返回的参数填入模板里,生成html(也可能是其它类型)文件。
initViewResolvers(context);
//用来管理FlashMap的,FlashMap主要用在redirect重定向中传递参数。
initFlashMapManager(context);
}

四、SpringMVC核心组件讲解

1、前端控制器DispatcherServlet
作用:接收请求,响应结果,相当于转发器,中央处理器。有了dispatcherServlet减少了其它组件之间的耦合度。
用户请求到达前端控制器,它就相当于mvc模式中的c,dispatcherServlet是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet的存在降低了组件之间的耦合性。

2、处理器映射器HandlerMapping
作用:根据请求的url查找Handler
HandlerMapping负责根据用户请求找到Handler即处理器,springmvc提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。

3、处理器适配器HandlerAdapter
作用:按照特定规则(HandlerAdapter要求的规则)去执行Handler
通过HandlerAdapter对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。

4、处理器Handler
Handler 是继DispatcherServlet前端控制器的后端控制器,在DispatcherServlet的控制下Handler对具体的用户请求进行处理。
由于Handler涉及到具体的用户业务请求,所以一般情况需要工程师根据业务需求开发Handler。

5、视图解析器View resolver(不需要工程师开发),由框架提供
作用:进行视图解析,根据逻辑视图名解析成真正的视图(view)
View Resolver负责将处理结果生成View视图,View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成View视图对象,最后对View进行渲染将处理结果通过页面展示给用户。 springmvc框架提供了很多的View视图类型,包括:jstlView、freemarkerView、pdfView等。
一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由工程师根据业务需求开发具体的页面。

6、视图View
View是一个接口,实现类支持不同的View类型(jsp、freemarker、pdf...)

五、手写springMvc框架思路:

1、配置web.xml,加载自定义的DispatcherServlet。

2、初始化阶段,在DispatcherServlet类中,实现下面几个步骤:

  1. 加载配置类。
  2. 扫描当前项目下的所有文件。
  3. 拿到扫描到的类,通过反射机制,实例化。并且放到ioc容器中。
  4. 初始化path与方法的映射。
  5. 获取请求传入的参数并处理参数通过初始化好的handlerMapping中拿出url对应的方法名,反射调用。

3、运行阶段,每一次请求将会调用doGet或doPost方法,它会根据url请求去HandlerMapping中匹配到对应的Method,然后利用反射机制调用Controller中的url对应的方法,并得到结果返回。

六、代码实现

在SpringMVC的框架实现中,少不了一些基本的注入类,例如:@Controller、@RequestMapping、@RequestParam等等,在上一篇文章中,根据需要实现的代码块,需要自定义一些注解类:

@MyController

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

@MyRequestMapping

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

@MyAutowired

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAutowired {boolean required() default true;
}

@MyRequestParam

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

@MyService

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

web.xm加载

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"><display-name>spring_mvc</display-name><servlet><servlet-name>DispatcherServlet</servlet-name><servlet-class>com.spring.dispathcer.DispatcherServlet</servlet-class></servlet><servlet-mapping><servlet-name>DispatcherServlet</servlet-name><url-pattern>/</url-pattern></servlet-mapping>
</web-app>

ClassUtils工具类封装

public class ClassUtils {/*** 从包package中获取所有的Class** @param pack* @return*/public static List<Class<?>> getClasses(String packageName) {// 第一个class类的集合List<Class<?>> classes = new ArrayList<Class<?>>();// 是否循环迭代boolean recursive = true;// 获取包的名字 并进行替换String packageDirName = packageName.replace('.', '/');// 定义一个枚举的集合 并进行循环来处理这个目录下的thingsEnumeration<URL> dirs;try {dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);// 循环迭代下去while (dirs.hasMoreElements()) {// 获取下一个元素URL url = dirs.nextElement();// 得到协议的名称String protocol = url.getProtocol();// 如果是以文件的形式保存在服务器上if ("file".equals(protocol)) {// 获取包的物理路径String filePath = URLDecoder.decode(url.getFile(), "UTF-8");// 以文件的方式扫描整个包下的文件 并添加到集合中findAndAddClassesInPackageByFile(packageName, filePath, recursive, classes);} else if ("jar".equals(protocol)) {// 如果是jar包文件// 定义一个JarFileJarFile jar;try {// 获取jarjar = ((JarURLConnection) url.openConnection()).getJarFile();// 从此jar包 得到一个枚举类Enumeration<JarEntry> entries = jar.entries();// 同样的进行循环迭代while (entries.hasMoreElements()) {// 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件JarEntry entry = entries.nextElement();String name = entry.getName();// 如果是以/开头的if (name.charAt(0) == '/') {// 获取后面的字符串name = name.substring(1);}// 如果前半部分和定义的包名相同if (name.startsWith(packageDirName)) {int idx = name.lastIndexOf('/');// 如果以"/"结尾 是一个包if (idx != -1) {// 获取包名 把"/"替换成"."packageName = name.substring(0, idx).replace('/', '.');}// 如果可以迭代下去 并且是一个包if ((idx != -1) || recursive) {// 如果是一个.class文件 而且不是目录if (name.endsWith(".class") && !entry.isDirectory()) {// 去掉后面的".class" 获取真正的类名String className = name.substring(packageName.length() + 1, name.length() - 6);try {// 添加到classesclasses.add(Class.forName(packageName + '.' + className));} catch (ClassNotFoundException e) {e.printStackTrace();}}}}}} catch (IOException e) {e.printStackTrace();}}}} catch (IOException e) {e.printStackTrace();}return classes;}/*** 以文件的形式来获取包下的所有Class** @param packageName* @param packagePath* @param recursive* @param classes*/public static void findAndAddClassesInPackageByFile(String packageName, String packagePath, final boolean recursive,List<Class<?>> classes) {// 获取此包的目录 建立一个FileFile dir = new File(packagePath);// 如果不存在或者 也不是目录就直接返回if (!dir.exists() || !dir.isDirectory()) {return;}// 如果存在 就获取包下的所有文件 包括目录File[] dirfiles = dir.listFiles(new FileFilter() {// 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)@Overridepublic boolean accept(File file) {return (recursive && file.isDirectory()) || (file.getName().endsWith(".class"));}});// 循环所有文件for (File file : dirfiles) {// 如果是目录 则继续扫描if (file.isDirectory()) {findAndAddClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive,classes);} else {// 如果是java类文件 去掉后面的.class 只留下类名String className = file.getName().substring(0, file.getName().length() - 6);try {// 添加到集合中去classes.add(Class.forName(packageName + '.' + className));} catch (ClassNotFoundException e) {e.printStackTrace();}}}}
}

未完待续。。。。

js如何在当前页面加载springmvc返回的页面_手写SpringMVC学习相关推荐

  1. html 判断页面加载完成,Javascript判断页面是否加载完成

    很多时候我们在使用document.getElementById的时候直接在script标签中获取对象,然后使用,此时程序会出现该对象为undefined. var dom=document.getE ...

  2. 页面加载事件html5,JavaScript页面加载事件实例讲解

    一.onload 加载事件 onload 是 window 对象的一个事件,也可以省略 window 直接使用. 常用方式: 这个事件是等待页面加载完成之后,再执行 注意:该事件相比于在 中的

  3. node.js css文件已经被加载但是无法渲染页面的问题和解决方法

    问题:在使用node.js创建了一个服务器,加载html页面后css文件已经被加载但是页面没有被渲染 如图 此时已经证明了路径是没有问题的,那么问题出现在哪里? 代码如下 const fs = req ...

  4. ajax离开页面方法,如果用户在页面加载完成之前离开页面,则触发jQuery ajaxError()处理程序...

    我们使用jQuery的全局ajaxError()处理函数来警告用户任何AJAX失败: $(document).ajaxError(function() { $("There was a ne ...

  5. springmvc原理详解(手写springmvc)

    最近在复习框架 在快看小说网搜了写资料 和原理 今天总结一下 希望能加深点映像  不足之处请大家指出 我就不画流程图了 直接通过代码来了解springmvc的运行机制和原理 回想用springmvc用 ...

  6. python selenium 等待页面加载完毕_Selenium_等待页面加载完毕

    隐式等待 WebDriver driver = newFirefoxDriver(); driver.get("www.baidu.com"); driver.manage().t ...

  7. 在一个html页面加载另一个html页面

    jquery方法: 例如:实现在section选择器中添加third,html; $('section').load("third.html"); 如果带有回调函数: //$('s ...

  8. HTML页面加载和解析流程详细介绍

    浏览器加载和渲染html的顺序.如何加快HTML页面加载速度.HTML页面加载和解析流程等等,在本文将为大家详细介绍下,感兴趣的朋友不要错过 浏览器加载和渲染html的顺序 1. IE下载的顺序是从上 ...

  9. html5 载入网页 显示,页面加载完之前显示Loading

    1.第一种方式 HTML loading... CSS .loader { position: fixed; left: 50%; top: 50%; margin: -0.2em 0 0 -0.2e ...

最新文章

  1. 在ASP.NET中值得注意的两个地方
  2. 专访中国移动钱岭:大数据更像是一种“倍增器”
  3. 看论文不用来回翻了,这款PDF阅读神器能自动提取前文信息,科研效率max!
  4. java 基本变量类型_Java自学-基本变量类型
  5. jsx后缀的是什么文件_React-从JSX到虚拟DOM
  6. C语言再学习 -- 三字母词(转)
  7. kali下生成web端后门
  8. 如何修改ant-input的高度_水质自动采样器的流量计功能如何应用?
  9. 数组深拷贝_JavaScript之深浅拷贝
  10. OpenCV精进之路(九):图像轮廓和图像分割修复——图像修复技术
  11. 汽车配件+供应链一体化:降低库存成本,提高运营效率
  12. HAWQ取代传统数仓实践(一)——为什么选择HAWQ
  13. 安装PdaNet以连接Android设备
  14. 水平放滑轮组计算机械效率,滑轮组机械效率     王凤霞
  15. 如何做CRM系统的客户开发?
  16. Poi导入excel(合并单元格)
  17. JDBCUtil工具类,单线程模式
  18. 36岁,被单位解聘,我干起了深夜外卖
  19. vue引入html报错
  20. shiro漏洞原理以及检测key值原理

热门文章

  1. 腾讯云成为国内首家FinOps基金会顶级会员
  2. 全新的 Fragment 通信方式
  3. 17 年安全界老兵,专注打造容器安全能行吗?
  4. 2020中关村论坛未来青年论坛:聚焦科技与产业数字化转型,让创新成果落地开花
  5. 定了!2020年,6种将死的编程语言!
  6. 生产环境使用HBase,你必须知道的最佳实践
  7. 云+X案例展 | 金融类:荣之联助力君康人寿构建新一代数据中心
  8. 云+X案例展 | 民生类:纷享销客助力沃得农机构筑智能化、信息化之路
  9. 10个业界最流行的Kubernetes发行版
  10. 云计算演进历程与模式 - 初识云计算知识专栏(2)