1. Spring集成web环境(了解)
1.1 web环境中的ApplicationContext
在web项目开发中的程序执行过程
- 客户端浏览器发送一个请求
- web服务器Tomcat接收到请求后,由
web容器
创建对应的servlet并初始化执行- servlet负责调用service层
- service层负责调用dao层
当使用spring的IoC容器后,service层和dao层都由spring负责创建,此时需要在servlet中创建ApplicaitonContext容器对象,使用以下的代码
// 配置文件的方式 ApplicationContext context = new ClassPathXmlApplicationContext("配置文件"); // 或者注解的方式 ApplicationContext context = new AnnotationConfigApplicationContext(配置类.class);
但是每次从容器中获得Bean时都要编写上面的代码 ,导致配置文件加载多次,ApplicationContext应用上下文对象创建多次。ApplicationContext对象应该只创建一次,可以使用ServletContextListener监听Web应用的启动,在Web应用启动时就加载Spring的配置文件,创建应用上下文对象ApplicationContext,再将其存储到最大的域servletContext域中,这样就能在任意位置从域中获得应用上下文ApplicationContext对象。
1.2 spring-web模块
在该模块中其核心的接口是
WebApplicationContext
,同时提供了XmlWebApplicationContext
和AnnotationConfigWebApplicationContext
来实现在web环境中创建IoC容器。
1.3 Spring集成Web环境的步骤
1.3.1 导入spring-web模块的坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
1.3.2 配置ContextLoaderListener创建IoC容器
在web.xml中配置监听器,用于在启动web容器(Tomcat)时,创建Spring提供的适用于web的IoC容器
1.3.2.1 IOC配置代码
Xml 方式: spring-web.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--配置需要扫描的包-->
<context:component-scan base-package="com.xuetang9.spring.demo"/>
</beans>
注解方式
package com.xuetang9.framework.spring.webmvc.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan("com.xuetang9.framework.spring.webmvc")
public class ApplicationConfig {
}
1.3.2.2 web容器启动代码
xml方式: web.xml中的配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--配置全局参数用于设置IOC容器的配置文件路径-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-web.xml</param-value>
</context-param>
<!--配置监听器创建适用于web的IOC容器-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
注解方式
package com.xuetang9.framework.spring.webmvc.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
/**
* 实现 AbstractAnnotationConfigDispatcherServletInitializer
*/
public class InitWebAppInit extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
// 返回配置类
return new Class[]{ApplicationConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
// 返回配置类
return new Class[]{ApplicationConfig.class};
}
@Override
protected String[] getServletMappings() {
// 返回映射处理
return new String[]{"/*"};
}
}
1.3.3 在Servlet中完成对象的注入
使用
Spring
提供的SpringBeanAutowiringSupport
类完成自动依赖注入。
package com.xuetang9.spring.demo.service;
public interface SectionService {
}
package com.xuetang9.spring.demo.service.impl;
import com.xuetang9.spring.demo.service.SectionService;
import org.springframework.stereotype.Service;
@Service
public class SectionServiceImpl implements SectionService {
}
package com.xuetang9.spring.demo.web.servlet;
import com.xuetang9.spring.demo.service.SectionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/index.html")
public class IndexServlet extends HttpServlet {
@Autowired
private SectionService sectionService;
@Override
public void init() throws ServletException {
// 通过SpringBeanAutowiringSupport完成servlet中对象的依赖注入
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, this.getServletContext());
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 打印sectionService
System.out.println(sectionService);
}
}
1.4 封装一个Servlet的基类完成注入
package com.xuetang9.spring.demo.web.servlet;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
public abstract class BaseServlet extends HttpServlet {
@Override
public void init() throws ServletException {
// 通过SpringBeanAutowiringSupport完成servlet中对象的依赖注入
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, this.getServletContext());
}
}
package com.xuetang9.spring.demo.web.servlet;
import com.xuetang9.spring.demo.service.SectionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/index.html")
public class IndexServlet extends BaseServlet {
@Autowired
private SectionService sectionService;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 打印sectionService
System.out.println(sectionService);
}
}
1.5 通过工具类单独获取IoC容器
在
Servlet
中可以通过WebApplicationContextUtils
来获取IoC容器比较原始的获取方式
// 通过工具类获取web的IoC容器
WebApplicationContext webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
// 从容器中获取对象
SectionService sectionService = webApplicationContext.getBean(SectionService.class);
// 打印对象
System.out.println(sectionService);
2. Spring Web MVC
2.1 Spring MVC 概述
Spring Web MVC最初是一个基于Servlet API的web框架技术,该技术包含了Spring核心框架,并且在每次启动时导入Spring IoC容器。
正规的名称是Spring Web MVC,但是通常简称Spring MVC框架。
它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时它还支持 RESTful 编程风格的请求。
在Spring 5.0版本提供了与Spring Web MVC并行的技术Spring WebFlux框架技术。它是基于spring-webflux项目开发的技术。
2.2 Spring MVC 基础应用
实现一个简单的 HelloWorld 应用
实现的步骤:
① 导入SpringMVC相关坐标
② 配置SpringMVC核心控制器DispathcerServlet
③ 配置SpringMVC核心文件 spring-mvc.xml
④ 创建Controller类并完成方法的映射
⑤ 创建hello.jsp页面
⑥ 客户端发起请求测试
2.2.1 导入SpringMVC的依赖坐标
<!--配置JavaEE开发需要的依赖坐标-->
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>8.0</version>
<scope>provided</scope>
</dependency>
<!--配置SpringMVC的依赖坐标-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
2.2.2 配置SpringMVC的核心控制器
在web.xml中配置DispatcherServlet
<!--配置SpringMVC的前端控制器DispatcherServlet-->
<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--配置SpringMVC需要的配置文件-->
<!--默认读取在/WEB-INF/目录下的以servlet-name拼接-servlet.xml的文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<!--启动web容器时加载servlet并初始化-->
<load-on-startup>1</load-on-startup>
</servlet>
<!--配置指定需要拦截的URL地址-->
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
2.2.3 配置SpringMVC核心配置文件
在resources目录下创建 spring-mvc.xml ,并配置相关内容
jsp配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--配置视图解析器-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>
</bean>
<!--启用MVC的注解驱动-->
<mvc:annotation-driven/>
<!--配置注解扫描的包-->
<context:component-scan base-package="com.xuetang9.spring.demo"/>
</beans>
thyemleaf配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!-- 控制层扫描 -->
<context:component-scan base-package="com.xuetang9.framework.spring.webmvc.schama.web.controller"/>
<!-- 注解驱动 -->
<mvc:annotation-driven />
<!-- 请求映射处理器 -->
<bean id="handlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
<!-- 模板解析器配置 -->
<bean id="templateResolver" class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver" >
<property name="prefix" value="/WEB-INF/template/"/>
<property name="suffix" value=".html"/>
<property name="characterEncoding" value="UTF-8"/>
</bean>
<bean id="templateEngine" class="org.thymeleaf.spring5.SpringTemplateEngine" >
<property name="templateResolver" ref="templateResolver"/>
</bean>
<!-- 视图解析器 -->
<bean id="viewResolver" class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
<property name="templateEngine" ref="templateEngine"/>
<property name="characterEncoding" value="UTF-8"/>
</bean>
</beans>
2.2.4 创建Controller类并完成方法的映射
package com.xuetang9.spring.demo.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloController {
@RequestMapping("/hello.html")
public String hello() {
return "hello";
}
}
2.2.5 创建视图页面
在WEN-INF目录下创建一个views文件夹,用来保存页面文件
JSP模板
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>SpringMVC</title>
</head>
<body>
<h1>Hello, Spring Web MVC!</h1>
</body>
</html>
thymeleaf模板
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<title>SpringMVC</title>
</head>
<body>
<h1>Hello, Spring Web MVC!</h1>
</body>
</html>
2.2.6 测试访问地址
2.3 SpringMVC的生命周期
生命周期
①用户发送请求至前端控制器DispatcherServlet。
②DispatcherServlet收到请求调用HandlerMapping处理器映射器。
③处理器映射器根据具体的请求找到具体的处理器(可以根据xml配置、注解进行查找),并返回一个HandlerExecutionChain的处理链对象给DispatcherServlet。
④DispatcherServlet根据HandlerExecutionChain得到HandlerAdapter处理器适配器并调用。
⑤HandlerAdapter经过适配调用具体的处理器Handler(Controller,也叫后端控制器)。
⑥Controller执行完成返回结果,可以是ModelAndView,String等其他对象数据。
⑦HandlerAdapter将controller执行结果并转换为ModelAndView返回给DispatcherServlet。
⑧DispatcherServlet将ModelAndView传给ViewReslover视图解析器。
⑨ViewReslover解析后返回具体View。
⑩DispatcherServlet根据View进行渲染视图并响应用户。
2.4 SpringMVC组件解析
2.4.1 DispatcherServlet:前端控制器
DispatcherServlet 是整个流程控制的中心,负责用来拦截所有请求,并派发请求到对应的处理器。当用户请求到达前端控制器,由它调用其它组件处理用户的请求,DispatcherServlet 的存在降低了组件之间的耦合性。相当于 MVC 模式中的 C。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NkdJPbc6-1617520677811)(imgs\image-20200904022053457.png)]
DispatcherServlet核心代码
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
String method = request.getMethod();
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", err));
}
finally {
if (asyncManager.isConcurrentHandlingStarted()) {
// Instead of postHandle and afterCompletion
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
}
else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}
DispatcherServlet的结构体系图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-js2l7IuT-1617520677814)(imgs\image-20200904103425050.png)]
2.4.2 HandlerMapping:处理器映射器
HandlerMapping 负责根据用户请求找到 Handler 即处理器,SpringMVC 提供了不同的映射器实现不同的映射方式,例如:配置文件方式,实现接口方式,注解方式等。
通常使用RequestMappingHandlerMapping
2.4.3 HandlerAdapter:处理器适配器
通过 HandlerAdapter 对处理器进行执行,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行。
通常使用RequestMappingHandlerAdapter
2.4.4 Handler:处理器(Controller)
它就是我们开发中要编写的具体控制器Controller。由 DispatcherServlet 把用户请求转发到 Handler。由Handler 对具体的用户请求进行处理。
2.4.5 ViewResolver:视图解析器
View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名,即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。
通常使用InternalResourceViewResolver。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sLrAukYA-1617520677818)(imgs\image-20200904030909442.png)]
thymeleaf 视图解析器
2.4.6 View:视图
SpringMVC 框架提供了很多的 View 视图类型的支持,包括:jstlView、freemarkerView、pdfView等。最常用的视图就是 jsp。一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由程序员根据业务需求开发具体的页面。
JSTLView
ThymeleafView
2.5 SpringMVC基础注解
注解 | 说明 |
---|---|
@Controller | 指明某个类是一个Controller,能被HandlerAdapter适配 |
@RequestMapping | 请求路径的映射,可以配置在类或者方法上面 |
@RequestParam | 配置在方法的参数前面,指明从request中获取指定的值并注入到参数中 |
2.5.1 @RequestMapping详解
-
作用:用于建立请求 URL 和处理请求方法之间的对应关系。
-
位置:
- 类上,请求URL 的第一级访问目录。此处不写的话,就相当于应用的根目录。
- 方法上,请求 URL 的第二级访问目录,与类上的使用@ReqquestMapping标注的一级目录一起组成完整虚拟访问路径。
-
属性:
- value/path:用于指定请求的URL。
- method:用于指定请求的方式,取值在枚举类型RequestMethod中。
- params:用于指定限制请求参数的条件。要求请求参数的key和value必须和配置的一模一样。
- consumes:用于指定限制请求的类型。
2.5.2 @RequestParam详解
-
作用:
- 获取请求中的参数,对应
request.getParameter()
和request.getParameterValues()
。
- 获取请求中的参数,对应
-
位置:
- 使用在方法的参数上。
-
属性:
- value/name:用于指定获取的参数的key值,不填写默认使用参数名作为key。
- required:用于指定请求中的参实是否是必须的,默认参数为必须。
- defaultValue:用于指定获取请求的参数不存在时使用的默认值。
3 在maven的pom.xml 配置jetty
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.4.5.v20170502</version>
<configuration>
<scanIntervalSeconds>10</scanIntervalSeconds>
<httpConnector>
<port>80</port>
</httpConnector>
<webApp>
<contextPath>/</contextPath>
</webApp>
</configuration>
</plugin>
型。
2.5.2 @RequestParam详解
-
作用:
- 获取请求中的参数,对应
request.getParameter()
和request.getParameterValues()
。
- 获取请求中的参数,对应
-
位置:
- 使用在方法的参数上。
-
属性:
- value/name:用于指定获取的参数的key值,不填写默认使用参数名作为key。
- required:用于指定请求中的参实是否是必须的,默认参数为必须。
- defaultValue:用于指定获取请求的参数不存在时使用的默认值。
3 在maven的pom.xml 配置jetty
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.4.5.v20170502</version>
<configuration>
<scanIntervalSeconds>10</scanIntervalSeconds>
<httpConnector>
<port>80</port>
</httpConnector>
<webApp>
<contextPath>/</contextPath>
</webApp>
</configuration>
</plugin>