• SpringBoot - WebMvcConfigurer的作用是什么?


    写在前面

    WebMvcConfigurer是一个接口,用于配置全局的SpringMVC的相关属性,采用JAVABEAN的方式来代替传统的XML配置文件,提供了跨域设置、静态资源处理器、类型转化器、自定义拦截器、页面跳转等能力。
    WebMvcConfigurer 在 Spring Boot 2.x 中官方建议使用该接口来实现自定义配置。所以,Spring Boot 2.x 中,自定义 SpringMVC 配置可以通过实现 WebMvcConfigurer 接口来完成。

    源码说明

    public interface WebMvcConfigurer {
    	//  配置路径匹配规则
        default void configurePathMatch(PathMatchConfigurer configurer) { }
    
    	// 内容协商
        default void configureContentNegotiation(ContentNegotiationConfigurer configurer) { }
    	
    	// 异步调用支持
        default void configureAsyncSupport(AsyncSupportConfigurer configurer) { }
    
    	// 静态资源默认处理器
        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) { }
    
    	// 信息转化器扩展
        default void extendMessageConverters(List<HttpMessageConverter<?>> converters) { }
    
    	// 异常处理器
        default void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) { }
    
    	// 异常处理器扩展
        default void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) { }
    
        @Nullable
        default Validator getValidator() {
            return null;
        }
    
        @Nullable
        default MessageCodesResolver getMessageCodesResolver() {
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    常用示例

    ① 配置路径匹配规则
    @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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    ② 配置静态资源映射器

    用于自定义静态资源的映射目录。

    // addResourceHandler:用于设置对外暴露的访问路径
    // addResourceLocations:用于映射内部文件放置的目录,需要以“/”结尾
    
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        /** 本地文件上传路径 */
        // 对外暴露的访问路径
        registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**")
        // 映射内部文件放置的目录,以“/”结尾
                .addResourceLocations("file:" + ServicexConfig.getProfile() + "/");
    
        /** swagger配置 */
        registry.addResourceHandler("/swagger-ui/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    ③ 配置请求拦截器

    可以设置多个拦截器,如对特定的URL设定处理规则、打印处理用户请求耗费的时间、定义防止重复提交等功能。

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 增加一个拦截器,对请求做一些自定义处理
        registry.addInterceptor(new 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;
                }
            }
        })
        // 设置拦截器的过滤路径规则:只拦截/admin/形式的请求
        .addPathPatterns("/admin/**")
        // 设置不需要拦截的过滤规则:不拦截/admin/login请求
        .excludePathPatterns("/admin/login");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    ④ 跨域设置
    方法一:
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 设置允许跨域的路径
        registry.addMapping("/**")
                // 设置允许跨域请求的域名
                .allowedOrigins("*")
                // 是否允许证书
                .allowCredentials(true)
                // 设置允许的方法
                .allowedMethods("GET", "POST", "DELETE", "PUT")
                // 设置允许的header属性
                .allowedHeaders("*")
                // 跨域允许时间
                .maxAge(3600);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    方法二:
    /**
     * 跨域配置
     */
    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        // 设置访问源地址
        config.addAllowedOriginPattern("*");
        // 设置访问源请求头
        config.addAllowedHeader("*");
        // 设置访问源请求方法
        config.addAllowedMethod("*");
        // 有效期 1800秒
        config.setMaxAge(1800L);
        // 添加映射路径,拦截一切请求
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        // 返回新的CorsFilter
        return new CorsFilter(source);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    ⑤ 视图控制器

    用于将请求的URL进行处理。

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        // 如果请求为:/admin,则重定向到/login
        registry.addRedirectViewController("/admin", "/login");
        // 如果请求为:/admin/delete,则返回500状态
        registry.addStatusController("/admin/delete", HttpStatus.INTERNAL_SERVER_ERROR);
    	// 如果请求URL为:/hello,则直接跳转到hello页面
    	registry.addViewController("/hello").setViewName("hello");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    ⑥ 内容协商

    用于将一个URL直接跳转到页面。

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        // 自定义策略
        configurer.favorPathExtension(true)// 是否通过请求Url的扩展名来决定mediaType,默认true
                .ignoreAcceptHeader(true)// 不检查Accept请求头
                .parameterName("mediaType")
                .defaultContentType(MediaType.TEXT_HTML)// 设置默认的MediaType
                .mediaType("html", MediaType.TEXT_HTML)// 请求以.html结尾的会被当成MediaType.TEXT_HTML
                .mediaType("json", MediaType.APPLICATION_JSON)// 请求以.json结尾的会被当成MediaType.APPLICATION_JSON
                .mediaType("xml", MediaType.APPLICATION_ATOM_XML);// 请求以.xml结尾的会被当成MediaType.APPLICATION_ATOM_XML
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    ⑦ 信息转化器扩展

    自定义FASTJSON为JSON消息的转换器,完成的功能如下:
    1、请求返回体使用FASTJSON来序列化;
    2、配置如果字段类型为Date,输出为"yyyy-MM-dd HH:mm:ss"格式;
    3、配置允许输出值为null的字段;
    4、配置字符类型字段,如果为null,输出为"",而非null;
    5、配置把Long类型的数据序列化成JSON后传给前端,解决前端可能会出现精度丢失的情况。

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        //1、首先定义一个convert消息转换对象
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
    
        //2、定义支持的mediaType类型,处理中文乱码的相关问题
        List<MediaType> mediaTypes = new ArrayList<>();
        mediaTypes.add(MediaType.APPLICATION_JSON);      // 返回JSON格式
        mediaTypes.add(MediaType.APPLICATION_JSON_UTF8); // 处理输出中文乱码
        mediaTypes.add(MediaType.TEXT_HTML);
        mediaTypes.add(new MediaType("application", "xml"));
        mediaTypes.add(new MediaType("text", "xml"));
        mediaTypes.add(new MediaType("application", "*+xml"));
        mediaTypes.add(MediaType.ALL);
        converter.setSupportedMediaTypes(mediaTypes);
    
        //3. 创建配置类
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setCharset(Charset.forName("UTF-8")); // 全局编码
        fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss"); // 全局时间格式化
    
        //4. 格式化返回内容
        SerializerFeature[] serializerFeatures = new SerializerFeature[]{
                SerializerFeature.PrettyFormat,             // 格式化
                SerializerFeature.WriteMapNullValue,        // 输出空值
                SerializerFeature.WriteNullListAsEmpty,     // List字段如果为null,输出为[],而非null
                SerializerFeature.WriteDateUseDateFormat,   // 日期格式化
                SerializerFeature.WriteNullStringAsEmpty,   // 字符类型字段如果为null,输出为"",而非null
                SerializerFeature.WriteNullBooleanAsFalse,  // Boolean字段如果为null,输出为false,而非null
                SerializerFeature.DisableCircularReferenceDetect, //消除对同一对象循环引用的问题,默认为false(如果不配置有可能会进入死循环)
                SerializerFeature.WriteNullNumberAsZero     //数字类型如果为null,输出为0,而非null
        };
        fastJsonConfig.setSerializerFeatures(serializerFeatures);
    
        //5. 配置Java类型对应的序列化类,序列换成json时, 将所有的long变成string,解决Long转json精度丢失的问题,因为js中得数字类型不能包含所有的java long值
        SerializeConfig serializeConfig = SerializeConfig.globalInstance;
        serializeConfig.put(BigInteger.class, ToStringSerializer.instance);
        serializeConfig.put(Long.class, ToStringSerializer.instance);
        serializeConfig.put(Long.TYPE, ToStringSerializer.instance);
        fastJsonConfig.setSerializeConfig(serializeConfig);
    
        converter.setFastJsonConfig(fastJsonConfig);
        converters.add(0,converter);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    其他方式

    A. WebMvcConfigurerAdapter
    B. WebMvcConfigurationSupport
    C. @EnableWebMvc

    A. WebMvcConfigurerAdapter

    在 Spring Boot 1.x 中我们自定义 SpringMVC 时继承的一个抽象类,这个抽象类本身是实现了 WebMvcConfigurer 接口。从 Spring5 开始,官方建议直接实现 WebMvcConfigurer 接口,而不是继承 WebMvcConfigurerAdapter。

    B. WebMvcConfigurationSupport

    在纯 Java 配置的 SSM 环境中,如果我们要自定义 SpringMVC 配置,有两种办法:
    第一种就是直接继承自 WebMvcConfigurationSupport 来完成 SpringMVC 配置;
    还有一种方案就是实现 WebMvcConfigurer 接口来完成自定义 SpringMVC 配置,如果使用第二种方式,则需要给 SpringMVC 的配置类上额外添加 @EnableWebMvc 注解,表示启用 WebMvcConfigurationSupport,这样配置才会生效。

    C. @EnableWebMvc

    如果在 Spring Boot 中使用了 @EnableWebMvc 注解,就会导致 Spring Boot 中默认的 SpringMVC 自动化配置失效,所以不建议使用该方式。

  • 相关阅读:
    【虹科干货】Lambda数据架构和Kappa数据架构——构建现代数据架构
    互换性测量与技术——偏差与公差的计算,公差图的绘制,配合与公差等级的选择方法
    docker的平替--podman
    Java计算机毕业设计基于SpringBoot音乐网项目(附源码讲解)
    StarRocks 运维工具 StarGo
    Python 潮流周刊#55:分享 9 个高质量的技术类信息源!
    凯百斯纳米盛装亮相2024济南生物发酵展专注于高压均质解决方案
    【前端开发】CSS BEM命名规范
    2023年中职“网络安全“—Linux系统渗透提权③
    青少年python系列 37.函数的变量与返回值
  • 原文地址:https://blog.csdn.net/goodjava2007/article/details/126132375