Shawn's Blog

蒸汽兔

初识SpringBoot-第五篇:Spring MVC配置及原理 & 拦截器应用

字数:1189 字 阅读时长:约 6 分钟 阅读

Spring Boot有许多包含Spring MVC的启动器。请注意,一些启动器包含对Spring MVC的依赖,而不是直接包含它。本节回答有关Spring MVC和Spring Boot的常见问题。

Spring Boot为Spring MVC提供自动配置,适用于大多数应用程序。

自动配置在Spring的默认值之上添加了以下功能:

  • 包含ContentNegotiatingViewResolverBeanNameViewResolver豆类。

  • 支持提供静态资源,包括对WebJars的支持( 官方文档介绍))。

  • 自动注册ConverterGenericConverterFormatterbean类。

    • Converter:转换器; public String hello(User user):类型转换使用Converter

    • Formatter 格式化器; 2017.12.17===Date;

      	@Bean
      		@ConditionalOnProperty(prefix = "spring.mvc", name = "date-format")//在文件中配置日期格式化的规则
      		public Formatter<Date> dateFormatter() {
      			return new DateFormatter(this.mvcProperties.getDateFormat());//日期格式化组件
      		}
      

      ==自己添加的格式化器转换器,我们只需要放在容器中即可==

  • 支持HttpMessageConverters官方文档介绍)。

    • HttpMessageConverter:SpringMVC用来转换Http请求和响应的;User—Json;

    • HttpMessageConverters 是从容器中确定;获取所有的HttpMessageConverter;

      ==自己给容器中添加HttpMessageConverter,只需要将自己的组件注册容器中(@Bean,@Component)==

  • 自动注册MessageCodesResolver官方文档介绍)。

  • 静态index.html支持。

  • 自定义Favicon支持(官方文档介绍)。

  • 自动使用ConfigurableWebBindingInitializerbean( 官方文档介绍)。

    ==我们可以配置一个ConfigurableWebBindingInitializer来替换默认的;(添加到容器)==

    初始化WebDataBinder;
    请求数据=====JavaBean;
    

如果您想保留Spring Boot MVC功能并且想要添加其他 MVC配置(拦截器,格式化程序,视图控制器和其他功能),您可以添加自己的@Configuration类类型WebMvcConfigurer不需要 @EnableWebMvc。如果您希望提供,或的 自定义实例RequestMappingHandlerMapping,则可以声明 实例以提供此类组件。RequestMappingHandlerAdapter ExceptionHandlerExceptionResolver WebMvcRegistrationsAdapter

如果您想完全控制Spring MVC,可以添加自己的@Configuration 注释@EnableWebMvc

扩展SpringMvc

在springboot默认mvc配置下,再自己扩展其配置工功能;最终效果:SpringMVC的自动配置和我们的扩展配置都会起作用;

1、编写一个springmvc.xml文件

<?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: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/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd">


    <mvc:view-controller path="/hello" view-name="success"/>
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/hello"/>
            <bean></bean>
        </mvc:interceptor>
    </mvc:interceptors>
</beans>

编写一个配置类(@Configuration)

改配置类是WebMvcConfigurationSupport类型;不能标注@EnableWebMvc(使用该注解代表将springboot默认配置失效);

springboot 2.0前:

@Configuration
public class MyMvcConfig extends WebMvcAutoConfigurationAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //浏览器发送 /shawn请求来到success页面
        registry.addViewController("/shawn").setViewName("success");
    }
}

spring boot2.0 继承WebMvcAutoConfigurationAdapter类已经过时:

//实现WebMvcConfigurer可以来扩展SpringMVC的功能(建议)
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //浏览器发送 /shawn请求来到success页面
        registry.addViewController("/shawn").setViewName("success");
    }
}

or

//继承WebMvcConfigurationSupport可以来扩展SpringMVC的功能,同时也相当于使用了@EnableWebMvc注解,springboot默认配置全部失效
@Configuration
public class MyMvcConfig extends WebMvcConfigurationSupport {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //浏览器发送 /shawn请求来到success页面
        registry.addViewController("/shawn").setViewName("success");
    }
}

原理:

1)、WebMvcAutoConfiguration是SpringMVC的自动配置类

2)、在做其他自动配置时会导入;@Import({WebMvcAutoConfiguration . EnableWebMvcConfiguration .class})

placeholder

例如参照添加视图方法addViewControllers功能来入手

  1. 从源码看EnableWebMvcConfiguration 继承了DelegatingWebMvcConfiguration类
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {

    private final WebMvcConfigurerComposite configurers = new  WebMvcConfigurerComposite();
    public DelegatingWebMvcConfiguration() {
    }

    //从容器中获取所有ebMvcConfigurer
    @Autowired(
        required = false
    )
    public void setConfigurers(List<WebMvcConfigurer> configurers) {
        if (!CollectionUtils.isEmpty(configurers)) {
            this.configurers.addWebMvcConfigurers(configurers);
        }

    }

    //设置视图方法
    protected void addViewControllers(ViewControllerRegistry registry) {
        this.configurers.addViewControllers(registry);
    }

    ...
}
  1. 点击该类addViewControllers 实现方法,进入WebMvcConfigurerComposite类中

    class WebMvcConfigurerComposite implements WebMvcConfigurer {
        private final List<WebMvcConfigurer> delegates = new ArrayList();
           
        public void addViewControllers(ViewControllerRegistry registry) {
            Iterator var2 = this.delegates.iterator();
    		//一个参考实现;将所有的WebMvcConfigurer相关配置都来一起调用;
            while(var2.hasNext()) {
                WebMvcConfigurer delegate = (WebMvcConfigurer)var2.next();
                delegate.addViewControllers(registry);
            }
       
        }
    

3)、容器中所有的WebMvcConfigurer都会一起起作用;

4)、我们的配置类也会被调用;

至此,扩展配置内容结束

全面接管SpringMVC

这一操作将SpringBoot对SpringMVC的自动配置全部废弃,所有配置都由我们自己配置;(不建议,此部分内容只是说明springboot提供了该操作场景)

实际实现

实现起来也很简单,我们需要在配置类中添加@EnableWebMvc即可;

//使用WebMvcConfigurerAdapter可以来扩展SpringMVC的功能
@EnableWebMvc
@Configuration
public class MyMvcConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
       // super.addViewControllers(registry);
        //浏览器发送 /atguigu 请求来到 success
        registry.addViewController("/shawn").setViewName("success");
    }
}

原理:

为什么@EnableWebMvc自动配置就失效了;我们首先来看看其源码是如何配置的。

1)@EnableWebMvc的核心

//导入了DelegatingWebMvcConfiguration类
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {

2)、DelegatingWebMvcConfiguration类

//继承了WebMvcConfigurationSupport类
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {

3)、WebMvcConfigurationSupport类

@Configuration
@ConditionalOnWebApplication
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class,
		WebMvcConfigurerAdapter.class })
//该注解标识如果容器中没有这个组件的时候,这个自动配置类才生效
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@AutoConfigureAfter({ DispatcherServletAutoConfiguration .class ,
		ValidationAutoConfiguration .class })
public class WebMvcAutoConfiguration {

4)、@EnableWebMvc将WebMvcConfigurationSupport组件导入进来;

5)、导入的WebMvcConfigurationSupport只是SpringMVC最基本的功能;

自定义@ResponseBody渲染

Spring用于HttpMessageConverters渲染@ResponseBody(或响应 @RestController)。您可以通过在Spring Boot上下文中添加适当类型的bean来提供其他转换器。如果您添加的bean是默认包含的类型(例如MappingJackson2HttpMessageConverterJSON转换),则它将替换默认值。HttpMessageConverters提供了类型的便利bean, 如果您使用默认的MVC配置,它始终可用。它有一些有用的方法来访问默认和用户增强的消息转换器(例如,如果要手动将它们注入自定义,它可能很有用RestTemplate)。

与正常的MVC使用情况一样,WebMvcConfigurer您提供的任何bean也可以通过覆盖该configureMessageConverters方法来提供转换器。但是,与普通的MVC不同,您只能提供所需的其他转换器(因为Spring Boot使用相同的机制来提供其默认值)。最后,如果您通过提供自己的@EnableWebMvc配置选择退出Spring Boot默认MVC 配置,则可以完全控制并使用getMessageConvertersfrom 手动完成所有操作 WebMvcConfigurationSupport

有关WebMvcAutoConfiguration 更多详细信息,请参阅 源代码。

处理多部分文件上载

Spring Boot包含Servlet 3 javax.servlet.http.PartAPI以支持上传文件。默认情况下,Spring Boot配置Spring MVC,每个文件的最大大小为1MB,单个请求中的文件数据最大为10MB。您可以覆盖这些值,中间数据的存储位置(例如,到/tmp 目录),以及使用MultipartProperties类中公开的属性将数据刷新到磁盘的阈值。例如,如果要指定文件不受限制,请将spring.servlet.multipart.max-file-size属性设置为-1

当您希望在Spring MVC控制器处理程序方法中接收多部分编码文件数据作为@RequestParam类型的注释参数时,多部分支持很有用MultipartFile

有关MultipartAutoConfiguration 详细信息,请参阅 源代码。

[注意]
建议使用容器的内置支持进行分段上传,而不是引入其他依赖项,例如Apache Commons File Upload。

关闭Spring MVC DispatcherServlet

默认情况下,所有内容都是从应用程序的根目录(/)提供的。如果您希望映射到其他路径,可以按如下方式配置:

spring.mvc.servlet.path = / acme

如果你有额外的servlet,你可以声明一个@Bean类型ServletServletRegistrationBean每个servlet ,Spring Boot会将它们透明地注册到容器中。因为servlet是以这种方式注册的,所以可以将它们映射到DispatcherServlet不调用它的子上下文。

配置DispatcherServlet你自己是不寻常的,但如果你真的需要这样做,还必须提供一种 @Bean类型DispatcherServletPath来提供自定义的路径DispatcherServlet

拦截器配置

模拟场景:

​ 登陆时,对没有用户session的操作进行拦截调到首页

实现

编写拦截器类LoginHandlerInterceptor,实现HandlerInterceptor接口

/**
 * 登陆检查,
 */
public class LoginHandlerInterceptor implements HandlerInterceptor {
    //目标方法执行之前
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Object user = request.getSession().getAttribute("loginUser");
        if(user == null){
            //未登陆,返回登陆页面
            request.setAttribute("msg","没有权限请先登陆");
            request.getRequestDispatcher("/index.html").forward(request,response);
            return false;
        }else{
            //已登陆,放行请求
            return true;
        }

    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

将该拦截器添加入容器

mvc自动配置类MyMvcConfig中重写拦截器方法写入规则

package com.shawn.chapter4.config;


@Configuration
//@EnableWebMvc
public class MyMvcConfig implements WebMvcConfigurer {


    //重写方法写入拦截规则
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**")
                .excludePathPatterns("/","/index","/login");
    }

}

相关资料

springboot官方文档

git相关项目


© Shawn Jim. All rights reserved. 本站总访问量 次, 访客数 人次.