spring cloud alibaba 使用swagger3.0

使用swagger3.0 的坑

开发环境介绍

首先版本

名称版本
spring colud alibaba2021.0.4.0
spring boot2.6.11
spring-boot-starter-actuactor2.6.11
swagger3.0.0
knife-spring-boot3.0.3
jdk11.17

1.版本冲突

1.1 只使用 springboot+cloud+swagger
1.2 冲突提示信息

使用这个配置会有冲突,导致异常提示:

Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
1.3 解决方案

解决方案很简单,配置文件中添加如下:

spring:
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher

问题就解决了。
这个时候使用访问http://127.0.0.1:8086/swagger-ui/
在这里插入图片描述

2. 添加spring-boot-starter-actuator时异常

使用了上述配置 ,然后在使用 项目监控 actuator 这个会有冲突,spring-boot-starter-actuator 与 springfox-boot-starter 冲突导致异常重新出现

Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException

如果要解决这个问题 ,需要如下2步骤

  1. application.yml 中添加上述配置
  2. 自定义 webmvcEndpointhandlerMapping
2.1 添加配置
spring:
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher
2.2 自定义 webmvcEndpointhandlerMapping
import org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
import org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

@Configuration
public class SwaggerConfig {

    /**
     * 解决springboot升到2.6.x之后  swagger与spring-boot-starter-actuator 的冲突
     */
    @Bean
    public WebMvcEndpointHandlerMapping webMvcEndpointHandlerMapping(WebEndpointsSupplier wes
            , ServletEndpointsSupplier ses, ControllerEndpointsSupplier ces, EndpointMediaTypes emt
            , CorsEndpointProperties cep, WebEndpointProperties wep, Environment env) {
        List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
        Collection<ExposableWebEndpoint> webEndpoints = wes.getEndpoints();
        allEndpoints.addAll(webEndpoints);
        allEndpoints.addAll(ses.getEndpoints());
        allEndpoints.addAll(ces.getEndpoints());
        String basePath = wep.getBasePath();
        EndpointMapping endpointMapping = new EndpointMapping(basePath);
        boolean shouldRegisterLinksMapping = shouldRegisterLinksMapping(wep, env, basePath);
        return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, emt
                , cep.toCorsConfiguration(), new EndpointLinksResolver(
                allEndpoints, basePath), shouldRegisterLinksMapping, null);
    }
    /**
     * shouldRegisterLinksMapping
     *
     * @param wep
     * @param env
     * @param basePath
     * @return
     */
    private boolean shouldRegisterLinksMapping(WebEndpointProperties wep, Environment env, String basePath) {
        return wep.getDiscovery().isEnabled() && (StringUtils.hasText(basePath) || ManagementPortType.get(env).equals(ManagementPortType.DIFFERENT));
    }
}
  1. 完成上述步骤 即可,使用访问http://127.0.0.1:8086/swagger-ui/
    在这里插入图片描述

3.使用knife4j 来优化界面显示

这里说一下这个knife4j,他是开源的一个增强工具,以前叫做swagger-bootstrap-ui,现在改为Knife4j。
版本最新为4.0 与3.0区别是,
3.0支持swagger3.0
4.0 支持swagger2.0和3.0 供用户自己选择。
详情看 [官方地址](https://doc.xiaominfo.com/docs/community/changelog)

添加依赖 knife4j-spring-boot-starter
swagger-ui 这个界面不友好,接口多了看起来比较麻烦,这个时候需要使用Knife4j。使用此插件步骤

  1. 引入依赖
  2. 自定义bean来处理冲突
  3. 使用新的接口来访问,禁用swagger-ui 访问 即可
3.1引入依赖
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-spring-boot-starter</artifactId>
            <version>3.0.3</version>
        </dependency>
3.2 自定义bean

这里将2中的 解决冲突的bean 合并一起了

import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
import org.springframework.boot.actuate.endpoint.web.EndpointMapping;
import org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes;
import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
import org.springframework.boot.actuate.endpoint.web.WebEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.util.StringUtils;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * @ClassName t1
 * @date 2023/3/13 0:03
 * @Description TODO
 * @Author [Miller-hw]
 * @Version 1.0
 */
@Configuration
@EnableKnife4j
public class Knife4jConfig {
    @Bean
    public Docket createRestApi(Environment env) {
        return new Docket(DocumentationType.OAS_30)
                .useDefaultResponseMessages(false)
                .groupName("1.0版本")
                .apiInfo(apiInfo())
                //只有当springboot配置文件为dev或test环境时,才开启swaggerAPI文档功能
//                .enable(flag)
                .enable(true)
                .select()
                // 这里指定Controller扫描包路径:设置要扫描的接口类,一般是Controller类
                .apis(RequestHandlerSelectors.any())  //这里采用包扫描的方式来确定要显示的接口
//                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) //这里采用包含注解的方式来确定要显示的接口
                // 配置过滤哪些,设置对应的路径才获取
//                .paths(PathSelectors.regex("/eid/.*?"))
                .paths(PathSelectors.any())
                .build();
        //防止Controller中参数中没有实体类或者返回值不是实体类导致Swagger Models页面扫描不到的情况
//                .additionalModels(typeResolver.resolve(EmailNotice.class))
//                .additionalModels(typeResolver.resolve(SmsNotice.class))
//                .additionalModels(typeResolver.resolve(WeChatNotice.class));
    }

    ///配置相关的api信息
    private ApiInfo apiInfo()
    {
        return new ApiInfoBuilder()
                .description("API调试文档")
                //作者信息
                .contact(new Contact("努力财富自由", "http://127.0.0.1:8081/doc.html", "xk8703@163.com"))
                .version("v1.0")
                .title("Eid服务端API文档")
                //服务Url
                .termsOfServiceUrl("")
                .build();
    }


    /**
     * 解决springboot升到2.6.x之后,knife4j报错
     * @param wes        the web endpoints supplier
     * @param ses    the servlet endpoints supplier
     * @param ces the controller endpoints supplier
     * @param emt          the endpoint media types
     * @param cep      the cors properties
     * @param wep       the web endpoints properties
     * @param env                 the environment
     * @return the web mvc endpoint handler mapping
     */
    @Bean
    public WebMvcEndpointHandlerMapping webMvcEndpointHandlerMapping(WebEndpointsSupplier wes
            , ServletEndpointsSupplier ses, ControllerEndpointsSupplier ces, EndpointMediaTypes emt
            , CorsEndpointProperties cep, WebEndpointProperties wep, Environment env) {
        List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();
        Collection<ExposableWebEndpoint> webEndpoints = wes.getEndpoints();
        allEndpoints.addAll(webEndpoints);
        allEndpoints.addAll(ses.getEndpoints());
        allEndpoints.addAll(ces.getEndpoints());
        String basePath = wep.getBasePath();
        EndpointMapping endpointMapping = new EndpointMapping(basePath);
        boolean shouldRegisterLinksMapping = shouldRegisterLinksMapping(wep, env, basePath);
        return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, emt
                , cep.toCorsConfiguration(), new EndpointLinksResolver(
                allEndpoints, basePath), shouldRegisterLinksMapping, null);
    }
    /**
     * shouldRegisterLinksMapping
     *
     * @param wep
     * @param env
     * @param basePath
     * @return
     */
    private boolean shouldRegisterLinksMapping(WebEndpointProperties wep, Environment env, String basePath) {
        return wep.getDiscovery().isEnabled() && (StringUtils.hasText(basePath) || ManagementPortType.get(env).equals(ManagementPortType.DIFFERENT));
    }

}
3.4 完成配置 关闭swagger-ui,使用knife4j
#  关闭 swagger-ui
springfox:
  documentation:
    swagger-ui:
      enabled: false

3.5 展示界面

使用地址 http://localhost:8086/doc.html
在这里插入图片描述

4. 使用示例

4.1 添加DTO文档
@Getter
@Setter
@ApiModel(value = "hello",description = "value 的值为model中的标题")
public class Hello implements Serializable {
    private static final long serialVersionUID = -6985352140066168201L;


    @ApiModelProperty("名称")
    private String name;
    @ApiModelProperty(value = "年龄")
    private int age;
    @ApiModelProperty(value = "生日")
    private String birth;

    public Hello() {
    }

    public Hello(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

在这里插入图片描述

4.2 添加API接口文档
@RestController
@Api(tags = {"hello"}) // 这里标记可以将同一类的接口放一起, 便于查找和管理
public class HelloController {

    @ApiOperation(value = "hello 接口",nickname = "hello-index",notes = "api接口备注") // nickname 基本没啥用,作用是文档中地址栏会多这么个路径
    // 请求参数的第一种写法
    @ApiImplicitParams({
            @ApiImplicitParam(name = "name",value = "名称而已",required = true,defaultValue = "hello",dataTypeClass = String.class,paramType = "path"),
            @ApiImplicitParam(name = "type",value = "类型",required = false,defaultValue = "null",dataTypeClass = Map.class,paramType = "query"),
            @ApiImplicitParam(name = "h",value = "hello",required = false,defaultValue = "null",dataTypeClass = Hello.class,paramType = "query"),
    })
    @GetMapping("/hello")
    public Object index(String name, String type, Hello h) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("code", 200);
        map.put("message", " hello world ");
        return map;
    }

    @GetMapping("/hello/t1")
    @ApiOperation(value = "显示model")
     // 请求参数的第二种写法
    public Hello hello(@ApiParam(name = "name", value = "名字",required = true,type = "String") String name,
                       @ApiParam(name = "age", value = "年龄",required = false,type = "int") int age) {
        return new Hello(name, age);
    }
}

在这里插入图片描述

在这里插入图片描述

4.3 关于@ApiModel 避坑的一点

比如你新增一个DTO,使用@ApiModel 做了标记,在Swagger Models 不会显示的。必须在controller 使用了此DTO且用到了@ApiOperation 标注才行如这种:

    @GetMapping("/hello/t1")
    @ApiOperation(value = "显示model")
    public Hello hello() {
        return new Hello();
    }

搞了好久 这个有点坑

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值