004-webmvc

核心组件

启动 ioc 容器

加载 PropertyResolver

我们有两种类型的文件(.properties.yml )需要支持。优先支持 yml,如果 yml 没有再读取 properties 文件。但是由于实际环境中,可能会有空的配置文件的存在的情况,所以我们不能粗暴的直接根据文件是否为 Empty 来读取。

并且,我们会发现如果再写一个获取 ClassLoader 的代码,会造成一定的冗余,我们期望的是一种更为强大的工具,使得我们给出一个 inputStream,可以得到我们想要的各种形式的资源,例如在 Resource ,这里的 prop 文件。这就是函数式接口的应用场景了。

实现 MVC

加载 DispatcherServlet

我们通过监听器来创建 DispatcherServlet。当监听到 Servlet 容器创建的时候,来创建 ioc 容器,同时注册 DispatcherServlet。

DispatcherServlet 细节

成员属性

init

这里主要进行初始化工作,当 servlet 被创建的时候,我们需要初始化所有的 Controller 和 urlPattern,将 urlPattern 与 Handler 进行绑定,以至于在之后接受 get 和 post 请求的时候,可以做到路由转发。

Handler 路径匹配

根据对应的 uri 找到应该调用的 Handler。

我们首先知道 uri 的格式为:../[...]/[...],而要与之进行匹配的 Handler 的 URL 的格式为 /[...]/{...},我们还要拿出 path variable。所以,这就需要用上正则匹配了。

请求类型分发处理

这两个方法主要分别用于处理 get 和 post 请求。对于 get 请求,可能有两种情况:

对于 post 请求,只有可能请求动态资源。

调用 controller 方法

分而治之后,我们应该想办法调用 controller 中的方法,为了调用这个方法,我们需要先填充方法的参数(体现在方法 Dispatcher.process())。


当参数填充完毕后,我们要用参数数组来 invoke 相关的方法。最后将结果返回。

将结果进行返回

假如我们能够正确调用方法,并返回方法返回值,那么就要对返回值进行进一步的处理。

返回值的有几种类型:

不符合上述要求的返回类型则报500错误。

视图解析

当我们从 controller 成功的调用了相应的方法,我们就要尝试将数据返回给前端了,如何根据 controller 中方法的返回类型来规定响应的内容呢?这就需要进行视图解析了。

确定 content-type

为了简单起见,我们仅仅支持几种最常用的 content-type 返回。并且将这些代码写死,也就是说,暂时无法根据请求头来动态确定返回的响应头中的 header。

支持的 content-type:

视图解析流程

springmvc 的视图的流程可以表示为:
004-webmvc-20231109

我们对其进行一定的简化,如下图所示:
DispatcherServlet_doService 1

上图中有两个很重要的组件,担当了视图解析的核心功能。一个是 ViewResovler,一个是 View

其中 ViewResovler 的作用大致为:根据 handler 返回的类型确定视图 View。简单来说,就是确定返回的后端数据类型。

View 就是我们返回数据 body 的抽象,为了简化流程(在 Springmvc 中,还需要经过 HttpOutputMessage 的处理),就在 View 中通过方法 renderMergedOutputModel 直接向浏览器返回数据了。

对 jsp 的处理

当我们想要请求转发或者重定向到 jsp file 的时候,我们就需要对 jsp 进行一些必要的准备:

开发 Web 应用

至此,框架的基本功能已经完成。故而,这一章节,主要专注于框架的测试方案。

Bug 以及解决

tomcat 报错 ClassNotFound

如下图所示:
004-webmvc-20231107
解决:

解决方法

004-webmvc-20231107_1
在 mvc 的类加载路径下的 lib 中加入即可解决这个问题。