Spring MVC学习 | 注解配置Spring MVC&总结

24 篇文章 0 订阅


学习视频🎥: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()方法即可

    /**
     * 1. 开放对静态资源的访问(配置默认servlet)
     */
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
    
  • 配置thymeleaf视图解析器(了解):在springmvc.xml文件配置thymeleaf时需要添加两个属性内部Bean,所以在配置类配置thymeleaf需要先创建出两个内部Bean,然后给thymeleafView视图解析器的属性赋值

    /**
     * 2.1 配置模板解析器
     */
    @Bean
    public ITemplateResolver templateResolver() {
        WebApplicationContext webApplicationContext = 
            ContextLoader.getCurrentWebApplicationContext();
        // ServletContextTemplateResolver需要一个ServletContext作为构造参数,可通过WebApplicationContext 的方法获得
        ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver(
            webApplicationContext.getServletContext());
    
        // 设置视图前缀
        templateResolver.setPrefix("/WEB-INF/templates/");
        // 设置视图后缀
        templateResolver.setSuffix(".html");
        // 设置编码方式
        templateResolver.setCharacterEncoding("UTF-8");
        // 设置模板
        templateResolver.setTemplateMode(TemplateMode.HTML);
        return templateResolver;
    }
    
    /**
     * 2.2 配置模板引擎,并为模板引擎注入模板解析器属性
     */
    @Bean
    public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
        SpringTemplateEngine templateEngine = new SpringTemplateEngine();
        templateEngine.setTemplateResolver(templateResolver);
        return templateEngine;
    }
    
    /**
     * 2.3 配置thymeleaf视图解析器,并为解析器注入模板引擎属性
     */
    @Bean
    public ViewResolver getThymeleafView(SpringTemplateEngine templateEngine) {
        // 先创建一个thymeleaf视图解析器对象
        ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
    
        // 设置编码方式
        viewResolver.setCharacterEncoding("utf-8");
    
        // 注入模板引擎属性
        viewResolver.setTemplateEngine(templateEngine);
    
        return viewResolver;
    }
    
  • 配置拦截器:与开放对静态资源的访问类似,在springmvc.xml文件中配置拦截器使用的同样是mvc名称空间中的标签<mvc:interceptors>,所以配置拦截器同样需要实现WebMvcConfigurer接口,然后实现addInterceptors()方法,配置拦截器需要创建拦截器对象以及设置拦截路径

    • 创建拦截器对象:先创建好拦截器类TestInterceptor,然后在方法中直接new一个拦截器类对象即可

    • 设置拦截路径:调用形参registryaddInterceptor()方法,并将拦截器对象TestInterceptor传入,然后addInterceptor()方法后通过addPathPatterns()方法设置拦截路径

  • 配置异常处理器

    • 配置异常处理器有两种方式

      ① 异常处理器在springmvc.xml中是通过<bean>标签配置的,所以在配置类中需要使用@Bean标识对应方法即可,然后在方法中直接new一个异常处理器对象(即SimpleMappingExceptionResolver类型的对象)
      ② 异常处理器的配置还有另外一种方法——实现WebMvcConfigurer接口的方法configureHandlerExceptionResolvers()或者extendedHandlerExceptionResolvers(),同样需要在方法中new一个SimpleMappingExceptionResolver类型的对象,该方法的形参就是一个异常处理器集合resolvers,通过异常处理器对象对属性赋值后,最后将该对象添加到resolvers集合中,由此可见,该方法可以配置多个异常处理器

    • 配置异常处理器时需要实现的两个功能,即给异常处理器对象的两个属性(exceptionMappingsexceptionAttribute)赋值

      ① 创建异常与视图名的映射关系:先创建一个Properties类型的对象prop,然后通过prop对象调用setProperty()方法,将异常对应的全类名与视图名建立映射关系(形成键值对),然后调用异常处理器对象中exceptionMappings属性对应的set方法,即setExceptionMappongs(),将prop传入即可

      ❓ 关于Properties类:Properties类继承Hashtable类,而Hashtable类实现了Map接口,所以Properties类也是通过键值对的形式对数据进行存储,一般用于操作.properties文件(也是键值对形式存储数据)

      ② 设置request域中异常信息的数据名(键):直接调用exceptionAttribute属性对应的set方法——setExceptionAttribute()方法给属性赋值即可,属性值就对应request域中异常信息的键

    /**
     * 4. 方式一配置异常处理器
     */
    @Bean
    public SimpleMappingExceptionResolver getExResolver() {
        // 创建异常处理器对象
        SimpleMappingExceptionResolver exResolver = new SimpleMappingExceptionResolver();
    
        // 创建一个Properties对象,用于建立异常与视图名的映射关系
        Properties prop = new Properties();
    
        // 将数学异常与视图名error进行绑定
        prop.setProperty("java.lang.ArithmeticException", "error");
    
        // 给异常处理器的exceptionMappings属性赋值
        exResolver.setExceptionMappings(prop);
    
        // 给exceptionAttribute赋值,设置request域中异常信息的键
        exResolver.setExceptionAttribute("ex");
    
        return exResolver;
    }
    
    /*+---------------------------------------------------------------------------------+*/
    
    /**
     * 4. 方式二配置异常处理器
     */
    @Override
    public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
        // 创建异常处理器对象
        SimpleMappingExceptionResolver exResolver = new SimpleMappingExceptionResolver();
    
        // 创建一个Properties对象,用于建立异常与视图名的映射关系
        Properties prop = new Properties();
    
        // 将数学异常与视图名error进行绑定
        prop.setProperty("java.lang.ArithmeticException", "error");
    
        // 给异常处理器的exceptionMappings属性赋值
        exResolver.setExceptionMappings(prop);
    
        // 给exceptionAttribute赋值,设置request域中异常信息的键
        exResolver.setExceptionAttribute("ex");
    
        resolvers.add(exResolver);
    }
    
  • 使用视图控制器:视图控制器同样需要实现WebMvcConfigurer接口的方法addViewControllers(),方法中直接通过形参registry调用方法addViewController()设置请求路径,然后在addViewController()方法后直接调用setViewName()方法设置请求路径对应的视图名

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        // 首页
        registry.addViewController("/").setViewName("index");
    }
    

1.3 完整配置过程

  1. 先删掉web.xml配置文件和springmvc.xml核心配置文件

  2. 创建出初始化类WebInit

    public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {
    
        /**
         * 指定Spring配置类
         * @return 返回Class数组,数组元素为配置类的class对象
         */
        @Override
        protected Class<?>[] getRootConfigClasses() {
            return new Class[]{SpringConfig.class};
        }
    
        /**
         * 指定Spring MVC配置类
         * @return 返回Class数组,数组元素为配置类的class对象
         */
        @Override
        protected Class<?>[] getServletConfigClasses() {
            return new Class[]{WebConfig.class};
        }
    
        /**
         * 指定DispatcherServlet的映射规则,即资源路径
         * @return 返回资源路径的字符串数组
         */
        @Override
        protected String[] getServletMappings() {
            return new String[]{"/"};
        }
    
        /**
         * 配置过滤器
         * @return 返回过滤器数组
         */
        @Override
        protected Filter[] getServletFilters() {
            // 1. 创建字符集过滤器CharacterEncodingFilter
            CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
            // 1.1 设置encoding属性为utf-8
            encodingFilter.setEncoding("utf-8");
    
            // 2. 创建请求方式过滤器
            HiddenHttpMethodFilter httpMethodFilter = new HiddenHttpMethodFilter();
    
            // 3. 创建过滤器数组并返回
            return new Filter[]{encodingFilter, httpMethodFilter};
        }
    }
    
  3. 创建Spring配置类SpringConfig(这里只是简单的创建,并无具体实现)

    @Configuration
    public class SpringConfig {
        
        // coding..
    }
    
  4. 创建Spring MVC配置类WebConfig

    @Configuration
    @ComponentScan(basePackages = "com.key.mvc")
    @EnableWebMvc
    public class WebConfig implements WebMvcConfigurer {
    
        /**
         * 1. 开放对静态资源的访问(配置默认servlet)
         */
        @Override
        public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
            configurer.enable();
        }
    
        /* 2. 配置thymeleaf视图解析器 */
    
        /**
         * 2.1 配置模板解析器
         */
        @Bean
        public ITemplateResolver templateResolver() {
            WebApplicationContext webApplicationContext = 
                ContextLoader.getCurrentWebApplicationContext();
            // ServletContextTemplateResolver需要一个ServletContext作为构造参数,可通过WebApplicationContext 的方法获得
            ServletContextTemplateResolver templateResolver = 
                new ServletContextTemplateResolver(webApplicationContext.getServletContext());
    
            // 设置视图前缀
            templateResolver.setPrefix("/WEB-INF/templates/");
            // 设置视图后缀
            templateResolver.setSuffix(".html");
            // 设置编码方式
            templateResolver.setCharacterEncoding("UTF-8");
            // 设置模板
            templateResolver.setTemplateMode(TemplateMode.HTML);
            return templateResolver;
        }
    
        /**
         * 2.2 配置模板引擎,并为模板引擎注入模板解析器属性
         */
        @Bean
        public SpringTemplateEngine templateEngine(ITemplateResolver templateResolver) {
            SpringTemplateEngine templateEngine = new SpringTemplateEngine();
            templateEngine.setTemplateResolver(templateResolver);
            return templateEngine;
        }
    
        /**
         * 2.3 配置thymeleaf视图解析器,并为解析器注入模板引擎属性
         */
        @Bean
        public ViewResolver getThymeleafView(SpringTemplateEngine templateEngine) {
            // 先创建一个thymeleaf视图解析器对象
            ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
    
            // 设置编码方式
            viewResolver.setCharacterEncoding("utf-8");
    
            // 注入模板引擎属性
            viewResolver.setTemplateEngine(templateEngine);
    
            return viewResolver;
        }
    
        /**
         * 3. 配置拦截器
         */
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            // 创建拦截器对象
            TestInterceptor testInterceptor = new TestInterceptor();
    
            // 添加拦截器对象,并设置拦截路径
            registry.addInterceptor(testInterceptor).addPathPatterns("/**");
        }
    
        /**
         * 4. 配置异常处理器
         */
        @Bean
        public SimpleMappingExceptionResolver getExResolver() {
            // 创建异常处理器对象
            SimpleMappingExceptionResolver exResolver = new SimpleMappingExceptionResolver();
    
            // 创建一个Properties对象,用于建立异常与视图名的映射关系
            Properties prop = new Properties();
    
            // 将数学异常与视图名error进行绑定
            prop.setProperty("java.lang.ArithmeticException", "error");
    
            // 给异常处理器的exceptionMappings属性赋值
            exResolver.setExceptionMappings(prop);
    
            // 给exceptionAttribute赋值,设置request域中异常信息的键
            exResolver.setExceptionAttribute("ex");
    
            return exResolver;
        }
    
    
        /**
         * 5. 配置视图控制器
         */
        @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");
        }
    }
    
  5. 对xml文件测试过的功能进行再测试一次:异常处理、拦截器、报文信息转换、域对象共享数据等


二、总结

2.1 常用组件

常用组件组件的实现和使用作用
前端控制器(中心控制器) DispatcherServlet由框架提供类型,开发人员只需在配置文件或配置类进行配置对请求和相应进行统一处理,是整个控制层的中心,调用其他组件对请求进行处理
处理器映射器 HandlerMapping直接由框架提供,无需创建和配置根据请求路径、请求方式等信息查找对应的处理器Handler,即控制器方法,然后获取控制器方法中所有相关对象(包括控制器对象及其对应的拦截器对象等),最后返回一个HandlerExecutionChain对象(处理执行链)
处理器 Handler直接由框架提供,无需创建和配置相当于控制器方法,对用户的请求做具体的处理,并将视图名交给视图解析器
处理器适配器 HandlerAdapter直接由框架提供,无需创建和配置执行Handler(控制器方法),并返回一个ModelAndView对象
视图解析器 ViewResolver/ThymeleafView由框架或其他依赖jar包提供类型,开发人员只需在配置文件或配置类进行配置根据视图名对视图进行解析,返回解析后的视图对象
视图 View框架提供视图类View,开发人员只需设置视图名将视图数据展示到页面

2.2 执行流程

📚常见八股文:Spring MVC执行流程

🔑文字描述

  1. 浏览器向服务器发起请求,交给前端控制器DispatcherServlet统一处理,DispatcherServlet对获取的请求路径进行解析,然后根据请求路径查找对应的请求映射(与@RequestMappingvalue值进行匹配)

  2. 如果匹配失败,即没有找到对应的请求映射,则DispatcherServlet将当前请求路径(或资源)交给服务器默认servletDefaultServlet处理,如果请求是一些静态资源(.css、.js等),则默认servlet能够处理,并成功发送给浏览器;如果请求是其他资源或路径,则默认servlet也无法处理,最终页面可能报404错误

  3. 如果匹配成功,此时DispatcherServlet会调用处理器映射器HandlerMapping对象进一步根据请求路径查找到对应的处理器Handler(即控制器方法),然后把与Handler相关的对象(包括控制器对象及其拦截器对象等)封装成一个HandlerExecutionChain对象(处理执行链,用于调用拦截器相关方法)并返回

  4. 在查找到请求路径对应的Handler(控制器方法)后,DispatcherServlet再根据Handler查找合适的处理器适配器HandlerAdapter来执行Handler

  5. 如果配置了拦截器,则在执行Handler前,会前执行拦截器的preHandle()方法,如果方法返回值为true,则继续执行Handler

  6. 处理器适配器HandlerAdapter调用handle()方法来间接执行Handler,并将Handler中所设置的模型数据和视图数据封装成一个ModelAndView对象返回。在这个过程中,除了完成请求的具体处理,Spring MVC还会对控制器方法中已有的配置(添加的形参、其他的注解)进行额外的处理

    ❓ 额外的处理

    • 报文信息转换(HttpMessageConveter):将请求报文信息(Json数据、xml等)转换成Java对象,将Java对象转换成响应报文信息
    • 数据类型转换:如果控制器方法中与请求参数对应的形参类型不是String,则Spring MVC会将String类型的请求参数转换成对应的形参类型
    • 数据格式化:对请求消息进行数据格式化,如将字符串转换成格式化数字或格式化日期等
    • 数据校验: 验证数据的有效性(长度、格式等)
  7. 如果配置了拦截器,则执行完Handler后会执行拦截器的postHandle()方法

  8. 执行完Handler后会获取到一个ModelAndView对象,DispatcherServlet会先判断此时是否出现异常,如果出现异常,会调用异常处理器改变此时的视图名,根据新的视图名更新ModelAndView对象

  9. 获取到最终的ModelAndView对象后,DispatcherServlet会将该对象传给processDispatchResult()方法,对模型数据和视图数据做进一步处理

  10. processDispatchResult()方法中调用render()方法,根据视图名采用对应的视图解析器,对视图进行解析和渲染,最后返回一个视图对象view

  11. 如果配置了拦截器,则在渲染视图后会执行拦截器的afterCompletion()方法

  12. 最后根据视图对象view将视图数据展示到页面上

🔑图解springmvc-execution-flow

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值