最近同事問我,spring boot集成了swagger,但是在使用攔截器的時候遇到了問題,頁面無法訪問。經過研究解決了這個問題。
配置問題解決
集成swagger就不囉嗦了,網上到處都是,直接看配置。
同事從網上找到的配置:
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);
}
}
這是他從網上找到的攔截器的配置:
@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,就是一個空白頁面,無法使用,現在要解決的就是這個問題。
打開谷歌瀏覽器的調試控制檯,查看network,如圖:
可以明顯看出,頁面加載數據的時候,並沒有報什麼錯誤,只是加載的資源都被攔截器攔截了,無法加載資源,可想而知,資源都被攔截器攔截了。
我分析了一下,加載資源的路徑,修改了一下攔截器資源配置:
@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();
}
}
這樣就沒有問題了。
另外的解決方案
網上還有另外一種說法,可以實現WebMvcConfigurer接口,代碼如下:
@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:
1、找到InterceptorRegistration類;
2、找到addInterceptor方法和excludePathPatterns方法,打上斷點;
3、debug模式啓動項目;
如果沒有進入斷點,那就說明你的配置根本沒有起到作用,看看註解是否沒寫。
如果進入了斷點,就要看看斷點處傳進來的參數是否是你配置的參數,不是那就是有問題,這時候再根據參數查找問題。
這樣基本就能解決問題了。
總結
網上很多東西都是抄來抄去,也不知道有沒有驗證,讓很多人摸不着頭腦。