前言
2020年7月份Springfox 3.0.0发布了,增加了对Webflux、OpenApi 3的支持,适应Gateway,微服务中为方便管理各微服务的接口文档,特此来摸索一下Spring Cloud Gateway集成管理,整个过程没什么代码,简单易用
1、环境及工具介绍
1、gradle,一个基于 JVM 的富有突破性构建工具,简化maven的xml繁琐配置
2、nacos,阿里开发的动态服务发现、配置和服务管理平台,appllo不喜欢用就它了
3、knife4j,Java MVC框架集成Swagger生成Api文档的增强解决方案,前身是swagger-bootstrap-ui(swagger2用的好好的为啥要用这玩意???原皮看厌倦了换上新鲜的感觉)
4、Spring Cloud版本用的是Hoxton.RELEASE,SpringBoot版本2.2.1.RELEASE
以上gradle、nacos环境自行百度搭建,比较简单,不做赘述了
2、微服务端
2.1、先写两个简单的微服务,这里起个很随便的名字(example、cart-service)
端口分别设置为8081和8082
server:
port: 8081
build.gradle:
plugins {
id 'org.springframework.boot' version '2.2.1.RELEASE'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
id 'java'
}
group 'com.asan.cart'
version '1.0.0-SNAPSHOT'
sourceCompatibility = 1.8
ext {
set('springBootVersion', "2.2.1.RELEASE")
set('springCloudVersion', "Hoxton.RELEASE")
set('alibabaCloudVersion', "2.2.1.RELEASE")
}
repositories {
mavenLocal()
maven {
url 'http://maven.aliyun.com/nexus/content/groups/public/'
}
}
configurations {
compile.exclude module: 'tomcat-embed-el'
compile.exclude module: 'spring-boot-starter-tomcat'
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
compile (
/** api文档 */
'com.github.xiaoymin:knife4j-spring-boot-starter:3.0.2',
/** nacos配置中心 */
'com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-config',
/** nacos注册与发现中心 */
'com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery',
'org.springframework.boot:spring-boot-starter-web',
'org.springframework.boot:spring-boot-starter-undertow'
)
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springBootVersion}"
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
mavenBom "com.alibaba.cloud:spring-cloud-alibaba-dependencies:${alibabaCloudVersion}"
}
}
这里主要就是启动微服务集成knife4j文档,因为tomcat老报错,容器就用的undertow,web默认用的tomcat,如果需要需要使用undertow,增加如下内容排除tomcat依赖:
configurations {
compile.exclude module: 'tomcat-embed-el'
compile.exclude module: 'spring-boot-starter-tomcat'
}
两个微服务客户端增加一个配置类:
package com.asan.example.config;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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;
@Configuration
@EnableSwagger2WebMvc
public class Swagger2Config {
@Bean
public Docket createRestApi(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.asan.example.controller"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
Contact contact = new Contact("阿三", "http://www.asan.com", "[email protected]");
return new ApiInfoBuilder()
.title("example服务文档")
.description("example服务API文档")
.contact(contact)
.version("1.0")
.build();
}
}
增加启动类ExampleApplication
package com.asan.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class ExampleApplication {
public static void main(String[] args) {
SpringApplication.run(ExampleApplication.class, args);
}
}
接着来一个Controller做文档展示:
Controller这里自己随便写吧,能看到就行,这里也贴一下吧显得不那么空
package com.asan.example.controller;
import com.alibaba.fastjson.JSON;
import com.asan.example.entity.Cat;
import com.asan.example.pojo.dto.CatDto;
import com.asan.example.pojo.vo.PageResult;
import com.asan.example.pojo.vo.ResultVO;
import com.asan.example.service.impl.CatServiceImpl;
import com.asan.example.util.BeanCopierUtil;
import com.asan.example.util.RedisClient;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import tk.mybatis.mapper.entity.Example;
@RestController
@RequestMapping("/v1/example/cat")
@Slf4j
public class CatController {
@Autowired
private CatServiceImpl catService;
@Autowired
private RedisClient redisClient;
@ApiOperation("获取信息")
@GetMapping
public ResultVO getCat(@ApiParam("主键") @RequestHeader("cid") Integer cid) {
Cat cat = catService.selectById(cid);
if (cat != null) {
// 测试缓存
redisClient.setForTimeMIN("SOA:TEXMPLE:CAT:"+cid.toString(), JSON.toJSONString(cat), 30);
}
return new ResultVO(cat);
}
@ApiOperation("新增信息")
@PostMapping
public ResultVO addCat(@RequestBody CatDto catDto) {
Cat cat = new Cat();
BeanCopierUtil.copy(catDto, cat);
catService.insert(cat);
return new ResultVO(Constants.RESULT_SUCCESS);
}
@ApiOperation("修改信息")
@PutMapping
public ResultVO updateCat(@RequestBody CatDto catDto) {
Cat cat = new Cat();
BeanCopierUtil.copy(catDto, cat);
catService.updateById(cat);
return new ResultVO(Constants.RESULT_SUCCESS);
}
@ApiOperation("删除信息")
@DeleteMapping
public ResultVO deleteCat(@ApiParam("主键") @RequestHeader("cid") Integer cid) {
catService.deleteById(cid);
return new ResultVO(Constants.RESULT_SUCCESS);
}
}
然后复制项目更改名称为cart-service,settings-gradle记得也改下
controller里仅修改了路径和类名CartController
3、gateway集成微服务端
启动类一样复制一个过来,改名GatewayApplication
build.gradle文件增加依赖
compile (
/** api文档 */
'com.github.xiaoymin:knife4j-spring-boot-starter:3.0.2',
/** nacos配置中心 */
'com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-config',
/** nacos注册与发现中心 */
'com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery',
'javax.servlet:javax.servlet-api:3.1.0',
'org.springframework.cloud:spring-cloud-starter-gateway'
)
下面增加一个配置类
package com.asan.gateway.config;
import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebFlux;
import java.util.ArrayList;
import java.util.List;
/**
* @author Jaakko
*/
@Configuration
@Primary
@EnableSwagger2WebFlux
public class SwaggerResourceConfig implements SwaggerResourcesProvider {
public static final String API_URI = "v2/api-docs";
private final RouteLocator routeLocator;
private final GatewayProperties gatewayProperties;
public SwaggerResourceConfig(RouteLocator routeLocator, GatewayProperties gatewayProperties) {
this.routeLocator = routeLocator;
this.gatewayProperties = gatewayProperties;
}
@Override
public List get() {
List resources = new ArrayList<>();
List routes = new ArrayList<>();
//获取所有路由的ID
routeLocator.getRoutes().subscribe(route -> routes.add(route.getId()));
//过滤出配置文件中定义的路由->过滤出Path Route Predicate->根据路径拼接成api-docs路径->生成SwaggerResource
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("**", API_URI)))));
return resources;
}
private SwaggerResource swaggerResource(String name, String location) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(name);
swaggerResource.setLocation(location);
swaggerResource.setSwaggerVersion("2.0");
return swaggerResource;
}
}
gateway nacos配置
server:
port: 9200
spring:
cloud:
gateway:
#配置路由路径
routes:
- id: example
uri: lb://example
predicates:
- Path=/example/**
filters:
- StripPrefix=1
- id: cart-service
uri: lb://cart-service
predicates:
- Path=/cart-service/**
filters:
- StripPrefix=1
discovery:
locator:
#开启从注册中心动态创建路由的功能
enabled: true
#使用小写服务名,默认是大写
lower-case-service-id: true
启动两个微服务端,再启动gateway服务
浏览器访问:localhost:9200/doc.html
这里某些依赖手动加进去的,并未实际验证!!!(你可能觉得坑,但八九不离十),可能存在兼容问题,大致应该可以,有问题可以留言讨论!!!
效果图这里就不截了,自行玩耍