阅读完需:约 13 分钟
为什么要使用WebMvcConfigurer?
WebMvcConfigurer
是一个接口,提供很多自定义的拦截器,例如跨域设置、类型转化器等等。可以说此接口为开发者提前想到了很多拦截层面的需求,方便开发者自由选择使用。由于Spring5.0
废弃了WebMvcConfigurerAdapter
,所以WebMvcConfigurer
继承了WebMvcConfigurerAdapter
大部分内容。
WebMvcConfigurer方法介绍
常用方法
//拦截器配置
void addInterceptors(InterceptorRegistry var1);
//视图跳转控制器
void addViewControllers(ViewControllerRegistry registry);
//静态资源处理
void addResourceHandlers(ResourceHandlerRegistry registry);
//默认静态资源处理器
void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer);
//这里配置视图解析器
void configureViewResolvers(ViewResolverRegistry registry);
//配置内容裁决的一些选项
void configureContentNegotiation(ContentNegotiationConfigurer configurer);
// 解决跨域问题
public void addCorsMappings(CorsRegistry registry) ;
//添加参数处理器
void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) ;
//添加返回值处理器
void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) ;
//添加消息转换器(Object->object)
void configureMessageConverters(List<HttpMessageConverter<?>> converters);
//添加格式转化器(String->Objrct)
void addFormatters(FormatterRegistry registry) ;
1.configurePathMatch
这个用到的比较少,这个是和访问路径有关的。举个例子,比如说PathMatchConfigurer
有个配置是setUseTrailingSlashMatch()
,如果设置为true的话(默认为true),后面加个斜杠并不影响路径访问,例如“/user”等同于“/user/”。我们在开发中很少在访问路径上搞事情,所以这个方法如果有需要的请自行研究吧。
// 用于在HandlerMappings中设置路径的匹配样式
public void configurePathMatch(PathMatchConfigurer configurer) {
// 配置是否使用通用后缀匹配符(".*")
// 如果设为true则当设置匹配"/users"时也会对"/users.*"进行匹配
// 默认值为true
configurer.setUseSuffixPatternMatch(true);
// 配置是否匹配url而不考虑是否存在拖尾斜杠
// 如果设为true则当匹配"/users"时也会匹配"/users/"
// 默认值为true
configurer.setUseTrailingSlashMatch(true);
// 配置是否后缀匹配模式只适用于显示注册的路径拓展
// 如果设置为true,当传递的路径参数中有特殊含义和作用的"."符号时框架不会对其进行处理
// 默认值为false
configurer.setUseRegisteredSuffixPatternMatch(true);
// 设置一个UrlPathHelper来帮助Spring解析路径
// 使用这个自定义的UrlPathHelper来覆盖默认的UrlPathHelper
// 或者是在多个HandlerMappings和MethodNameResolvers中共享UrlPathHelper
configurer.setUrlPathHelper(new UrlPathHelper());
// 设置一个PathMatcher用于匹配URL路径
// 默认的是AntPathMatcher
configurer.setPathMatcher(new AntPathMatcher());
// 设置一个路径前缀来匹配controller中的方法,
// 在Spring初始化阶段,如果第二个参数检测结果返回为true则
// "/prefix"会作为一个前缀添加到requestMapping的前面,
// 比如方法上的RequestMapping的注解为"/method",则这个方法
// 最终的匹配路径是"/prefix/method"
// 初始化的地方为RequestMappingHandler.getPathPrefix()
configurer.addPathPrefix("/prefix", (aClass) -> true);
}
2. configureContentNegotiation
这个东西直译叫做内容协商机制,主要是方便一个请求路径返回多个数据格式。ContentNegotiationConfigurer这个配置里面你会看到MediaType,里面有众多的格式。此方法不在多赘述。
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
// 设置解析用户请求的内容格式的策略,SpringMVC 默认加载两个该接口的实现类:
// ServletPathExtensionContentNegotiationStrategy–根据文件扩展名。
// HeaderContentNegotiationStrategy–根据HTTP Header里的Accept字段。
configurer.strategies(new ArrayList<>());
// 设置是否在URL中的path的拓展是否应该被用于作为被要求的内容格式
// 默认设置为true
// 如果一个请求的url为"/content.pdf"则会被认为是请求"application/pdf"
// 同时直接忽略"Accept"头中的格式
configurer.favorPathExtension(true);
// 向mediaTypes集合中添加,这里添加的顺序必须要是有序的以方便参数策略工作
// 在这里注册的所有的拓展名都是反射型文件下载攻击的白名单
configurer.mediaType("pdf", MediaType.APPLICATION_PDF)
.mediaType("json", MediaType.APPLICATION_JSON);
// 将一个hashMap中所有的键值对都作为内容格式加入configurer中
configurer.mediaTypes(new HashMap<>());
// 将原来记录的MediaTypes清除并更换为新的HashMap中的内容
configurer.replaceMediaTypes(new HashMap<>());
// 设置当无法找到相匹配的类型时是否忽略URL路径中的类型
// 设置为false则当找不到时会抛出HttpMediaTypeNotAcceptableException
// 默认设置为true
configurer.ignoreUnknownPathExtensions(true);
// 当favorPathExtension被设置的时候,这个方法被用于确认是否只使用被注册
// 的匹配类型来进行路径解析
// 默认未设置值
configurer.useRegisteredExtensionsOnly(true);
// 设置一个request的parameter是否会被解析为media type
// 如果要使用的话需要增加一个mediaType(String, MediaType)
// 默认设置为false
configurer.favorParameter(true);
// 设置要用于确定请求的媒体类型的参数的名称
// 默认值为"format"
configurer.parameterName("format");
// 设置时候禁止进行对request头的"Accept"的检查
// 默认未false
configurer.ignoreAcceptHeader(false);
// 设置当请求的类型没有匹配的时候的默认类型,按优先级顺序排序
// 如果想要支持所有的类型可以在最后使用MediaType.ALL
// 默认下没有任何设置
configurer.defaultContentType(MediaType.APPLICATION_JSON, MediaType.APPLICATION_PDF);
// 设置当没有任何类型被请求的时候的自定义类型处理策略
// 默认没有进行设置
configurer.defaultContentTypeStrategy(new PathExtensionContentNegotiationStrategy());
}
3. configureAsyncSupport
顾名思义,这是处理异步请求的。只能设置两个值,一个超时时间(毫秒,Tomcat下默认是10000毫秒,即10秒),还有一个是AsyncTaskExecutor,异步任务执行器。
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
// 设置一个异步线程池
// 默认使用SimpleAsyncTaskExecutor
configurer.setTaskExecutor(new SimpleAsyncTaskExecutor());
// 设置异步request等待被处理的超时时间
// 默认的大小为10秒
configurer.setDefaultTimeout(100);
// 设置Callable任务的拦截器
configurer.registerCallableInterceptors(new CallableProcessingInterceptor(){});
// 设置Callable任务的带有延迟的拦截器
configurer.registerDeferredResultInterceptors(new DeferredResultProcessingInterceptor() {});
}
4. configureDefaultServletHandling
这个接口可以实现静态文件可以像Servlet一样被访问。
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
// 激活默认的default servlet
// 默认的servlet由tomcat提供,一般的名字叫做"default",匹配路径为"/"
configurer.enable();
// 设置default servlet的名称
configurer.enable("default");
}
5. addFormatters
增加转化器或者格式化器。这边不仅可以把时间转化成你需要时区或者样式。还可以自定义转化器和你数据库做交互,比如传进来userId,经过转化可以拿到user对象。
//传入的FormatterRegister默认为WebConversionService
public void addFormatters(FormatterRegistry registry) {
// 增加一个formatter
registry.addFormatter(new CurrencyStyleFormatter());
// 增加一个为指定类型进行类型转换的formatter
registry.addFormatterForFieldType(String.class, new CurrencyStyleFormatter());
// 增加一个对注解进行formatter的FormatterFactory
registry.addFormatterForFieldAnnotation(new AnnotationFormatterFactory<Annotation>() {
@Override
public Set<Class<?>> getFieldTypes() {
return null;
}
@Override
public Printer<?> getPrinter(Annotation annotation, Class<?> fieldType) {
return null;
}
@Override
public Parser<?> getParser(Annotation annotation, Class<?> fieldType) {
return null;
}
});
}
6. addInterceptors
盼望着,盼望着,你一个常用的方法来了。这个方法可以自定义写拦截器,并指定拦截路径。
public void addInterceptors(InterceptorRegistry registry) {
// 增加一个拦截器
InterceptorRegistration interceptorRegistration = registry.addInterceptor(new HandlerInterceptor() {});
// 给拦截器拦截的pathPattern
interceptorRegistration.addPathPatterns("/pathPattern1", "/pathPattern2");
// 设置不拦截的pathPattern
interceptorRegistration.excludePathPatterns("/pathPattern1", "/pathPattern2");
// 给拦截器设置一个PathMatcher
interceptorRegistration.pathMatcher(new AntPathMatcher());
// 给拦截器设置一个顺序权重
interceptorRegistration.order(1);
// 增加一个对web请求的拦截器
registry.addWebRequestInterceptor(new WebRequestInterceptor() {
@Override
public void preHandle(WebRequest request) throws Exception { }
@Override
public void postHandle(WebRequest request, ModelMap model) throws Exception { }
@Override
public void afterCompletion(WebRequest request, Exception ex) throws Exception { }
});
}
7. addResourceHandlers
自定义资源映射。这个东西也比较常用,业务场景就是自己的服务器作为文件服务器,不利用第三方的图床,就需要一个虚拟路径映射到我们服务器的地址。值得一提的是,如果你的项目是war包启动,一般都是再Tomcat中配置一下(配置方法请百度);如果是jar包启动(SpringBoot经常用这种方式启动),就可以用到这个方法了。
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 增加一个资源处理器用于针对URL中对静态资源的调用
// 处理器将会对每一个匹配上的URL进行调用
// 允许使用诸如"/static/**"或者/css/{filename:\\w+\\.css}
ResourceHandlerRegistration registration = registry.addResourceHandler("/pathPatterns");
// 添加一个或多个资源地址用于处理静态资源的请求,多个静态资源库如果
// 有同样的文件会选择优先级高的
registration.addResourceLocations("/resourceLocation1", "/resourceLocation2");
// 设置静态资源处理器的缓存时间
// 0表示没有缓存,大于0的数表示缓存过期的秒数
registration.setCachePeriod(0);
// 设置一个缓存管理器,管理器中的缓存时间设置会覆盖上一步中设置的缓存过期时间
registration.setCacheControl(CacheControl.empty());
// 返回一个资源处理器链,设置为true表示使用缓存,推荐为true
ResourceChainRegistration resourceChainRegistration = registration.resourceChain(true);
// 给ResourceChain添加一个resolver
// ResourceResolver用于根据url解析获取静态文件
resourceChainRegistration.addResolver(new ResourceResolver() {
@Override
public Resource resolveResource(HttpServletRequest request, String requestPath, List<? extends Resource> locations, ResourceResolverChain chain) {
return null;
}
@Override
public String resolveUrlPath(String resourcePath, List<? extends Resource> locations, ResourceResolverChain chain) {
return null;
}
});
// 给resourceChain添加一个resourceTransformer
// resourceTransformer用于给返回的静态文件进行一些自定义修改
resourceChainRegistration.addTransformer(new ResourceTransformer() {
@Override
public Resource transform(HttpServletRequest request, Resource resource, ResourceTransformerChain transformerChain) throws IOException {
return null;
}
});
// 返回是否当前的pathPattern已经被注册
Boolean has = registry.hasMappingForPattern("/pathPattern");
// 为当前的资源处理器设置一个优先级
registry.setOrder(1);
}
8. addCorsMappings
这个是设置跨域问题的,几乎是每个后台服务器都需要配置的东西。
public void addCorsMappings(CorsRegistry registry) {
// 允许指定的pathPattern可以进行跨域请求
CorsRegistration corsRegistration = registry.addMapping("/pathPattern");
// 设置允许哪些可以进行跨域访问,设置为"*"表示允许所有
// 默认设置为允许所有
corsRegistration.allowedOrigins("http://domain1.com", "http://domain2.com");
// 设置允许的跨域请求动作,设置为"*"表示允许所有
// 默认设置为允许简单动作,包括GET POST HEAD
corsRegistration.allowedMethods("GET", "POST");
// 设置允许的请求头,默认设置为允许所有,即"*"
corsRegistration.allowedHeaders("Cache-Control", "Content-Language");
// 设置response的头结构,不支持"*"
corsRegistration.exposedHeaders("Cache-Control", "Content-Language");
// 设置浏览器是否需要发送认证信息
corsRegistration.allowCredentials(true);
// 设置客户端保存pre-flight request缓存的时间
// pre-flight request 预检请求
corsRegistration.maxAge(1);
}
9. addViewControllers
这个方法可以实现,一个路径自动跳转到一个页面。不过现在多为前后端分离的项目,是不是可以把跳转路由的问题直接扔给前端。
public void addViewControllers(ViewControllerRegistry registry) {
// 为指定的url设置一个viewController
ViewControllerRegistration viewControllerRegistration
= registry.addViewController("/admin/**");
// 为url设置返回值,默认值为200
viewControllerRegistration.setStatusCode(HttpStatus.valueOf(404));
// 设置真实有效的view名,如果不设置默认为null
viewControllerRegistration.setViewName("/foo/bar");
// 设置原url和跳转到的url
RedirectViewControllerRegistration redirectViewControllerRegistration
= registry.addRedirectViewController("/urlPath", "/redirectUrl");
// 设置跳转url的状态码,默认为302
redirectViewControllerRegistration.setStatusCode(HttpStatus.valueOf(302));
// 是否将以斜杠("/")开头的定重定向URL解释为相对于当前ServletContext
// 默认值为true
redirectViewControllerRegistration.setContextRelative(true);
//是否传播当前请求的查询参数,默认值为false
redirectViewControllerRegistration.setKeepQueryParams(true);
// 对于设置的url将直接返回状态码而不进行任何body的渲染
registry.addStatusController("/urlPath", HttpStatus.valueOf(404));
// 设置当前viewController的优先值,默认为1
// 注解的Controller的优先值为0
registry.setOrder(1);
}
10. configureViewResolvers
public void configureViewResolvers(ViewResolverRegistry registry) {
// 返回是否当前有resolver被注册
boolean has = registry.hasRegistrations();
// 启用contentNegotiatingViewResolver来前置所有其他配置的视图
// 解析器,并根据客户端请求的媒体类型在所有选择的视图中进行选择
registry.enableContentNegotiation();
// 启用contentNegotiatingViewResolver来前置所有其他配置的视图
// 解析器,并根据客户端请求的媒体类型在所有选择的视图中进行选择
registry.enableContentNegotiation(true);
}
11. addArgumentResolvers
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
// 添加一个方法参数处理器
resolvers.add(new HandlerMethodArgumentResolver() {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return false;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
return null;
}
});
}
12. addReturnValueHandlers
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {
// 添加一个方法返回值处理器
handlers.add(new HandlerMethodReturnValueHandler() {
@Override
public boolean supportsReturnType(MethodParameter returnType) {
return false;
}
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
}
});
}
13. configureMessageConverters
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
// 添加一个http消息转换器
converters.add(new ByteArrayHttpMessageConverter());
}
14. extendMessageConverters
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
// 用于扩展或修改已配置的转换器列表的钩子
converters.add(1, new ByteArrayHttpMessageConverter());
}
15. configureHandlerExceptionResolvers
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
// 添加一个处理异常的解析器
resolvers.add(new DefaultHandlerExceptionResolver());
}
16. extendHandlerExceptionResolvers
public void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
// 用于拓展活修改已经加入配置中的解析器
resolvers.add(1, new DefaultHandlerExceptionResolver());
}
17. getValidator
public Validator getValidator() {
return null;
}
18. getMessageCodesResolver
public MessageCodesResolver getMessageCodesResolver() {
return null;
}