大家都知道,在前后端分离开发的时代,前后端接口对接是一项必不可少的工作。
可是,作为后端开发,怎么和前端更好的配合,才能让自己不心累、脑累,直接扔给前端一个后端开放api接口文档或者页面,让前端不用看着难受,也不用前端老问你,来愉快的合作呢?
原来可能我们一直用的是Swagger,不得不说Swagger是一个非常好的框架,自从它的出现,大大减少了我们对接的繁重工作。(以前我们开发可是经常要写开发接口文档的)
可是我们在用Swagger时,不管是Swagger本身,还是SwaggerUI,用起来其实不是那么的便捷,尤其是SwaggerUI,反正我用起来真的很是难受,也许是因为它不是我们国人开发的,所以操作方面根本没有我们国人的操作习惯设计。
幸好啊,我们国人也是很厉害的。
Knife4j这个东东,简直是及时雨,用起来丝滑的很。看看它的界面,是不是就是国人的思维设计?
有了这个东东,那么我们来研究一下,怎么让他来集成我们的Gateway,那么如何实现Gateway,可以查看我的上一篇文章。
轻量级的Spring Cloud Gateway实践,实现api和websocket转发https://blog.csdn.net/t610654893/article/details/137783310?spm=1001.2014.3001.5501
那么,我在这个项目基础上,实现Knife4j的集成实现。
首先,我来说一下我的整体项目结构:
--- 俩个主要的Spring Boot名
【app-server】前端接口服务
【manager-server】后端管理平台服务器接口
--- 微服网关、配置等平台服务
【cloud-server】
---【gateway-starter】路由套件
--- 等等
【common-server】公共starter目录的服务
---【boot-starter】公共套件
--- 等等
好,那么我们先从gateway着手来实现。首先pom.xml内引入:
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
在Gateway项目内,新增一个类集成SwaggerResourcesProvider来配置SwaggerProvider,获取Api-doc!
/**
* <b>功能:</b>SWAGGER聚合服务<br>
*/
@Slf4j
@Component
@Primary
@AllArgsConstructor
public class SwaggerResourceConfig implements SwaggerResourcesProvider {
@Resource
private Environment env;
private final RouteLocator routeLocator;
private final GatewayProperties gatewayProperties;
@Override
public List<SwaggerResource> get() {
List<SwaggerResource> resources = new ArrayList<>();
List<String> routes = new ArrayList<>();
routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
gatewayProperties.getRoutes().stream().filter(routeDefinition -> routes.contains(routeDefinition.getId())).forEach(route -> {
route.getPredicates().stream()
.filter(predicateDefinition ->
("Path").equalsIgnoreCase(predicateDefinition.getName()))
.forEach(predicateDefinition ->
resources.add(swaggerResource(route.getId(),
predicateDefinition.getArgs().get(NameUtils.GENERATED_NAME_PREFIX + "0").replace("**", "v3/api-docs"))));
});
return resources;
}
private SwaggerResource swaggerResource(String name, String location) {
log.info("name:{},location:{}", name, location);
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(env.getProperty(name));
swaggerResource.setLocation(location + "?group=KN");
swaggerResource.setSwaggerVersion("3.0.3");
return swaggerResource;
}
}
为了能更好的实现界面的客观性,我们这里写了一个swaggerResource的方法,此方法主要是为了能更好的表达我们的Api接口是属于谁的。比如说我们在Gateway的配置内配置了:routes[0].id=lb://app-server, 那么我们在配置后再加一个app-server=分组接口,那么在Knife4j内就可以更直观的选择属于app-server的项目API了。
我们这里主要还是你为了集成Swagger的内容,来完成Knife4j的前段实现。
因为Gateway里没有配置SwaggerConfig,而运行Swagger-ui又需要依赖一些接口,所以我们还需要自己来实现swagger-resource端点。
这里其实也很简单,我们再新建一个类,来完成我们对swagger-resource的实现。
/**
* <b>功能:</b>SWAGGER聚合服务<br>
*/
@RestController
public class SwaggerHandler {
@Autowired(required = false)
private SecurityConfiguration securityConfiguration;
@Autowired(required = false)
private UiConfiguration uiConfiguration;
private final SwaggerResourcesProvider swaggerResources;
@Autowired
public SwaggerHandler(SwaggerResourcesProvider swaggerResources) {
this.swaggerResources = swaggerResources;
}
@GetMapping("/swagger-resources/configuration/security")
public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {
return Mono.just(new ResponseEntity<>(
Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK));
}
@GetMapping("/swagger-resources/configuration/ui")
public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {
return Mono.just(new ResponseEntity<>(
Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));
}
@GetMapping("/swagger-resources")
public Mono<ResponseEntity> swaggerResources() {
return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
}
@GetMapping("/api")
@SentinelResource("api")
public Set<ApiDefinition> apiRules() {
return GatewayApiDefinitionManager.getApiDefinitions();
}
@GetMapping("/gateway")
@SentinelResource("gateway")
public Set<GatewayFlowRule> apiGateway() {
return GatewayRuleManager.getRules();
}
@GetMapping("/flow")
@SentinelResource("flow")
public List<FlowRule> apiFlow() {
return FlowRuleManager.getRules();
}
}
Gateway端接口已经配置完成。接下来配置实现客户端,由于我的工程俩个server都引入了boot-server,所以这里我只在boot-server内实现即可。
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-micro-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
客户端服务基本也就是按照Swagger的配置写config即可。这样更加方便我们以Swagger为基础更增强我们的api接口发布。为了更详尽的使用,我们一一实现。
增加Swagger 配置类
@EnableOpenApi
@Configuration
@EnableConfigurationProperties(value = {SwaggerProperties.class})
public class SwaggerConfiguration {
@Resource
private SwaggerProperties swaggerProperties;
@Bean
public Docket createRestApi() {
Boolean enable = swaggerProperties.getEnable();
String tryHost = swaggerProperties.getTryHost();
return new Docket(DocumentationType.OAS_30)
.groupName("KN")
// 定义是否开启swagger,false为关闭,可以通过变量控制
.enable(enable)
// 将api的元信息设置为包含在json ResourceListing响应中。
.apiInfo(apiInfo())
// 接口调试地址
.host(tryHost)
// 选择哪些接口作为swagger的doc发布
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.regex("/api/.*"))
.build();
}
/**
* <b>功能描述:</b>API 页面上半部分展示信息<br>
* <b>修订记录:</b><br>
* <li>20201225 | 田星亮 | 创建方法</li><br>
*/
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title(swaggerProperties.getApplicationName())
.description(swaggerProperties.getApplicationDescription())
.termsOfServiceUrl("https://www.kn.com/")
.contact(new Contact("KN", null, "admin@kn.com"))
.version(swaggerProperties.getApplicationVersion())
.build();
}
}
这里我们再增强一下,使我们的接口更符合api接口规范,给API头增加名为Token的头,在createRestApi方法Docket实现内增加俩个方法后缀,并付上实现:
.build()
// 授权信息设置,必要的header token等认证信息
.securitySchemes(securitySchemes())
.securityContexts(securityContexts());
/**
* <b>功能描述:</b>设置授权信息<br>
*/
private List<SecurityScheme> securitySchemes() {
return Collections.singletonList(new ApiKey("token", "token", In.HEADER.toValue()));
}
/**
* <b>功能描述:</b>授权信息全局应用<br>
*/
private List<SecurityContext> securityContexts() {
return Collections.singletonList(
SecurityContext.builder()
.securityReferences(Collections.singletonList(new SecurityReference("token", new AuthorizationScope[]{new AuthorizationScope("global", "")})))
.build()
);
}
上方内配置项详解,完成灵活调用
@Data
@ConfigurationProperties("swagger")
public class SwaggerProperties {
/**
* 是否开启swagger,生产环境一般关闭,所以这里定义一个变量
*/
private Boolean enable;
/**
* 项目应用名
*/
private String applicationName;
/**
* 项目版本信息
*/
private String applicationVersion;
/**
* 项目描述信息
*/
private String applicationDescription;
/**
* 接口调试地址
*/
private String tryHost;
}
至此,我们配置完成,打开Gateway所属的端口链接即可完成Knife4j的访问。Knife4j的配置内还有一些高级项配置,大家按照自己需要增强哦,比如说api排序这个我就很喜欢。