项目环境

SpringBoot 2.7.12

knife4j 3.0.3

jdk1.8

首先创建好项目

引入依赖

<!-- knife4j 接口文档 -->
<dependency>
    <groupId>com.github.xiaoymin</groupId>
    <artifactId>knife4j-spring-boot-starter</artifactId>
    <version>3.0.3</version>
</dependency>

配置文件

SwaggerConfig 配置文件

@EnableKnife4j
@Configuration
@EnableSwagger2
@Import(BeanValidatorPluginsConfiguration.class)
// 在 Swagger 3.X 以下版本报错时可以加此注解解决,但是在3.X版本以上的,加此注解会导致页面无法打开
//@EnableWebMvc
public class SwaggerConfig {

    /**
     * 创建API
     */
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.OAS_30)
                // 是否启用 Swagger
                .enable(true)
                // .useDefaultResponseMessages(false)
                // 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息)
                .apiInfo(apiInfo())
//                .groupName("3.X 版本")
                .select()
                // 方式一: 配置扫描 所有想在swagger界面的统一管理接口,都必须在此包下
//                .apis(RequestHandlerSelectors.basePackage("com.ss.minio"))
//                .apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
//                 方式二: 只有当方法上有  @ApiOperation 注解时才能生成对应的接口文档
//                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                // 扫描所有
//                .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.any())
                .build();
                /* 设置安全模式,swagger可以设置访问token */
//                .securitySchemes(securitySchemes())
//                .securityContexts(securityContexts())
                // 请求前缀
//                .pathMapping("/dev-api");

    }

    /**
     * 安全模式,这里指定token通过Authorization头请求头传递
     */
    private List<SecurityScheme> securitySchemes() {
        List<SecurityScheme> apiKeyList = new ArrayList<>();
        apiKeyList.add(new ApiKey("Authorization", "Authorization", In.HEADER.toValue()));
        return apiKeyList;
    }

    /**
     * 安全上下文
     */
    private List<SecurityContext> securityContexts() {
        List<SecurityContext> securityContexts = new ArrayList<>();
        securityContexts.add(
                SecurityContext.builder()
                        .securityReferences(defaultAuth())
                        .operationSelector(o -> o.requestMappingPattern().matches("/.*"))
                        .build());
        return securityContexts;
    }

    /**
     * 默认的安全上引用
     */
    private List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        List<SecurityReference> securityReferences = new ArrayList<>();
        securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
        return securityReferences;
    }

    /**
     * 添加摘要信息
     */
    private ApiInfo apiInfo() {
        // 用ApiInfoBuilder进行定制
        return new ApiInfoBuilder()
                // 设置标题
                .title("标题:xxx接口文档")
                // 描述
                .description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...")
                .termsOfServiceUrl("http://127.0.0.1/#/login")
                // 作者信息
                .contact(new Contact("ss", "ww.abc.com", "123@qq.com"))
                // 版本
                .version("版本号:1.0")
                .build();
    }

}

是否开启 knife4j 增强配置,页面访问浏览器是否需要账号密码登录

# knife4j 配置
knife4j:
  # 开启增强
  enable: true
  # 开启登录认证
  basic:
    enable: true
    username: admin
    password: 123456

swagger UI

如果想通过 swagger 的 UI 查看内容,添加以下依赖

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-boot-starter</artifactId>
    <version>3.0.0</version>
</dependency>

添加以后启动会出现以下问题,这是因为 SpringBoot 版本太高,不兼容

org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException

解决方法

需要在 SwaggerConfig 配置添加内添加以下内容

    /**
     * 解决SpringBoot和Swagger2冲突
     */
    @Bean
    public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
        return new BeanPostProcessor() {
            @Override
            public Object postProcessAfterInitialization(@NotNull Object bean, @NotNull 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");
                    assert field != null;
                    field.setAccessible(true);
                    return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
                } catch (IllegalArgumentException | IllegalAccessException e) {
                    throw new IllegalStateException(e);
                }
            }
        };
    }

配置完成测试

添加以下测试类

import io.swagger.annotations.*;
import org.springframework.web.bind.annotation.*;
import java.util.*;

/**
 * swagger 用户测试方法
 */
@Api(tags = "用户信息管理")
//@Api(tags = {"用户信息管理"})
//@ApiOperation("用户信息管理")
@RestController
@RequestMapping("/test/user")
public class TestController {
    private final static Map<Integer, UserEntity> users = new LinkedHashMap<>();

    static {
        users.put(1, new UserEntity(1, "admin", "admin123", "15000000000"));
        users.put(2, new UserEntity(2, "ceshi", "admin123", "18012345678"));
    }

    @ApiOperation("获取用户列表")
    @GetMapping("/list")
    public List<UserEntity> userList() {
        return new ArrayList<>(users.values());
    }

    @ApiOperation(value = "获取用户详细")
    @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class)
    @GetMapping("/{userId}")
    public UserEntity getUser(@PathVariable Integer userId) {
        if (!users.isEmpty() && users.containsKey(userId)) {
            return users.get(userId);
        } else {
            return null;
        }
    }

    @ApiOperation("新增用户")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", value = "用户id", dataType = "Integer", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "username", value = "用户名称", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "password", value = "用户密码", dataType = "String", dataTypeClass = String.class),
            @ApiImplicitParam(name = "mobile", value = "用户手机", dataType = "String", dataTypeClass = String.class)
    })
    @PostMapping("/save")
    public void save(UserEntity user) {
        if (Objects.isNull(user) || Objects.isNull(user.getUserId())) {
            throw new RuntimeException("用户ID不能为空");
        }
        users.put(user.getUserId(), user);
    }

    @ApiOperation("更新用户")
    @PutMapping("/update")
    public void update(@RequestBody UserEntity user) {
        if (Objects.isNull(user) || Objects.isNull(user.getUserId())) {
            throw new RuntimeException("用户ID不能为空");
        }
        if (users.isEmpty() || !users.containsKey(user.getUserId())) {
            throw new RuntimeException("用户不存在");
        }
        users.remove(user.getUserId());
        users.put(user.getUserId(), user);
    }

    @ApiOperation("删除用户信息")
    @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class)
    @DeleteMapping("/{userId}")
    public void delete(@PathVariable Integer userId) {
        if (!users.isEmpty() && users.containsKey(userId)) {
            users.remove(userId);
        } else {
            throw new RuntimeException("用户不存在");
        }
    }
}

@ApiModel(value = "UserEntity", description = "用户实体")
class UserEntity {
    @ApiModelProperty("用户ID")
    private Integer userId;
    @ApiModelProperty("用户名称")
    private String username;
    @ApiModelProperty("用户密码")
    private String password;
    @ApiModelProperty("用户手机")
    private String mobile;
    public UserEntity() {
    }
    public UserEntity(Integer userId, String username, String password, String mobile) {
        this.userId = userId;
        this.username = username;
        this.password = password;
        this.mobile = mobile;
    }
    public Integer getUserId() {
        return userId;
    }
    public void setUserId(Integer userId) {
        this.userId = userId;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getMobile() {
        return mobile;
    }
    public void setMobile(String mobile) {
        this.mobile = mobile;
    }
}

启动项目,浏览器访问

http://127.0.0.1:8080/doc.html

http://127.0.0.1:8080/swagger-ui/index.html

问题一

swagger ui 地址不能访问,配置 WebMvcConfig,添加以下内容

import org.springframework.context.annotation.Configuration;
import org.springframework.http.CacheControl;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import java.util.concurrent.TimeUnit;

/**
 * web 配置类
 */
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {

    /**
     * 解决 org.springframework.context.ApplicationContextException: Failed to start bean <br>
     * 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
     * 发现如果继承了 WebMvcConfigurationSupport,则在yml中配置的相关内容会失效。 需要重新指定静态资源
     *
     * @param registry ResourceHandlerRegistry
     * @see <a href="https://www.mobaijun.com/posts/3051425539.html"></a>
     */
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**")
                .addResourceLocations("classpath:/static/");
        registry.addResourceHandler("swagger-ui.html", "doc.html")
                .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
        /* swagger配置 */
        registry.addResourceHandler("/swagger-ui/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/")
                .setCacheControl(CacheControl.maxAge(5, TimeUnit.HOURS).cachePublic());
        super.addResourceHandlers(registry);
    }
}

问题二

knife4jswagger-ui 不显示接口文档内容,需要在 application.yml 中添加以下配置

# 解决 knife4j 不显示
spring:
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher

再次访问地址,恭喜完成

http://127.0.0.1:8080/doc.html

http://127.0.0.1:8080/swagger-ui/index.html

最后修改:2025 年 03 月 14 日
如果觉得我的文章对你有用,请随意赞赏