一、WebMvcConfigurer

  • WebMvcConfigurer 作为配置类,采用 JavaBean 的形式来代替传统的 XML 配置文件形式,进而针对框架个性化定制。就是 SpringMVCXML 配置文件的 JavaConfig(编码)实现方式。即,WebMvcConfigurer 就是 JavaConfig 形式的 SpringMVC 的配置文件。
  • 提供了跨域设置静态资源处理器类型转化器自定义拦截器页面跳转等能力
  • WebMvcConfigurer 是一个接口,需要自定义一个对象,实现接口并覆盖某个方法。
    public interface WebMvcConfigurer {
    	// 帮助配置 HandlerMapping,配置路径匹配规则<(^-^)>
    	default void configurePathMatch(PathMatchConfigurer configurer) {}
    	// 处理内容协商
    	default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {}
    	// 异步请求调用支持
    	default void configureAsyncSupport(AsyncSupportConfigurer configurer) {}
    	// 配置默认 Servlet,静态资源默认处理器 <(^-^)>
    	default void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {}
    	// 配置内容转换器,可以把时间转化成需要的时区或者格式,还可以将对象A转换为B对象。<(^-^)>
    	default void addFormatters(FormatterRegistry registry) {}<(^-^)>
    	// 配置拦截器
    	default void addInterceptors(InterceptorRegistry registry) {}
    	// 处理静态资源,静态资源映射器 <(^-^)>
    	default void addResourceHandlers(ResourceHandlerRegistry registry) {}
    	// 配置全局跨域,配置跨域设置
    	default void addCorsMappings(CorsRegistry registry) {}
    	// 配置视图页面跳转 <(^-^)>
    	default void addViewControllers(ViewControllerRegistry registry) {}
    	// 配置视图解析器
    	default void configureViewResolvers(ViewResolverRegistry registry) {}
    	// 自定义参数解析器,处理请求参数
    	default void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {}
    	// 自定义控制器方法返回值处理器
    	default void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {}
    	// 配置消息转化器
    	default void configureMessageConverters(List<HttpMessageConverter<?>> converters) {}
    	// 配置扩展 SpringMVC 框架的消息转化器
    	default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {}
    	// 配置异常处理器
    	default void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {}
    	// 扩展异常处理器
    	default void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {}
    	// JSR303 的自定义验证器
    	@Nullable
    	default Validator getValidator() {
    		return null;
    	}
    	// 消息处理对象
    	@Nullable
    	default MessageCodesResolver getMessageCodesResolver() {
    		return null;
    	}
    }
    

1.配置路径匹配规则(configurePathMatch)

  • 配置路径的匹配规则如下:(一般都不需要配置,默认的就完全够用了)
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
    	// 是否使用尾斜杠匹配, 默认为TRUE。TRUE, 表示"/hello"和"/hello/"都能匹配。
    	configurer.setUseTrailingSlashMatch(false);
     
    	// 为所有的接口添加统一前缀。如果的URL为: "/hello", 则转换为: "/api/hello"
    	configurer.addPathPrefix("api", c -> c.isAnnotationPresent(RestController.class));
     
    	// UrlPathHelper是一个处理URL地址的帮助类, 自带了一些优化URL的方法;
    	// 如:getSanitizedPath,就是将"//"自动转换为"/", 所以当输入为"//"也是没有问题的,
    	UrlPathHelper urlPathHelper = new UrlPathHelper();
    	configurer.setUrlPathHelper(urlPathHelper);
    }
    

2.配置静态资源处理(addResourceHandlers)

  • addResourceHandlers方法是SpringMVC框架提供的一种配置静态资源的方式,它可以将指定的资源路径映射到一个或多个URL路径上,并指定资源的缓存策略、版本号以及是否允许目录列表等选项。具体来说,addResourceHandlers方法需要传入一个ResourceHandlerRegistry对象作为参数,然后在这个对象上调用addResourceHandler方法,来添加一个或多个处理器。
    @Configuration  // 一定要配置为配置类
    public class WebMvcConfig implements WebMvcConfigurer {
    
        /***
         * 配置静态访问资源(需要注意不要和addViewControllers冲突)
         * @param registry 资源处理程序注册表
         */
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
        	registry
        		.addResourceHandler("/"+ environment.getProperty("linux.imagesPattern") +"/**")
        		.addResourceLocations("file:" + environment.getProperty("linux.avatar"));
            registry
                    // 指定静态资源的URL路径,当访问myStatic/**和yourStatic/**都会在static目录里找静态资源
                    .addResourceHandler("/myStatic/**", "/yourStatic/**")
                    .addResourceLocations("classpath:/static/")
                    // 于设置缓存控制头(cache-control header)30天过期(30天内请求相同资源则不在发送请求)
                    .setCacheControl(CacheControl.maxAge(30, TimeUnit.DAYS).cachePublic())
                    .resourceChain(false)
                    // 添加 VersionResourceResolver ,且指定版本号
                    .addResolver(new VersionResourceResolver()
                            .addFixedVersionStrategy("1.0.0", "/**"));
        }
    }
    

3.注册页面跳转(addViewControllers)

  • SpringBoot 中使用页面视图技术,比如 Thymeleaf。要跳转显示某个页面,必须通过 Controller 对象。也就是我们需要创建一个 Controller,转发一个视图才行。如果我们现在需要显示多个页面,可以无需这个 controlleraddViewControllers() 完成请求到视图跳转。
    在这里插入图片描述

  • ① 在templates目录下创建一个视图:test.html

    • 配置Thymeleaf模板(默认启动会请求/templates/index.html)
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>登录页面</title>
    </head>
    <body>
      <h1 style="color: red; text-align: center">欢迎来到登录页面!!!</h1>
    </body>
    </html>
    

    在这里插入图片描述

  • ② 创建 SpringMVC 配置类

    • setOrder(int order),设置当前视图控制器的执行顺序,当有多个视图控制器针对同一请求路径时,可以使用该方法进行优先级排序。
    • setStatusCode(HttpStatus statusCode),配置访问不存在资源的响应码。
    @Configuration
    public class MvcSetting implements WebMvcConfigurer {
    	// 跳转页面视图
        @Override
        public void addViewControllers(ViewControllerRegistry registry) {
        	//
        	//转发的方式
            registry.addViewController("/login").setViewName("/test");
            //重定向的方式
            //registry.addRedirectViewController("/login", "/templates/test.html");
           /*
           		注意:直接使用重定向的方式到templates目录下是访问不到资源的,因为templates目录下的资源默认是受到保护的,不能直接进行访问,可以添加下面的代码对访问资源的放行来重定向到静态资源上。
           */
        }
        /*@Override
    	public void addResourceHandlers(ResourceHandlerRegistry registry) {
        	//registry.addResourceHandler("/templates/**").addResourceLocations("classpath:/templates/");
    	}*/
    }
    
  • ③ 结果展示
    在这里插入图片描述


4.跨域配置(addCorsMappings)

  • 出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)。
  • 简单说A应用只能访问A应用后台传来数据,B应用只能访问B应用后台传来的数据,如果A应用用Ajax获取数据时的URL地址中的协议、端口、域名其中有一个和B应用不对应的话,则是A应用跨域了想获取B应用数据,是不允许的。
  • 当一个请求url的 协议域名端口 三者之间任意一个与当前页面url不同即为跨域
  • 下面展示了两种设置全局跨域的方法:
    @Configuration
    public class CorsConfig implements WebMvcConfigurer {
    
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            // 添加映射路径(凡是在addMapping配置的路径则代表可以跨域访问),这里表示所有的都可以跨域访问
            registry.addMapping("/**")
                    //设置放行哪些域
                    .allowedOriginPatterns("*")
                    // 放行哪些请求方式,也可以使用.allowedMethods("*")放行全部
                    .allowedMethods("GET", "POST", "PUT", "DELETE")
                    // 放行哪些请求头部信息
                    .allowedHeaders("*")
                    // 是否允许跨域请求携带凭证Cookie发送
                    .allowCredentials(true)
                    // 设置响应的缓存时间
                    .maxAge(3600)
                    // 暴露哪些响应头部信息
                    .exposedHeaders("Authorization");
        }
    
    /*    @Bean
        public FilterRegistrationBean<CorsFilter> corsFilter() {
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            CorsConfiguration config = new CorsConfiguration();
            config.addAllowedOriginPattern("*");
            config.addAllowedHeader("*");
            config.addAllowedMethod("*");
            config.setAllowCredentials(true);
            config.setMaxAge(3600L);
            source.registerCorsConfiguration("/**", config);
            FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source));
            bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
            return bean;
        }*/
    }
    
  • 上面的方式实现跨域访问好像有点问题,可以使用下面的方式:
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.cors.CorsConfiguration;
    import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
    import org.springframework.web.filter.CorsFilter;
     
    @Configuration // 一定不能忽略此注解
    public class MyCorsFilter {
        @Bean
        public CorsFilter corsFilter() {
            // 1.创建 CORS 配置对象
            CorsConfiguration config = new CorsConfiguration();
            // 支持域
            config.addAllowedOriginPattern("*");
            // 是否发送 Cookie
            config.setAllowCredentials(true);
            // 支持请求方式
            config.addAllowedMethod("*");
            // 允许的原始请求头部信息
            config.addAllowedHeader("*");
            // 暴露的头部信息
            config.addExposedHeader("*");
            // 2.添加地址映射
            UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
            corsConfigurationSource.registerCorsConfiguration("/**", config);
            // 3.返回 CorsFilter 对象
            return new CorsFilter(corsConfigurationSource);
        }
    }
    

5.数据格式化(addFormatters)

(1)Formatter

  • Formatter<T> 是数据转换接口,将一种数据类型转换为另一种数据类型。与 Formatter<T> 功能类似的还有 Converter<S, T>。Formatter<T> 只能将 String 类型转为其他数据类型。 这点在 Web 应用中适用广泛。因为 Web 请求的所有参数都是 String 类型的,我们需要把 String 转为 Integer、Long、Date 等等。
  • Spring 中内置的一些 Formatter<T>:
    • DateFormatter:String 和 Date 之间的解析与格式化。
    • InetAddressFormatter:String 和 InetAddress 之间的解析与格式化。
    • PercentStyleFormatter:对百分数进行一个格式化。
    • NumberFormatter:String 和 Number 之间的解析与格式化。
  • 我们在使用 @DateTimeFormat、@Numberformat 注解时,就是通过 Formatter<T> 解析 String 类型到我们期望的 Date 或 Number 类型。
  • Formatter<T> 也是 Spring 的扩展点,我们处理特殊格式的请求数据时,能够自定义合适的 Formatter<T>,将请求的 String 数据转为我们的某个对象,使用这个对象更加方便我们后续的编码。
    public interface Formatter<T> extends Printer<T>, Parser<T> {
    }
    
  • Formatter<T> 是一个组合接口,没有自己的方法。内容来自 Printer<T> 和 parse<T> 两个接口。
    • Printer<T>:将 T 类型转为 String,格式化输出。

      @FunctionalInterface
      public interface Printer<T> {
      	String print(T object, Locale locale);
      }
      
    • Parser<T>:将 String 类型转为期望的 T 对象。

      @FunctionalInterface
      public interface Parser<T> {
      	T parse(String text, Locale locale) throws ParseException;
      }
      

(2)内容转换器

  • 我们在实际的项目开发中,可能面对多种类型的项目,复杂程度有简单,有复杂的。特别是和硬件打交道的项目,数据的格式与一般的 name:jack,age:20 不同。数据有可能是一串数据 “1345;46;dfd;ASDS;12DF;df&12”
  • ① 自定义 Formatter
    public class DeviceInfoFormatter implements Formatter<List<String>> {
    
        @Override
        public List<String> parse(String text, Locale locale) throws ParseException {
            String[] infos = text.split(";");
            List<String> stringList = Arrays.asList(infos);
            return stringList;
        }
    
        @Override
        public String print(List<String> object, Locale locale) {
            return object.toString();
        }
    }
    
  • ② 登记内容转换器
    @Configuration
    public class MvcSetting implements WebMvcConfigurer {
        // 跳转视图页面控制器
        @Override
        public void addViewControllers(ViewControllerRegistry registry) {
    
            registry.addViewController("/login").setViewName("/login");
    
        }
        // 登记内容转换器
        @Override
        public void addFormatters(FormatterRegistry registry) {
            registry.addFormatter(new DeviceInfoFormatter());
        }
    }
    
  • ③ 创建 Controller 接收请求
    @Controller
    public class DeviceController {
        @ResponseBody
        @PostMapping("/device/postInfo")
        public String postDeviceInfo(@RequestParam("deviceInfo")List<String> list){
            return list.toString();
        }
    }
    
  • ④ 测试与结果展示
    在这里插入图片描述

6.拦截器配置(addInterceptors)

(1)自定义拦截器

  • HandlerIntercepter 接口和它的实现类被称为拦截器,是 SpringMVC 的一种对象。拦截器是 SpringMVC 框架提供的对象与 Servlet 无关。拦截器能够预先处理发给 Controller 的请求。可以决定请求是否被 Controller 处理。用户请求是先由 DispatchServlet 接收后,在 Controller 之前执行的拦截器对象。
  • SpringBoot中,我们可以使用拦截器来对请求进行统一的预处理或后处理。拦截器可以用于日志记录权限检查性能监控事务控制等方面,是一个非常重要的组件。要在SpringBoot中实现拦截器,则首先要创建一个实现HandlerInterceptor接口的拦截器类。该接口定义了三个方法,分别是preHandlepostHandleafterCompletion,用于在请求处理前请求处理后请求完成后进行处理。
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.stereotype.Component;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * 这里我自定义了一个拦截器的拦截规范,后面需要配置到WebMvcConfigurer
     * 我们可以自定义多个拦截器,到时候全部配置到WebMvcConfigurer里
     * 注:这里我定义的拦截器就当权限权限路径拦截(具体项目里我们可以起一个见名知意的拦截器 如:PermissionInterceptor)
     **/
    @Component  // 加载到Bean容器里
    public class MyInterceptor implements HandlerInterceptor {
    
        private final Logger log = LoggerFactory.getLogger(this.getClass());
        
        /***
         * 在请求处理前进行调用(Controller方法调用之前)
         * 可以在这一阶段进行全局权限校验等操作
         */
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws Exception {
            log.info("【preHandle】在请求处理前进行调用,自定义拦截器被执行。。。。");
            // 这下面我们可以进行权限校验,校验token操作.....
            // .....
            //上面的代码执行完,若可以放行本次请求则一定要返回true,这样才会到达Controller
            return true;
        }
    
        /***
         * 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
         * 可以在这个阶段来操作 ModelAndView
         */
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
                               ModelAndView modelAndView) throws Exception {
            log.info("【postHandle】请求处理之后进行调用,自定义拦截器被执行。。。。");
        }
    
        /***
         * 在整个请求结束之后被调用,也就是在DispatcherServlet渲染了对应的视图之后执行,主要用于资源清理工作。
         */
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
                                    Object handler, Exception ex) throws Exception {
            log.info("【afterCompletion】在整个请求结束之后被调用,自定义拦截器被执行。。。。");
        }
    }
    

(2)配置拦截器

  • 我们配置完拦截器之后,这时拦截器只是一个未被注册的普通类,这时需要把一个或者多个拦截器注册到WebMvcConfigurer

  • InterceptorRegistry类方法介绍:

    方法名描述
    addInterceptor该方法用于向拦截器链中添加一个拦截器。interceptor参数为待添加的拦截器对象,可以是自定义的拦截器类或Spring提供的预置拦截器。返回值为InterceptorRegistration对象,用于进一步配置该拦截器的属性。
    addWebRequestInterceptor该方法用于向WebRequest拦截器链中添加一个拦截器。interceptor参数为待添加的拦截器对象,可以是自定义的WebRequestInterceptor类或者Spring提供的预置拦截器。也是返回值为InterceptorRegistration对象,用于进一步配置该拦截器的属性。
    getInterceptors用于获取当前已经添加到拦截器链中的所有拦截器,返回值为List对象,表示拦截器列表。
  • InterceptorRegistration类方法介绍:

    方法名描述
    order该方法用于设置拦截器的执行顺序,即在拦截器链中的位置。order参数为一个整数,值越小表示越先执行。
    addPathPatterns该方法用于设置需要拦截的请求路径模式,即满足哪些请求路径时才会触发该拦截器。若 /** 则拦截全部;传入的参数是一个字符串数组,包含多个Ant风格的路径模式,例如 “/api/**”、"/user/*"等。
    excludePathPatterns该方法用于设置不需要拦截的请求路径模式,即满足哪些请求路径时不会触发该拦截器。一般不拦截,如登录或者Swagger等。传入的参数是一个字符串数组,包含多个Ant风格的路径模式,例如 “/api/login”、"/user/login"等。
    pathMatcher该方法用于设置该拦截器所使用的PathMatcher实例,从而可以自定义路径匹配逻辑。
    @Configuration  // 一定要配置为配置类
    public class WebMvcConfig implements WebMvcConfigurer {
    
        @Resource
        private MyInterceptor myInterceptor;
        
        /***
         * 配置拦截器信息
         * @param registry 拦截器注册表
         */
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
    
            // 配置myInterceptor的拦截规范(如拦截的路径等等)
           registry.addInterceptor(myInterceptor)
            // 设置拦截器的配置规则
                    // 指定拦截器的执行顺序。值越小,越先执行拦截器(但是得整型)。
                    .order(1)
                    // 设置需要拦截的路径(这里拦截所有的路径)
                    .addPathPatterns("/api/**", "/user/*", "/**")
                    // 设置拦截器的放行资源(代表不拦截)
                    // 设置登录放行
                    .excludePathPatterns("/login")
                    // 设置Swagger访问放行
                    .excludePathPatterns("/swagger-ui.html/**", "/swagger-ui.html", "/swagger-ui.html#/**")
                    // 如资源文件放行
                    .excludePathPatterns("/doc.html", "classpath:/META-INF/resources/");
            // 若有多个拦截器则在下面需要配置多个(如下面interceptorB,我们需要对这个进行路径拦截的配置)
            // InterceptorRegistration interceptorB = registry.addInterceptor(自定义的拦截器对象);
        }
    }
    

二、参考


Logo

2万人民币佣金等你来拿,中德社区发起者X.Lab,联合德国优秀企业对接开发项目,领取项目得佣金!!!

更多推荐