本文介绍
该篇文章主要讲解SpringMVC的执行流程,即前端控制器、控制器等组件的调用
先从Spring的一个基础案例,转到SpringMVC。以此来观察到SpringMVC做了哪些改变
然后分析SpringMVC程序的执行流程,知道代码是如何跑起来的,一个请求又是如何返回一个页面的
最后根据SpringMVC的架构图,讲解程序中没有体现的、SpringMVC封装好的那些组件
作者能力有限,只作为自己学习的笔记,可能理解有误差(毕竟全信书不如不看书嘛)
Spring简单执行示例
案例内容:
浏览器访问:localhost/UserServlet,返回一个页面
- 项目目录
- web.xml配置
指定要拦截的请求路径是/UserServlet,由UserServlet类进行处理
<servlet>
<servlet-name>UserServlet</servlet-name>
<servlet-class>com.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/UserServlet</url-pattern>
</servlet-mapping>
- UserServlet
打印语句到控制台,然后返回success.jsp页面
public class UserServlet extends HttpServlet{
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws Exception{
System.out.println("user servlet is running...");
req.getRequestDispatcher("success.jsp").forward(req,resp);
}
//doPost方法省略
}
改造成SpringMVC
上述程序改造成SpringMVC
- 指定表现成业务处理器,并将其配置成Spring的bean(等同于Servlet)
当前端访问时,就会执行该程序
需要设置方法的访问地址,确定什么请求会执行这个方法
设置要跳转的页面,不然会报错,如果不设置跳转页面,输出语句也会正常执行
//设定当前类为Spring的控制类
@Controller
public class UserController{
//设定当前方法的访问映射地址,相当于之前web.xml中配置的<url-pattern>
@RequestMapping("/save")
//设置当前方法返回值类型为String,用于指定请求完成后跳转的页面
public String save(){
System.out.println("user mvc controller is running...");
//返回跳转的页面名称
return "success.jsp";
}
}
- 创建spring-mvc.xml配置文件
等同于spring的xml配置文件,只是需要区分一下。此时可以删除原来的spring的配置文件
在配置文件中开启组件扫描注解驱动,不然扫描不到上边类的@Controller注解,也就无法把UserController交给springMVC控制
<context:component-scan base-package="com"/>
- 修改web.xml
用DispatcherServlet顶替掉之前的UserServlet,目前可以将DispatcherServlet理解成== 看大门 == 的,专门拦截请求
既然要拦截请求,那么作为一个正经看大门的,也要有原则!所以需要配置具体拦截哪个请求
看大门的有了,那么用户真正想进去的还是== 办公室 (UserController)== 啊,只有spring加载了才可以。所以加上,把spring-mvc.xml文件加载进来
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--初始化时,读取spring-mvc.xml文件的配置,加载bean-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring-mvc.xml</param-value>
</init-param>
</servlet>
<!--读取bean中所有添加了映射注解的内容-->
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
程序执行流程分析
- 服务器启动
- 加载web.xml中的DispatcherServlet
- 读取spring-mvc.xml中的配置,加载所有com包中所有标记为bean的类
- 读取bean中方法上标注@RequestMapping的内容(知道自己可以处理哪些请求)
- 处理请求
- DispatcherServlet配置拦截所有请求(因为在web.xml中配置的是/)
- 使用请求路径与所有加载的@RequestMapping的内容进行对比
- 找到匹配的访问路径,执行对应的方法
- 根据方法返回值,在webapp目录中查找对应的页面并展示
SpringMVC架构图以及执行流程(可以直接跳过来)
架构图
名词解释(官方话):
- 前端控制器DispatcherServlet: 整体流程控制中心,降低组件间的耦合性
- 处理器映射器HandlerMapping: 根据用户请求找到对应具体的Handler处理器
- 处理器Handler: 业务处理的核心类(servlet类似,自己开发)
- 处理器适配器HandlAdapter: 对Handler处理器进行执行,即找到要执行的servlet方法
- 视图解析器View Resolver: 将处理结果生成View视图
- View: 最终产出的页面结果
执行流程
- 用户发送请求 --> 前端控制器
- 前端控制器(若配置了拦截此路径)会拦截此请求,然后调用处理器映射器
- 处理器映射器确定要调用哪个处理器,并可能执行处理器链(过滤器、拦截器),最后将处理器地址返回给前端控制器
- 前端控制器拿着地址调用处理器适配器,由其去调用具体的处理器(业务处理方法实现)
- 处理器会返回页面以及数据(Model And View)给处理器适配器
- 处理器适配器将其再返回给前端控制器
- 前端控制器调用视图解析器,将MV解析成JSP或者HTML,返回给前端控制器
- 最后前端控制器将解析完的页面返回给用户
自己理解
可能有点啰嗦,但是却很能理解(基于真事改编)**
一次请求就可以看做是你去银行办事
假设小明(没错,就是他)今天要去银行开通手机支付
- 你不能直接去柜台办理(除非你特别豪横、有钱、知道哪个柜台可以办理这个业务)
- 所以第一步是去咨询前台(前端控制器),告诉前台小哥哥/小姐姐你要办理更改密码这个业务
- 前台在电脑上查询(处理器映射器)这个业务是哪个柜台能办理(前台业务能力真低)
- 然后前台就告诉你在预约机器(处理器适配器)上排队取号,选便民服务(不要问我这是不是真的,我不知道)
- 当轮到你时,你就去柜台(处理器)办理业务,柜台小姐姐说已经改好了,但是需要你在手机银行软件上转账三次进行激活(激活操作就相当于Model And View,此时用户还不能直接处理这个数据)
- 小明不知道该怎么操作,于是还是要问前台(前端控制器)
- 那业务低的前台(前端控制器)就问问他们的经理(视图解析器)
- 经理(视图解析器)告诉前台(前端控制器)操作步骤(View),然后前台再告诉小明,自此,小明这个业务才算完成