使用WebMvcConfigurer配置SpringMVC过程

 更新时间:2024年12月12日 10:06:01   作者:小豹子的技术笔记  
WebMvcConfigurer配置类用于Java代码配置SpringMvc,实现该接口或继承WebMvcConfigurationSupport类,常用方法:addInterceptors(拦截器)、addViewControllers(视图控制器)等

一、前言

WebMvcConfigurer配置类是使用Java代码代替传统的xml配置文件,对SpirngMvc进行配置的一种方式,需要创建一个配置类@Configuration实现WebMvcConfigurer 接口(推荐)。

二、使用方式

官方推荐使用实现WebMvcConfigurer接口(推荐)或者继承WebMvcConfigurationSupport类来实现代码配置。

1.配置类实现WebMvcConfigurer接口

@Configuration
public class WebMvcConfg implements WebMvcConfigurer {}

2.配置类继承WebMvcConfigurationSupport

@Configuration
public class WebMvcConfg extends WebMvcConfigurationSupport {}

三、WebMvcConfigurer接口常用方法

addInterceptors:拦截器

  • addInterceptor:需要一个实现HandlerInterceptor接口的拦截器实例
  • addPathPatterns:用于设置拦截器的过滤路径规则;- addPathPatterns(“/**”)对所有请求都拦截
  • excludePathPatterns:用于设置不需要拦截的过滤规则
  • 拦截器主要用途:进行用户登录状态的拦截,日志的拦截等。

addCorsMappings:跨域

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")  //浏览器允许所有的域访问 / 注意 * 不能满足带有cookie的访问,Origin 必须是全匹配
                .allowCredentials(true)   // 允许带cookie访问
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                 .allowedHeaders("token")
                .maxAge(3600);
    }

configureContentNegotiation:默认内容协商配置

内容协商:在 HTTP 协议中,内容协商是这样一种机制,通过为同一 URI 指向的资源提供不同的展现形式,可以使用户代理选择与用户需求相适应的最佳匹配

  @Override
  public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    // 是否通过请求Url的扩展名来决定media type
    configurer.favorPathExtension(false);
    //不检查Accept请求头    设置默认的media type
configurer.ignoreAcceptHeader(true).defaultContentType(MediaType.APPLICATION_JSON_UTF8);
  }

上面代码说白了就是告诉系统什么类型用什么来标识。

addViewControllers:跳转指定页面

以前写SpringMVC的时候,如果需要访问一个页面,必须要写Controller类,然后再写一个方法跳转到页面,感觉好麻烦,其实重写WebMvcConfigurer中的addViewControllers方法即可达到效果了。

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        // 绑定指定URL访问的view名称,这行的意思是在访问/路径时会自动跳转到index.html;如/login则不受影响
        registry.addViewController("/").setViewName("forward:/index.html");
    }

resourceViewResolver:视图解析器

configureMessageConverters:信息转换器

配置在接收request (请求)和返回response (响应)时的数据转换器,最常用到的就是fastJson的转换,配置如下所示

该方法会替换所有默认的MessageConverters,使用自定义添加converters,在实际项目中应用比例也比较小;

     /**
 * 消息内容转换配置
 */
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    //StringHttpMessageConverter默认使用的字符集是ISO-8859-1,改为输出的JSON字符串为UTF-8字符集
    converters.add(new StringHttpMessageConverter(StandardCharsets.UTF_8));
    
    //添加fastjson消息转换器
    converters.add(fastJsonHttpMessageConverters());
}

/**
 * 引入Fastjson解析json,不使用默认的jackson,必须在pom.xml引入fastjson的jar包,并且版必须大于1.2.10
 *
 * @return
 */
@Bean
public FastJsonHttpMessageConverter fastJsonHttpMessageConverters() {
    //1、定义一个convert转换消息的对象
    FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();

    //2、添加fastjson的配置信息
    FastJsonConfig fastJsonConfig = new FastJsonConfig();

    SerializerFeature[] serializerFeatures = new SerializerFeature[]{
            //    输出key是包含双引号
            //SerializerFeature.QuoteFieldNames,
            //    是否输出为null的字段,若为null 则显示该字段
            SerializerFeature.WriteMapNullValue,
            //    数值字段如果为null,则输出为0
            SerializerFeature.WriteNullNumberAsZero,
            //     List字段如果为null,输出为[],而非null
            SerializerFeature.WriteNullListAsEmpty,
            //    字符类型字段如果为null,输出为"",而非null
            SerializerFeature.WriteNullStringAsEmpty,
            //    Boolean字段如果为null,输出为false,而非null
            SerializerFeature.WriteNullBooleanAsFalse,
            //    Date的日期转换器
            SerializerFeature.WriteDateUseDateFormat,
            //    循环引用(如果不配置有可能会进入死循环)
            SerializerFeature.DisableCircularReferenceDetect,
            //    格式化JSON
            SerializerFeature.PrettyFormat
    };


    fastJsonConfig.setSerializerFeatures(serializerFeatures);
    fastJsonConfig.setCharset(Charset.forName("UTF-8"));


    //3.解决乱码问题。定义响应的MIME类型,设置响应的content-type为application/json;charset=UTF-8
    List<MediaType> fastMediaType = new ArrayList<>();
    fastMediaType.add(MediaType.valueOf(MediaType.APPLICATION_JSON_VALUE));

    //4.converter消息转换器添加配置信息
    fastConverter.setSupportedMediaTypes(fastMediaType);

    //5、在convert中添加配置信息
    fastConverter.setFastJsonConfig(fastJsonConfig);

    return fastConverter;
}

extendMessageConverters:信息转换器

1.使用

springboot2.0版本以后推荐使用extendMessageConverters来进行web配置,这个方法不会覆盖springmvc已默认添加的HttpMessageConverter

即:在默认加载的消息转换器基础上继续添加自定义的converters实例

@Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        converters.add(customerMappingJackson2HttpMessageConverter());
    }

    @Bean
    public MappingJackson2HttpMessageConverter customerMappingJackson2HttpMessageConverter(){
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        //设置日期格式

        ObjectMapper objectMapper = messageConverter.getObjectMapper();
        SimpleDateFormat smt = new SimpleDateFormat("yyyy-MM-dd");
        objectMapper.setDateFormat(smt);
        messageConverter.setObjectMapper(objectMapper);

        //设置中文编码格式
        List<MediaType> list = new ArrayList<MediaType>();
        list.add(MediaType.APPLICATION_JSON);
        messageConverter.setSupportedMediaTypes(list);
        return messageConverter;
    }

应用场景

空值处理

  • 请求和返回的数据有很多空值,这些值有时候并没有实际意义,我们可以过滤掉和不返回,或设置成默认值。
  • 比如通过重写getObjectMapper方法,将返回结果的空值不进行序列化:
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter
                mappingJackson2HttpMessageConverter =
                new MappingJackson2HttpMessageConverter();

        // 调整ObjectMapper对象序列化行为
        ObjectMapper objectMapper = mappingJackson2HttpMessageConverter.getObjectMapper();
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

        mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);
        converters.add(0,mappingJackson2HttpMessageConverter);

    }

响应字段格式调整

将Long类型转为字符串方式返回,Date格式改为时间戳返回(底层原理:调整MappingJackson2HttpMessageConverter类中ObjectMapper序列化行为)

@Configuration
public class JacksonConfig implements WebMvcConfigurer {

    @Value("${xss.enabled:false}")
    private boolean enableXss;

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();

        ObjectMapper objectMapper = jackson2HttpMessageConverter.getObjectMapper();

        SimpleModule simpleModule = new SimpleModule();

        //Long类型序列化成字符串,避免Long精度丢失
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
//        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);

        // XSS序列化
        if (enableXss) {
            simpleModule.addDeserializer(String.class, new XssJacksonDeserializer());
        }

        // Date
        simpleModule.addSerializer(Date.class, new JacksonDateSerializer());
        simpleModule.addDeserializer(Date.class, new JacksonDateDeserializer());
        simpleModule.addSerializer(LocalDateTime.class, new JacksonLocalDateTimeSerializer());
        simpleModule.addDeserializer(LocalDateTime.class, new JacksonLocalDateTimeDeserializer());

        objectMapper.registerModule(simpleModule)
                .registerModule(new JavaTimeModule())
                .registerModule(new ParameterNamesModule())
                .registerModule(new Jdk8Module());

        jackson2HttpMessageConverter.setObjectMapper(objectMapper);

        //放到第一个
        converters.add(0, jackson2HttpMessageConverter);
    }

}
  • addResourceHandlers:静态资源
  • addResoureHandler:请求静态资源的路径
  • addResourceLocations:静态资源存放位置,可以配置多个,按先后顺序查找
  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    // 10 days
    addCacheControl(registry, "img", 864000);
    addCacheControl(registry, "vendor", 864000);
    // 1 day
    addCacheControl(registry, "scripts", 86400);
    addCacheControl(registry, "styles", 86400);
    addCacheControl(registry, "views", 86400);
  }

  private void addCacheControl(ResourceHandlerRegistry registry, String folder, int cachePeriod) {
    registry.addResourceHandler(String.format("/%s/**", folder))
        .addResourceLocations(String.format("classpath:/static/%s/", folder))
        .setCachePeriod(cachePeriod);
  }

可以对静态资源做缓存控制之类的。

HttpMessageConverter接口

  • Http请求响应报文其实都是字符串,当请求报文到java程序会被封装为一个ServletInputStream流,供开发人员读取请求报文,响应报文则通过ServletOutputStream流,来输出响应报文。从流中只能读取到原始的字符串报文,同样输出流也是。
  • 那么在报文SpringMVC 输入和输出都存在一个字符串到java对象的转化问题。这一过程,在SpringMVC是通过HttpMessageConverter来解决的。
  • 在SpringMVC的处理过程中,一次请求报文和一次响应报文,分别被抽象为一个请求消息HttpInputMessage和一个响应消息HttpOutputMessage。处理请求时,由合适的消息转换器将请求报文绑定为方法中的形参对象,在这里同一个对象就有可能出现多种不同的消息形式,如json、xml。同样响应请求也是同样道理。

(1)HttpInputMessage 将请求的信息先转为 InputStream 对象,InputStream 再由 HttpMessageConverter 转换为 SpringMVC 需要的java对象;

(2)SpringMVC 返回一个 java 对象, 并通过 HttpMessageConverter 转为响应信息,接着 HttpOutputMessage 将响应的信息转换为OutputStream,接着给出响应。

简单说就是 HTTP request (请求)和response (响应)数据的转换器

通常实现HttpMessageConverter接口的转换器有以下几种:

  • ByteArrayHttpMessageConverter: 负责读取二进制格式的数据和写出二进制格式的数据;
  • StringHttpMessageConverter: 负责读取字符串格式的数据和写出二进制格式的数据;
  • ResourceHttpMessageConverter:负责读取资源文件和写出资源文件数据;
  • FormHttpMessageConverter: 负责读取form提交的数据(能读取的数据格式为 application/x-www-form-urlencoded,不能读取multipart/form-data格式数据);负责写入application/x-www-from-urlencoded和multipart/form-data格式的数据;
  • MappingJacksonHttpMessageConverter: 负责读取和写入json格式的数据;
  • SourceHttpMessageConverter: 负责读取和写入 xml 中javax.xml.transform.Source定义的数据;
  • Jaxb2RootElementHttpMessageConverter: 负责读取和写入xml 标签格式的数据;
  • AtomFeedHttpMessageConverter: 负责读取和写入Atom格式的数据;
  • RssChannelHttpMessageConverter: 负责读取和写入RSS格式的数据

在SpringMVC / SpringBoot中@ResponseBody这类注解默认使用的是jackson来解析json

3.HttpMessageConverter请求信息转换器执行流程

当用户发送请求后,@Requestbody 注解会读取请求body中的数据,默认的请求转换器HttpMessageConverter通过获取请求头Header中的Content-Type来确认请求头的数据格式,从而来为请求数据适配合适的转换器。

  • 例如contentType=applicatin/json,那么转换器会适配MappingJacksonHttpMessageConverter
  • 响应时候的时候同理,@Responsebody注解会启用HttpMessageConverter,通过检测Header中Accept属性来适配的响应的转换器。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Spring中的@Async原理分析

    Spring中的@Async原理分析

    这篇文章主要介绍了Spring中的@Async原理分析,自定义new ThreadPoolExecutor并调用invokeAll等进行并发编程,后面发现只要在方法上添加@Async注解,并使用@EnableAsync进行开启默认会使用SimpleAsyncTaskExecutor类型,需要的朋友可以参考下
    2024-01-01
  • java实现flappy Bird小游戏

    java实现flappy Bird小游戏

    这篇文章主要为大家详细介绍了java实现flappy Bird小游戏,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-12-12
  • 单例Bean注入多例Bean属性失效问题的四种解决方案

    单例Bean注入多例Bean属性失效问题的四种解决方案

    在实际的开发过程中,我们有可能会遇到这样一个场景:多例对象 A 需要作为属性注入给单例对象 B,但是我们每次获取 B 的时候,发现注入的 A 每次都是同一个,并不是多例的,所以本文给大家介绍了如何解决单例Bean注入多例Bean属性失效问题,需要的朋友可以参考下
    2024-05-05
  • Java实现爬取百度图片的方法分析

    Java实现爬取百度图片的方法分析

    这篇文章主要介绍了Java实现爬取百度图片的方法,结合实例形式分析了java基于jsonp爬取百度图片的相关原理、操作技巧与注意事项,需要的朋友可以参考下
    2018-12-12
  • Java如何将若干时间区间进行合并的方法步骤

    Java如何将若干时间区间进行合并的方法步骤

    这篇文章主要介绍了Java如何将若干时间区间进行合并的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-02-02
  • Java+opencv3.2.0之scharr滤波器

    Java+opencv3.2.0之scharr滤波器

    这篇文章主要为大家详细介绍了Java+opencv3.2.0之scharr滤波器的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02
  • 详解Spring中实现接口动态的解决方法

    详解Spring中实现接口动态的解决方法

    最近在工作遇到的一个,发现网上的资料较少,所以想着总结分享下,下面这篇文章主要给大家介绍了关于Spring中实现接口动态的解决方法,文中通过完整的示例代码给大家介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧。
    2017-07-07
  • 源码解析Spring 数据库异常抽理知识点总结

    源码解析Spring 数据库异常抽理知识点总结

    在本篇文章里小编给大家分享了关于源码解析Spring 数据库异常抽理知识点内容,对此有需要的朋友们学习参考下。
    2019-05-05
  • Java日志API管理最佳实践详解

    Java日志API管理最佳实践详解

    这篇文章主要介绍了Java日志API管理最佳实践详解,记录日志只是有效地利用日志的第一步,更重要的是如何对程序运行时产生的日志进行处理和分析。,需要的朋友可以参考下
    2019-06-06
  • Mybatis中的延迟加载详细解析

    Mybatis中的延迟加载详细解析

    这篇文章主要介绍了Mybatis中的延迟加载详细解析,延迟加载就是在真正需要使用数据时才发起查询,不用的时候不进行查询,按需加载(懒加载),需要的朋友可以参考下
    2023-12-12

最新评论