SpringMVC 基本工作流程
文章目录
- SpringMVC 的工作流程
- 1. 总图
- 2. DispatcherServlet
- 3. 必需的配置
- 4. 加载配置文件的两个时机
- 5. 定义控制器
- 6. 创建 JSP 视图
SpringMVC 的工作流程
1. 总图
如上图,Spring MVC 程序的完整执行流程如下:
-
用户通过浏览器发送请求,请求会被 Spring MVC 的『前端控制器』DispatcherServlet 接收。
-
DispatcherServlet 拦截到请求后,会调用『处理器映射器』HandlerMapping 。
-
『处理器映射器』根据请求 URL 找到具体的『处理器』Handler ,生成『处理器』对象(如果有,还会生成拦截器对象)并返回给 DispatcherServlet 。
-
DispatcherServlet 根据返回信息(Handler)选择合适的『处理器适配器』HandlerAdapter 。
-
HandlerAdapter 会调用并指定 Handler 。此处和上述所说的处理器 Handler ,就是我们所编写的 Controller 类。
-
Controller 执行完成后,会返回一个 ModelAndView 对象,该对象中会包含『视图名』和『模型对象』。
-
HandlerAdapter 将 ModelAndView 返回给 DispatcherServlet 。
-
DispatcherServlet 会根据返回信息(ModelAndView)选择一个合适的『视图解析器』ViewResolver 。
-
视图解析器 ViewResolver 解析视图后,会向 DispatcherServlet 返回具体的 View 对象。
-
DispatcherServlet 对 View 进行渲染。即,将『模型数据』填充至『视图』中。
-
DispatcherServlet 将渲染后的结果返回、发送给客户端浏览器。
在上述执行过程中,DispatcherServlet、HandlerMapping、HandlerAdapter 和 ViewResolver 对象的工作都是在框架内部执行的,开发人员并不需要关心这些对象内部实现过程。
和程序员有关的内容只有 Handler(即,代码中的 Controller),和 ModelAndView 对象。
2. DispatcherServlet
Spring Web 的『模型 - 视图 - 控制器』(MVC)框架是围绕 DispatcherServlet 设计的,它处理所有的 HTTP 请求和响应。
以下是对应于到 DispatcherServlet 的传入 HTTP 请求的事件顺序:
-
在接收到 HTTP 请求后,DispatcherServlet 会查询 HandlerMapping,并通过 Adapter 调用相应的 Controller 。
-
Controller 接受请求并根据使用的 GET 或 POST 方法调用相应的服务方法。 服务方法将基于定义的业务逻辑设置模型数据,并将视图名称返回给 DispatcherServlet 。
-
DispatcherServlet 将从 ViewResolver 获取请求的定义视图。当视图完成,DispatcherServlet 将模型数据传递到最终的视图,并在浏览器上呈现。
3. 必需的配置
需要通过使用 web.xml 文件中的 URL 映射来映射希望 DispatcherServlet 处理的请求。
<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_3_1.xsd"
version="3.1">
...
<!-- 配置 SpringMVC 前端控制器 -->
<servlet>
<servlet-name>HelloWeb</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
...
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>HelloWeb</servlet-name>
<url-pattern>*.do</url-pattern> <!-- 后缀拦截 -->
</servlet-mapping>
</web-app>
4. 加载配置文件的两个时机
SpringMVC 有两次加载 Spring 配置文件的时机:
首先在 SpringMVC 项目启动时,会依据 web.xml 配置文件中所配置的监听器:ContextLoaderListener 去加载对应位置下的 Spring 配置文件。
-
Spring 配置文件版:web.xml
<context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:spring-dao.xml, classpath:spring-service.xml </param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener>
-
Spring 代码配置版:web.xml
<context-param> <param-name>contextClass</param-name> <param-value> <!-- 相较于 XML 配置,Java 代码配置『多』一个这个 --> org.springframework.web.context.support.AnnotationConfigWebApplicationContext </param-value> </context-param> <context-param> <param-name>contextConfigLocation</param-name> <param-value> com.example.config.SpringServiceConfig, com.example.config.SpringDaoConfig </param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener>
无论你有没有利用第一次加载时机(配置 ContextLoadListener),那么 Spring MVC 都会继续进入第二个加载配置文件时机:根据 DispatcherServlet 的初始化配置(<init-param>)加载对应位置的 Spring 配置。
-
Spring 配置文件版:web.xml
<servlet> <servlet-name>sampleServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-web.xml</param-value> </init-param> </servlet> <servlet-mapping> ... </servlet-mapping>
-
Spring 代码配置版:web.xml
<servlet> <servlet-name>sampleServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param><!-- 相较于 XML 配置,Java 代码配置『多』一个这个 --> <param-name>contextClass</param-name> <param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value> </init-param> <init-param> <param-name>contextConfigLocation</param-name> <param-value>com.example.config.SpringWebConfig</param-value> </init-param> </servlet> <servlet-mapping> ... </servlet-mapping>
如果是 XML 配置文件,这里的 Spring 配置文件的路径如果是以 classpath: 开始,则表示配置文件是在 classpath 路径下。否则,就是在项目的工程根目录(webapp)>下。
SpringMVC 首先加载的是 <context-param> 配置的内容,而并不会去初始化 servlet。只有进行了网站的跳转,经过了 DispatcherServlet 的导航的时候,才会初始化 Servlet,从而加载 <init-param> 中的内容。
一般而言,
-
<context-param> 配置的 Spring 配置文件,习惯性叫 applicationContext ,或 webApplicationContext ,表示全局性 Spring 配置。
-
<init-param> 配置的 Spring 配置文件可以叫 SpringWebApplicationContext ,表示 spirng-webmvc(web 层)相关的 Spring 配置。
现在来看看 SpringWebConfig.java 文件的必需配置:
@Configuration
@EnableWebMvc
@ComponentScan("com.example.inlet.controllers")
public class SpringWebConfig implements WebMvcConfigurer {
...
}
Spring MVC 配置类的关键,除了实现 WebMvcConfigurer 接口之外,还有就是需要标注 @EnableWebMvc 注解。
因为 @EnableWebMvc 注解的存在,Spring MVC 会自动创建、激活使用 19 个 Bean,这 19 个 Bean 在各个场景、环境中默默地支持着 Spring MVC 框架的的工作。
当然,如果也可以不使用 @EnableWebMvc 注解,这样的话,你需要直接(或间接地)去声明这 19 个 Bean(或其等价的替代品)。否则,Spring MVC 就不会以你想当然地方式运行。
另外,你也无须担心这默认的 19 个 Bean 是否符合你的需求,在合适的常见中,当你觉得其中的某个所提供的功能并非你所需要,你可以自定义 Bean 去覆盖、替代它(们)。
5. 定义控制器
DispatcherServlet 将请求委派给控制器以执行特定于其的功能。 @Controller 注释指示特定类充当控制器的角色。@RequestMapping 注释用于将 URL 映射到整个类或特定处理程序方法。
@Controller
public class HelloController {
@RequestMapping(value="/hello", method=RequestMethod.GET)
public ModelAndView printHello() {
ModelAndView mav = new ModelAndView();
mav.addObject("message", "Hello Spring MVC Framework!");
mav.setViewName("/WEB-INF/jsp/hello.jsp");
return mav;
}
}
@Controller 注释将类定义为 Spring MVC 控制器。
@RequestMapping 的第一个用法表示此控制器上的所有处理方法都与 /hello
路径相关。
@RequestMapping(method = RequestMethod.GET) 用于声明 printHello 方法作为控制器的默认服务方法来处理 HTTP GET 请求。可以定义另一个方法来处理同一 URL 的任何 POST 请求。
value 属性指示处理程序方法映射到的 URL,method 属性定义处理 HTTP GET 请求的服务方法。关于以上定义的控制器,需要注意以下几点:
-
在服务方法中定义所需的业务逻辑。可以根据需要在此方法内调用其他方法。
-
基于定义的业务逻辑,将在此方法中创建一个模型。可以设置不同的模型属性,这些属性将被视图访问以呈现最终结果。此示例创建且有属性 message 的模型。
-
定义的服务方法可以返回一个 String,它包含要用于渲染模型的视图的名称。此示例将
"hello"
返回为逻辑视图名称。
6. 创建 JSP 视图
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
Spring MVC 支持许多类型的视图用于不同的表示技术。包括 JSP,HTML,PDF,Excel 工作表,XML,Velocity 模板,XSLT,JSON,Atom 和 RSS 源,JasperReports 等。这里使用的是 JSP 模板,并在 /WEB-INF/hello/hello.jsp 中写一个简单的 hello 视图:
<html>
<head>
<title>Hello Spring MVC</title>
</head>
<body>
<h2>${message}</h2>
</body>
</html>
这里 ${message}
是在 Controller 中设置的属性。可以在视图中显示多个属性。
另一张图,表达了同样的逻辑:
推荐阅读
-
库存 SpringMVC:MVC 主流流程
-
适用于 KingbaseES V8 的可流动工作流程适配器
-
巴特勒商务版的基本操作流程
-
Google Play 支付、银行卡订单和掉单问题处理流程 ....-2.准备工作
-
用 php 实现扫地的基本流程和详细步骤
-
拖放式工作流程开发有哪些突出优势?
-
Java 框架】SpringMVC(一)--基本环境和基本结构体系
-
[小型团队自动化] (II) 使用 Vault 作为凭证存储的无人机 CI -- 构建自己的 CI/CD 工作流程
-
[数据仓库 BO] BODS 工作的基本结构
-
什么是数据库事物?为什么需要数据库事物,事物有哪些特征?事物的隔离级别是什么?-1.什么是数据库事务? 1.事务是作为一个逻辑单元执行的一系列操作。一个逻辑工作单元必须具备四个属性,即ACID(原子性、一致性、隔离性和持久性)属性,只有这样才能成为事务: 原子性 2.事务必须是一个原子工作单元;它的数据修改要么全部执行,要么全部不执行。 一致性 3.事务完成时,所有数据必须保持一致。在相关数据库中,所有规则都必须适用于事务的修改,以保持所有数据的完整性。事务结束时,所有内部数据结构(如 B 树索引或双向链接表)必须正确无误。 隔离 4.并发事务的修改必须与其他并发事务的修改隔离。一个事务会在另一个并发事务修改之前或之后查看某一状态下的数据,而不会查看中间状态下的数据。这就是所谓的可序列化,因为它允许重新加载起始数据和重放一系列事务,从而使数据最终处于与原始事务执行时相同的状态。 持久性 5.事务完成后,它对系统的影响是永久性的。即使在系统发生故障的情况下,修改也会保留。 2. 为什么需要数据库事物,事物有哪些特征? 事物对数据库的作用是对数据进行一系列操作,要么全部成功,要么全部失败,防止出现中间状态,确保数据库中的数据始终处于正确、和谐的状态。 特征:原子性、一致性、隔离性、持久性,以及其他特征 原子性(Atomicity):所有操作在事务开始后,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出现错误时,会回滚到事务开始前的状态,所有操作就像没有发生一样。也就是说,事务是一个不可分割的整体,就像化学中的原子一样,是物质的基本单位。 一致性(Consistency):在事务开始之前和结束之后,数据库的完整性约束都没有被破坏。例如,如果 A 转钱给 B,A 不可能扣除这笔钱,但 B 却没有收到这笔钱。 隔离:在同一时间内,只允许一个事务请求相同的数据,不同事务之间没有干扰。例如,甲正在从一张银行卡上取款,在甲取款过程结束之前,乙不能向这张卡转账。 持久性(耐用性):事务完成后,事务对数据库的所有更新都将保存到数据库中,无法回滚 3.事务的隔离级别有哪些? 数据库事务有四种隔离级别,从低到高分别是未提交读取(Read uncommitted)、已提交读取(Read committed)、可重复读取(Repeatable read)、可序列化(Serializable)。此外,事务的并发操作中可能会出现脏读、不可重复读、幽灵读等情况。事务并发问题 脏读:事务 A 读取事务 B 更新的数据,然后事务 B 回滚操作,那么事务 A 读取的数据就是脏数据。 不可重复读取:事务 A 多次读取同一数据,事务 B 在事务 A 多次读取期间更新并提交数据,导致事务 A 多次读取同一数据时结果不一致。 幻影读取:系统管理员 A 将数据库中所有学生的具体分数改为 ABCDE 等级,但系统管理员 B 在此时插入了具体分数的记录,当系统管理员 A 更改结束后发现仍有一条记录未被更改,仿佛发生了幻觉,这称为幻影读取。 小结:不可重复读和幻读容易混淆,不可重复读侧重于修改,幻读侧重于增删。解决不可重复读问题只需锁定满足条件的行,解决幻读问题则需要锁定表 MySQL 事务隔离级别