感悟:
- 总体上理解知识点,先抓住知识点的脉络,再去抠细节,效率更高
SpringMVC快速入门使用
注意:
必须配置tomcat的deployment
注解开发注意
同时必须完成"/"的映射,及相当于设置了首页,不然核心控制器的url-pattern写为/的话一直报错。
@RequestMapping("/")
public String index(){
return "cc";
}
1.配置的方式开发SpringMVC
目的:帮助理解原理
1.1创建项目导入依赖
导入项目依赖:
- spring-context
- spring-web
- spring-webmvc
- javax.servlet
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>war</packaging>
<name>MVCTest</name>
<groupId>chen.com</groupId>
<artifactId>MVCTest</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>5.0.2.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
导入以上依赖之后,项目中自动导入了如下的jar包
1.2配置web.xml(前端控制器)
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<!--web-app下配置servlet,用来给tomcat扫描加载-->
<!--配置springMvc核心控制器 也即前端控制器-->
<servlet>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--初始化参数,类路径下寻找SpringMVC配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:SpringMVC.xml</param-value>
</init-param>
<!--tomcat已启动就加载-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<url-pattern>*.ac</url-pattern>
</servlet-mapping>
<!--配置首页-->
<welcome-file-list>
<welcome-file>cc.html</welcome-file>
</welcome-file-list>
</web-app>
1.3springmvc配置文件
加载类路径下的springmvc的配置文件(contextConfigLocation)
项目结构:
SpringMVC放在resources目录下,编译之后放在了classes下。(classpath)
SpringMVC配置文件
?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--以上为bean,mvc,context的命名空间的导入-->
<!--1.没有配置映射器 因为默认可省 此处由默认的BeanNameURLHandlerMapping完成映射-->
<bean class="originalController" name="/hello.ac"/>
<!--2.没有配置适配器默认可省,此处handler实现了Controller接口,由默认的适配器SimpleControllerHandlerAdapter来完成handler的执行-->
<!--3.没有配置视图解析器,因为当使用绝物理路径时默认可省略-->
<!--<bean name="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">-->
<!--<property name="prefix" value="/WEB_INF/"></property>-->
<!--<property name="suffix" value=".html"></property>-->
<!--</bean>-->
</beans>
1.4实现Controller接口
- 实现Controller
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;
public class originalController implements Controller {
public ModelAndView handleRequest(javax.servlet.http.HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse) throws Exception {
ModelAndView modelAndView =new ModelAndView();
modelAndView.setViewName("/hello.html");
return modelAndView;
}
}
因为modelAndView.setViewName("/hello.html");是真实途径物理视图名,因此在springMVC的配置文件不需要写视图解析器,hello.html放在根路径下,即webapp目录下,因为在根路径下此文件可以直接访问。(不安全)
1.5分析SpringMVC工作流程
执行流程:
- 用户发送请求
- 请求交由核心控制器执行
- 核心控制器找到映射器,由映射器根据请求匹配到对应的
Handler
,然后将找到的Handler
和所有匹配的HandlerInterceptor
(拦截器)绑定到创建的HandlerExecutionChain
对象上并返回 - 由核心控制器,将返回的handler交由对应的处理器适配器解析执行(上述案例因为实现了Controller接口,所以交由SimpleControllerHandlerAdapter来完成handler的执行)
- 处理完业务之后返回一个ModelAndView对象
- 最后由核心控制器交由视图解析器来完成对ModelAndView的解析
- 跳转到对应的JSP/html页面
1.6 拓展
前面的案例使用BeanNameURLHandlerMapping,同时我们也可以使用SimpleUrlHandlerMapping,使用方式如下,可以完成多个url映射一个handler
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--以上为bean,mvc,context的命名空间的导入-->
<bean class="originalController" id="helloC"></bean>
<!-- 注册SimpleUrlHandlerMapping映射器-->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/hello.action">helloC</prop>
<prop key="/bye.action">helloC</prop>
</props>
</property>
</bean>
</beans>
originalController依然实现Controller接口,因此会使用默认的适配器ControllerHandlerAdapter进行处理handler(originalController)
2.注解的方式开发SpringMVC
目的:快速开发
2.1导入依赖
以为视图解析选择thymeleaf相关的因此导入thymeleaf的依赖
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.3.18.RELEASE</spring.version>
<thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
</properties>
<dependencies>
<dependency>
...其他的依赖省略
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring4</artifactId>
<version>${thymeleaf.version}</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>${thymeleaf.version}</version>
</dependency>
</dependencies>
2.2配置web.xml
基本不变,可以配置过滤编码器
在SpringMVC的控制器中,如果没有对编码进行任何的操作,那么获取到的中文数据是乱码
即使我们在handle()方法中,使用request对象设置编码也不行!原因也非常简单,我们SpringMVC接收参数是通过控制器中的无参构造方法,再经过handle()方法的object对象来得到具体的参数类型的
<!-- 编码过滤器 -->
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>
org.springframework.web.filter.CharacterEncodingFilter
</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2.4配置springMVC的配置文件
- 扫描controller包
- 配置视图解析器选择thymeleaf模板引擎代替jsp
- 可以配置适配器和映射器,但默认可以省略
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!--以上为bean,mvc,context的命名空间的导入-->
<!--扫描controller包-->
<context:component-scan base-package="com.Controller" />
<!--可省略,因为会加载默认的适配器和映射器 -->
<!--<mvc:annotation-driven />-->
<!-- 模板解析器 -->
<bean id="myTemplateResolver" class="org.thymeleaf.templateresolver.ServletContextTemplateResolver">
<property name="prefix" value="/WEB-INF/templates/" />
<property name="suffix" value=".html" />
<property name="templateMode" value="HTML5" />
<property name="cacheable" value="false" />
<property name="characterEncoding" value="UTF-8"/>
</bean>
<bean id="myTemplateEngine" class="org.thymeleaf.spring4.SpringTemplateEngine">
<property name="templateResolver" ref="myTemplateResolver" />
</bean>
<bean class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
<property name="templateEngine" ref="myTemplateEngine" />
<property name="characterEncoding" value="UTF-8" />
</bean>
</beans>
分析<mvc:annotation-driven />
使 用它会自动加载 RequestMappingHandlerMapping (处理映射器) 和
RequestMappingHandlerAdapter ( 处 理 适 配 器 )
此标签相当于如下配置:
#############################
<!-- HandlerMapping -->
<class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerM
apping"></bean>
<bean
class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
###############################
<!-- HandlerAdapter -->
<bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerA
dapter"></bean>
<bean
class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"></bean>
<bean
class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
##############################
<!-- HadnlerExceptionResolvers -->
<bean
class="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExcept
ionResolver"></bean>
<bean
class="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolv
er"></bean>
<bean
class="org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver"
></bean>
2.5写handler
@Controller
public class TestController {
@RequestMapping("/hello")
public String test(){
return "hello";
}
@RequestMapping("/")
public String index(){
return "cc";
}
}
前端控制器 DispatcherServlet
也称核心控制器
用户请求到达前端控制器,它就相当于 mvc 模式中的 c,dispatcherServlet 是整个流程控制的中心,由它调用其它组件处理用户的请求,dispatcherServlet 的存在降低了组件之间的耦合性。
映射器 HandlerMapping
确定哪个URL对应哪个处理器handler(即controller),有多种映射器,不同映射器有不同的映射方式
HandlerMapping
功能就是根据请求匹配到对应的 Handler
,然后将找到的 Handler
和所有匹配的 HandlerInterceptor
(拦截器)绑定到创建的 HandlerExecutionChain
对象上并返回。
HandlerMapping
只是一个接口类,不同的实现类有不同的匹对方式,根据功能的不同我们需要在 SpringMVC 容器中注入不同的映射处理器 HandlerMapping
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iYwtGBDv-1607602528218)(C:\Users\hello\AppData\Roaming\Typora\typora-user-images\image-20201114105900825.png)]
来看看HandlerMapping的接口实现类:
大致上分为两大类 AbstractUrlHandlerMapping
和 AbstractHandlerMethodMapping
。都继承自 AbstractHandlerMapping
抽象类,实现 HandlerMapping
接口。
**简书处理器映射器的分析:**https://www.jianshu.com/p/f04816ee2495
总结可简单的分为三种映射器:
- BeanNameUrlHandlerMapping (默认有)
- SimpleUrlHandlerMapping
- RequestMappingHandlerMapping (注解)(默认有)
适配器 HandlerAdapter
处理器是通过适配器来执行的,这是适配器模式的应用,通过扩展适配器可以对更多类型的处理器进行执行
前面说了由映射处理器(HandlerMapping
) 映射出对应的 handler
,但是接下来的 handler
是怎么去解析执行,怎么去调用 handler
对应的视图方法,这个时候就需要用到 handler
的适配器。
不同的映射处理器(HandlerMapping
) 映射出来的 handler
对象是不一样的,AbstractUrlHandlerMapping
映射器映射出来的是 handler
是 Controller
对象,AbstractHandlerMethodMapping
映射器映射出来的 handler
是 HandlerMethod
对象。由此我们猜想映射的处理器也应该有很多种,不同的映射由不同的适配器来负责解析。
看一下适配器HandlerAdapter的实现链
我们来看DispatchServlet源码
如图当我们没有写适配器的时候,DispatchServlet会帮我们加载默认的适配器
首先扫描注入容器的适配器,这里需要注意下<mvc:annotation-driven/>
会帮我们注入 RequestMappingHandlerAdapter
、HttpRequestHandlerAdapter
和 SimpleControllerHandlerAdapter
这三个配置器,我们需要注意下不要手动重复注入。
当我们没有写<mvc:annotation-driven/>
标签帮我们注入,也没有手动注入,从上面源码最后一步可以看到容器在初始化的时候检测到会自动帮我们注入 RequestMappingHandlerAdapter
、HttpRequestHandlerAdapter
和 SimpleControllerHandlerAdapter
这三个适配器器。
总结可简单的分为四种适配器:
- SimpleControllerHandlerAdapter (实现Controller接口)(默认有)
- HttpRequestHandlerAdapter
- RequestMappingHandlerAdapter(注解)(默认有)
- SimpleServletHandlerAdapter
处理器 Handler
它就是我们开发中要编写的具体业务控制器(controller层)。由 DispatcherServlet 把用户请求转发到 Handler。由Handler 对具体的用户请求进行处理。
视图解析器 View Resolver
View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。
jsp
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
tpRequestHandlerAdapter
- RequestMappingHandlerAdapter(注解)(默认有)
- SimpleServletHandlerAdapter
处理器 Handler
它就是我们开发中要编写的具体业务控制器(controller层)。由 DispatcherServlet 把用户请求转发到 Handler。由Handler 对具体的用户请求进行处理。
视图解析器 View Resolver
View Resolver 负责将处理结果生成 View 视图,View Resolver 首先根据逻辑视图名解析成物理视图名即具体的页面地址,再生成 View 视图对象,最后对 View 进行渲染将处理结果通过页面展示给用户。
jsp
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">