- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
前言:
我们经常在springboot单体项目中,集成swagger来整合接口文档;
但是在微服务springcloud项目下,业务模块众多,如果再像之前一样单独访问每个模块的 swagger-ui.html ,则非常麻烦,怎么解决呢???
既然我们已经通过 nacos和gateway 实现统一访问,那我们也可以通过网关将所有的应用的swagger界面聚合起来。
这样前端开发的时候只需要访问网关的swagger就可以,而不用访问每个应用的swagger。
整体项目结构如下:
|-springcloud demo
|-----service-gateway //网关
|-----service-order //订单服务
|-----service-user //用户服务
由于服务接口订单和用户两个模块其实属性是差不多,只是接口不一样,因此就随便挑一个服务的配置来说吧
service-user:用户服务的接口
每个微服务只需要引入和swagger相关的依赖即可
同时引入nacos依赖,pom.xml文件相关配置如下:
<!--Nacos-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--Swagger相关-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
接下来是配置swagger的相关配置,SwaggerConfig.java配置如下:
@Configuration
@EnableSwagger2
@RequiredArgsConstructor
public class SwaggerConfig {
private final SwaggerProperties swaggerProperties;
@Value("${token.requestHeader}")
private String requestHeader;
@Value("${token.startWith}")
private String startWith;
@Bean
@SuppressWarnings("all")
public Docket createRestApi() {
ParameterBuilder ticketPar = new ParameterBuilder();
List<Parameter> pars = new ArrayList<>();
ticketPar.name(requestHeader).description("token")
.modelRef(new ModelRef("string"))
.parameterType("header")
.defaultValue(startWith)
.required(true)
.build();
pars.add(ticketPar.build());
return new Docket(DocumentationType.SWAGGER_2)
.enable(swaggerProperties.getEnabled())
.apiInfo(apiInfo())
.host(swaggerProperties.getHost())
.select()
.apis(RequestHandlerSelectors.basePackage("com.xx.controller")) //指定扫描的包名, 如果不指定会扫描整个项目
.paths(Predicates.not(PathSelectors.regex("/error.*")))
.build()
.globalOperationParameters(pars);
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.description(swaggerProperties.getDescription())
.title(swaggerProperties.getTitle())
.version(swaggerProperties.getVersion())
.build();
}
}
SwaggerProperties.java
@Data
@Configuration
@ConfigurationProperties(prefix = "swagger")
public class SwaggerProperties {
// 是否启用swagger
private Boolean enabled;
// 描述
private String description;
// 标题
private String title;
//版本
private String version;
// ip和host
private String host;
}
application.yml
server:
port: 8001
spring:
application:
name: user
cloud:
nacos:
server-addr: 127.0.0.1:8848
discovery:
server-addr: ${spring.cloud.nacos.server-addr}
token:
startWith: Bearer
requestHeader: Authorization
swagger:
enabled: true
host: 127.0.0.1:${server.port}
description: springcloud
title: swagger 接口文档
version: @project.version@
开启客户端
@SpringBootApplication
@EnableFeignClients
@EnableSwagger2
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}
当然,在服务的模块中还有和自己服务相关的业务接口(Controller代码),在这里就不列举了
订单模块(service-order)的代码配置和用户是类似的
有了nacos注册中心,服务模块的接口也已完成,最后一步是把我们所有的微服务都聚合到一个文档,统一输出到前端,供开发者调用了
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
server:
port: 8080
spring:
cloud:
nacos:
server-addr: 127.0.0.1:8848
discovery:
server-addr: ${spring.cloud.nacos.server-addr}
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: user_route
uri: lb://user
predicates:
- Path=/api/user/**
filters:
- StripPrefix=2 // 去掉路径的前缀,具体等级根据path 确定
- id: order_route
uri: lb://order
predicates:
- Path=/api/order/**
filters:
- SwaggerHeaderFilter // 如果是高版本的SpringCloud Gateway,则去掉,否则会报错
- StripPrefix=2
在我们使用Spring Boot等单体架构集成swagger项目时,是通过对包路径进行业务分组,然后在前端进行不同模块的展示,而在微服务架构下,我们的一个服务就类似于原来我们写的一个业务组
springfox-swagger提供的分组接口是swagger-resource,返回的是分组接口名称、地址等信息
在Spring Cloud微服务架构下,我们需要重写该接口,主要是通过网关的注册中心动态发现所有的微服务文档,代码如下:
@Configuration
@Primary
@RequiredArgsConstructor
public class SwaggerResourceConfig implements SwaggerResourcesProvider {
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("**", "v2/api-docs"))));
});
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;
}
}
接口:
@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)));
}
}
// 注意:这里不能添加 @EnableSwagger2
@SpringBootApplication
@EnableFeignClients
public class GateWayApplication {
public static void main(String[] args) {
SpringApplication.run(GateWayApplication.class, args);
}
}
最后分别依次启动项目:
打开文档地址:http://localhost:8080/swagger-ui.html
在集成Spring Cloud Gateway网关的时候,会出现没有basePath的情况(即定义的例如/user、/order等微服务的前缀), ,因此,在Gateway网关需要添加一个Filter实体Bean,代码如下:
@Component
public class SwaggerHeaderFilter extends AbstractGatewayFilterFactory {
private static final String HEADER_NAME = "X-Forwarded-Prefix";
private static final String URI = "/v2/api-docs";
@Override
public GatewayFilter apply(Object config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
String path = request.getURI().getPath();
if (!StringUtils.endsWithIgnoreCase(path,URI )) {
return chain.filter(exchange);
}
String basePath = path.substring(0, path.lastIndexOf(URI));
ServerHttpRequest newRequest = request.mutate().header(HEADER_NAME, basePath).build();
ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();
return chain.filter(newExchange);
};
}
}
然后在配置文件指定这个filter
spring:
cloud:
nacos:
server-addr: 127.0.0.1:8848
discovery:
server-addr: ${spring.cloud.nacos.server-addr}
gateway:
discovery:
locator:
enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由
routes:
- id: user_route
uri: lb://user
predicates:
- Path=/api/user/**
filters:
- SwaggerHeaderFilter
- StripPrefix=2 // 去掉路径的前缀,具体等级根据path 确定
- id: order_route
uri: lb://order
predicates:
- Path=/api/order/**
filters:
- SwaggerHeaderFilter // 如果是高版本的SpringCloud Gateway,则去掉,否则会报错
- StripPrefix=2
特别注意:如果是高版本的Spring Cloud Gateway,那么yml配置文件中的SwaggerHeaderFilter配置应该去掉
前言 这个东西有啥用,好玩? 确实, 好玩归好玩,其实很有使用场景。 可以自己选则一些业务节点触发这个机器人助手的消息推送; 简单举例: 有人给你的系统留下反馈意见了,推送到运营群去; 2.项目部署成
1. JWT 简介 JSON Web Token(JWT) 是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为 JSON 对象在各方之间安全地传输信息。该信息可以被验证和信
我的页面上有多个 ajax 调用,我想将它们合并为一个函数。 目前我在几个地方都有这种类型的功能: function AjaxCallOne () { //do something $.ajax(
我的 Facebook 集成基本上可以在我的应用程序中运行:出现 Facebook 对话框,用户可以选择“允许”或“不允许”。但是,我不明白 API 是如何工作的!我有一个使用此代码的 Activit
我必须将文件夹结构从我的应用程序共享到 OneDrive。 我已经检查了一个驱动器的 sdk,但在那个 sdk 中只能共享文件而不是文件夹,并且没有在该 sdk 中创建文件夹的选项 https://g
我是支付网关集成方面的新手。我必须在我的项目 (CORE PHP) 中集成 CCAvenue 支付网关集成。但是我不知道如何为开发人员测试创建商户帐户,如何获取商户 key 等。我已经进行了研发,但是
我正在尝试将“社交选项”集成到我的应用程序中。 我有 iOS6,但我的想法是有一个适用于 iOS5 的应用程序。使用 Twitter 框架非常简单,并且可以在 r.0 版本和 6.0 版本的设备上运行
我正在尝试将 flurryAds 集成到我的 iPhone 应用程序中,但我无法做到这一点。我导入名为 的 .h 文件 #import "Flurry.h" #import "FlurryAds.h"
我正在尝试在我的网站中实现类似 facebook 的按钮和评论,但我在 IE7 中遇到了评论框问题。 COMMENT USING 下拉框不知何故没有显示其他可用选项。这是我用来实现它的代码片段:
关闭。这个问题是off-topic .它目前不接受答案。 想改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 关闭 11 年前。 Improve th
我正在使用 SOAP API 进行 PayPal 集成(Express Checkout)。在 DoExpressCheckout 调用后,我调用 GetExpressCheckoutDetails。
我正在尝试将 paypal 作为支付网关之一集成到我的应用程序中,但在我点击支付按钮后它会返回以下错误。 错误 java.lang.RuntimeException:无法使用 Intent { cmp
我目前正在尝试将 paypal 结账与我们的在线商店集成。我们正在针对 Sandbox 进行测试。除了 IPN(即时付款通知)之外的所有内容都有效。 我们阅读了很多有关 Paypal 更改其安全模型的
我正在开发一个 android 应用程序,我想在其中集成 facebook 之类的。我正在浏览链接 http://developers.facebook.com/docs/guides/mobile/
所以我正在尝试构建一个集成了 FitBit 的 iOS 应用程序 (Swift 2)。 一旦用户打开“步行”页面,用户应该能够看到他每天的步数。 理想情况下,我们不希望每个用户都注册到 FitBit。
我是集成投递箱的新手,但我不太确定如何生成调用以获取请求 token secret 。 https://www.dropbox.com/developers/reference/api#request
我已经成功集成了 PayPal。一切正常。但我希望我的表格在成功付款后重定向到我的网站。另一个问题:如何从 PayPal 得到回应?这是我的 Paypal 表格。谢谢。 `
我在我的 Android 应用程序中集成了 Paypal 。我有一个主要 Activity - 和关于 Activity ,我在其中显示 Paypal 按钮。关于从主 Activity 访问的 Act
前言: 小编引入的图片和文字描述都是来自于尚硅谷的视频讲解,在此感谢尚硅谷的老师,同时也结合 seata文档官方文档进行整合 项目地址(gitee): https://gitee.com/qine
目录 1. demo project 1.1 接口准备 1.2 配置准备 2. docker 开启远程连接
我是一名优秀的程序员,十分优秀!