最近同事問我,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模式啓動項目;
若是沒有進入斷點,那就說明你的配置根本沒有起到做用,看看註解是否沒寫。
若是進入了斷點,就要看看斷點處傳進來的參數是不是你配置的參數,不是那就是有問題,這時候再根據參數查找問題。
這樣基本就能解決問題了。
網上不少東西都是抄來抄去,也不知道有沒有驗證,讓不少人摸不着頭腦。