目录

简介

依赖

常用接口详解

路径匹配规则:configurePathMatch

异步调用支持:configureAsyncSupport

☆☆☆静态资源处理器:addResourceHandlers

静态资源默认处理器:configureDefaultServletHandling

格式化器和转换器:addFormatters

☆☆☆拦截器:addInterceptors

☆☆☆跨域设置:addCorsMappings

方式一:重写WebMvcConfigurer里的addCorsMappings。

方式二:使用过滤器配置配置跨域

☆☆☆视图控制器:addViewControllers

☆☆☆视图解析器:configureViewResolvers

☆☆☆参数解析器:addArgumentResolvers

☆☆☆返回值处理器: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);
	}
}

以上内容为个人学习理解,如有问题,欢迎在评论区指出。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐