今日目标
能够编写SpringMVC入门案例
了解SpringMVC原理
1. SpringMVC介绍
1.1 SpringMVC概述
思考:SpringMVC框架有什么优点?
-
SpringMVC是一种基于Java实现MVC模型的轻量级Web框架
-
优点
使用简单,开发便捷(相比于Servlet)
天然的与Spring框架集成(如IOC容器、AOP等)
请求处理简化:支持用户请求数据自动映射封装
响应处理简化:自动转换为json数据输出
2 入门案例【重点】
思考:在Controller中如何定义访问路径,如何响应数据?
2.1 实现步骤
1 创建web工程(Maven结构)
2 导入坐标(SpringMVC+Servlet)
3 SpringMVCConfig 配置类 配置前缀”/pages/”和后缀”.jsp”
4 ServletConfig 配置类创建IOC容器和拦截请求路径”/”
5 自定义控制器类(StudentController)
6 开发视图页面/pages/success.jsp
2.2 代码实现
【第一步】创建web工程(Maven结构)
【第二步】导入坐标(SpringMVC+Servlet)
<dependencies>
<!--spring-webmvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.15</version>
</dependency>
<!--servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
注意事项:
-
课程版本基于Spring主版本5.3.15制作
-
导入spring-webmvc坐标自动依赖spring相关坐标
【第三步】SpringMVCConfig 配置类 配置前缀”/pages/”和后缀”.jsp”
完整的配置代码
package com.zbbmeta.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
/**
* SpringMVC配置类
*/
@Configuration //1.标识当前是配置类 指定这个类为配置类,替代application.xml
@ComponentScan("com.zbbmeta")//2.配置扫描web层包 代替<context:component-scan base-package="com.zbbmeta" />
public class SpringMvcConfig {
//3.配置视图解析器,配置视图前缀与后缀
@Bean
public InternalResourceViewResolver internalResourceViewResolver(){
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/pages/");//配置前缀
viewResolver.setSuffix(".jsp");//配置后缀
return viewResolver;
}
}
【第四步】创建ServletConfig 配置类创建IOC容器和拦截请求路径”/”
package com.zbbmeta.config;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;
/**
* tomcat启动时调用会调用当前类AbstractDispatcherServletInitializer实现的方法
*/
public class ServletConfig extends AbstractDispatcherServletInitializer {
//在tomcat启动时调用,用于创建springmvc框架的IOC容器对象
//加载springmvc配置类,产生springmvc容器(本质还是spring容器)
@Override
protected WebApplicationContext createServletApplicationContext() {
//初始化WebApplicationContext对象
AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext();
//加载指定配置类
ac.register(SpringMvcConfig.class);
return ac;
}
// 指定SpringMVC要处理哪些请求, /表示SpringMVC处理项目中的所有请求, 静态资源不要让SpringMVC处理,要放行
//设置DispatcherServlet绑定处理请求的路径"/",处理除了jsp的所有资源请求
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
//加载spring的配置类
@Override
protected WebApplicationContext createRootApplicationContext() {
return null;
}
}
【第五步】自定义控制器类(StudentController)
@Controller
public class StudentController {
@RequestMapping("/save")
public String save(Model model){
model.addAttribute("info","欢迎学习SpringMVC");
return "success";
}
}
注意事项
对于SpringMVC而言,Controller方法返回值默认表示要跳转的页面,没有对应的页面就会报错。如果不想跳转页面而是响应数据,那么就需要在方法上使用@ResponseBody注解。
【第六步】开发视图页面/pages/success.jsp
<%--
Created by IntelliJ IDEA.
User: zbb
Date: 0011
Time: 23:56
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>hello</title>
</head>
<body>
${info}
</body>
</html>
运行结果
启动项目需要在Idea中集成项目,不清楚怎么集成的可以去查看之前的文章
web-4-理解Tomcat中的HTTP请求和Servlet响应处理机制
2.3 案例注解和类解析
2.3.1 @Controller注解
-
名称:@Controller
-
类型:类注解
-
位置:SpringMVC控制器类定义上方
-
作用:设定SpringMVC的核心控制器bean
-
范例
@Controller
public class StudentController {
}
2.3.2 @RequestMapping注解
-
名称:@RequestMapping
-
类型:方法注解
-
位置:SpringMVC控制器方法定义上方
-
作用:设置当前控制器方法请求访问路径
-
范例
@RequestMapping("/save")
public String save(Model model){
model.addAttribute("info","欢迎学习SpringMVC");
return "success";
}
注意:其实@RequestMapping注解还可以写到类上面,表示类下面的所有方法前面都会有该地址
2.3.3 @ResponseBody注解
-
名称:@ResponseBody
-
类型:方法注解
-
位置:SpringMVC控制器方法定义上方
-
作用:设置当前控制器方法响应内容为当前返回值,无需解析
-
范例
@RequestMapping("/save")
@ResponseBody
public String save(){
System.out.println("user save ...");
return "success";
}
思考:如果在方法上添加了该注解,会和例子结果有什么区别?
2.4.4 AbstractDispatcherServletInitializer类
-
AbstractDispatcherServletInitializer类是SpringMVC提供的快速初始化Web3.0容器的抽象类
-
AbstractDispatcherServletInitializer提供三个接口方法供用户实现
-
createServletApplicationContext()方法,创建Servlet容器时,加载SpringMVC对应的bean并放入WebApplicationContext对象范围中,而WebApplicationContext的作用范围为ServletContext范围,即整个web容器范围。
-
//加载springmvc配置类,产生springmvc容器(本质还是spring容器)
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMvcConfig.class);
return ctx;
}
-
getServletMappings()方法,设定SpringMVC对应的请求映射路径,设置为/表示拦截所有请求,任意请求都将转入到SpringMVC进行处理。
//设置由springmvc控制器处理的请求映射路径
protected String[] getServletMappings() {
return new String[]{"/"};
}
-
createRootApplicationContext()方法,如果创建Servlet容器时需要加载非SpringMVC对应的bean,即加载Spring容器中业务bean,使用这个方法进行,使用方式同createServletApplicationContext()
//加载spring配置类
protected WebApplicationContext createRootApplicationContext() {
return null;
}
3 入门案例工作流程分析【理解】
思考:在上面的时候我们配置类ServletConfig,没有做任何注解,那么为什么,SpringMVC项目启动的时候就能识别他? 这个类又是谁调用的?
3.1 Tomcat启动调用ServletConfig流程
在SpringMVC中,有两个应用上下文:RootApplicationContext、WebApplicationContext。
-
WebApplicationContext是DispatcherServlet专属的上下文(可以理解为是SpringMVC容器),用来加载Controller、ViewResolver、HandlerMapping等web相关的Bean。
-
RootApplicationContext(可以理解为是Spring容器)则是加载数据库、Service业务层等中间件中的Bean。其中,WebApplicationContext继承了RootApplicationContext中的所有Bean,以便在@Controller中注入@Service等依赖。WebApplicationContext是子容器可以使用父容器中的对象
在 Servlet 3.0 环境下,Servlet 容器会在 classpath 下搜索实现了 javax.servlet.ServletContainerInitializer 接口的任何类,找到之后用它来初始化 Servlet 容器。
Spring 实现了以上接口,实现类叫做 SpringServletContainerInitializer, 它会依次搜寻实现了 WebApplicationInitializer接口的任何类,并委派这个类实现配置。
而AbstractDispatcherServletInitializer的父类则实现了WebApplicationInitializer接口。
AbstractDispatcherServletInitializer提供三个接口方法供用户实现
1.createServletApplicationContext()方法,创建Servlet容器时,加载SpringMVC对应的bean并放入WebApplicationContext对象范围中
2.而WebApplicationContext的作用范围为ServletContext范围,即整个web容器范围
3.2 Tomcat启动配置创建Servlet和IOC容器流程
代码逻辑分析
-
1.【源代码分析】服务器启动运行,创建IOC容器
-
2.【源代码分析】创建DispatcherServlet运行构造函数
-
3.【源代码分析】将IOC容器存储到ServletContext中
3.3 启动服务器初始化过程
-
服务器启动,执行ServletConfigInitializer类,初始化web容器
-
执行createServletApplicationContext方法,创建了WebApplicationContext对象
-
加载SpringMvcConfig配置类
-
执行@ComponentScan加载对应的bean
-
加载UserController,每个@RequestMapping的名称对应一个具体的方法
-
执行getServletMappings方法,定义所有的请求都通过SpringMVC
3.4 springmvc执行流程(面试题)
SpringMVC执行流程:一个核心控制器和三大组件
-
DispatcherServlet:前端控制器,是整体流程控制的中心,由其调用其它组件处理用户的请求,有效的降低了组件间的耦合性
-
RequestMappingHandlerMapping :处理器映射器,负责根据用户请求路径找到对应Controller控制器方法
-
RequestMappingHandlerAdapter :处理器适配器,执行Controller控制器的方法
-
InternalResourceViewResolver :视图解析器,根据Controller控制器方法返回值解析找到展现数据的jsp页面输出数据展现
3.5 Servlet容器初始化的简化格式
Spring 3.2 开始引入一个简易的 WebApplicationInitializer 实现类,这就是 AbstractAnnotationConfigDispatcherServletInitializer。
package com.zbbmeta.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
/**
* Servlet容器初始化的配置类
* AbstractAnnotationConfigDispatcherServletInitializer 专门针对注解的配置编写的抽象类
*/
public class ServletAnnotationConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
// 暂时不管,整合Spring才需要
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
//在tomcat启动时调用,用于创建springmvc框架的IOC容器对象
//加载springmvc配置类, Tomcat会拿这个配置类去创建IoC容器,产生springmvc容器(本质还是spring容器)
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] {SpringMvcConfig.class};
}
// 指定SpringMVC要处理哪些请求, /表示SpringMVC处理项目中的所有请求, 静态资源不要让SpringMVC处理,要放行
//设置DispatcherServlet绑定处理请求的路径"/",处理除了jsp的所有资源请求
@Override
protected String[] getServletMappings() {
return new String[] {"/"};
}
}
注意:ServletAnnotationConfig和ServletConfig二者留其一