当前位置: 首页 > news >正文

WebMvcConfigurer和WebMvcConfigurationSupport(MVC配置)

一:基本介绍

WebMvcConfigurer是接口,用于配置全局的SpringMVC的相关属性,采用JAVABean的方式来代替传统的XML配置文件,提供了跨域设置、静态资源处理器、类型转化器、自定义拦截器、页面跳转等能力。
WebMvcConfigurationSupport是webmvc的配置类,如果在springboot项目中,有配置类继承了WebMvcConfigurationSupport,那么webmvc的自动配置类WebMvcAutoConfiguration就会失效。

两者都是Spring MVC中的组件,具体的区别如下:

1.实现方式不同

WebMvcConfigurer:是一个接口,它提供了多个回调方法,可以用于自定义Spring MVC的配置(如消息转换器、拦截器等)。我们在使用时只需要实现该接口,重写其中的方法即可。
WebMvcConfigurationSupport:是一个抽象类,它也提供了多个回调方法,用于自定义Spring MVC的配置,但是需要继承该类并重写其中的方法。

2.作用不同

WebMvcConfigurer:
主要用于添加或修改Spring MVC的配置,如添加拦截器,自定义消息转换器等。
WebMvcConfigurationSupport:
主要用于完全自定义Spring MVC的配置,如果我们需要对Spring MVC的配置进行大量的自定义,可以选择继承该类并重写其中的方法。但是需要注意的是,继承该类会覆盖Spring MVC的部分默认配置。因此,当我们只需要对部分配置进行自定义时,应该使用WebMvcConfigurer。

3.继承关系不同

WebMvcConfigurer:
没有继承关系,我们只需要实现该接口即可使用。
WebMvcConfigurationSupport:
是一个抽象类,需要继承后才能使用。

4.总结

在日常开发中推荐优先使用WebMvcConfigurer的方式(官方推荐),因为简单方便,也没有特别复杂的定制需求;若我们项目中使用的MVC存在着更加复杂的配置需求推荐WebMvcConfigurationSupport,通过继承此类,我们可以说对官方的MVC代码进行重写操作,但是因为其配置量较大,实现比较复杂,因此在日常开发中使用WebMvcConfigurationSupport并不常见。

二:配置摘要

常用自定义配置如下:
1.addInterceptors(拦截器配置)
2.addCorsMappings(全局跨域处理)
3.addViewControllers(注册视图控制器)(可以让地址对应资源文件,如html文件)
4.addResourceHandlers(配置静态资源处理)(可以在客户端直接访问静态资源信息)

三:Spring和SpringBoot中配置步骤区别

1.Spring中配置WebMvcConfigurer方式:

①创建一个Java 类,实现WebMvcConfigurer接口

@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {// 自定义配置代码
}

②注入到Bean容器里

@Configuration
public class AppConfig {@Beanpublic MyWebMvcConfig myWebMvcConfig() {return new MyWebMvcConfig();}
}
2.SpringBoot中配置WebMvcConfigurer方式:(这种方式简单)

创建一个 Java 类,并实现WebMvcConfigurer接口

@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {// 自定义配置代码
}

四:拦截器(addInterceptors)

在SpringBoot中,可以使用拦截器来对请求进行统一的预处理或后处理。拦截器用于日志记录、权限检查、性能监控、事务控制等方面。SpringBoot中实现拦截器,首先要创建一个实现HandlerInterceptor接口的拦截器类。该接口定义了三个方法,分别是preHandle、postHandle和afterCompletion,用于在请求处理前、请求处理后和请求完成后进行处理。

1.HandlerInterceptor接口方法详解:

①preHandler
在请求处理之前被调用。该方法在Interceptor类中最先执行,用来进行一些前置初始化操作或是对当前请求做预处理,也可以进行一些判断来决定请求是否要继续进行下去。该方法的返回值是Boolean类型,当它返回false时,表示请求结束,后续的Interceptor和Controller都不会再执行;当它返回为true时会继续调用下一个Interceptor的preHandle方法,如果已经是最后一个Interceptor的时候就会调用当前请求的Controller方法。
②postHandler
在请求处理完成之后调用。也就是Controller方法调用之后执行,但是它会在DispatcherServlet进行视图返回渲染之前被调用,所以我们可以在这个方法中对Controller处理之后的ModelAndView对象进行操作。
③afterCompletion
在整个请求结束后调用。就是对应的Interceptor类的postHandler方法返回true时才执行。就是说该方法将在整个请求结束之后,
也就是在DispatcherServlet渲染了对应的视图之后执行。此方法主要用来进行资源清理。
注:官方其实不建议我们非要把3个方法都重写,我们只要对需要的方法重写接口,就比如大部分项目只需要重写preHandler方法

2.InterceptorRegistry类方法介绍:

①addInterceptor
该方法用于向拦截器链中添加一个拦截器。interceptor参数为待添加的拦截器对象,可以是自定义的拦截器类或Spring提供的预置拦截器。返回值为InterceptorRegistration对象,用于进一步配置该拦截器的属性。
②addWebRequestInterceptor
该方法用于向WebRequest拦截器链中添加一个拦截器。interceptor参数为待添加的拦截器对象,可以是自定义的WebRequestInterceptor类或者Spring提供的预置拦截器。也是返回值为InterceptorRegistration对象,用于进一步配置该拦截器的属性。
③getInterceptors
用于获取当前已经添加到拦截器链中的所有拦截器,返回值为List<HandlerInterceptor>对象,表示拦截器列表。

3.InterceptorRegistration类方法介绍:

①order
该方法用于设置拦截器的执行顺序,即在拦截器链中的位置。order参数为一个整数,值越小表示越先执行。
②addPathPatterns
该方法用于设置需要拦截的请求路径模式,即满足哪些请求路径时才会触发该拦截器。若"/**"则拦截全部;传入的参数是一个字符串数组,包含多个Ant风格的路径模式,例如"/api/**""/user/*"等。
③excludePathPatterns
该方法用于设置不需要拦截的请求路径模式,即满足哪些请求路径时不会触发该拦截器。一般不拦截,如登录或者Swagger等传入的参数是一个字符串数组,包含多个Ant风格的路径模式,例如 "/api/login""/user/login"等。
④pathMatcher
该方法用于设置该拦截器所使用的PathMatcher实例,从而可以自定义路径匹配逻辑。

注:拦截的路径或者放行的路径是以Controller开始的,如我们在application.yml配置的地址前缀则不包含

五:跨域(addCorsMappings)

参考:SpringBoot解决跨域的三种方式

1.CorsRegistry类方法介绍:

①addMapping
该方法用于添加允许跨域访问的路径,String类型,若存在多个路径则需要在CorsRegistry里配置多个

2.CorsRegistration类方法介绍:

CorsRegistration是CorsRegistry的辅助类,使用它可以对单个跨域请求进行更细粒度的配置。
①allowedOrigins(低版本使用,但是现在高版本也支持)
设置允许跨域请求的来源URL。该方法接受多个参数,每个参数为一个允许的来源URL。或者设置"*"
②allowedOriginPatterns(一般使用这种方式)
设置允许跨域请求的来源URL的模式。该方法接受多个参数,每个参数为一个允许的来源URL模式。或者设置"*"
③allowCredentials
设置是否允许跨域请求携带凭证信息。默认情况下,浏览器不会向跨域请求发送Cookie等凭证信息。如果希望携带凭证信息,则需要将allowCredentials方法设置为true。
④allowedMethods
设置允许跨域请求的HTTP方法。该方法接受多个参数,每个参数为一种允许的HTTP请求方式。
⑤allowedHeaders
设置允许请求携带的HTTP头信息。该方法接受多个参数,每个参数为一种允许的HTTP头信息。(放行哪些请求头部信息)
⑥exposedHeaders
设置响应头信息,这些信息允许客户端访问。该方法接受多个参数,每个参数为一种允许的响应头信息。(暴露哪些响应头信息)
⑦combine
将当前CorsRegistration对象与另一个CorsConfiguration对象合并,返回合并后的CorsConfiguration对象。可以使用该方法将多个CorsRegistration对象的配置合并到同一个CorsConfiguration对象中。
⑧maxAge
设置响应的缓存时间,单位为秒,默认30分钟。
例如,当设置maxAge为3600时,如果浏览器在一小时内再次向同一个目标URL发送跨域请求,就可以直接使用以前的预检请求结果,而不需要再次进行预检请求。maxAge属性只影响预检请求的缓存时间,而不会影响正常的跨域请求,因此不会对实际的业务逻辑产生影响。此外,maxAge属性的具体值需要根据实际情况进行调整,过小的缓存时间可能会导致频繁的预检请求,过大的缓存时间可能会使跨域请求的控制权得不到及时更新,从而增加安全风险。

六:注册页面跳转(addViewControllers)

addViewControllers方法是SpringMVC中WebMvcConfigurer接口定义的一个方法,用于注册一个简单的视图控制器,以便将请求路径映射到一个具体的视图页面。在一些简单的场景下,我们可能只需要将某个请求路径直接映射到一个固定的视图页面,而不需要进行额外的逻辑处理。此时,可以使用addViewControllers方法来快速注册一个视图控制器,并指定对应的请求路径和视图名称即可。但是我们需要额外注意的是,我们在SpringBoot中处理视图跳转时最好集成Thymeleaf,因为它是SpringBoot指定认可的并且,Thymeleaf与SpringMVC协同工作,可以方便地实现快速开发Web应用程序。

1.配置

在SpringBoot配置Thymeleaf的一些信息:
导入Thymeleaf坐标:

<!--导入SpringBoot集成Thymeleaf启动器-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

在application.yml配置Thymeleaf配置信息:

    spring:# 配置Thymeleaf模板(默认启动会请求/templates/index.html)thymeleaf:cache: false                      # 是否有模板缓存prefix: classpath:/templates/     # 模板放置的位置suffix: .html                     # 模板后缀mode: HTML                        # 模板类型encoding: UTF-8                   # 模板编码
2.ViewControllerRegistry类说明:

①addViewController(String urlPath)
通过urlPath参数指定的请求URL路径(例如"/home")注册一个简单的视图控制器,该方法返回一个ViewControllerRegistration对象,通过该对象可以设置相关属性,如视图名称、请求方式等。如:registry.addViewController(“/login”);
②setOrder(int order)
设置当前视图控制器的执行顺序,当有多个视图控制器针对同一请求路径时,可以使用该方法进行优先级排序。默认情况下,不同的视图控制器按照它们被注册的顺序执行。
③addRedirectViewController(String urlPath, String redirectUrl)
注册一个重定向视图控制器,将urlPath请求路径重定向到指定的重定向地址redirectUrl。
如:registry.addRedirectViewController(“/toBaidu”,“https://www.baidu.com”);

3.ViewControllerRegistration类说明:

①setViewName(String viewName)
资源路径的前缀
②setStatusCode(HttpStatus statusCode)
配置访问不存在资源的响应码,如下常见的:
HttpStatus.BAD_REQUEST:请求参数错误或格式不正确,例如缺少必需参数、参数类型错误等。
HttpStatus.UNAUTHORIZED:未经授权访问,需要用户登录或提供凭证。
HttpStatus.FORBIDDEN:已经授权但访问被禁止,通常意味着权限不足或需要进行进一步身份验证。
HttpStatus.NOT_FOUND:请求的资源不存在,通常使用自定义的404错误页面进行提示。
HttpStatus.METHOD_NOT_ALLOWED:请求方式不支持,例如GET请求访问只支持POST的接口时会返回405错误。
HttpStatus.INTERNAL_SERVER_ERROR:服务器内部错误,需要在后台进行排查和修复。
示例:registry.addViewController(“/**”).setStatusCode(HttpStatus.NOT_FOUND);
说明:访问不存在的页面我一律按照404处理,但是我们templates/error/404.html页面需要存在

注:按照之前配置的thymeleaf配置来说,默认根路径为resources/templates,跳转的资源文件都是.html文件

七:静态资源处理(addResourceHandlers)

addResourceHandlers方法是SpringMVC框架提供的一种配置静态资源的方式,它可以将指定的资源路径映射到一个或多个URL路径上,并指定资源的缓存策略、版本号以及是否允许目录列表等选项。具体来说,addResourceHandlers方法需要传入一个ResourceHandlerRegistry对象作为参数,然后在这个对象上调用addResourceHandler方法,来添加一个或多个处理器。

1.ResourceHandlerRegistry类方法介绍:

①addResourceHandler
该方法用于指定静态资源的URL路径,支持Ant风格的通配符,如"/resources/**"表示匹配所有以"/resources/"开头的请求。

2.ResourceHandlerRegistration类方法介绍:

①addResourceLocations
该方法为静态资源所在的物理路径或URL。可以使用多个addResourceLocations方法指定多个路径,如下例:

registry.addResourceHandler("/resources/**").addResourceLocations("classpath:/static/", "file:/opt/files/")

说明:
classpath:/static/表示在项目的Classpath下(即src/main/resources文件夹下)查找static文件夹,file:/opt/files/表示在系统中的/opt/files/目录下查找文件。

②setCacheControl
此方法用于设置缓存控制头(cache-control header),CacheControl是一个封装了缓存策略的类。例如:

CacheControl cc = CacheControl.maxAge(30, TimeUnit.DAYS).cachePublic();
registry.addResourceHandler("/resources/**").addResourceLocations("classpath:/static/").setCacheControl(cc);

说明:这将指示浏览器缓存静态资源30天,并且它们是public缓存,意味着中间代理服务器也可以缓存资源。
③setCachePeriod
该方法用于设置静态资源缓存时间,参数类型为Duration类型。如:

registry.addResourceHandler("/resources/**").addResourceLocations("classpath:/static/").setCachePeriod(Duration.ofMinutes(5));

说明:静态资源缓存的过期时间为5分钟
④setOptimizeLocations
此方法用于启用或禁用位置优化。如果启用位置优化,则将优化静态资源的位置,以便并发访问静态资源时可以获得更好的性能。默认情况下,位置优化是禁用的。
⑤setUseLastModified
此方法用于启用或禁用上次修改时间检查(last-modified check)。如果启用上次修改时间检查,则在每个请求中发送一个if-modified-since头,以检查是否需要返回新内容。默认情况下,上次修改时间检查是启用的。
⑥resourceChain
用于开启或关闭ResourceChain模式。当开启ResourceChain模式时,每个资源文件都会自动添加版本号,避免浏览器缓存问题。
例如:

registry.addResourceHandler("/resources/**").addResourceLocations("classpath:/static/").resourceChain(true);

注意,要使ResourceChain生效,还需要设置addResolver如:

.resourceChain(false)// 添加VersionResourceResolver,且指定版本号.addResolver(new VersionResourceResolver().addFixedVersionStrategy("1.0.0", "/**")); // 下次访问地址:http://localhost:8881/resources/1.0.0/xxx.css

八:代码示例(WebMvcConfigurer)

package com.syh.pdd.config.web;import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.*;import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;@Configuration
public class WebConfig implements WebMvcConfigurer {// 用户头像@Value("${file.userImage.writePath}")private String userImageWritePath;@Value("${file.userImage.readPath}")private String userImageReadPath;/*** 映射文件路径配置*/@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");registry.addResourceHandler("BJTPReadpath").addResourceLocations("file:"+ "BJTPSavepath");// 浏览器测试图片回显路径: http://IP:8080/file/ewm/Img/2023/10/12/图片名称.jpgregistry// 图片回显路径.addResourceHandler("file/ewm/Img/**")// 图片存放路径.addResourceLocations("file:D:/file/ewm/Img/");}}/*** 跨域配置添加*/@Overridepublic void addCorsMappings(CorsRegistry registry) {// 设置允许跨域的路径registry.addMapping("/**")// 设置允许跨域请求的域名//  .allowedOrigins("*").allowedOriginPatterns("*")// 是否允许证书 不再默认开启.allowCredentials(true)// 设置允许的方法.allowedMethods("*")// 跨域允许时间.maxAge(3600);}//解决中文乱码问题@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {//解决中文乱码converters.add(responseBodyConverter());//解决 添加解决中文乱码后 上述配置之后,返回json数据直接报错 500:no convertter for return value of typeconverters.add(messageConverter());}@Beanpublic HttpMessageConverter<String> responseBodyConverter(){StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));return converter;}@Beanpublic MappingJackson2HttpMessageConverter messageConverter() {MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();converter.setObjectMapper(getObjectMapper());return converter;}@Beanpublic ObjectMapper getObjectMapper() {return new ObjectMapper();}/***  格式化返回的内容*  https://my.oschina.net/u/3681868/blog/3075150* */@Overridepublic void extendMessageConverters(List<HttpMessageConverter<?>> converters) {MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();ObjectMapper objectMapper = converter.getObjectMapper();// 时间格式化objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));// 设置格式化内容converter.setObjectMapper(objectMapper);converters.add(0, converter);}/*** 添加Web项目的拦截器*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {//放行路径List<String> jwtExcludePatterns = new ArrayList();// 登录接口放行jwtExcludePatterns.add("/api/user/login");// 验证码放行jwtExcludePatterns.add("/api/user/getVerify/**");// 前端更换头像请求,没有走拦截器,此处放行jwtExcludePatterns.add("/api/user/updatePicture");// 对所有api开头的访问路径,都通过MyInterceptor拦截器进行拦截,MyInterceptor代码在下面registry.addInterceptor(new MyInterceptor()).addPathPatterns("/api/**").excludePathPatterns(jwtExcludePatterns);}/*解析器  使用方法在文章末尾*/@Overridepublic void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {WebMvcConfigurer.super.addArgumentResolvers(resolvers);}
}

九:代码示例(拦截器)

<dependency><groupId>net.minidev</groupId><artifactId>json-smart</artifactId>
</dependency>
<dependency><groupId>com.vaadin.external.google</groupId><artifactId>android-json</artifactId><version>0.0.20131108.vaadin1</version><scope>compile</scope>
</dependency>package com.syh.pdd.config.web;import com.syh.pdd.Utils.token.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import net.minidev.json.JSONObject;
import org.springframework.http.HttpMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;/*** 自定义拦截器类token认证* 注意:可以实现多个拦截器,只需要继续实现HandlerInterceptor即可            */
@Slf4j
public class MyInterceptor implements HandlerInterceptor {/*** 访问控制器方法前执行*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {// ==========!!!!!!注意注意注意   注意注意   注意注意   ========================/** 前端在请求的时候会发送一个OPTION请求来验证本次请求是否安全,* 但是springboot的拦截器会拦截所有请求。因为第一次是OPTION没有携带JWT,所以验证失败* */if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {return true;}// 获取tokenString token = request.getHeader("token");// 校验tokenif (JwtUtil.checkToken(token)) {log.info(request.getRequestURL() + ">>>" +new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "通过token验证");return true; // 放行} else{//设置response状态response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);response.setCharacterEncoding("UTF-8");response.setContentType("application/json; charset=utf-8");//设置失败响应数据JSONObject res = new JSONObject();res.put("status","101010");res.put("msg","登录过期,请重新登录");PrintWriter out = null ;out = response.getWriter();out.write(res.toString());out.flush();out.close();return false; // 拦截}}/*** 访问控制器方法后执行*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {}/*** postHandle方法执行完成后执行,一般用于释放资源*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {}
}/*** Web配置类*/
@Configuration
public class WebConfig implements WebMvcConfigurer {/*** 添加Web项目的拦截器*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {//放行路径List<String> jwtExcludePatterns = new ArrayList();// 登录接口放行jwtExcludePatterns.add("/system/user/login");// 验证码放行jwtExcludePatterns.add("/system/user/getVerify/**");// 对所有图片资源放行jwtExcludePatterns.add("/Project/saveFile/**");// 拦截路径:对所有访问路径,都通过MyInterceptor类型的拦截器进行拦截registry.addInterceptor(new MyInterceptor()).addPathPatterns("/**").excludePathPatterns(jwtExcludePatterns);}
}

十:代码示例(WebMvcConfigurationSupport)

package com.hssmart.config.web;import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.List;@Configuration
public class WebConfig extends WebMvcConfigurationSupport{// 自定义一个拦截器@AutowiredUserArgumentResolver userArgumentResolver;/*** 映射文件路径配置*/@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");/*** 说明:增加虚拟路径(经过本人测试:在此处配置的虚拟路径,用springboot内置的tomcat时有效,用外部的tomcat也有效;所以用到外部的tomcat时不需在tomcat/config下的相应文件配置虚拟路径了,阿里云linux也没问题)*///registry.addResourceHandler("/pic/**").addResourceLocations("file:E:/pic/");registry.addResourceHandler("BJTPReadpath").addResourceLocations("file:"+ "BJTPSavepath");//阿里云(映射路径去除盘符)//registry.addResourceHandler("/ueditor/image/**").addResourceLocations("/upload/image/");//registry.addResourceHandler("/ueditor/video/**").addResourceLocations("/upload/video/");//用户图片路径registry.addResourceHandler("/Project/saveFile/user/userImg/**"(网络路径,其实可以任意定义)).addResourceLocations("file:D:/JAVA/Project/saveFile/user/userImg/"(储存路径));super.addResourceHandlers(registry);}/*** 跨域配置添加*/@Overridepublic void addCorsMappings(CorsRegistry registry) {// 设置允许跨域的路径registry.addMapping("/**")// 设置允许跨域请求的域名.allowedOrigins("*")// 是否允许证书 不再默认开启.allowCredentials(true)// 设置允许的方法 springboot较高版本不能使用*号// .allowedMethods("GET", "POST", "PUT", "OPTIONS", "DELETE", "PATCH").allowedMethods("*")// 跨域允许时间.maxAge(3600);}//解决中文乱码问题@Overridepublic void configureMessageConverters(List<HttpMessageConverter<?>> converters) {super.configureMessageConverters(converters);//解决中文乱码converters.add(responseBodyConverter());//解决 添加解决中文乱码后 上述配置之后,返回json数据直接报错 500:no convertter for return value of typeconverters.add(messageConverter());}@Beanpublic HttpMessageConverter<String> responseBodyConverter(){StringHttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8"));return converter;}@Beanpublic MappingJackson2HttpMessageConverter messageConverter() {MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();converter.setObjectMapper(getObjectMapper());return converter;}@Beanpublic ObjectMapper getObjectMapper() {return new ObjectMapper();}/***  格式化返回的内容(格式转换器)*  https://my.oschina.net/u/3681868/blog/3075150* */@Overridepublic void extendMessageConverters(List<HttpMessageConverter<?>> converters) {MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();ObjectMapper objectMapper = converter.getObjectMapper();// 生成JSON时,将所有Long转换成String//SimpleModule simpleModule = new SimpleModule();//simpleModule.addSerializer(Long.class, ToStringSerializer.instance);//simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);//objectMapper.registerModule(simpleModule);// 时间格式化objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));// 设置格式化内容converter.setObjectMapper(objectMapper);converters.add(0, converter);}/*** 解析器,该方法可实现可不实现,需要自定义。作用在调用Controller方法的参数传入之前,有返回值*/@Overridepublic void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {// userArgumentResolver该类对Controller传入的参数做了具体处理resolvers.add(userArgumentResolver);}}

自定义解析器

@Configuration
public class UserArgumentResolver implements HandlerMethodArgumentResolver {@AutowiredUserservice userservice;// 此方法返回true,下面的参数才会执行@Overridepublic boolean supportsParameter(MethodParameter methodParameter) {// 获取传入参数的类型Class<?> type = methodParameter.getParameterType();// 如果参数类型有为User类的则符合,进入resolveArgument方法if (UserPojo.class == type) {return true;}return false;}// 该方法为拦截方法,将结果返回给controller@Overridepublic Object resolveArgument(MethodParameter methodParameter,ModelAndViewContainer modelAndViewContainer,NativeWebRequest nativeWebRequest,WebDataBinderFactory webDataBinderFactory) throws Exception {HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);HttpServletResponse response = nativeWebRequest.getNativeResponse(HttpServletResponse.class);String userTick = CookieUtil.getCookieValue(request, "userTicket");if (StringUtils.isBlank(userTick)) {return null;}UserPojo userPojo = userservice.getUserByCookie(userTick, request, response);if (userPojo == null) {return null;}return userPojo;}
}@GetMapping("goods")
public Result showGoods(UserPojo user){// 注意:这里的User参数不是由前端传入的,而是由addArgumentResolvers方法处理之后传进来的log.info(user.toString());// 根据处理之后传入的参数判断是否登录if (user == null)return Result.error();return Result.ok();
}

相关文章:

WebMvcConfigurer和WebMvcConfigurationSupport(MVC配置)

一:基本介绍 WebMvcConfigurer是接口&#xff0c;用于配置全局的SpringMVC的相关属性&#xff0c;采用JAVABean的方式来代替传统的XML配置文件&#xff0c;提供了跨域设置、静态资源处理器、类型转化器、自定义拦截器、页面跳转等能力。 WebMvcConfigurationSupport是webmvc的…...

用 javascript 来回答宇宙外面是什么

宇宙外面是什么呢? 估计这个问题要困扰很多人, 让我们用一段 javascript 代码来回答一下. 一, 从一段代码说起 var 地球 {名字 : "地球",女友 : "月亮",外面 : {名字 : "太阳系",老大 : "太阳",老二 : {名字 : "木星",二…...

我的性能优化经验

专业方向&#xff1a;App cpu/memory/gpu/流畅度/响应时间的优化&#xff0c;Anr&#xff0c;Framework CarPowerManagementService模块的&#xff08;STR&#xff09;&#xff0c;从0~1完成性能监控体系搭建&#xff0c;完成3大版本迭代高质量性能交付 响应时间&#xff1a; …...

XSLT 编辑 XML

XSLT 编辑 XML 介绍 XSLT&#xff08;可扩展样式表语言转换&#xff09;是一种用于转换XML文档的语言。它允许开发人员将XML数据转换为其他格式&#xff0c;如HTML、PDF或纯文本。XSLT通过使用XPath查询来定位XML文档中的元素&#xff0c;并对这些元素应用转换规则。在本教程…...

数智读书笔记系列010 生命3.0:人工智能时代 人类的进化与重生

书名&#xff1a;生命3.0 生命3.0&#xff1a;人工智能时代,人类的进化与重生 著者&#xff1a;&#xff3b;美&#xff3d;迈克斯•泰格马克 迈克斯・泰格马克 教育背景与职业 教育背景&#xff1a;迈克斯・泰格马克毕业于麻省理工学院&#xff0c;获物理学博士学位。职业经…...

Transfomer的各层矩阵

一、输入 输入一句话&#xff1a;Hello CYZLAB the inspired world 每个单词为一个token 二、Embedding 这里的词向量维度为6&#xff0c;矩阵的行数为token数&#xff0c;列数是词向量的维度 这列是注释不算hello122694CYZLAB222372the222596inspired132440world431273 …...

代码随想录第51天

99.岛屿数量 深搜 import java.util.*;class Main{static int[][] directions {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};static boolean[][] visited;public static void main(String[] args) {Scanner sc new Scanner(System.in);int n sc.nextInt();int m sc.nextInt();int…...

基础库httpx的使用

urllib 库和 requests 库的使用&#xff0c;已经可以爬取绝大多数网站的数据&#xff0c;但对于某些网站依然无能为力。什么情况?这些网站强制使用HTTP/2.0协议访问&#xff0c;这时 urllib 和requests 是无法爬取数据的&#xff0c;因为它们只支持 HTTP/1.1&#xff0c;不支持…...

c++中如何保持结构体的线程安全?3D坐标的线程安全:从理论到最优解

使用mutex的困扰 struct Point3d {std::mutex mtx;double x, y, z;void set(double nx, double ny, double nz) {std::lock_guard<std::mutex> lock(mtx);x nx; y ny; z nz;} };这种方案虽然安全&#xff0c;但性能开销确实不小。每次访问都需要加锁解锁&#xff0c;…...

Zabbix6.0升级为6.4

为了体验一些新的功能&#xff0c;比如 Webhook 和问题抑制等&#xff0c;升级个小版本。 一、环境信息 1. 版本要求 一定要事先查看官方文档&#xff0c;确认组件要求的版本&#xff0c;否则版本过高或者过低都会出现问题。 2. 升级前后信息 环境升级前升级后操作系统CentOS…...

答题考试系统v1.6.1高级版源码分享+uniapp+搭建测试环境

一.系统介绍 一款基于FastAdminThinkPHPUniapp开发的小程序答题考试系统&#xff0c;支持多种试题类型、多种试题难度、练题、考试、补考模式&#xff0c;提供全部前后台无加密源代码&#xff0c;支持私有化部署 二.测试环境 系统环境&#xff1a;CentOS、 运行环境&#x…...

【Lua热更新】下篇 -- 更新中

上篇链接&#xff1a;【Lua热更新】上篇 文章目录 三、xLua热更新&#x1f4d6;1.概述&#x1f4da;︎2.导入xLua框架&#x1f516;3. C#调用Lua3.1Lua解析器3.2Lua文件夹的重定向3.3Lua解析器管理器3.4全局变量获取3.5全局函数获取3.6映射到List和Dictionary3.7映射到类3.8映…...

射频测试入门学习(三)——程控仪器是怎样和电脑连接通信的

目录 一、程控仪器需要哪些条件 二、可程控仪器 三、专业的仪器通信软件、驱动 四、编程语言 五、电脑控制仪器条件汇总 六、仪器指令查询 七、结语 一、程控仪器需要哪些条件 1、需要具备硬件条件(可程控的仪器、个人计算机(PC)) 2、专业的仪器通信软件、驱动 3、…...

并发控制之Semaphore

Semaphore 作用 信号量&#xff0c;用于控制同时访问特定资源的线程数量&#xff0c;通过协调各个线程&#xff0c;以确保对共享资源的访问不会导致冲突或数据不一致等问题&#xff0c;有点类似令牌桶&#xff0c;内部维护一组许可证&#xff0c; acquire获取许可证&#xf…...

第R3周:RNN-心脏病预测

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 &#x1f37a;要求&#xff1a; 1 本地读取并加载数据。 2 了解循环神经网络&#xff08;RNN&#xff09;的构建过程 3 测试集accuracy到达87% &#x1f37b;拔…...

【数值特性库】入口文件

数值特性库入口文件为lib.rs。该文件定义一系列数字特性的trait&#xff08;特征&#xff09;&#xff0c;这些特性可以被不同的数字类型实现&#xff0c;从而提供一套通用的数值操作方法。下面是对代码中关键部分的解释&#xff1a; 一、基础设置 #![doc(html_root_url “h…...

RestTemplate实时接收Chunked编码传输的HTTP Response

学习调用AI接口的时候&#xff0c;流式响应都是使用的 Transfer-Encoding: chunked&#xff0c;图方便想用RestTemplate&#xff0c;但是平时用到的都是直接返回响应对象的类型。使用bing搜索到一种方式&#xff0c;使用下面的代码来读取&#xff0c;于是掉这个坑里了&#xff…...

GIT区域介绍及码云+GIt配置仓库

GIT区域介绍 创建文件夹git init 1、git有3个区域 工作区&#xff08;working directory&#xff09;&#xff1a;项目的根目录&#xff0c;不包 括.git在内的其他文件暂存区&#xff08;stage area&#xff09;&#xff1a;是一个看不见的区域&#xff0c;git add 命令就是将文…...

网络安全怎么学习

当我们谈论网络安全时&#xff0c;我们正在讨论的是保护我们的在线空间&#xff0c;这是我们所有人的共享责任。网络安全涉及保护我们的信息&#xff0c;防止被未经授权的人访问、披露、破坏或修改。 一、网络安全的基本概念 网络安全是一种保护&#xff1a;它涉及保护我们的设…...

PugiXML,一个高效且简单的 C++ XML 解析库!

嗨&#xff0c;大家好&#xff01;我是一行。今天要给大家介绍 PugiXML&#xff0c;这可是 C 里处理 XML 数据的得力助手。它能轻松地读取、修改和写入 XML 文件&#xff0c;就像一个专业的 XML 小管家&#xff0c;不管是解析配置文件&#xff0c;还是处理网页数据&#xff0c;…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

【Java_EE】Spring MVC

目录 Spring Web MVC ​编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 ​编辑参数重命名 RequestParam ​编辑​编辑传递集合 RequestParam 传递JSON数据 ​编辑RequestBody ​…...

数据库分批入库

今天在工作中&#xff0c;遇到一个问题&#xff0c;就是分批查询的时候&#xff0c;由于批次过大导致出现了一些问题&#xff0c;一下是问题描述和解决方案&#xff1a; 示例&#xff1a; // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

Mysql中select查询语句的执行过程

目录 1、介绍 1.1、组件介绍 1.2、Sql执行顺序 2、执行流程 2.1. 连接与认证 2.2. 查询缓存 2.3. 语法解析&#xff08;Parser&#xff09; 2.4、执行sql 1. 预处理&#xff08;Preprocessor&#xff09; 2. 查询优化器&#xff08;Optimizer&#xff09; 3. 执行器…...

A2A JS SDK 完整教程:快速入门指南

目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库&#xff…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用

文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么&#xff1f;1.1.2 感知机的工作原理 1.2 感知机的简单应用&#xff1a;基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...

Python竞赛环境搭建全攻略

Python环境搭建竞赛技术文章大纲 竞赛背景与意义 竞赛的目的与价值Python在竞赛中的应用场景环境搭建对竞赛效率的影响 竞赛环境需求分析 常见竞赛类型&#xff08;算法、数据分析、机器学习等&#xff09;不同竞赛对Python版本及库的要求硬件与操作系统的兼容性问题 Pyth…...

如何配置一个sql server使得其它用户可以通过excel odbc获取数据

要让其他用户通过 Excel 使用 ODBC 连接到 SQL Server 获取数据&#xff0c;你需要完成以下配置步骤&#xff1a; ✅ 一、在 SQL Server 端配置&#xff08;服务器设置&#xff09; 1. 启用 TCP/IP 协议 打开 “SQL Server 配置管理器”。导航到&#xff1a;SQL Server 网络配…...

Python常用模块:time、os、shutil与flask初探

一、Flask初探 & PyCharm终端配置 目的: 快速搭建小型Web服务器以提供数据。 工具: 第三方Web框架 Flask (需 pip install flask 安装)。 安装 Flask: 建议: 使用 PyCharm 内置的 Terminal (模拟命令行) 进行安装,避免频繁切换。 PyCharm Terminal 配置建议: 打开 Py…...