SpringBoot项目集成knif4j,从此告别手写Api文档

SpringBoot项目集成knif4j,从此告别手写Api文档

SpringBoot项目集成knif4j,从此告别手写Api文档

前言

作为一名后台开发人员,在前后端分离项目的开发过程中,我们写好了后台接口之后总免不了要给前端同事提供一份详细的API接口文档,写完一个接口又要补充一个接口的文档,过程还挺繁琐的。那么有没有一款工具让我们不用再些这些繁琐的API文档呢?答案是有的。之前我们在项目中配置swagger结合相关的注解来生成API文档界面,只是界面不是那么美观,还必须在每个接口控制器方法中添加很多的注解,代码侵入性比较强。

现在越来越多的开发人员使用Knif4j来生成API文档,它是升级版的swagger, 不仅具有美观的界面,而且不需要在控制器方法中添加非常多的参数注解。哪怕不加任何注解,只要在项目中集成并配置好Docket类bean,就能生成界面美观的API接口文档,而且还有接口调试功能。

1 项目介绍

Knife4j的前身是swagger-bootstrap-ui,前身swagger-bootstrap-ui是一个纯swagger-uiui皮肤项目

一开始项目初衷是为了写一个增强版本的swagger的前端ui,但是随着项目的发展,面对越来越多的个性化需求,不得不编写后端Java代码以满足新的需求,在swagger-bootstrap-ui的1.8.5~1.9.6版本之间,采用的是后端Java代码和Ui都混合在一个Jar包里面的方式提供给开发者使用。这种方式虽说对于集成swagger来说很方便,只需要引入jar包即可,但是在微服务架构下显得有些臃肿。

因此,项目正式更名为knife4j,取名knife4j是希望它能像一把匕首一样小巧、轻量并且功能强悍。更名也是希望把她做成一个为Swagger接口文档服务的通用性解决方案,不仅仅只是专注于前端Ui前端。

swagger-bootstrap-ui的所有特性都会集中在knife4j-spring-ui包中,并且后续也会满足开发者更多的个性化需求。主要的变化是项目的相关类包路径更换为com.github.xiaoymin.knife4j前缀,开发者使用增强注解时需要替换包路径后端Java代码和ui包分离为多个模块的jar包,以面对在目前微服务架构下更加方便的使用增强文档注解(使用SpringCloud微服务项目,只需要在网关层集成UI的jar包即可,因此分离前后端)

knife4j沿用swagger-bootstrap-ui的版本号,第1个版本从1.9.6开始,关于使用方法,请参考[版本说明](2.6 版本说明 | knife4j (xiaominfo.com))。

目前主要支持以Java开发为主,并且是依赖于大环境下使用的Spring MVCSpring BootSpring Cloud框架。

当然,Knife4j也提供了离线版本,只要是符合Swagger的OpenAPI版本的规范JSON,都可以通过简单的配置进行适配,离线版本是适合于任何语言中使用Swagger非常的灵活方便。

2 界面鉴赏

Knife4j采用Vue+And Design Vue组件重写,相关功能界面如下,供大家赏鉴:

接口文档显示界面如下:

SpringBoot项目集成knif4j,从此告别手写Api文档

接口调试界面如下:

SpringBoot项目集成knif4j,从此告别手写Api文档

Swagger Models功能

SpringBoot项目集成knif4j,从此告别手写Api文档

SpringBoot项目集成knif4j,从此告别手写Api文档

3 快速开始

本次示例使用Spring Boot作为脚手架来快速集成Knife4j,Spring Boot版本2.3.5.RELEASE,Knife4j版本2.0.7,完整代码可以去参考knife4j-spring-boot-fast-demo

第一步:在maven项目的pom.xml中引入Knife4j的依赖包,代码如下:

<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>2.0.7</version>
</dependency>

第二步:新建Knife4j配置类,配置Docket bean:

@Configuration
@EnableSwagger2WebMvc
public class Knife4jConfiguration {

@Bean(value = "defaultApi2")
public Docket defaultApi2() {
Docket docket=new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder()
//.title("swagger-bootstrap-ui-demo RESTful APIs")
.description("# swagger-bootstrap-ui-demo RESTful APIs")
.termsOfServiceUrl("http://www.xx.com/")
.contact("xx@qq.com")
.version("1.0")
.build())
//分组名称
.groupName("2.X版本")
.select()
//这里指定Controller扫描包路径
.apis(RequestHandlerSelectors.basePackage("com.github.xiaoymin.knife4j.controller"))
.paths(PathSelectors.any())
.build();
return docket;
}
}

最終整个工程目录结构如下图:

SpringBoot项目集成knif4j,从此告别手写Api文档

IndexController.java包含一个简单的RESTful接口,代码示例如下:

@Api(tags = "首页模块")
@RestController
public class IndexController {
@ApiImplicitParam(name = "name",value = "姓名",required = true)
@ApiOperation(value = "向客人问好")
@GetMapping("/sayHi")
public ResponseEntity<String> sayHi(@RequestParam(value = "name")String name){
return ResponseEntity.ok("Hi:"+name);
}
}

此时,启动Spring Boot工程,在浏览器中访问:http://localhost:17790/doc.html

界面效果图如下:

SpringBoot项目集成knif4j,从此告别手写Api文档

5 blogserver项目集成knif4j

第一步:项目的pom.xml文件中引入knife4j-spring-boot-starter起步依赖

<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.2</version>
</dependency>

这里笔者用了最新的3.0.2版本

第二步:新建Knife4j配置类:

package org.sang.config;

import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import springfox.documentation.spi.service.contexts.SecurityContext;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;


@Configuration
@EnableSwagger2
@EnableKnife4j
@Import(BeanValidatorPluginsConfiguration.class)
public class Knife4jConfig
{

@Bean
public Docket createRestApi(){

Predicate<RequestHandler> selector1 = RequestHandlerSelectors
.basePackage("org.sang.controller"); //扫描包改成自己项目下的Controller类所在的包

return new Docket(DocumentationType.SWAGGER_2)
.groupName("VBlog博客平台")
.apiInfo(apiInfo())
.select()
.apis(selector1)
.paths(PathSelectors.any())
.build()
.securityContexts(securityContexts())
.securitySchemes(securitySchemas());

}

private ApiInfo apiInfo(){
return new ApiInfoBuilder()
.title("VBlog博客平台RESTful APIs")
.description("VBlog博客平台 api接口文档")
.version("1.0")
.build();

}

private List<SecurityScheme> securitySchemas(){
List<SecurityScheme> list = new ArrayList();
list.add(new ApiKey("loginToken", "loginToken", "header"));
return list;
}


private List<SecurityReference> securityReferences(){
AuthorizationScope[] authorizationScopes = new AuthorizationScope[]
{new AuthorizationScope("global", "accessEverything")};
List<SecurityReference> securityReferences = new ArrayList<>();
securityReferences.add(new SecurityReference("loginToken", authorizationScopes));
return securityReferences;
}


private List<SecurityContext> securityContexts(){

List<SecurityContext> list = new ArrayList();
SecurityContext securityContext = SecurityContext.builder()
.securityReferences(securityReferences())
.forPaths(PathSelectors.regex("/*"))
.build();
list.add(securityContext);

return list;
}
}

第三步:新建WebApplicationConfig类重写addViewControllers方法

package org.sang.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebApplicationConfig implements WebMvcConfigurer {

@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("doc.html");
}
}

重写addViewControllers方法的目的是为了服务启动后能顺利访问到API文档界面

第四步:在控制器类上加上@Api注解, 在路由方法上加上@ApiOperation注解对路由方法进行描述,加上@ApiImplicitParam对接口入参进行详细描述。

示例代码:

@RestController
@RequestMapping(path = "/role")
@Api(value="roleController", tags = "角色相关API")
public class RoleController {

@Autowired
private RoleService roleService;

private static final Logger logger = LoggerFactory.getLogger(RoleController.class);

@PostMapping(path = "/addRole")
@ApiOperation(value = "addRole", notes = "添加角色", produces = "application/json",
consumes = "application/json", response = RespBean.class)
@ApiImplicitParam(name
="role", value = "角色对象", dataTypeClass = Role.class, paramType="body", required = true)
public RespBean<Integer> addRole(@RequestBody Role role) {
logger.info("roleCode={},roleName={}",role.getRoleCode(),role.getRoleName());
int addCount = roleService.addRole(role);
RespBean<Integer> respBean = new RespBean<>(200, "success");
respBean.setData(addCount);
return respBean;
}
}

@Api注解方法属性说明:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Api {
// Api名称
String value() default "";
// Api标签
String[] tags() default {""};

/** @deprecated */
@Deprecated
// Api描述,已过时
String description() default "";

/** @deprecated */
@Deprecated
// Api基础路径,已过时
String basePath() default "";

/** @deprecated */
@Deprecated
// Api位置,已过时
int position() default 0;
// 响应参数数据类型,json格式数据类型为application/json
String produces() default "";
// 请求参数数据类型
String consumes() default "";
// 协议:http|https|dubbo|rmi
String protocols() default "";
// 认证信息
Authorization[] authorizations() default {@Authorization("")};
// 是否隐藏
boolean hidden() default false;
}

这个注解主要用在控制器类上

@ApiOperation注解方法属性说明

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiOperation {
// Api操作方法名称
String value();
// Api操作方法注意点
String notes() default "";
// Api操作方法标签集合
String[] tags() default {""};
// 响应对象类
Class<?> response() default Void.class;
// 响应体容器
String responseContainer() default "";
// 响应体引用
String responseReference() default "";
// http请求类型
String httpMethod() default "";

/** @deprecated */
@Deprecated
int position() default 0;
// Api操作方法昵称
String nickname() default "";
// 响应体参数类型,若无则与@Api中的该参数值保持一致
String produces() default "";
// 请求体参数类型,若无则与@Api中的该参数值保持一致
String consumes() default "";
// 接口请求协议,若无则与@Api中的该参数值保持一致
String protocols() default "";
// 接口调用认证信息,若无则与@Api中的该参数值保持一致
Authorization[] authorizations() default {@Authorization("")};
// 是否隐藏,默认显示
boolean hidden() default false;
// 响应头
ResponseHeader[] responseHeaders() default {@ResponseHeader(
name = "",
response = Void.class
)}
;
// 响应码,默认为200
int code() default 200;
// 扩展参数类别
Extension[] extensions() default {@Extension(
properties = {@ExtensionProperty(
name = "",
value = ""
)}
)};
// 忽略json视图,默认否
boolean ignoreJsonView() default false;
}

这个注解主要用在控制器类中的路由方法上

@ApiImplicitParams注解方法属性说明:

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiImplicitParams {
ApiImplicitParam[] value();
}

这个注解主要用于控制器类中的路由方法中有多个参数时使用,它的value值是个@ApiImplicitParam数组

@ApiImplicitParam 注解方法属性说明:

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiImplicitParam {
// 参数名称
String name() default "";
// 参数显示名称
String value() default "";
// 参数默认值
String defaultValue() default "";
// 允许的多个值
String allowableValues() default "";
// 是否必须
boolean required() default false;

String access() default "";
// 是否允许多个
boolean allowMultiple() default false;
// 参数数据类型
String dataType() default "";
// 参数数据类型类
Class<?> dataTypeClass() default Void.class;
// 参数类型:query|body|path
String paramType() default "";
// 参数示例
String example() default "";
// 参数详细示例
Example examples() default @Example({@ExampleProperty(
mediaType = "",
value = ""
)
})
;

String type() default "";
// 参数格式
String format() default "";
// 是否允许参数值为空
boolean allowEmptyValue() default false;
// 参数是否只读
boolean readOnly() default false;
// 集合格式
String collectionFormat() default "";
}

6 效果体验

第一步: 启动blogserver项目服务和vue-element-admin前端项目服务

启动blogserver项目服务时在IDEA中选中启动类BlogserverApplication类下的main函数->右键->Debug BlogserverApplication

启动vue-element-admin前端项目服务时在项目根目录下:右键->Git Bash Here

在弹出的命令控制台中输入命令npm run dev 然后回车

控制台出现如下日志信息代表启动成功

 App running at:
- Local: http://localhost:3000/
- Network: unavailable

Note that the development build is not optimized.
To create a production build, run npm run build.

第二步:打开谷歌浏览器输入http://localhost:8081/blog/doc.html 后回车

由于后台项目中通过SpringSecurity配置了安全认证,浏览器首先会跳转到 http://localhost:3000/#/login 登录页面进项登录,登录成功后再次输入http://localhost:8081/blog/doc.html 后回车就进入了Api文档首页VBlog博客平台RESTful APIs 效果图如下:

SpringBoot项目集成knif4j,从此告别手写Api文档

SpringBoot项目集成knif4j,从此告别手写Api文档

点击文档下面的调试可进入接口调试界面

我们输入请求参数后,再点击右上角的发送按钮即可测试接口的可用性,下面的响应内容去可以看到接口的返回信息。这样我们就可以直接通过文档页面测试接口,而不需要打开postman来调试接口了。

更多关于Knif4j增强文档功能请读者查看官方文档增强模式部分:https://doc.xiaominfo.com/knife4j/documentation/enhance.html

7 小结

本文我们通过Knife4j的官方文档学习了Knife4j项目以及如何在自己的SpringBoot项目中集成knife4j-spring-boot-strater组件自动生成升级版的Swagger2API文档。总结起来就一下四个步骤:

  • pom.xml文件中引入knife4j-spring-boot-strater组件的起步依赖


  • 配置swagger2文档Docket类bean,在接口扫描基础包中制定自己项目中控制器类所在的包名


  • 重写WebMvcConfigurer#addViewControllers方法,添加文档文件doc.html视图


  • 控制器类上添加@Api注解, 控制器中操作方法上添加@ApiOperationApiImplicitParam 注解


其中,第四步为可选项,用户也可步添加这三个注解,knif4j也能根据Spring MVC的注解生成接口文档,只是在页面显示的Api接口很多值都是默认值。

好了,本文就写到这里,希望读者朋友们都能动手实践一遍,亲自体验一把knife4j带来的神奇功能!

参考文档

【1】Knife4j官方文档:  

  https://doc.xiaominfo.com/knife4j/documentation


【2】接口文档从Swagger升级成knife4j使用教程

 https://baijiahao.baidu.com/s?id=1683466038755184828


推荐阅读

【1】 再见收费的Xshell,我使用国产良心软件FinalShell替代了它


【2】当跨域遇上 Spring Security


【3】vue-element-admin整合spring-boot权限设计之实现用户授权功能


【4】vue-element-admin整合spring-boot实现权限控制之用户管理篇


【5】vue-element-admin整合spring-boot实现权限控制之用户管理篇

原文始发于微信公众号(阿福谈Web编程):SpringBoot项目集成knif4j,从此告别手写Api文档

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/42302.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!