目录
☆☆☆静态资源处理器:addResourceHandlers
静态资源默认处理器:configureDefaultServletHandling
方式一:重写WebMvcConfigurer里的addCorsMappings。
☆☆☆视图解析器:configureViewResolvers
☆☆☆返回值处理器:addReturnValueHandlers
简介
WebMvcConfigurer是一个接口,里面提供了很多web应用常用的拦截方法。通过实现该接口,可以实现web应用 跨域设置、类型转化器、自定义拦截器、页面跳转等功能。
@Configuration
@EnableWebMvc
public class MyWebMvcConfigurer implements WebMvcConfigurer {
}
依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.6.7</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.19</version>
</dependency>
常用接口详解
路径匹配规则:configurePathMatch
设置前端请求url与后端接口url的匹配规则。
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
// 默认为true,是否使用尾斜杠匹配:如果设置为true,则“/hello”和“/hello/”都能匹配
configurer.setUseTrailingSlashMatch(false);
// 为所有RestController接口添加统一前缀api:如果controller的url为“/hello” --> "/api/hello"
configurer.addPathPrefix("api", c -> c.isAnnotationPresent(RestController.class));
// UrlPathHelper是一个处理url地址的帮助类,里面自带了一些优化url的方法;
// 比如:getSanitizedPath,就是将// 换成/。所以我们在输入地址栏的时候,//也是没有问题的,
UrlPathHelper urlPathHelper = new UrlPathHelper();
configurer.setUrlPathHelper(urlPathHelper);
// 路径匹配器 PathMatcher是一个接口,springmvc默认使用的是AntPathMatcher
// configurer.setPathMatcher();
}
异步调用支持:configureAsyncSupport
配置异步请求处理选项,可以设置超时时间和异步调用执行器。
@Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
//核心线程数
threadPoolTaskExecutor.setCorePoolSize(5);
threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true);
//最大线程数
threadPoolTaskExecutor.setMaxPoolSize(5);
//配置队列大小
threadPoolTaskExecutor.setQueueCapacity(50);
//配置线程池前缀
threadPoolTaskExecutor.setThreadNamePrefix("async-service-");
threadPoolTaskExecutor.initialize();
// 设置异步调用执行器(线程池)
configurer.setTaskExecutor(threadPoolTaskExecutor);
// 设置超时时间
configurer.setDefaultTimeout(20000);
}
☆☆☆静态资源处理器:addResourceHandlers
自定义静态资源映射目录。
addResourceHandler:对外暴露的访问路径
addResourceLocations:映射内部文件放置的目录,以“/”结尾
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 如果url请求为/resource_test/hello.html,就会去test_file路径下找hello.html文件
registry.addResourceHandler("/resource_test/**")
.addResourceLocations("classpath:/test_file/");
}
静态资源默认处理器:configureDefaultServletHandling
简单地说,configureDefaultServletHandling是配置静态资源不拦截。
如果已经重写了addResourceHandlers方法,基本上就不需要再覆盖configureDefaultServletHandling,因为此时已经覆盖并提供了静态资源映射。
如果覆盖configureDefaultServletHandling方法并启用它,此时会注册一个默认的Handler:DefaultServletHttpRequestHandler,这个Handler也是用来处理静态文件的,它会尝试映射/。当DispatcherServelt映射/时(/ 和/ 是有区别的),并且没有找到合适的Handler来处理请求时,就会交给DefaultServletHttpRequestHandler 来处理。
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
configurer.enable("MyDefaultServletName");
}
格式化器和转换器:addFormatters
增加转换器或格式化器:web入参时,可以将前端入参类型转换为另一种类型再接收。或者是对前端入参进行一些全局的自定义处理。
Formatter和Converter都能将一种类型转换为另一种类型,不同的是Formatter的源类型必须是一个String。而Converter可以自定义源类型和转换类型 。
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new Formatter<Integer>() {
@Override
public Integer parse(String text, Locale locale) {
return text.equals("小明") ? 0 : 1;
}
@Override
public String print(Integer object, Locale locale) {
return object == 0 ? "小明123" : "小红123";
}
});
// registry.addConverter(new Converter<String, Integer>() {
// @Override
// public Integer convert(String source) {
// return source.equals("只要998") ? 998 : 999;
// }
// });
}
☆☆☆拦截器:addInterceptors
为web请求增加拦截器,可以对指定url请求做一些自定义处理:比如权限校验、登录判断等。
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 增加一个拦截器,可以对拦截请求做一些自定义处理
registry.addInterceptor(new HandlerInterceptor() {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Object user = request.getSession().getAttribute("loginUser");
if(user == null){ //未登陆,返回登陆页面
request.setAttribute("msg","没有权限请先登陆");
request.getRequestDispatcher("/index.html").forward(request,response);
return false;
}else{ //已登陆,放行请求
return true;
}
}
})
// 设置拦截器的过滤路径规则:只拦截/admin/形式的请求
.addPathPatterns("/admin/**")
// 设置不需要拦截的过滤规则:不拦截/admin/login请求
.excludePathPatterns("/admin/login");
}
☆☆☆跨域设置:addCorsMappings
方式一:重写WebMvcConfigurer里的addCorsMappings。
如果已经为请求配置了拦截器,该跨域设置不会生效。
当请求进入后台时,会先进入拦截器,当拦截器验证通过之后,才会执行跨域。因此我们需要让跨域在拦截器之前执行,而过滤器会比拦截器先执行,所以我们可以使用方式二中的CorsFilter进行跨域配置。
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
.allowCredentials(true)
.allowedHeaders("*")
.maxAge(3600);
}
方式二:使用过滤器配置配置跨域
private CorsConfiguration corsConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.setAllowedMethods(Arrays.asList("POST", "GET", "PUT", "OPTIONS", "DELETE"));
corsConfiguration.setAllowCredentials(true);
corsConfiguration.setMaxAge(3600L);
return corsConfiguration;
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", corsConfig());
return new CorsFilter(source);
}
☆☆☆视图控制器:addViewControllers
页面跳转:如果controller逻辑只是一个页面跳转逻辑,则可以使用addViewControllers以减少控制器代码的编写。
@Override
public void addViewControllers(ViewControllerRegistry registry) {
// 如果请求url为/test,则直接跳转到hello页面
registry.addViewController("/test").setViewName("hello");
}
☆☆☆视图解析器:configureViewResolvers
自定义视图解析器。
视图解析器:将逻辑视图解析成物理视图。
比如:controller返回一个"hello"逻辑视图,经过下列代码解析后,就会根据/WEB-INF/jsp/xxx.jsp去查找对应地址的视图文件,再将xxx.jsp返回给前端。
/**
* 配置请求视图映射
* @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) {
registry.viewResolver(resourceViewResolver());
/*registry.jsp("/WEB-INF/jsp/",".jsp");*/
}
☆☆☆参数解析器:addArgumentResolvers
通常用于在Controller中方法参数传入之前对参数进行处理,然后将处理后的参数传给controller方法中的参数。
// 自定义注解
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AdminParam {
}
// MyUser实例类
@Data
@ToString
@AllArgsConstructor
public class MyUser {
private String userName;
private String age;
}
// 测试controller
@GetMapping("/admin")
public String admin(@AdminParam MyUser myUser) {
// myUser对象不由前端传入,而是由参数解析器根据请求头中的信息获取。
return myUser.toString();
}
// 自定义参数解析器,当参数有@AdminParam注解时,返回当前用户给controlller参数
@Component
public class MyHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
// 判断参数是否需要进行参数解析
// 可以根据参数类型、是否有指定注解等来决定是否进行参数解析
return parameter.hasParameterAnnotation(AdminParam.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
// 这里方便测试,直接构造了一个虚拟User,实际情况可以根据token解析用户信息。
MyUser myUser = new MyUser("jack", "25");
return myUser;
}
}
@Configuration
@EnableWebMvc
public class MyWebMvcConfigurer implements WebMvcConfigurer {
@Autowired
private HandlerMethodArgumentResolver myHandlerMethodArgumentResolver;
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
// 注册参数解析器
resolvers.add(myHandlerMethodArgumentResolver);
}
}
☆☆☆返回值处理器:addReturnValueHandlers
通常用于对controller的返回对象作统一的封装,处理controller返回的数据后再将数据返回该前端。
@Data
@AllArgsConstructor
public class ResponseResult {
private int code;
private Object content;
private String message;
}
@Component
public class MyHandlerMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
@Override
public boolean supportsReturnType(MethodParameter returnType) {
// 当controller方法有@AdminParam注解时,执行handlerReturnValue处理逻辑
return !ObjectUtils.isEmpty(returnType.getAnnotatedElement().getAnnotation(AdminParam.class));
}
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
// 构造ResponseResult标准返回对象返回结果
ResponseResult result = new ResponseResult(200, returnValue, "success");
response.getWriter().write(JSON.toJSONString(result));
}
}
@Configuration
@EnableWebMvc
public class MyWebMvcConfigurer implements WebMvcConfigurer {
@Autowired
private HandlerMethodReturnValueHandler myHandlerMethodReturnValueHandler;
@Override
public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {
handlers.add(myHandlerMethodReturnValueHandler);
}
}
以上内容为个人学习理解,如有问题,欢迎在评论区指出。