Spring MVC 中的 5 大核心组件
前端控制器: 类似于超市的入口;
用户控制器: 类似于不同类型的货品架,为用户提供具体的商品买卖;
映射器: 类似于超市里的导购员。请问,我要的这个牌子的辣椒酱在哪里,哦,在这里;
适配器: 统一控制器,让其有一致对外的接口;
视图解析器: 找到视图,并负责渲染视图。
前端控制器
前端控制器(DispatcherServlet)是 Spring MVC 中最核心的组件,相当于整个程序中的行政、调度中心。其它的组件都是它的附庸,为前端控制器提供相关的服务。
DispatcherServlet 的基本功能。
1 请求分流
浏览器向 Spring MVC 程序发起的所有请求都会汇流给 DispatcherServlet 组件。再由 DispatcherServlet 分流到具体的用户控制器;
为什么要对所有请求集中分流?
可以从 2 个维度理解:
- 安全性: 如同去拜访某一个公司,所有的来访人员都要经由前台工作人员登记、确认后才会被引导到具体的会客室,前台可以对来访人员的身份进行初步认定和筛选。请求分流的性质也是如此,确保只能通过一个入口进入程序;
- 标准化: 每一个请求都会以相同的方式进行分流处理。如同造访公司,如果对每一个人的来访有区别或者说没有统一的接待标准,一定会产生额外的工作量。统一协调,标准化项目,可以高度简化处理流程。
调度中心
一次请求、响应的完成,需要多个组件通力合作。如何协调各个组件的工作,保证请求、响应过程有条不紊的进行,则需要一个指挥者或说一个核心灵魂组件。DispatcherServlet 就是每一次请求、响应过程中的组织者、调度者。
用户控制器
映射控制器
原生 Servlet 开发中,需要在 web.xml 中注册、映射 Servlet 后浏览器才能请求到。 基于 Spring MVC 的 WEB 项目,用户如何在浏览器中请求到用户控制器?
使用注解 2 步就可以搞定:
- 在类前面添加 @Controller 注解,此注解的作用是通知 Spring MVC 的上下文对象(WebApplicationContext), 控制器的创建交给你了
@Controller
public class HelloAction {
//省略……
}
- 在控制器的方法前面添加 @RequestMapping 注解。使用此注解可提供一个逻辑名向用户映射此方法。
@RequestMapping("/hello")
public String hello() {
System.out.pirntln("hello");
return "hello";
}
映射器
映射器的作用就是检查用户的请求路径中是否存在对应的控制器组件。
用户控制器的映射方式。前面提到可使用 @RequestMapping 注解对外映射控制器组件。其实 Spring MVC 还可以使用 @Bean 注解实现相同的功能 。
- @Bean 注解映射: 打开项目中的 WebConfig 配置类,添加如下代码;
public class HelloAction {
public String hello() implements Controller{
System.out.println("hello");
return "hello";
}
}
@Bean(name = "/hello")
public HelloAction hello() {
return new HelloAction();
}
适配器
所谓适配器组件,其本质就是运用适配器设计模式,匹配不兼容的接口规范。
如上图,调用者只能识别接口 2 类型,但是 A 提供的是接口 1 类型。适配器可以把接口 1 转换成接口 2。这样使用者就能使用 A 提供的功能了。
为什么要使用适配器组件?
欲解答这个问题,则先要了解如果不使用适配器组件,则如何编写用户控制器。既然称为用户控制器,则是开发者根据需要在框架外部定义的一个组件,Spring MVC 不可能未卜先知它的存在。
如果要让 Spring MVC 识别这个控制器,有一种方案 :预先定义好接口,强制性要求开发者在设计控制器时遵循接口规范。
比如说实现 Controller 接口编写控制器。
@Controller
public class HelloAction implements org.springframework.web.servlet.mvc.Controller {
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
return null;
}
}
除此之外,Spriing MVC 提供有更灵活的用户控制器设计方案,可使用 “ 普通 JAVA 类” 充当控制器,控制器中的方法也可由开发者随性命名。
此时,就需要适配器组件把这些不符合规范的控制器以统一的接口方式告诉给 Spring MVC 。
Spring MVC 提供了 3 个默认适配器:
这些适配对象都实现了 HandlerAdapter 接口,此接口就有一个统一的内部调用方法。
简要描述 3 个适配器的应用场景:
- SimpleControllerHandlerAdapter: 简单的控制器处理器适配器,支持实现了 Controller 接口的控制器;
- HttpRequestHandlerAdapter: http 请求处理器适配器,要求编写的控制器时实现 HttpRequestHandler 接口。此类控制器可以很方便的获取请求包中的相关信息。但,真正使用的并不多;
- RequestMappingHandlerAdapter: 注解处理器适配器,适配使用了注解的用户控制器。本课程中的就是使用了此适配器,此适配器的实现比前两个都复杂。
视图解析器
用户控制器中的方法的返回值可以是字符串,如果没有视图解析器的解析,这个字符串就是一个字符串。如果有了视图解析器,则会把这个字符串当成一个视图的逻辑名,并映射到真正的物理视图。
视图解析器和映射器的有相似之处,映射器是入口时根据请求控制器逻辑名找到物理控制器,视图解析器是出口时根据视图逻辑名找到物理视图。
Spring MVC 默认使用的 InternalResourceViewResolver 作为视图解析器, 提供对 JSP 视图的支持。
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
无论是 Spring MVC 默认提供的、还是开发者自行定义的视图解析器,都必须实现 ViewResolver 接口:
public interface ViewResolver {
@Nullable
View resolveViewName(String viewName, Locale locale) throws Exception;
}
配置视图解析器
视图解析器需要在 Spring MVC 项目中显示配置,Spring MVC 虽然提供了视图解析器,但它不可能知道开发者会把物理视图放在哪个位置,所以,需要通过配置指定物理视图的真正位置。
配置 InternalResourceViewResolver 很简单。打开 WebConfig 配置类,在配置类中添加如下代码;
@Bean
public InternalResourceViewResolver viewResolver() {
InternalResourceViewResolver inResolver=new InternalResourceViewResolver();
inResolver.setPrefix("/WEB-INF/jsp/");
inResolver.setSuffix(".jsp");
return inResolver;
}
解释一下上面的代码:
- @Bean 注解表示此对象由 Spring 容器创建;
- inResolver.setPrefix ("/WEB-INF/jsp/") 表示 JSP 页面视图所在物理位置;
- inResolver.setSuffix (".jsp") 表示 JSP 视图的后缀。