金华高端网站设计,wordpress建站产品导入不同目录,广告外链购买交易平台,微信链接的微网站怎么做一、简介 WebMvcConfigurer配置类其实是Spring内部的一种配置方式#xff0c;采用JavaBean的形式来代替传统的xml配置文件形式进行针对框架个性化定制#xff0c;可以自定义一些Handler#xff0c;Interceptor#xff0c;ViewResolver#xff0c;MessageConverter。基于ja…
一、简介 WebMvcConfigurer配置类其实是Spring内部的一种配置方式采用JavaBean的形式来代替传统的xml配置文件形式进行针对框架个性化定制可以自定义一些HandlerInterceptorViewResolverMessageConverter。基于java-based方式的spring mvc配置需要创建一个配置类并实现WebMvcConfigurer 接口 在Spring Boot 1.5版本都是靠重写WebMvcConfigurerAdapter的方法来添加自定义拦截器消息转换器等。SpringBoot 2.0 后该类被标记为Deprecated弃用。 官方推荐直接实现WebMvcConfigurer或者直接继承WebMvcConfigurationSupport方式一实现WebMvcConfigurer接口推荐方式二继承WebMvcConfigurationSupport类具体实现可看这篇文章。https://blog.csdn.net/fmwind/article/details/82832758 二、WebMvcConfigurerAdapter类被弃用后的两种选择 1、过时方式继承WebMvcConfigurerAdapter
Spring 5.0 以后WebMvcConfigurerAdapter会取消掉。 WebMvcConfigurerAdapter是实现WebMvcConfigurer接口
Configuration public class WebConfig extends WebMvcConfigurerAdapter { //TODO }
2、现用方式
1实现WebMvcConfigurer
Configuration public class WebMvcConfg implements WebMvcConfigurer { //TODO }
2现用方式继承WebMvcConfigurationSupport
Configuration public class WebMvcConfg extends WebMvcConfigurationSupport { //TODO }
3、另外参考
WebMvcConfigurerAdapter类被弃用后的两种选择 - 掘金 三、WebMvcConfigurer接口
全部接口
public interface WebMvcConfigurer {void configurePathMatch(PathMatchConfigurer var1);void configureContentNegotiation(ContentNegotiationConfigurer var1);void configureAsyncSupport(AsyncSupportConfigurer var1);void configureDefaultServletHandling(DefaultServletHandlerConfigurer var1);void addFormatters(FormatterRegistry var1);void addInterceptors(InterceptorRegistry var1);void addResourceHandlers(ResourceHandlerRegistry var1);void addCorsMappings(CorsRegistry var1);void addViewControllers(ViewControllerRegistry var1);void configureViewResolvers(ViewResolverRegistry var1);void addArgumentResolvers(ListHandlerMethodArgumentResolver var1);void addReturnValueHandlers(ListHandlerMethodReturnValueHandler var1);void configureMessageConverters(ListHttpMessageConverter? var1);void extendMessageConverters(ListHttpMessageConverter? var1);void configureHandlerExceptionResolvers(ListHandlerExceptionResolver var1);void extendHandlerExceptionResolvers(ListHandlerExceptionResolver var1);Validator getValidator();MessageCodesResolver getMessageCodesResolver();
}常用的方法 /* 拦截器配置 */
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) ;
四、接口说明
2.1 addInterceptors拦截器
addInterceptor需要一个实现HandlerInterceptor接口的拦截器实例addPathPatterns用于设置拦截器的过滤路径规则addPathPatterns(/**)对所有请求都拦截excludePathPatterns用于设置不需要拦截的过滤规则拦截器主要用途进行用户登录状态的拦截日志的拦截等。
Override
public void addInterceptors(InterceptorRegistry registry) {super.addInterceptors(registry);registry.addInterceptor(new TestInterceptor()).addPathPatterns(/**).excludePathPatterns(/emp/toLogin,/emp/login,/js/**,/css/**,/images/**);
}
例如此方法用来专门注册一个Interceptor如HandlerInterceptorAdapter
Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new MyInterceptor()).addPathPatterns(/**).excludePathPatterns(/emp/toLogin,/emp/login,/js/**,/css/**,/images/**);}
}
addPathPatterns(/**)对所有请求都拦截但是排除了/toLogin和/login请求的拦截。当spring boot版本升级为2.x时访问静态资源就会被HandlerInterceptor拦截,网上有很多处理办法都是如下写法.excludePathPatterns(/index.html,/,/user/login,/static/**);
2.2 addViewControllers页面跳转 以前写SpringMVC的时候如果需要访问一个页面必须要写Controller类然后再写一个方法跳转到页面感觉好麻烦其实重写WebMvcConfigurer中的addViewControllers方法即可达到效果了
Override
public void addViewControllers(ViewControllerRegistry registry) {registry.addViewController(/toLogin).setViewName(login);
} 值的指出的是在这里重写addViewControllers方法并不会覆盖WebMvcAutoConfigurationSpringboot自动配置中的addViewControllers在此方法中Spring Boot将“/”映射至index.html这也就意味着自己的配置和Spring Boot的自动配置同时有效这也是我们推荐添加自己的MVC配置的方式。
2.3 addResourceHandlers静态资源 比如我们想自定义静态资源映射目录的话只需重写addResourceHandlers方法即可。 注如果继承WebMvcConfigurationSupport类实现配置时必须要重写该方法具体见其它文章。
Configuration
public class MyWebMvcConfigurerAdapter implements WebMvcConfigurer {/*** 配置静态访问资源* param registry*/Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler(/my/**).addResourceLocations(classpath:/my/);}
} 通过addResourceHandler添加映射路径然后通过addResourceLocations来指定路径。我们访问自定义my文件夹中的elephant.jpg 图片的地址为 http://localhost:8080/my/elephant.jpg 如果你想指定外部的目录也很简单直接addResourceLocations指定即可代码如下
Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler(/my/**).addResourceLocations(file:E:/my/);
}
addResoureHandler指的是对外暴露的访问路径addResourceLocations指的是内部文件放置的目录
2.4 configureDefaultServletHandling默认静态资源处理器
Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {configurer.enable();configurer.enable(defaultServletName);
} 此时会注册一个默认的HandlerDefaultServletHttpRequestHandler这个Handler也是用来处理静态文件的它会尝试映射/。当DispatcherServelt映射/时/ 和/ 是有区别的并且没有找到合适的Handler来处理请求时就会交给DefaultServletHttpRequestHandler 来处理。注意这里的静态资源是放置在web根目录下而非WEB-INF 下。 可能这里的描述有点不好懂我自己也这么觉得所以简单举个例子例如在webroot目录下有一个图片1.png 我们知道Servelt规范中web根目录webroot下的文件可以直接访问的但是由于DispatcherServlet配置了映射路径是/ 它几乎把所有的请求都拦截了从而导致1.png 访问不到这时注册一个DefaultServletHttpRequestHandler 就可以解决这个问题。其实可以理解为DispatcherServlet破坏了Servlet的一个特性根目录下的文件可以直接访问DefaultServletHttpRequestHandler是帮助回归这个特性的。 2.5 configureViewResolvers视图解析器 这个方法是用来配置视图解析器的该方法的参数ViewResolverRegistry 是一个注册器用来注册你想自定义的视图解析器等。ViewResolverRegistry 常用的几个方法Spring Boot配置接口 WebMvcConfigurer_实现webmvcconfigurer-CSDN博客 /*** 配置请求视图映射* return*/
Bean
public InternalResourceViewResolver resourceViewResolver()
{InternalResourceViewResolver internalResourceViewResolver new InternalResourceViewResolver();//请求视图文件的前缀地址internalResourceViewResolver.setPrefix(/WEB-INF/jsp/);//请求视图文件的后缀internalResourceViewResolver.setSuffix(.jsp);return internalResourceViewResolver;
}/*** 视图配置* param registry*/
Override
public void configureViewResolvers(ViewResolverRegistry registry) {super.configureViewResolvers(registry);registry.viewResolver(resourceViewResolver());/*registry.jsp(/WEB-INF/jsp/,.jsp);*/
} 从方法名称我们就能看出这个方法是用来配置视图解析器的该方法的参数ViewResolverRegistry 是一个注册器用来注册你想自定义的视图解析器等。ViewResolverRegistry 常用的几个方法
)enableContentNegotiation()
/** 启用内容裁决视图解析器*/ public void enableContentNegotiation(View... defaultViews) { initContentNegotiatingViewResolver(defaultViews); } 该方法会创建一个内容裁决解析器ContentNegotiatingViewResolver 该解析器不进行具体视图的解析而是管理你注册的所有视图解析器所有的视图会先经过它进行解析然后由它来决定具体使用哪个解析器进行解析。具体的映射规则是根据请求的media types来决定的。
2).UrlBasedViewResolverRegistration() public UrlBasedViewResolverRegistration jsp(String prefix, String suffix) { InternalResourceViewResolver resolver new InternalResourceViewResolver(); resolver.setPrefix(prefix); resolver.setSuffix(suffix); this.viewResolvers.add(resolver); return new UrlBasedViewResolverRegistration(resolver); } 该方法会注册一个内部资源视图解析器InternalResourceViewResolver 显然访问的所有jsp都是它进行解析的。该方法参数用来指定路径的前缀和文件后缀如
registry.jsp(/WEB-INF/jsp/, .jsp); 对于以上配置假如返回的视图名称是example它会返回/WEB-INF/jsp/example.jsp给前端找不到则报404。
3). beanName() public void beanName() { BeanNameViewResolver resolver new BeanNameViewResolver(); this.viewResolvers.add(resolver); } 该方法会注册一个BeanNameViewResolver 视图解析器这个解析器是干嘛的呢它主要是将视图名称解析成对应的bean。什么意思呢假如返回的视图名称是example它会到spring容器中找有没有一个叫example的bean并且这个bean是View.class类型的如果有返回这个bean。
4).viewResolver() public void viewResolver(ViewResolver viewResolver) { if (viewResolver instanceof ContentNegotiatingViewResolver) { throw new BeanInitializationException( addViewResolver cannot be used to configure a ContentNegotiatingViewResolver. Please use the method enableContentNegotiation instead.); } this.viewResolvers.add(viewResolver); } 这个方法想必看名字就知道了它就是用来注册各种各样的视图解析器的包括自己定义的。 2.6 configureContentNegotiation配置内容裁决的一些参数 上面我们讲了configureViewResolvers 方法假如在该方法中我们启用了内容裁决解析器那么configureContentNegotiation(ContentNegotiationConfigurer configurer) 这个方法是专门用来配置内容裁决的一些参数的。这个比较简单我们直接通过一个例子看 public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { /* 是否通过请求Url的扩展名来决定media type */ configurer.favorPathExtension(true) /* 不检查Accept请求头 */ .ignoreAcceptHeader(true) .parameterName(mediaType) /* 设置默认的media yype */ .defaultContentType(MediaType.TEXT_HTML) /* 请求以.html结尾的会被当成MediaType.TEXT_HTML*/ .mediaType(html, MediaType.TEXT_HTML) /* 请求以.json结尾的会被当成MediaType.APPLICATION_JSON*/ .mediaType(json, MediaType.APPLICATION_JSON); } 到这里我们就可以举个例子来进一步熟悉下我们上面讲的知识了假如我们MVC的配置如下
EnableWebMvc Configuration public class MyWebMvcConfigurerAdapte extends WebMvcConfigurerAdapter { Override public void configureViewResolvers(ViewResolverRegistry registry) { registry.jsp(/WEB-INF/jsp/, .jsp); registry.enableContentNegotiation(new MappingJackson2JsonView()); } Override public void configureContentNegotiation(ContentNegotiationConfigurer configurer) { configurer.favorPathExtension(true) .ignoreAcceptHeader(true) .parameterName(mediaType) .defaultContentType(MediaType.TEXT_HTML) .mediaType(html, MediaType.TEXT_HTML) .mediaType(json, MediaType.APPLICATION_JSON); } } controller的代码如下: Controller public class ExampleController { RequestMapping(/test) public ModelAndView test() { MapString, String map new HashMap(); map.put(哈哈, 哈哈哈哈); map.put(呵呵, 呵呵呵呵); return new ModelAndView(test, map); } } 在WEB-INF/jsp目录下创建一个test.jsp文件内容随意。现在启动tomcat在浏览器输入以下链接http://localhost:8080/test.json浏览器内容返回如下
{ 哈哈:哈哈哈哈, 呵呵:呵呵呵呵 } 在浏览器输入http://localhost:8080/test 或者http://localhost:8080/test.html内容返回如下
this is test.jsp 显然两次使用了不同的视图解析器那么底层到底发生了什么在配置里我们注册了两个视图解析器ContentNegotiatingViewResolver 和 InternalResourceViewResolver还有一个默认视图MappingJackson2JsonView。controller执行完毕之后返回一个ModelAndView其中视图的名称为example1。
1.返回首先会交给ContentNegotiatingViewResolver 进行视图解析处理而ContentNegotiatingViewResolver 会先把视图名example1交给它持有的所有ViewResolver尝试进行解析本实例中只有InternalResourceViewResolver2.根据请求的mediaType再将example1.mediaType这里是example1.json 和example1.html作为视图名让所有视图解析器解析一遍两步解析完毕之后会获得一堆候选的ListView 再加上默认的MappingJackson2JsonView 3.根据请求的media type从候选的ListView 中选择一个最佳的返回至此视图解析完毕。现在就可以理解上例中为何请求链接加上.json 和不.json 结果会不一样。当加上.json 时表示请求的media type 为MediaType.APPLICATION_JSON而InternalResourceViewResolver 解析出来的视图的ContentType与其不符而与MappingJackson2JsonView 的ContentType相符所以选择了MappingJackson2JsonView 作为视图返回。当不加.json 请求时默认的media type 为MediaType.TEXT_HTML所以就使用了InternalResourceViewResolver解析出来的视图作为返回值了。我想看到这里你已经大致可以自定义视图了。
2.7 addCorsMappings跨域 通常为统一配置解决跨域问题提供了两种代码第一种比较短是通过创建MyWebMvcConfig类实现WebMvcConfigurer接口中的addCorsMappings方法。
具体的代码如下
Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping(/**).allowedOriginPatterns(*).allowedMethods(GET, HEAD, POST, PUT, DELETE, OPTIONS).allowCredentials(true).maxAge(3600).allowedHeaders(*);}
} 因为代码较短作为新手自然也喜欢更加简洁的代码这在项目开始阶段似乎能够解决问题。 但是后续如果添加自定义的拦截器包括Spring securityaddCorsMappings方法实现的统一跨域配置就会失效其原因在于请求经过的先后顺序 当请求到来时会先进入拦截器中而不是进入Mapping映射中所以返回的头信息中并没有配置的跨域信息。浏览器就会报跨域异常。 第二种方法实现一个CORS拦截器 既然请求会先进入拦截器中那么你可以尝试“以毒攻毒”实现一个CORS拦截器 Configuration
public class GlobalCorsConfig {Beanpublic CorsFilter corsFilter() {//1.添加CORS配置信息CorsConfiguration config new CorsConfiguration();//放行任意原始域。放行单个原始域。使用config.addAllowedOrigin(yourdomain.com)config.addAllowedOriginPattern(*);//是否发送Cookie信息config.setAllowCredentials(true);//放行哪些请求方式。放行任意请求方式可以使用config.addAllowedMethod(*)config.addAllowedMethod(OPTIONS);config.addAllowedMethod(HEAD);config.addAllowedMethod(GET);config.addAllowedMethod(PUT);config.addAllowedMethod(POST);config.addAllowedMethod(DELETE);config.addAllowedMethod(PATCH);//放行任意请求头config.addAllowedHeader(*);//2.添加映射路径UrlBasedCorsConfigurationSource configSource new UrlBasedCorsConfigurationSource();configSource.registerCorsConfiguration(/**, config);//3.返回新的CorsFilter.return new CorsFilter(configSource);}
}
2.8 configureMessageConverters信息转换器
/**
* 消息内容转换配置* 配置fastJson返回json转换* param converters*/
Override
public void configureMessageConverters(ListHttpMessageConverter? converters) {//调用父类的配置super.configureMessageConverters(converters);//创建fastJson消息转换器FastJsonHttpMessageConverter fastConverter new FastJsonHttpMessageConverter();//创建配置类FastJsonConfig fastJsonConfig new FastJsonConfig();//修改配置返回内容的过滤fastJsonConfig.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect,SerializerFeature.WriteMapNullValue,SerializerFeature.WriteNullStringAsEmpty);fastConverter.setFastJsonConfig(fastJsonConfig);//将fastjson添加到视图消息转换器列表内converters.add(fastConverter);}
2.9 addArgumentResolvers参数解析器 在Springboot中的WebMvcConfigurer接口在Web开发中经常被使用例如配置拦截器、配置ViewController、配置Cors跨域等。本文主要讲解另一个方法addArgumentResolvers()在实例中的应用。
1、方法作用 该方法可以用在对于Controller中方法参数传入之前对该参数进行处理。然后将处理好的参数在传给Controller中的方法。 官方API文档解释添加解析器以支持自定义控制器方法参数类型。 这不会覆盖对解析处理程序方法参数的内置支持。要自定义对参数解析的内置支持请RequestMappingHandlerAdapter直接配置。
2、场景描述 在权限场景中通常会有要求用户登录之后才能访问的场景。对于这些问题可以多种解决方案如使用CookieSession的会话控制、使用拦截器、使用SpringSecurity或shiro等权限管理框架等。 这里使用CookieSession处理。处理的逻辑为 用户第一次登录之后会得到一个cookie在以后每次的访问过程中都会携带Cookie进行访问。在后台的Controller中对于需要登录权限的访问接口都要先获取Cookie中的Token再使用Token从session中获取用户登录信息来判断用户登录情况决定是否放行。
3、存在问题 如果在每个需要登录权限访问的方法中都要写这个逻辑就会使代码重复出现了冗余。代码基本如下
GetMapping(goods)
public Result showGoods1(HttpSession session, CookieValue(Token) String token){// 你每次都要在这里判断token或sessionif (token null || MyObjectUtil.isEmpty(session.getAttribute(token))){return Result.error();}return Result.ok();
}所以需要寻找是否有更好的解决方法。
最终找到addArgumentResolvers()这个方法。只需要在这个方法中进行处理即可。
4、问题解决
该方法的处理流程如下 代码如下 Controller中的方法 GetMapping(goods)
public Result showGoods(User user){// 注意这里的User参数不是由前端传入的而是由addArgumentResolvers方法处理之后传进来的log.info(user.toString());// 根据处理之后传入的参数判断是否登录if (user null)return Result.error();return Result.ok();
}WebMvcController实现了类 Configuration
public class WebConfig implements WebMvcConfigurer {Autowiredprivate UserArgumentResolver userArgumentResolver;/*** 该方法作用在调用Controller方法的参数传入之前* param resolvers*/Overridepublic void addArgumentResolvers(ListHandlerMethodArgumentResolver resolvers) {// userArgumentResolver该类对Controller传入的参数做了具体处理resolvers.add(UserArgumentResolver);}// 其他配置
}UserArgumentResolver自定义实现类 /*** 该类用于WebConfig配置类的addArgumentResolvers方法传入*/
Component
public class UserArgumentResolver implements HandlerMethodArgumentResolver {/*** 该方法用于判断Controller中方法参数中是否有符合条件的参数* 有则进入下一个方法resolveArgument* 没有则跳过不做处理* param parameter* return*/Overridepublic boolean supportsParameter(MethodParameter parameter) {// 获取传入参数的类型Class? type parameter.getParameterType();// 如果参数类型有为User类的则符合,进入resolveArgument方法if (User.class type)return true;return false;}/*** 该方法在上一个方法同通过之后调用* 在这里可以进行处理根据情况返回对象——返回的对象将被赋值到Controller的方法的参数中* param parameter* param mavContainer* param webRequest* param binderFactory* return* throws Exception*/Overridepublic Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {HttpServletRequest request webRequest.getNativeRequest(HttpServletRequest.class);HttpSession session request.getSession();// 获取cookieCookie[] cookies request.getCookies();String token null;for (Cookie c : cookies){if (c.getName().equals(token)){token c.getValue();break;}}// 如果token不存在则返回nullif (token null) return null;// 获取session中对象User user (User)session.getAttribute(token);return user;}
} 参考
Spring Boot配置接口 WebMvcConfigurer_实现webmvcconfigurer-CSDN博客
SpringBoot——》WebMvcConfigurerAdapter详解-CSDN博客
https://www.cnblogs.com/wurao/p/15556787.html
WebMvcConfigurer addArgumentResolvers() 添加参数解析器 - 人人编程网