文章目录
- 一、注解配置Spring MVC
- 1.1 初始化类
- 1.2 Spring MVC配置类
- 1.3 完整配置过程
- 二、总结
-
学习视频🎥:https://www.bilibili.com/video/BV1Ry4y1574R
一、注解配置Spring MVC
1.1 初始化类
🔑注解配置的原理
- 在servlet3.0之后的环境中,服务器(或者说容器)会在类路径(src目录下)中查询
javax.servlet.ServletContainerInitializer
接口的实现类,如果找到该实现类就用他来配置服务器 - 而Spring中就提供了
ServletContainerInitializer
接口的一个实现类——SpringServletContainerInitializer
,该实现类中又会查询WebApplicationInitializer
接口的实现类,在Spring3.2之后,对WebApplicationInitializer
创建了一个便利的基础实现类——AbstractAnnotationConfigDispatcherServletInitializer
,因此我们创建的初始化配置类WebInit只需继承AbstractAnnotationConfigDispatcherServletInitializer
并重写其方法,此时服务器会自动查找到我们创建的初始化类WebInit,然后用它来配置服务器
🔑初始化类需要重写的几个方法
方法 | 方法返回值类型 | 解释 |
---|
getRootConfigClasses() | Class<?>[] | 指定Spring配置类;将Spring配置类的class对象添加到Class数组中返回即可;可以指定多个Spring配置类,也可以不指定(因为方法的默认返回值是长度为0的数组) |
getServletConfigClasses() | Class<?>[] | 指定Spring MVC配置类;将Spring MVC配置类的class对象添加到Class数组中返回即可;同样可以指定多个Spring MVC配置类 |
getServletMappigs() | String[] | 指定前端控制器DispatcherServlet 的映射规则(资源路径);将资源路径添加到String数组中返回即可;相当于web.xml中<url-pattern> 标签的作用,可以设置多个资源路径 |
getServletFilters() | Filter[] | 配置过滤器;将过滤器类的class对象添加到Class数组中返回即可,过滤器的class在数组中位置决定了过滤器的配置顺序;也可以配置多个过滤器 |
❓ 关于Spring配置类
- 在Spring的学习中,可以创建一个类,类上添加
@Configuration
、@ComponnetScan
等注解,将类标识为配置类,然后在类中通过@Bean
注解添加其他配置,用于代替Spring的配置文件,Spring MVC配置类与之类似 - 在Spring MVC中添加Spring配置类属于SSM整合部分,这里只是简单创建一个被
@Configuration
标识的类作为Spring配置类,不添加其他功能实现;或者不添加也可以
1.2 Spring MVC配置类
💬概述:Spring MVC配置类命名为WebConfig,用于代替Spring MVC的核心配置文件——springmvc.xml,springmvc.xml中配置过的功能就是WebConfig类中需要实现的功能
🔑WebConfig的具体实现
💡 前5个必须配置,后面的选择配置
-
将WebConfig标识为配置类:在类上添加@Conguration
注解
-
开启组件扫描:在WebConfig配置类上添加@ComponnetScan
注解,注解的basePackages
属性中添加需要扫描的包或类(basePackages
是数组,可以添加多个扫描包或类)
-
开启注解驱动:在WebConfig类上添加@EnableWebMvc
注解,表示开启注解驱动的意思,无需添加属性
-
开放对静态资源的访问(配置默认servlet):在springmvc.xml中开放对静态资源的访问使用的是<mvc:default-servlet-handler>
标签,不是简单的<bean>
标签,所以在配置类中实现该功能需要先实现WebMvcConfigurer
接口,然后实现接口的configureDefaultServletHandling()
方法,在方法中直接通过形参configurer
调用enable()
方法即可
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
-
配置thymeleaf视图解析器(了解):在springmvc.xml文件配置thymeleaf时需要添加两个属性内部Bean,所以在配置类配置thymeleaf需要先创建出两个内部Bean,然后给thymeleafView视图解析器的属性赋值
@Bean
public ITemplateResolver templateResolver() {
WebApplicationContext webApplicationContext =
ContextLoader.getCurrentWebApplicationContext();
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(
webApplicationContext.getServletContext());
templateResolver.setPrefix("/WEB-INF/templates/");
templateResolver.setSuffix(".html");
templateResolver.setCharacterEncoding("UTF-8");
templateResolver.setTemplateMode(TemplateMode.HTML);
return templateResolver;
}
@Bean
public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
return templateEngine;
}
@Bean
public ViewResolver getThymeleafView(SpringTemplateEngine templateEngine) {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setCharacterEncoding("utf-8");
viewResolver.setTemplateEngine(templateEngine);
return viewResolver;
}
-
配置拦截器:与开放对静态资源的访问类似,在springmvc.xml文件中配置拦截器使用的同样是mvc名称空间中的标签<mvc:interceptors>
,所以配置拦截器同样需要实现WebMvcConfigurer
接口,然后实现addInterceptors()
方法,配置拦截器需要创建拦截器对象以及设置拦截路径
-
配置异常处理器
-
配置异常处理器有两种方式
① 异常处理器在springmvc.xml中是通过<bean>
标签配置的,所以在配置类中需要使用@Bean
标识对应方法即可,然后在方法中直接new一个异常处理器对象(即SimpleMappingExceptionResolver
类型的对象)
② 异常处理器的配置还有另外一种方法——实现WebMvcConfigurer
接口的方法configureHandlerExceptionResolvers()
或者extendedHandlerExceptionResolvers()
,同样需要在方法中new一个SimpleMappingExceptionResolver
类型的对象,该方法的形参就是一个异常处理器集合resolvers
,通过异常处理器对象对属性赋值后,最后将该对象添加到resolvers
集合中,由此可见,该方法可以配置多个异常处理器
-
配置异常处理器时需要实现的两个功能,即给异常处理器对象的两个属性(exceptionMappings
、exceptionAttribute
)赋值
① 创建异常与视图名的映射关系:先创建一个Properties
类型的对象prop
,然后通过prop
对象调用setProperty()
方法,将异常对应的全类名与视图名建立映射关系(形成键值对),然后调用异常处理器对象中exceptionMappings
属性对应的set方法,即setExceptionMappongs()
,将prop
传入即可
❓ 关于Properties
类:Properties
类继承Hashtable
类,而Hashtable
类实现了Map
接口,所以Properties
类也是通过键值对的形式对数据进行存储,一般用于操作.properties文件(也是键值对形式存储数据)
② 设置request域中异常信息的数据名(键):直接调用exceptionAttribute
属性对应的set方法——setExceptionAttribute()
方法给属性赋值即可,属性值就对应request域中异常信息的键
@Bean
public SimpleMappingExceptionResolver getExResolver() {
SimpleMappingExceptionResolver exResolver = new SimpleMappingExceptionResolver();
Properties prop = new Properties();
prop.setProperty("java.lang.ArithmeticException", "error");
exResolver.setExceptionMappings(prop);
exResolver.setExceptionAttribute("ex");
return exResolver;
}
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
SimpleMappingExceptionResolver exResolver = new SimpleMappingExceptionResolver();
Properties prop = new Properties();
prop.setProperty("java.lang.ArithmeticException", "error");
exResolver.setExceptionMappings(prop);
exResolver.setExceptionAttribute("ex");
resolvers.add(exResolver);
}
-
使用视图控制器:视图控制器同样需要实现WebMvcConfigurer
接口的方法addViewControllers()
,方法中直接通过形参registry
调用方法addViewController()
设置请求路径,然后在addViewController()
方法后直接调用setViewName()
方法设置请求路径对应的视图名
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
}
1.3 完整配置过程
-
先删掉web.xml配置文件和springmvc.xml核心配置文件
-
创建出初始化类WebInit
public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
encodingFilter.setEncoding("utf-8");
HiddenHttpMethodFilter httpMethodFilter = new HiddenHttpMethodFilter();
return new Filter[]{encodingFilter, httpMethodFilter};
}
}
-
创建Spring配置类SpringConfig(这里只是简单的创建,并无具体实现)
@Configuration
public class SpringConfig {
}
-
创建Spring MVC配置类WebConfig
@Configuration
@ComponentScan(basePackages = "com.key.mvc")
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
@Bean
public ITemplateResolver templateResolver() {
WebApplicationContext webApplicationContext =
ContextLoader.getCurrentWebApplicationContext();
ServletContextTemplateResolver templateResolver =
new ServletContextTemplateResolver(webApplicationContext.getServletContext());
templateResolver.setPrefix("/WEB-INF/templates/");
templateResolver.setSuffix(".html");
templateResolver.setCharacterEncoding("UTF-8");
templateResolver.setTemplateMode(TemplateMode.HTML);
return templateResolver;
}
@Bean
public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
return templateEngine;
}
@Bean
public ViewResolver getThymeleafView(SpringTemplateEngine templateEngine) {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setCharacterEncoding("utf-8");
viewResolver.setTemplateEngine(templateEngine);
return viewResolver;
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
TestInterceptor testInterceptor = new TestInterceptor();
registry.addInterceptor(testInterceptor).addPathPatterns("/**");
}
@Bean
public SimpleMappingExceptionResolver getExResolver() {
SimpleMappingExceptionResolver exResolver = new SimpleMappingExceptionResolver();
Properties prop = new Properties();
prop.setProperty("java.lang.ArithmeticException", "error");
exResolver.setExceptionMappings(prop);
exResolver.setExceptionAttribute("ex");
return exResolver;
}
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
registry.addViewController("/testUser").setViewName("test-user");
registry.addViewController("/success").setViewName("success");
registry.addViewController("/testHttpMsg").setViewName("test-httpMsg");
}
}
-
对xml文件测试过的功能进行再测试一次:异常处理、拦截器、报文信息转换、域对象共享数据等
二、总结
2.1 常用组件
常用组件 | 组件的实现和使用 | 作用 |
---|
前端控制器(中心控制器) DispatcherServlet | 由框架提供类型,开发人员只需在配置文件或配置类进行配置 | 对请求和相应进行统一处理,是整个控制层的中心,调用其他组件对请求进行处理 |
处理器映射器 HandlerMapping | 直接由框架提供,无需创建和配置 | 根据请求路径、请求方式等信息查找对应的处理器Handler ,即控制器方法,然后获取控制器方法中所有相关对象(包括控制器对象及其对应的拦截器对象等),最后返回一个HandlerExecutionChain 对象(处理执行链) |
处理器 Handler | 直接由框架提供,无需创建和配置 | 相当于控制器方法,对用户的请求做具体的处理,并将视图名交给视图解析器 |
处理器适配器 HandlerAdapter | 直接由框架提供,无需创建和配置 | 执行Handler (控制器方法),并返回一个ModelAndView 对象 |
视图解析器 ViewResolver/ThymeleafView | 由框架或其他依赖jar包提供类型,开发人员只需在配置文件或配置类进行配置 | 根据视图名对视图进行解析,返回解析后的视图对象 |
视图 View | 框架提供视图类View ,开发人员只需设置视图名 | 将视图数据展示到页面 |
2.2 执行流程
📚常见八股文:Spring MVC执行流程
🔑文字描述
-
浏览器向服务器发起请求,交给前端控制器DispatcherServlet
统一处理,DispatcherServlet
对获取的请求路径进行解析,然后根据请求路径查找对应的请求映射(与@RequestMapping
的value
值进行匹配)
-
如果匹配失败,即没有找到对应的请求映射,则DispatcherServlet
将当前请求路径(或资源)交给服务器默认servletDefaultServlet
处理,如果请求是一些静态资源(.css、.js等),则默认servlet能够处理,并成功发送给浏览器;如果请求是其他资源或路径,则默认servlet也无法处理,最终页面可能报404错误
-
如果匹配成功,此时DispatcherServlet
会调用处理器映射器HandlerMapping
对象进一步根据请求路径查找到对应的处理器Handler
(即控制器方法),然后把与Handler
相关的对象(包括控制器对象及其拦截器对象等)封装成一个HandlerExecutionChain
对象(处理执行链,用于调用拦截器相关方法)并返回
-
在查找到请求路径对应的Handler
(控制器方法)后,DispatcherServlet
再根据Handler
查找合适的处理器适配器HandlerAdapter
来执行Handler
-
如果配置了拦截器,则在执行Handler
前,会前执行拦截器的preHandle()
方法,如果方法返回值为true,则继续执行Handler
-
处理器适配器HandlerAdapter
调用handle()
方法来间接执行Handler
,并将Handler
中所设置的模型数据和视图数据封装成一个ModelAndView
对象返回。在这个过程中,除了完成请求的具体处理,Spring MVC还会对控制器方法中已有的配置(添加的形参、其他的注解)进行额外的处理
❓ 额外的处理
- 报文信息转换(HttpMessageConveter):将请求报文信息(Json数据、xml等)转换成Java对象,将Java对象转换成响应报文信息
- 数据类型转换:如果控制器方法中与请求参数对应的形参类型不是String,则Spring MVC会将String类型的请求参数转换成对应的形参类型
- 数据格式化:对请求消息进行数据格式化,如将字符串转换成格式化数字或格式化日期等
- 数据校验: 验证数据的有效性(长度、格式等)
-
如果配置了拦截器,则执行完Handler
后会执行拦截器的postHandle()
方法
-
执行完Handler
后会获取到一个ModelAndView
对象,DispatcherServlet
会先判断此时是否出现异常,如果出现异常,会调用异常处理器改变此时的视图名,根据新的视图名更新ModelAndView
对象
-
获取到最终的ModelAndView
对象后,DispatcherServlet
会将该对象传给processDispatchResult()
方法,对模型数据和视图数据做进一步处理
-
在processDispatchResult()
方法中调用render()
方法,根据视图名采用对应的视图解析器,对视图进行解析和渲染,最后返回一个视图对象view
-
如果配置了拦截器,则在渲染视图后会执行拦截器的afterCompletion()
方法
-
最后根据视图对象view
将视图数据展示到页面上
🔑图解
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)