当前位置:   article > 正文

WebMvcConfigurer 和 WebMvcConfigurationSupport

webmvcconfigurationsupport

一、前言 

WebMvcConfigurer 是一个接口,用于配置全局的SpringMVC的相关属性,采用JAVABean的方式来代替传统的XML配置文件,提供了跨域设置、静态资源处理器、类型转化器、自定义拦截器、页面跳转等能力。

WebMvcConfigurationSupport是webmvc的配置类,如果在springboot项目中,有配置类继承了WebMvcConfigurationSupport,那么webmvc的自动配置类WebMvcAutoConfiguration就会失效。

官方推荐直接实现WebMvcConfigurer 或者 继承WebMvcConfigurationSupport,

方式一:实现WebMvcConfigurer接口(推荐),方式二:继承WebMvcConfigurationSupport(/səˈpɔːt/)类。 

二、WebMvcConfigurer 

  1. package com.syh.pdd.config.web;
  2. import com.fasterxml.jackson.databind.DeserializationFeature;
  3. import com.fasterxml.jackson.databind.ObjectMapper;
  4. import org.springframework.beans.factory.annotation.Value;
  5. import org.springframework.context.annotation.Bean;
  6. import org.springframework.context.annotation.Configuration;
  7. import org.springframework.http.converter.HttpMessageConverter;
  8. import org.springframework.http.converter.StringHttpMessageConverter;
  9. import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
  10. import org.springframework.web.method.support.HandlerMethodArgumentResolver;
  11. import org.springframework.web.servlet.config.annotation.*;
  12. import java.nio.charset.Charset;
  13. import java.text.SimpleDateFormat;
  14. import java.util.ArrayList;
  15. import java.util.List;
  16. @Configuration
  17. public class WebConfig implements WebMvcConfigurer {
  18. // 用户头像
  19. @Value("${file.userImage.writePath}")
  20. private String userImageWritePath;
  21. @Value("${file.userImage.readPath}")
  22. private String userImageReadPath;
  23. /**
  24. * 映射文件路径配置
  25. */
  26. @Override
  27. public void addResourceHandlers(ResourceHandlerRegistry registry) {
  28. registry.addResourceHandler("/webjars/**")
  29. .addResourceLocations("classpath:/META-INF/resources/webjars/");
  30. registry.addResourceHandler("BJTPReadpath")
  31. .addResourceLocations("file:"+ "BJTPSavepath");
  32. // 浏览器测试图片回显路径: http://IP:8080/file/ewm/Img/2023/10/12/图片名称.jpg
  33. registry
  34. // 图片回显路径
  35. .addResourceHandler("file/ewm/Img/**")
  36. // 图片存放路径
  37. .addResourceLocations("file:D:/file/ewm/Img/");
  38. }
  39. }
  40. /**
  41. * 跨域配置添加
  42. */
  43. @Override
  44. public void addCorsMappings(CorsRegistry registry) {
  45. // 设置允许跨域的路径
  46. registry.addMapping("/**")
  47. // 设置允许跨域请求的域名
  48. // .allowedOrigins("*")
  49. .allowedOriginPatterns("*")
  50. // 是否允许证书 不再默认开启
  51. .allowCredentials(true)
  52. // 设置允许的方法
  53. .allowedMethods("*")
  54. // 跨域允许时间
  55. .maxAge(3600);
  56. }
  57. //解决中文乱码问题
  58. @Override
  59. public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
  60. //解决中文乱码
  61. converters.add(responseBodyConverter());
  62. //解决 添加解决中文乱码后 上述配置之后,返回json数据直接报错 500:no convertter for return value of type
  63. converters.add(messageConverter());
  64. }
  65. @Bean
  66. public HttpMessageConverter<String> responseBodyConverter(){
  67. StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
  68. return converter;
  69. }
  70. @Bean
  71. public MappingJackson2HttpMessageConverter messageConverter() {
  72. MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
  73. converter.setObjectMapper(getObjectMapper());
  74. return converter;
  75. }
  76. @Bean
  77. public ObjectMapper getObjectMapper() {
  78. return new ObjectMapper();
  79. }
  80. /**
  81. * 格式化返回的内容
  82. * https://my.oschina.net/u/3681868/blog/3075150
  83. * */
  84. @Override
  85. public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
  86. MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
  87. ObjectMapper objectMapper = converter.getObjectMapper();
  88. // 时间格式化
  89. objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
  90. objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
  91. // 设置格式化内容
  92. converter.setObjectMapper(objectMapper);
  93. converters.add(0, converter);
  94. }
  95. /**
  96. * 添加Web项目的拦截器
  97. */
  98. @Override
  99. public void addInterceptors(InterceptorRegistry registry) {
  100. //放行路径
  101. List<String> jwtExcludePatterns = new ArrayList();
  102. // 登录接口放行
  103. jwtExcludePatterns.add("/api/user/login");
  104. // 验证码放行
  105. jwtExcludePatterns.add("/api/user/getVerify/**");
  106. // 前端更换头像请求,没有走拦截器,此处放行
  107. jwtExcludePatterns.add("/api/user/updatePicture");
  108. // 对所有api开头的访问路径,都通过MyInterceptor拦截器进行拦截,MyInterceptor代码在下面
  109. registry.addInterceptor(new MyInterceptor()).addPathPatterns("/api/**")
  110. .excludePathPatterns(jwtExcludePatterns);
  111. }
  112. /*解析器 使用方法在文章末尾*/
  113. @Override
  114. public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
  115. WebMvcConfigurer.super.addArgumentResolvers(resolvers);
  116. }
  117. }

1、自定义拦截器

什么是拦截器:在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。拦截是AOP的一种实现策略

为什么需要拦截器:在做身份认证或者是进行日志的记录时,我们需要通过拦截器达到我们的目的。最常用的登录拦截、或是权限校验、或是防重复提交、或是根据业务像12306去校验购票时间,总之可以去做很多的事情

  1. <dependency>
  2. <groupId>net.minidev</groupId>
  3. <artifactId>json-smart</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>com.vaadin.external.google</groupId>
  7. <artifactId>android-json</artifactId>
  8. <version>0.0.20131108.vaadin1</version>
  9. <scope>compile</scope>
  10. </dependency>
  1. package com.syh.pdd.config.web;
  2. import com.syh.pdd.Utils.token.JwtUtil;
  3. import lombok.extern.slf4j.Slf4j;
  4. import net.minidev.json.JSONObject;
  5. import org.springframework.http.HttpMethod;
  6. import org.springframework.web.servlet.HandlerInterceptor;
  7. import org.springframework.web.servlet.ModelAndView;
  8. import javax.servlet.http.HttpServletRequest;
  9. import javax.servlet.http.HttpServletResponse;
  10. import java.io.IOException;
  11. import java.io.PrintWriter;
  12. import java.text.SimpleDateFormat;
  13. import java.util.Date;
  14. /**
  15. * 自定义拦截器类token认证
  16. * 注意:可以实现多个拦截器,只需要继续实现HandlerInterceptor即可
  17. */
  18. @Slf4j
  19. public class MyInterceptor implements HandlerInterceptor {
  20. /**
  21. * 访问控制器方法前执行
  22. */
  23. @Override
  24. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
  25. // ==========!!!!!!注意注意注意 注意注意 注意注意 ========================
  26. /*
  27. * 前端在请求的时候会发送一个OPTION请求来验证本次请求是否安全,
  28. * 但是springboot的拦截器会拦截所有请求。因为第一次是OPTION没有携带JWT,所以验证失败
  29. * */
  30. if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
  31. return true;
  32. }
  33. // 获取token
  34. String token = request.getHeader("token");
  35. // 校验token
  36. if (JwtUtil.checkToken(token)) {
  37. log.info(request.getRequestURL() + ">>>" +
  38. new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "通过token验证");
  39. return true; // 放行
  40. } else{
  41. //设置response状态
  42. response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
  43. response.setCharacterEncoding("UTF-8");
  44. response.setContentType("application/json; charset=utf-8");
  45. //设置失败响应数据
  46. JSONObject res = new JSONObject();
  47. res.put("status","101010");
  48. res.put("msg","登录过期,请重新登录");
  49. PrintWriter out = null ;
  50. out = response.getWriter();
  51. out.write(res.toString());
  52. out.flush();
  53. out.close();
  54. return false; // 拦截
  55. }
  56. }
  57. /**
  58. * 访问控制器方法后执行
  59. */
  60. @Override
  61. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
  62. }
  63. /**
  64. * postHandle方法执行完成后执行,一般用于释放资源
  65. */
  66. @Override
  67. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
  68. }
  69. }
  1. /**
  2. * Web配置类
  3. */
  4. @Configuration
  5. public class WebConfig implements WebMvcConfigurer {
  6. /**
  7. * 添加Web项目的拦截器
  8. */
  9. @Override
  10. public void addInterceptors(InterceptorRegistry registry) {
  11. //放行路径
  12. List<String> jwtExcludePatterns = new ArrayList();
  13. // 登录接口放行
  14. jwtExcludePatterns.add("/system/user/login");
  15. // 验证码放行
  16. jwtExcludePatterns.add("/system/user/getVerify/**");
  17. // 对所有图片资源放行
  18. jwtExcludePatterns.add("/Project/saveFile/**");
  19. // 拦截路径:对所有访问路径,都通过MyInterceptor类型的拦截器进行拦截
  20. registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**")
  21. .excludePathPatterns(jwtExcludePatterns);
  22. }
  23. }

三、WebMvcConfigurationSupport

  1. package com.hssmart.config.web;
  2. import com.fasterxml.jackson.databind.DeserializationFeature;
  3. import com.fasterxml.jackson.databind.ObjectMapper;
  4. import org.springframework.beans.factory.annotation.Value;
  5. import org.springframework.context.annotation.Bean;
  6. import org.springframework.context.annotation.Configuration;
  7. import org.springframework.http.converter.HttpMessageConverter;
  8. import org.springframework.http.converter.StringHttpMessageConverter;
  9. import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
  10. import org.springframework.web.servlet.config.annotation.CorsRegistry;
  11. import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
  12. import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
  13. import java.nio.charset.Charset;
  14. import java.text.SimpleDateFormat;
  15. import java.util.List;
  16. @Configuration
  17. public class WebConfig extends WebMvcConfigurationSupport{
  18. // 自定义一个拦截器
  19. @Autowired
  20. UserArgumentResolver userArgumentResolver;
  21. /**
  22. * 映射文件路径配置
  23. */
  24. @Override
  25. protected void addResourceHandlers(ResourceHandlerRegistry registry) {
  26. registry.addResourceHandler("swagger-ui.html")
  27. .addResourceLocations("classpath:/META-INF/resources/");
  28. registry.addResourceHandler("/webjars/**")
  29. .addResourceLocations("classpath:/META-INF/resources/webjars/");
  30. /**
  31. * 说明:增加虚拟路径(经过本人测试:在此处配置的虚拟路径,用springboot内置的tomcat时有效,
  32. 用外部的tomcat也有效;所以用到外部的tomcat时不需在tomcat/config下的相应文件配置虚拟路径了,阿里云linux也没问题)
  33. */
  34. //registry.addResourceHandler("/pic/**").addResourceLocations("file:E:/pic/");
  35. registry.addResourceHandler("BJTPReadpath")
  36. .addResourceLocations("file:"+ "BJTPSavepath");
  37. //阿里云(映射路径去除盘符)
  38. //registry.addResourceHandler("/ueditor/image/**").addResourceLocations("/upload/image/");
  39. //registry.addResourceHandler("/ueditor/video/**").addResourceLocations("/upload/video/");
  40. //用户图片路径
  41. registry.addResourceHandler("/Project/saveFile/user/userImg/**"(网络路径,其实可以任意定义))
  42. .addResourceLocations("file:D:/JAVA/Project/saveFile/user/userImg/"(储存路径));
  43. super.addResourceHandlers(registry);
  44. }
  45. /**
  46. * 跨域配置添加
  47. */
  48. @Override
  49. public void addCorsMappings(CorsRegistry registry) {
  50. // 设置允许跨域的路径
  51. registry.addMapping("/**")
  52. // 设置允许跨域请求的域名
  53. .allowedOrigins("*")
  54. // 是否允许证书 不再默认开启
  55. .allowCredentials(true)
  56. // 设置允许的方法 springboot较高版本不能使用*号
  57. // .allowedMethods("GET", "POST", "PUT", "OPTIONS", "DELETE", "PATCH")
  58. .allowedMethods("*")
  59. // 跨域允许时间
  60. .maxAge(3600);
  61. }
  62. //解决中文乱码问题
  63. @Override
  64. public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
  65. super.configureMessageConverters(converters);
  66. //解决中文乱码
  67. converters.add(responseBodyConverter());
  68. //解决 添加解决中文乱码后 上述配置之后,返回json数据直接报错 500:no convertter for return value of type
  69. converters.add(messageConverter());
  70. }
  71. @Bean
  72. public HttpMessageConverter<String> responseBodyConverter(){
  73. StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));
  74. return converter;
  75. }
  76. @Bean
  77. public MappingJackson2HttpMessageConverter messageConverter() {
  78. MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
  79. converter.setObjectMapper(getObjectMapper());
  80. return converter;
  81. }
  82. @Bean
  83. public ObjectMapper getObjectMapper() {
  84. return new ObjectMapper();
  85. }
  86. /**
  87. * 格式化返回的内容(格式转换器)
  88. * https://my.oschina.net/u/3681868/blog/3075150
  89. * */
  90. @Override
  91. public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
  92. MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
  93. ObjectMapper objectMapper = converter.getObjectMapper();
  94. // 生成JSON时,将所有Long转换成String
  95. //SimpleModule simpleModule = new SimpleModule();
  96. //simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
  97. //simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
  98. //objectMapper.registerModule(simpleModule);
  99. // 时间格式化
  100. objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
  101. objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
  102. // 设置格式化内容
  103. converter.setObjectMapper(objectMapper);
  104. converters.add(0, converter);
  105. }
  106. /**
  107. * 解析器,该方法可实现可不实现,需要自定义。作用在调用Controller方法的参数传入之前,有返回值
  108. */
  109. @Override
  110. public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
  111. // userArgumentResolver该类对Controller传入的参数做了具体处理
  112. resolvers.add(userArgumentResolver);
  113. }
  114. }

1、解析器

(1)自定义解析器

  1. @Configuration
  2. public class UserArgumentResolver implements HandlerMethodArgumentResolver {
  3. @Autowired
  4. Userservice userservice;
  5. // 此方法返回true,下面的参数才会执行
  6. @Override
  7. public boolean supportsParameter(MethodParameter methodParameter) {
  8. // 获取传入参数的类型
  9. Class<?> type = methodParameter.getParameterType();
  10. // 如果参数类型有为User类的则符合,进入resolveArgument方法
  11. if (UserPojo.class == type) {
  12. return true;
  13. }
  14. return false;
  15. }
  16. // 该方法为拦截方法,将结果返回给controller
  17. @Override
  18. public Object resolveArgument(MethodParameter methodParameter,
  19. ModelAndViewContainer modelAndViewContainer,
  20. NativeWebRequest nativeWebRequest,
  21. WebDataBinderFactory webDataBinderFactory) throws Exception {
  22. HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
  23. HttpServletResponse response = nativeWebRequest.getNativeResponse(HttpServletResponse.class);
  24. String userTick = CookieUtil.getCookieValue(request, "userTicket");
  25. if (StringUtils.isBlank(userTick)) {
  26. return null;
  27. }
  28. UserPojo userPojo = userservice.getUserByCookie(userTick, request, response);
  29. if (userPojo == null) {
  30. return null;
  31. }
  32. return userPojo;
  33. }
  34. }

(2)在controller中使用

  1. @GetMapping("goods")
  2. public Result showGoods(UserPojo user){
  3. // 注意:这里的User参数不是由前端传入的,而是由addArgumentResolvers方法处理之后传进来的
  4. log.info(user.toString());
  5. // 根据处理之后传入的参数判断是否登录
  6. if (user == null)
  7. return Result.error();
  8. return Result.ok();
  9. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/576393
推荐阅读
相关标签
  

闽ICP备14008679号