项目环境
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);
}
}
问题二
knife4j
和 swagger-ui
不显示接口文档内容,需要在 application.yml
中添加以下配置
# 解决 knife4j 不显示
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
再次访问地址,恭喜完成