一、SpringMVC 概述
SpringMVC 是一种基于 Java 实现 MVC 模型的轻量级 Web 框架
优点:
(1)使用简单、开发便捷 ( 相比于 Servlet)
(2)灵活性强
二、SpringMVC 入门案例
①:使用 SpringMVC 技术需要先导入 SpringMVC 坐标与 Servlet 坐标
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
②:创建 SpringMVC 控制器类(等同于 Servlet 功能)
//定义表现层控制器bean
@Controller
public class UserController {
//设置映射路径为/save,即外部访问路径
@RequestMapping("/save")
//设置当前操作返回结果为指定json数据(本质上是一个字符串信息)
@ResponseBody
public String save(){
System.out.println("user save ...");
return "{'info':'springmvc'}";
}
//设置映射路径为/delete,即外部访问路径
@RequestMapping("/delete")
@ResponseBody
public String delete(){
System.out.println("user save ...");
return "{'info':'springmvc'}";
}
}
③:初始化 SpringMVC 环境(同 Spring 环境),设定 SpringMVC 加载对应的 bean
//springmvc配置类,本质上还是一个spring配置类
@Configuration
@ComponentScan("com.itheima.controller")
public class SpringMvcConfig {
}
④:初始化 Servlet 容器,加载 SpringMVC 环境,并设置 SpringMVC 技术处理的请求
//web容器配置类
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
//加载springmvc配置类,产生springmvc容器(本质还是spring容器)
protected WebApplicationContext createServletApplicationContext() {
//初始化WebApplicationContext对象
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
//加载指定配置类
ctx.register(SpringMvcConfig.class);
return ctx;
}
//设置由springmvc控制器处理的请求映射路径
protected String[] getServletMappings() {
return new String[]{"/"};
}
//加载spring配置类
protected WebApplicationContext createRootApplicationContext() {
return null;
}
}
三、工作流程解析
将 SpringMVC 的使用过程总共分两个阶段来分析,分别是 启动服务器初始化过程和 单次请求过程
1. 启动服务器初始化过程
(1) 服务器启动,执行 ServletContainersInitConfig 类,初始化 web 容器功能类似于以前的web.xml
(2) 执行 createServletApplicationContext 方法,创建了 WebApplicationContext 对象该方法加载 SpringMVC 的配置类 SpringMvcConfig 来初始化 SpringMVC 的容器
(3) 加载 SpringMvcConfig 配置类
(4) 执行 @ComponentScan 加载对应的 bean。扫描指定包及其子包下所有类上的注解,如 Controller 类上的 @Controller 注解
(5) 加载 UserController ,每个 @RequestMapping 的名称对应一个具体的方法。此时就建立了 /save 和 save 方法的对应关系
(6) 执行 getServletMappings 方法,设定 SpringMVC 拦截请求的路径规则。【/】 代表所拦截请求的路径规则,只有被拦截后才能交给 SpringMVC 来处理请求
2. 单次请求过程
(1) 发送请求 http://localhost/save
(2)web 容器发现该请求满足 SpringMVC 拦截规则,将请求交给 SpringMVC 处理
(3) 解析请求路径 /save
(4) 由 /save 匹配执行对应的方法 save( )
上面的第五步已经将请求路径和方法建立了对应关系,通过 /save 就能找到对应的 save 方法
(5) 执行 save()
(6) 检测到有 @ResponseBody 直接将 save() 方法的返回值作为响应体返回给请求方
四、bean 加载控制
因为功能不同,如何避免 Spring 错误加载到 SpringMVC 的 bean?
加载 Spring 控制的 bean 的时候排除掉 SpringMVC 控制的 bean
方式一: Spring 加载的 bean 设定扫描范围为精准范围,例如 service 包、 dao 包等
@Configuration@ComponentScan({"com.itheima.service","com.itheima.dao"}) public class SpringConfig { }
方式二: Spring 加载的 bean 设定扫描范围为 com.itheima, 排除掉 controller 包中的 bean
@Configuration//@ComponentScan({"com.itheima.service","com.itheima.dao"})
//设置spring配置类加载bean时的过滤规则,当前要求排除掉表现层对应的bean
//excludeFilters属性:设置扫描加载bean时,排除的过滤规则
//type属性:设置排除规则,当前使用按照bean定义时的注解类型进行排除
//classes属性:设置排除的具体注解类,当前设置排除@Controller定义的bean
@ComponentScan(value="com.itheima",
excludeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = Controller.class
)
)
public class SpringConfig {
}
方式三: 不区分 Spring 与 SpringMVC的环境,加载到同一个环境中(了解即可)
有了 Spring 的配置类,要想在 tomcat 服务器启动将其加载,我们需要修改 ServletContainersInitConfig
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer { protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMvcConfig.class);
return ctx;
}
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringConfig.class);
return ctx;
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
对于上述的配置方式, Spring 还提供了一种更简单的配置方式,可以不用再去创建
AnnotationConfigWebApplicationContext 对象,不用手动 register 对应的配置类
//web配置类简化开发,仅设置配置类类名即可public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
}