前言
学完了大数据基本组件,SpringMVC 也得了解了解,为的是之后 SpringBoot 能够快速掌握。SpringMVC 可能在大数据工作中用的不多,但是 SSM 毕竟是现在就业必知必会的东西了。SpringBoot 在数仓开发可能会经常用到,所以不废话学吧。
1、SpringMVC 概述
1.1、请求响应模式演进过程
1.1.1、三层架构
- web:页面数据的收集以及产生页面
- service:业务处理
- dao:数据持久化
弊端:一个 Servlet 只能一个处理请求。
1.1.2、MVC 模式
浏览器将请求发送给控制器,控制器调用 Service 层,再由 Service 层调用 dao 层得到数据,将得到的数据组织成数据模型(封装成对象),然后将页面和数据模型封装到一起返回给浏览器。这样,一个 Servlet 就可以处理多个请求了。
MVC 模式下的 view 一般用的是 jsp,但是现在我们一般都用的是 HTML、CSS、E lementUI、Vue 这些技术:
1.13、异步调用
异步调用模式下,我们不再需要将 jsp 和 model 共同返回给浏览器展示了,而是页面和 model 分开,页面用 html、vue 这些前端技术,model 需要将它封装成 json 对象返回给我们的前端(因为 java 对象不能直接返回给页面):
这样,我们的前端页面就可以从 json 中把数据抽取出来,然后组织成页面展示到浏览器上面。
异步调用下 SpringMVC 的任务
- Controller 层的开发
- 数据转为 json 格式返回给前端
2、SpringMVC 入门案例
2.1、入门案例
使用 Servlet 开发 web 程序的过程:
- 创建 web 工程
- 设置 tomcat 服务器
- 导入依赖(Servlet)
- 定义处理请求的功能类(UserServlet)
- 配置请求映射关系
使用 SpringMVC 开发 web 程序的过程:
- 创建 web 工程
- 设置 tomcat 服务器
- 导入依赖(SpringMVC + Servlet)
- 定义处理请求的功能类(UserController)
- 配置请求映射关系
- 将 SpringMVC 设定加载到 Tomcat 容器中
0、配置环境
1、导入依赖
<build><plugins><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.2</version><configuration><port>85</port><path>/</path><ignorePackaging>true</ignorePackaging></configuration></plugin></plugins></build><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.0.RELEASE</version></dependency></dependencies>
2、初始化SpringMVC环境
@Configuration
public class SpringMvcConfig {
}
3、创建 SpringMVC 控制器类(等同于 Servlet 功能)
@Controller
public class UserController {@RequestMapping("/save")public void save(){System.out.println("user save ...");}}
4、设定SpringMVC加载对应的Bean
@Configuration
@ComponentScan("com.lyh.controller") // 扫描
public class SpringMvcConfig {}
5、初始化 Servlet 容器,加载SpringMVC 环境,并设置 SpringMVC 请求拦截的路径
/*** Servlet 容器配置类*/
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {/*** 加载SpringMVC容器对象* @return*/protected WebApplicationContext createServletApplicationContext() {AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();ctx.register(SpringMvcConfig.class);return ctx;}/*** 请求由谁来处理?tomcat/springmvc* @return*/protected String[] getServletMappings(){return new String[]{"/"}; // 所有请求都由 springmvc 来处理}/*** 加载 Spring 的配置对应的容器对象* @return*/protected WebApplicationContext createRootApplicationContext() {return null;}
}
6、报错1
访问 localhost:85/save 报错:
7、设置请求返回值为 json 信息 并添加注解@ResponseBody 代表返回内容就是响应内容
8、重新请求 localhost:85/save
2.2、注解&配置类说明
2.2.1、注解
名称 | 类型 | 位置 | 作用 | 参数 |
@Controller | 类注解 | 控制器类上方 | 设置SpringMVC的核心控制器Bean | 无参 |
@RequestMapping | 方法注解 | 控制器方法上面 | 设置当前控制器方法请求访问路径 | @RequestMapping("/save") 访问的时候就访问 localhost:85/save |
@ResponseBody | 方法注解 | 控制器方法上面 | 设置当前控制器方法的返回值就是响应内容 | 无参 |
2.2.2、AbstractDispatcherServletInitializer
AbstractDispatcherServletInitializer 是 SpringMVC 提供的快速初始化 Web3.0 容器的抽象类,它提供了三个接口抽象方法供用户实现:
1)createServletApplicationContext
作用:加载 SpringMVC 容器,一旦 tomcat 启动,就会把这个容器加载到 tomcat 容器中。
2)getServletMappings
作用:设定 SpringMVC 对应的请求路径,也就是哪些请求由 SpringMVC 管,哪些由 tomcat 管。返回 "/" 代表拦截所有请求交给 SpringMVC 处理。
3)createRootApplicationContext
作用:加载除了 SpringMVC 之外的所有容器的内容(Bean)
这里我们没有其它容器,所以直接返回 null。
2.3、总结
对于一次性工作,我们以后做项目直接 CV 大法然后改一改就好了。我们真正做的最多的还是多次工作:定义控制器、定义控制器中的方法等。
3、SpringMVC 工作流程分析
工作流程主要分为两部分:
- 启动服务器
- 发送一次请求
3.1、服务器初始化过程
在 Web3.0 的规范中,我们不再需要 web.xml 来配置,而是通过一个配置类(继承 AbstractDispatcherServletInitializer 抽象类)来完成。
3.2、单次请求工作流程
4、Bean 加载控制
4.1、Controller 加载控制与业务 Bean 加载控制
现在我们的项目结构是这样的:
-
config目录存入的是配置类,我们之后的配置类会有:
-
ServletContainersInitConfig
-
SpringConfig
-
SpringMvcConfig
-
JdbcConfig
-
MybatisConfig
-
-
controller目录存放的是SpringMVC的controller类
-
service目录存放的是service接口和实现类
-
dao目录存放的是dao/Mapper接口
4.1.1、SpringMVC 相关 Bean 加载控制
- SpringMVC 加载的 Bean 都放在 com.lyh.controller 包下
controller 包下的所有 Bean 会被 SpringMVC 来加载,而其它包(dao、service等)下的 Bean 都应该由 Spring 来加载,但是如何控制 Spring 不去加载 SpringMVC 中的 Bean ?
4.1.2、Spring 相关 Bean 加载控制
- 方式一:Spring 加载的 Bean 设定扫描范围为 com.lyh,排除掉 controller 包内的 Bean
- 方式二:Spring 加载的 Bean 设定扫描范围为精准范围,比如 service、dao包等
- 方式三:不区分 Spring 和 SpringMVC 的环境,都加载到同一个环境中。
方式一:只加载 Spring 管理的 Bean:
@Configuration
@ComponentScan({"com.lyh.service","com.lyh.dao"})
public class SpringConfig {}
方式二:按照注解进行过滤,过滤掉由 SpringMVC 管理的包下的 Bean:
@Configuration
@ComponentScan(value = "com.lyh",excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class))
public class SpringConfig {}
测试
public class App {public static void main(String[] args) {AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);// 如果Controller类被Spring注册了,会输出对象地址// 如果没有被注册,那么会报错System.out.println(ctx.getBean(UserController.class));}
}
注意:在测试时,SpringMvcConfig 的注解 Configuration 需要去掉,因为 SpringConfig 中我们设置 Spring 会扫描所有 com.lyh 目录下的目录(除了 exclude 之外的),但是 Spring 会把所有带有 @Configuration 注解的类加载一遍,而 SpringMvcConfig 上面除了 @Configuration 之外还有一个注解 @ComponentScan 用来扫描 controller 包,所以 Spring 又会把 controller 目录下的 Bean 加载一遍。
所以我们可以把这两个带有 @Configuration 注解的配置类放到 com.lyh 包外边,防止被 Spring 加载。
到这里,我们需要把由 Spring 加载的环境配置放到 ServletContainersInitConfig 中:
这样,当服务器启动后,tomcat 容器中就不只有 SpringMVC 的容器了,还有 Spring 的容器。
4.1.3、简化开发
目前,我们需要在 Servlet 容器中分别指定两个配置类(SpringMVC 和 Spring),能不能再简化一些呢? 答案是可以的,我们只需要继承抽象类 AbstractAnnotationConfigDispatcherServletInitializer 即可:
本节注解说明:
名称 | 位置 | 作用 | 参数 |
@ComponentScan | 类注解 | 类定义上方 | excludeFilters:排除扫描路径中加载的bean,需要指定类别(type)和具体项(classes) includeFilters:加载指定的bean,需要指定类别(type)和具体项(classes) |
5、Postman
目前我们测试请求都是直接在地址栏输入参数,但是这种方式只能模拟 get 请求,对于 post 请求我们还需要创建表单,对于更复杂的 Ajax 请求我们不只需要表单,还是配置 JavaScript 代码来完成异步提交。
postman 的作用就是用来模拟各种网页请求的,所以作为一个后端程序员,我们就再也不用去写一些恶心的前端代码去测试了。