最近同事问我,spring boot集成了swagger,可是在使用拦截器的时候遇到了问题,页面没法访问。通过研究解决了这个问题。html
集成swagger就不啰嗦了,网上处处都是,直接看配置。java
同事从网上找到的配置:web
import com.xxx.xxxx.xxx.xxx.LoginInterceptor; import com.fasterxml.classmate.TypeResolver; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.ResponseEntity; import org.springframework.web.context.request.async.DeferredResult; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.schema.WildcardType; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.Contact; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; import java.util.Collections; import static springfox.documentation.schema.AlternateTypeRules.newRule; @Configuration @EnableSwagger2 public class Swagger2Config extends WebMvcConfigurationSupport { @Autowired private TypeResolver typeResolver; @Bean public Docket productApi() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.basePackage("com.xxx.xxx.controller")) .paths(PathSelectors.any()) .build() .apiInfo(metaData()) .alternateTypeRules( //自定义规则,若是遇到DeferredResult,则把泛型类转成json newRule(typeResolver.resolve(DeferredResult.class, typeResolver.resolve(ResponseEntity.class, WildcardType.class)), typeResolver.resolve(WildcardType.class))) ; } private ApiInfo metaData() { return new ApiInfoBuilder() .title("通用服务 APIs") /*.description("\"REST API for Online Store\"")*/ .version("1.0.0") /* .license("Apache License Version 2.0") .licenseUrl("https://www.apache.org/licenses/LICENSE-2.0\"")*/ .contact(new Contact("易保科技", "", "mail@mail")) .build(); } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("swagger-ui.html") .addResourceLocations("classpath:/META-INF/resources/"); registry.addResourceHandler("/webjars/**") .addResourceLocations("classpath:/META-INF/resources/webjars/"); super.addResourceHandlers(registry); } }
这是他从网上找到的拦截器的配置:spring
@Configuration public class WebMvcConfig extends WebMvcConfigurationSupport { public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LoginInterceptor()) // addPathPatterns 用于添加拦截规则 , 先把全部路径都加入拦截, 再一个个排除 .addPathPatterns("/**") .excludePathPatterns(Collections.singletonList("/swagger-ui.html")); super.addInterceptors(registry); } }
如今的测试结果就是,打开http://host:port/path/swagger-ui.html,就是一个空白页面,没法使用,如今要解决的就是这个问题。apache
打开谷歌浏览器的调试控制台,查看network,如图:
能够明显看出,页面加载数据的时候,并无报什么错误,只是加载的资源都被拦截器拦截了,没法加载资源,可想而知,资源都被拦截器拦截了。json
我分析了一下,加载资源的路径,修改了一下拦截器资源配置:api
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginInterceptor) // addPathPatterns 用于添加拦截规则 , 先把全部路径都加入拦截, 再一个个排除 .addPathPatterns("/**") .excludePathPatterns("/swagger-ui.html") .excludePathPatterns("/swagger-resources/**") .excludePathPatterns("/error") .excludePathPatterns("/webjars/**"); }
另外两个类实际是同一个做用,因此合并两个类:浏览器
@Configuration @EnableSwagger2 public class TestMVCConfig extends WebMvcConfigurationSupport { @Resource private TypeResolver typeResolver; @Resource private LoginInterceptor loginInterceptor; @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("swagger-ui.html") .addResourceLocations("classpath:/META-INF/resources/"); registry.addResourceHandler("/webjars/**") .addResourceLocations("classpath:/META-INF/resources/webjars/"); } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginInterceptor) // addPathPatterns 用于添加拦截规则 , 先把全部路径都加入拦截, 再一个个排除 .addPathPatterns("/**") .excludePathPatterns("/swagger-ui.html") .excludePathPatterns("/swagger-resources/**") .excludePathPatterns("/error") .excludePathPatterns("/webjars/**"); } @Bean public Docket productApi() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.basePackage("com.xxx.xxx.controller")) .paths(PathSelectors.any()) .build() .apiInfo(metaData()) .alternateTypeRules( //自定义规则,若是遇到DeferredResult,则把泛型类转成json newRule(typeResolver.resolve(DeferredResult.class, typeResolver.resolve(ResponseEntity.class, WildcardType.class)), typeResolver.resolve(WildcardType.class))) ; } private ApiInfo metaData() { return new ApiInfoBuilder() .title("通用服务 APIs") /*.description("\"REST API for Online Store\"")*/ .version("1.0.0") /* .license("Apache License Version 2.0") .licenseUrl("https://www.apache.org/licenses/LICENSE-2.0\"")*/ .contact(new Contact("易保科技", "", "mail@mail")) .build(); } }
这样就没有问题了。async
网上还有另一种说法,能够实现WebMvcConfigurer接口,代码以下:ide
@Configuration @EnableWebMvc @EnableSwagger2 public class WebMVCConfig implements WebMvcConfigurer{ @Resource private TypeResolver typeResolver; @Resource private LoginInterceptor loginInterceptor; @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("swagger-ui.html") .addResourceLocations("classpath:/META-INF/resources/"); registry.addResourceHandler("/webjars/**") .addResourceLocations("classpath:/META-INF/resources/webjars/"); } @Override public void addInterceptors(InterceptorRegistry registry) { List<String> excludePathPatterns = new ArrayList<>(); excludePathPatterns.add("/swagger-ui.html"); excludePathPatterns.add("/swagger-resources/**"); excludePathPatterns.add("/error"); excludePathPatterns.add("/webjars/**"); // addPathPatterns 用于添加拦截规则 , 先把全部路径都加入拦截, 再一个个排除 registry.addInterceptor(loginInterceptor) .addPathPatterns("/**") .excludePathPatterns(excludePathPatterns); } @Bean public Docket productApi() { return new Docket(DocumentationType.SWAGGER_2) .select() .apis(RequestHandlerSelectors.basePackage("com.xx.sss.controller")) .paths(PathSelectors.any()) .build() .apiInfo(metaData()) .alternateTypeRules( //自定义规则,若是遇到DeferredResult,则把泛型类转成json newRule(typeResolver.resolve(DeferredResult.class, typeResolver.resolve(ResponseEntity.class, WildcardType.class)), typeResolver.resolve(WildcardType.class))) ; } private ApiInfo metaData() { return new ApiInfoBuilder() .title("通用服务 APIs") /*.description("\"REST API for Online Store\"")*/ .version("1.0.0") /* .license("Apache License Version 2.0") .licenseUrl("https://www.apache.org/licenses/LICENSE-2.0\"")*/ .contact(new Contact("易保科技", "", "mail@mail")) .build(); } }
可是这种配置想要生效,必须加@EnableWebMvc注解,否则不起做用。为何?
官方源码注释:
/** * Defines callback methods to customize the Java-based configuration for * Spring MVC enabled via {@code @EnableWebMvc}. * * <p>{@code @EnableWebMvc}-annotated configuration classes may implement * this interface to be called back and given a chance to customize the * default configuration. *
经过@enableWebMVC启用Spring MVC,自定义基于Java config 定义回调方法。 @EnableWebMVC带注释的配置类能够实现这个接口自定义默认配置。
固然若是你以为本身的配置没问题,可是仍然不起做用,这时候该怎么办?请按照一下步骤debug:
一、找到InterceptorRegistration类;
二、找到addInterceptor方法和excludePathPatterns方法,打上断点;
三、debug模式启动项目;
若是没有进入断点,那就说明你的配置根本没有起到做用,看看注解是否没写。
若是进入了断点,就要看看断点处传进来的参数是不是你配置的参数,不是那就是有问题,这时候再根据参数查找问题。
这样基本就能解决问题了。
网上不少东西都是抄来抄去,也不知道有没有验证,让不少人摸不着头脑。