在微服务中引入Knife4j,我使用的是将Knife4j放到公共的配置模块下,这样其他微服务需要使用到swagger就可以直接导入使用,在配置文件配置我需要的一些配置即可,这样的优势在于可以完美兼容所有的微服务,并且不需要去重复配置。从此告别手写开发文档

PS:如果是单应用的话也可以使用

代码部分

引入依赖,最新版即可
<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-spring-boot-starter</artifactId>
    <version>3.0.3</version>
</dependency>		
新建Knife4jConfiguration类
使用到EnableSwagger2注解,用来开启swagger和EnableKnife4j来开启knife4j
/**
 * @program: e-commerce
 * @description: knife4j配置类
 * @author: JiaChaoYang
 * @date: 2022-09-24 21:03
 **/
@Configuration
@EnableSwagger2
@EnableKnife4j
public class Knife4jConfiguration {

	/*需要在配置文件里配置这三个配置*/
    /*配置开启禁用swagger*/
    @Value("${swagger.enabled}")
    private boolean enabled;

    /*配置模块名*/
    @Value("${swagger.groupName}")
    private String groupName;

    /*配置需要扫描的包*/
    @Value("${swagger.basePackage}")
    private String basePackage;

    /**
    * @Description: Swagger 实例 Bean是Docket,所以通过配置Docket实例来配置Swagger
    * @return: springfox.documentation.spring.web.plugins.Docket
    * @Author: JiaChaoYang
    * @Date: 2022-09-24 - 11:36
    */
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.OAS_30)//文档类型,我这里使用的是swagger3
                //是否启用swagger
                .enable(enabled)
                //包名,模块名
                .groupName(groupName)
                //删除swagger中的操作的响应体
                .useDefaultResponseMessages(false)
                //展示在Swagger页面上的自定义工程描述信息
                .apiInfo(apiInfo())
                //选择展示哪些接口
                .select()
                //配置需要扫描的路径(controller)
                .apis(RequestHandlerSelectors.basePackage(basePackage))
                //给所有文档都生成文档路径
                .paths(PathSelectors.any())
                .build();
    }

    /**
    * @Description: Swagger的描述信息
    * @return: springfox.documentation.service.ApiInfo
    * @Author: JiaChaoYang
    * @Date: 2022-09-24 - 11:33
    */
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                //描述信息
                .description("测试Knife4j")
                //可以通过swagger联系一个人,即联系方式
                .contact(new Contact("JiaChaoYang", "https://127.0.0.1:9001/doc.html", "j15030047216@163.com"))
                //版本
                .version("v1.0")
                //标题
                .title("测试文档")
                .build();
    }
为了防止不在同一包下扫描不到需要在resources下新建META-INF文件夹,再在META-INF文件夹下新建spring.factories(推荐),或者启动类使用@ComponentScan扫描(推荐)。或者把包名全部改为一样的(不推荐)

在这里插入图片描述

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.qihengyun.core.Knife4jConfiguration

其他模块引用,只需要在bootstrap.yml或者application.yml中配置这三个参数就可以了

1.是否开启Swagger。在生产环境下使用的话会暴露接口,所以在配置文件去控制是否打开
2.模块名
3.需要扫描的类的路径

swagger:
  enabled: true
  groupName: 登录鉴权微服务模块
  basePackage: 你的controller路径

需要在拦截器配置让MVC加载Swagger的静态资源

/**
    * @Description: 让MVC加载Swagger的静态资源
    * @Param: [registry]
    * @return: void
    * @Author: JiaChaoYang
    * @Date: 2022/9/24 - 20:55
    */
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {

        registry.addResourceHandler("/**").
                addResourceLocations("classpath:/static/");
        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("doc.html")
                .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");

        super.addResourceHandlers(registry);
    }

如果有拦截器和过滤器的话需要将Swagger放到白名单,即不去鉴权,需要把下边的配置给排除掉

"springfox",
"swagger",
"v3",
"webjars",
"doc.html",
"favicon.ico",
"api-docs"

运行(http://127.0.0.1:端口/doc.html)

在这里插入图片描述

到这里配置就结束了,当然还有一个很严重的问题,就是springboot2.6和springfox不兼容的问题,在配置文件去修改mvc匹配策略有点治标不治本,所以参考了一下GitHub上的大佬的配置,只需要放到Knife4j的配置类即可

@Bean
    public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
        return new BeanPostProcessor() {

            @Override
            public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {
                    customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
                }
                return bean;
            }

            private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {
                List<T> copy = mappings.stream()
                        .filter(mapping -> mapping.getPatternParser() == null)
                        .collect(Collectors.toList());
                mappings.clear();
                mappings.addAll(copy);
            }

            @SuppressWarnings("unchecked")
            private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
                try {
                    Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
                    field.setAccessible(true);
                    return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
                } catch (IllegalArgumentException | IllegalAccessException e) {
                    throw new IllegalStateException(e);
                }
            }
        };
    }
Logo

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

更多推荐