盒子
盒子
Posts List
  1. 前言
  2. Spring MVC
  3. 源码分析
    1. DispatcherServlet
      1. 过程
  4. Spring MVC 如何以统一的方式,将数据纳入不同的视图并显示?

Spring MVC

前言

Spring 是啥?

MVC 是啥?

Spring MVC 是一个基于 Spring 的 Web 框架.

在 Java Web 中,需要自己实现 HttpServlet,Spring MVC 对 平时用到的 Servlet 进行了一层封装.

Spring MVC

下面以一个完整的后端渲染流程大致说明一下.

原文 : 通过项目逐步深入了解Spring MVC(一)

在前后端分离项目中,无需 ModelAndView,直接返回 json 数据.

  1. DispatcherServlet(前端控制器) 接受所有的 Web 请求.

  2. 前端控制器请求 HandlerMapping(处理器映射器) 查找 Handler.(Handler 也就是 Controller 层)

    可根据 xml 配置,注解查找.(包括URL, Http方法, 请求报文头和请求参数 Cookie 等)

  3. HandlerMapping 向 DispatcherServlet 返回 Handler.

  4. DispatcherServlet 调用 HandlerAdapter(处理器适配器) 去执行 Handler.

  5. HandlerAdapter 执行 Handler.

  6. Handler 执行完成返回 ModelAndView 给 HandlerAdapter.

  7. HandlerAdapter 向 DispatcherServlet 返回 ModelAndView.

    ModelAndView 是 Spring MVC 的一个底层对象,包括 Model 和 View.

  8. DIspatcherServlet 请求 ViewResolver(视图解析器) 去进行视图解析.

    根据逻辑视图名解析成真正的视图

  9. ViewResolver 向 DispatcherServlet 返回 View

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

  10. DispatcherServlet 进行视图渲染

    视图渲染将模型数据(在 ModelAndView 中)填充到 request 域

    这一层就是 jsp,Thymeleaf 页面开发吧?

  11. DispatcherServlet 向用户相应结果

源码分析

DispatcherServlet

DispatcherServlet 的继承链 :

DispatcherServlet –> FrameworkServlet –> HttpServletBean –> HttpServlet

DispatcherServlet 其实是 HttpServlet 的子类.本质上也是一个 Servlet.

详情可见 : HttpServlet

大概介绍一下,Java EE 开发时,会继承 HttpServlet,实现里面的 doGet(),doPost() 等方法来相应 Http 请求.

1
2
3
4
5
public class Login extends javax.servlet.http.HttpServlet{
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// ...
}
}

Spring MVC 把这种细节屏蔽了.

看构造方法,

1
2
3
4
public DispatcherServlet(WebApplicationContext webApplicationContext) {
super(webApplicationContext);
setDispatchOptionsRequest(true);
}

这里传入了一个 WebApplicationContext.

看 : Spring 启动流程

ApplicationContext 是 Spring IOC 的容器(也称 上下文),WebApplicationContext 继承自 ApplicationContext,为 Spring MVC 提供上下文环境.使之在 Web 环境可以访问 Spring 的上下文.有了这个,相应就可以通过 Spring 来管理 Bean 之类的啦…

通过 WebApplicationContext,可以访问 :

  1. ServletContext

    Web 服务器提供

  2. request, session, globalsession

  3. HttpServletRequest

    服务器获取客户端数据

  4. HttpServletResponse

    服务器向客户端传递数据

至于 WebApplicationContext 的创建,则由 Spring 来完成.

在一个 Spring MVC 项目中,通过在 web.xml 中配置 :

1
2
3
4
<listener>
<description>spring listener</description>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

ContextLoaderListener 指定 Web 应用程序启动时载入 IOC 容器.

// todo 具体怎么加载呢?

过程

SpringMVC源码分析系列-精简

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// spring-webmvc
// org.springframework.web.servlet.DispatcherServlet
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
...
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
//1.调用handlerMapping获取handlerChain
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
// 2.获取支持该handler解析的HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
...
// 3.使用HandlerAdapter完成handler处理
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
// 4.视图处理(页面渲染)
applyDefaultViewName(request, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
...
}

对应上文 Spring MVC 的 11 个步骤…

// todo [先到此]

Spring MVC 如何以统一的方式,将数据纳入不同的视图并显示?

服务端渲染才会考虑这一点.

底层(Servlet)是 HttpServletResponse.

将视图数据通过 HttpServletResponse 输出前,借助不同的视图技术 API,结合数据和模板文件,生成最终结果.