通过前面的介绍,我们知道Spring MVC是一个以DispatcherServlet为中心,众多组件协同工作的Servlet服务。Spring中允许用户灵活的配置MVC中的各个组件,这就是Spring MVC配置的意义。本文会对Spring提供的各个MVC配置进行详细的介绍,本文主要参考了Spring的官方文档

MVC配置

启用MVC配置

使用MVC配置的第一步肯定是开启MVC配置,Spring提供了@EnableWebMvc注解来启用MVC配置,该注解会引入解析MVC配置的组件。

@Configuration
@EnableWebMvc
public class WebConfig {
}

WebMvcConfigurer

MVC的组件比较多,结构比较复杂,用户在不了解源码的情况下很难直接进行配置,所以Spring提供了WebMvcConfigurer用于告诉用户有哪些属性可以配置。下文我们会一一介绍接口中的方法。

类型转换服务

我们可以通过FormatterRegistry向配置中注册类型转换和格式化等服务,如下就配置了MVC日期与String类型之间的转换逻辑。

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
        registrar.setUseIsoFormat(true);
        registrar.registerFormatters(registry);
    }
}

校验服务

Spring容器默认提供了参数校验服务Validator,Controller中的参数会由Validator进行校验,MVC配置允许用户自定义校验逻辑,接口定义如下所示:

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public Validator getValidator() {
        // ...
    }
}

拦截器

Spring允许用户对所有的请求进行统一处理,如权限校验、时区参数设置等等,处理逻辑可以放在请求处理前、请求处理后和请求处理完成,配置的逻辑如下所示。

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LocaleChangeInterceptor());
        registry.addInterceptor(new ThemeChangeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
        registry.addInterceptor(new SecurityInterceptor()).addPathPatterns("/secure/*");
    }
}

消息转换服务

上面我们介绍了FormatterRegistry,FormatterRegistry主要提供了简单类型之间的转换,如String转int等,但是对于复杂请求体的转换,如@RequestBody中的JSON反序列化为对象等操作,就需要HttpMessageConverter的参与了。Spring默认提供了很多常见的转换服务如Jackson转换和货币日期等的转换。

@Configuration
@EnableWebMvc
public class WebConfiguration implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
                .indentOutput(true)
                .dateFormat(new SimpleDateFormat("yyyy-MM-dd"))
                .modulesToInstall(new ParameterNamesModule());
        converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
        converters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
    }
}

View配置

Spring运行根据请求路径直接返回View视图,用户可以通过配置ViewControllerRegistry实现这个功能。

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

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

Spring还允许用户自定以视图解析逻辑并通过ViewResolverRegistry注册到MVC中:

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.enableContentNegotiation(new MappingJackson2JsonView());
        registry.freeMarker().cache(false);
    }

    @Bean
    public FreeMarkerConfigurer freeMarkerConfigurer() {
        FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
        configurer.setTemplateLoaderPath("/freemarker");
        return configurer;
    }
}

静态资源配置

如果用户某次请求的数据是静态资源,那么这次请求不应该由Controller逻辑进行处理。Spring提供了ResourceHandlerRegistry让用户配置静态资源匹配规则。

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**")
            .addResourceLocations("/public", "classpath:/static/")
            .setCacheControl(CacheControl.maxAge(Duration.ofDays(365)));
    }
}

当DispatcherServlet映射到"/"路径后,我们仍然可以配置处理静态资源的默认Servlet,静态资源的映射路径是"/**",优先级比"/"低。一般情况下静态资源的Servlet应该是最低的,启用静态资源的servelt的示例如下所示:

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable("myCustomDefaultServlet");
    }
}

路径匹配规则

我们都知道在Controller上添加@RequestMapping方法之后,Spring会把请求映射到对应的Controller方法上,那么我们可不可以控制这个路径匹配过程呢?Spring提供了PathMatchConfigurer让用户可以配置路径匹配规则:

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer
            .setPatternParser(new PathPatternParser())
            .addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController.class));
    }

    private PathPatternParser patternParser() {
        // ...
    }
}

高级配置

@EnableWebMvc注解的原理就是向容器中注入类名为DelegatingWebMvcConfiguration,该类会读取各个WebMvcConfigurer并对MVC进行配置。所以我们也可以不使用@EnableWebMvc,通过自定义DelegatingWebMvcConfiguration的形式对MVC进行更灵活的配置。

@Configuration
public class WebConfig extends DelegatingWebMvcConfiguration {

    // ...
}

我是御狐神,欢迎大家关注我的微信公众号:wzm2zsd
qrcode_for_gh_83670e17bbd7_344-2021-09-04-10-55-16

本文最先发布至微信公众号,版权所有,禁止转载!

御狐神
27 声望4 粉丝