Spring MVC 核心组件(上)

1. 前言

本节课将和大家一起聊聊 Spring MVC 中的几大核心组件,通过对这些组件的了解,你将对 Spring MVC 的工作机制有更深入的理解,能更容易地编写 Spring MVC 项目,也能轻松地解决程序运行过程的问题。

本节课程,你将学习到:

  • Spring MVC 的核心组件及其功能。对核心组件功能的理解将是本节的重点;
  • Spring MVC 核心组件的配置。

本章节难点在于理解组件之间的依赖关系。

Tips: 本主题内容分上、下两个章节讲解。

2. 组件概述

现代企业项目,都是基于模块或组件开发。Spring MVC 项目也是严格遵循这种约定和规范。WEB 应用程序的交互模式是基于请求与响应的。在请求、响应过程中,Spring MVC 不是一个人在战斗,而是提供了众多的组件一起协调工作。

先请出 Spring MVC 中的 5 大核心组件,并用一句话概括其功能。混个眼熟,具体功能描述及使用方式在后面慢慢展开。

  • 前端控制器: 类似于超市的入口;
  • 用户控制器: 类似于不同类型的货品架,为用户提供具体的商品买卖;
  • 映射器: 类似于超市里的导购员。请问,我要的这个牌子的辣椒酱在哪里,哦,在这里;
  • 适配器: 统一控制器,让其有一致对外的接口;
  • 视图解析器: 找到视图,并负责渲染视图。

除了这几大核心组件,还有其它的诸多辅助性组件,当使用到时再逐一介绍。

3. 前端控制器

深入了解前端控制器之前,先抛出一个问题:控制器是什么?

别被控制器这个名字吓住。其实和原生 Servlet 开发中开发者自定义的 Servlet 的功能是一样的。当然,因为有 Spring 的加持,使用起来,是非常之轻量级的。

Spring MVC 中的控制器有 2 类:

  • 中央控制器,或叫前端控制器:Spring MVC 框架提供,对所有请求进行分流;
  • 用户控制器,或叫响应控制器: 由开发者实现,用来响应用户的具体请求。如登录请求、注册请求……

前端控制器(DispatcherServlet)是 Spring MVC 中最核心的组件,相当于整个程序中的行政、调度中心。其它的组件都是它的附庸,为前端控制器提供相关的服务。

Tips: DispatcherServlet 必须在 Spring MVC 项目启动时被创建。DispatcherServlet 的纯 JAVA 配置请查阅《纯 JAVA 搭建 Spring MVC 项目》章节内容。

DispatcherServlet 的基本功能。

3.1 请求分流

浏览器向 Spring MVC 程序发起的所有请求都会汇流给 DispatcherServlet 组件。再由 DispatcherServlet 分流到具体的用户控制器;
图片描述

为什么要对所有请求集中分流?

可以从 2 个维度理解:

  • 安全性: 如同去拜访某一个公司,所有的来访人员都要经由前台工作人员登记、确认后才会被引导到具体的会客室,前台可以对来访人员的身份进行初步认定和筛选。请求分流的性质也是如此,确保只能通过一个入口进入程序;
  • 标准化: 每一个请求都会以相同的方式进行分流处理。如同造访公司,如果对每一个人的来访有区别或者说没有统一的接待标准,一定会产生额外的工作量。统一协调,标准化项目,可以高度简化处理流程。

3.2 调度中心

一次请求、响应的完成,需要多个组件通力合作。如何协调各个组件的工作,保证请求、响应过程有条不紊的进行,则需要一个指挥者或说一个核心灵魂组件。DispatcherServlet 就是每一次请求、响应过程中的组织者、调度者。

Tips: DispatcherServlet 本质就是一个和 Spring MVC 程序一起启动的 Servlet 。在现有的 MVC 框架,如 Struts MVC 中使用过滤器作为前端控制器。

4. 用户控制器

用户控制处理器(简称用户控制器或控制器 \ 处理器)提供具体的响应用户请求的逻辑。用户控制器虽然由用户自定义编写,但也需要直接或间接遵循 Spring MVC 的控制器编写规范。

Tips: 如果说前端控制器是大门,那么用户控制器就是具体的洽谈部门。

4.1 编写控制器

Spring MVC 提供了很灵活的用户控制器编写方案。

  1. 通过实现 Spring MVC 提供的 org.springframework.web.servlet.mvc.Controller 接口;
public class HelloAction implements org.springframework.web.servlet.mvc.Controller {
   	@Override
   	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
   		System.out.println("Bean URL ");
   		return null;
   	}
}
  1. Spring MVC 支持 POJO (普通 JAVA 类)充当控制器。
public class HelloAction  {
   	public String hello() {
   		return "hello";
   	}
}

Tips: 使用 POJO 充当用户控制器,显然要简洁很多。这是常见的编写方案。

4.2 映射控制器

原生 Servlet 开发中,需要在 web.xml 中注册、映射 Servlet 后浏览器才能请求到。 基于 Spring MVCWEB 项目,用户如何在浏览器中请求到用户控制器?

使用注解 2 步就可以搞定:

  1. 在类前面添加 @Controller 注解,此注解的作用是通知 Spring MVC 的上下文对象(WebApplicationContext), 控制器的创建交给你了;
@Controller
public class HelloAction  {
    //省略……
}
  1. 在控制器的方法前面添加 @RequestMapping 注解。使用此注解可提供一个逻辑名向用户映射此方法。
@RequestMapping("/hello")
public String hello() {
	System.out.pirntln("hello");
	return "hello";
}

难道就这么简单,是的,要不咱们测试一下:

Tips: 404 ?页面资源没找到,为什么会是这个样子?

哦!那是因为还没有告诉 Spring MVC 当控制器响应浏览器请求时,如何找到页面视图,这是视图解析器组件的工作。好吧,等会儿,我们就会聊到视图解析器。

Tips: 怎么证明控制器被请求到,很简单,你将在控制台上看到 hello 字符的输出。

5. 映射器

映射器的作用就是检查用户的请求路径中是否存在对应的控制器组件。

Tips: 有点类似于导购员。客户报一个商品名,然后告诉你真正的商品所在位置。

图片描述

使用 Spring MVC 时,如果开发者没有显示配置映射器,Spring MVC 会启动默认的映射器组件。

DispatcherServlet 所在包的根目录下有名为 DispatcherServlet.properties 的文件,已经配置了很多默认组件信息,开发者不用做任何配置,便能启动这些组件工作。

图片描述

打开此文件可以看到有 2 种类型的映射器信息:

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

这两个映射器分别为哪一种请求寻找控制器了?

回答这个问题之间,先了解用户控制器的映射方式。前面提到可使用 @RequestMapping 注解对外映射控制器组件。其实 Spring MVC 还可以使用 @Bean 注解实现相同的功能 。

先假设存在如下的控制器:

public class HelloAction {
	public String hello() implements Controller{
		System.out.println("hello");
		return "hello";
	}
}
  • @Bean 注解映射: 打开项目中的 WebConfig 配置类,添加如下代码;
 @Bean(name = "/hello")
 public HelloAction hello() {
  	return new HelloAction();
  }

Tips: “hello” 前面一定要加上 “/” 。

如果使用 @Bean 注解的方式映射控制器,则用户控制器需要实现 org.springframework.web.servlet.mvc.Controller 接口, 意味着必须是一个标准的控制器。

此处的 @Bean 的作用就是告诉 Spring MVC:你要创建它,其名字被当成一个访问控制器的 URL。

BeanNameUrlHandlerMapping 映射器的功能就是查找有没有哪一个 Bean 的名字和用户请求的路径相匹配。
RequestMappingHandlerMapping 映射器就是查找由 @RequestMapping 注解映射的控制器。

无论使用这 2 种映射器的哪一种,理论上都无需显示配置。Spring 会根据你的请求信息选择对应的映射器。

显然,使用 @RequestMapping 映射更直接、可观。所以,RequestMappingHandlerMapping 映射器使用的更多。

6. 小结

本节课和大家一起讲解了 Spring MVC 中的 前端控制器、用户控制器、映射器的功能及使用方式 。其它的几个核心组件将在下一章节中和大家一一展开。

一个完整的 Spring MVC 项目不仅仅只依靠这几大组件,还有更多的组件在后台默默地付出着。随着学习的深入,这些组件也将会逐步出现在大家面前。