本文主要是介绍springcloud alibaba gateway方式集成swagger3.0,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1、项目结构
gateway 网关服务
user 用户服务
product 产品服务
common 公用服务
依赖关系 其它3个服务都引用了common
2、代码
1、加依赖
common项目 swagger包
<dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</version></dependency><!--swagger ui--><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>3.0.3</version></dependency>
gateway需要移除swagger配置
2、写配置
common项目
Swagger3Config
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.actuate.autoconfigure.web.server.ManagementPortType;
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
import org.springframework.boot.actuate.endpoint.web.*;
import org.springframework.boot.actuate.endpoint.web.annotation.ControllerEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.annotation.ServletEndpointsSupplier;
import org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpMethod;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.ResponseBuilder;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Response;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;import java.util.ArrayList;
import java.util.Collection;
import java.util.List;/*** @program: hy-cloud* @description: swagger 3.0* @author: loren* @Description: TODO* @create: 2023-02-06 17:33**/
@Configuration
@EnableOpenApi //注解启动用Swagger的使用,同时在配置类中对Swagger的通用参数进行配置
public class Swagger3Config implements EnvironmentAware {private String applicationName;private String applicationDescription;@Beanpublic Docket createRestApi(){//返回文档概要信息return new Docket(DocumentationType.OAS_30).apiInfo(apiInfo()).select().apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)).apis(RequestHandlerSelectors.withClassAnnotation(Api.class)).paths(PathSelectors.any()).build()
// .globalRequestParameters(getGlobalRequestParameters()).globalResponses(HttpMethod.GET,getGlobalResponseMessage()).globalResponses(HttpMethod.POST,getGlobalResponseMessage());}/*生成接口信息,包括标题,联系人等*/private ApiInfo apiInfo() {return new ApiInfoBuilder().title(applicationName+"接口文档").description(applicationDescription).contact(new Contact("接口文档","地址","邮箱")).version("1.0").build();}/*封装全局通用参数*//*private List<RequestParameter> getGlobalRequestParameters() {List<RequestParameter> parameters=new ArrayList<>();parameters.add(new RequestParameterBuilder().name("uuid").description("设备uuid").required(true).in(ParameterType.QUERY).query(q->q.model(m->m.scalarModel((ScalarType.STRING)))).required(false).build());return parameters;}*//*封装通用相应信息*/private List<Response> getGlobalResponseMessage() {List<Response> responseList=new ArrayList<>();responseList.add(new ResponseBuilder().code("404").description("未找到资源").build());return responseList;}@Beanpublic WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebEndpointsSupplier webEndpointsSupplier, ServletEndpointsSupplier servletEndpointsSupplier,ControllerEndpointsSupplier controllerEndpointsSupplier, EndpointMediaTypes endpointMediaTypes,CorsEndpointProperties corsProperties, WebEndpointProperties webEndpointProperties, Environment environment) {List<ExposableEndpoint<?>> allEndpoints = new ArrayList<>();Collection<ExposableWebEndpoint> webEndpoints = webEndpointsSupplier.getEndpoints();allEndpoints.addAll(webEndpoints);allEndpoints.addAll(servletEndpointsSupplier.getEndpoints());allEndpoints.addAll(controllerEndpointsSupplier.getEndpoints());String basePath = webEndpointProperties.getBasePath();EndpointMapping endpointMapping = new EndpointMapping(basePath);boolean shouldRegisterLinksMapping = webEndpointProperties.getDiscovery().isEnabled() &&(org.springframework.util.StringUtils.hasText(basePath) || ManagementPortType.get(environment).equals(ManagementPortType.DIFFERENT));return new WebMvcEndpointHandlerMapping(endpointMapping, webEndpoints, endpointMediaTypes, corsProperties.toCorsConfiguration(), new EndpointLinksResolver(allEndpoints, basePath), shouldRegisterLinksMapping, null);}@Overridepublic void setEnvironment(Environment environment) {this.applicationDescription = environment.getProperty("spring.application.description");this.applicationName = environment.getProperty("spring.application.name");}
WebMvcConfig
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/swagger-ui/**").addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/").resourceChain(false);registry.addResourceHandler("/swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");}@Overridepublic void addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/swagger-ui/").setViewName("forward:/swagger-ui/index.html");}
gateway 网关服务、
SwaggerHandler
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.*;import java.util.Optional;/*** swaggger*/
@RestController
@RequestMapping("/swagger-resources")
public class SwaggerHandler {@Autowired(required = false)private SecurityConfiguration securityConfiguration;@Autowired(required = false)private UiConfiguration uiConfiguration;private final SwaggerResourcesProvider swaggerResources;@Autowiredpublic SwaggerHandler(SwaggerResourcesProvider swaggerResources) {this.swaggerResources = swaggerResources;}@GetMapping("/configuration/security")public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() {return Mono.just(new ResponseEntity<>(Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK));}@GetMapping("/configuration/ui")public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() {return Mono.just(new ResponseEntity<>(Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK));}@GetMapping("")public Mono<ResponseEntity> swaggerResources() {return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));}
SwaggerProvider
import lombok.AllArgsConstructor;
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.Primary;
import org.springframework.stereotype.Component;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;import java.util.ArrayList;
import java.util.List;/*** @program: hy-cloud* @description: SwaggerProvider* @author: loren* @Description: TODO* @create: 2023-02-07 10:00**/
@Component
@Primary
@AllArgsConstructor
public class SwaggerProvider implements SwaggerResourcesProvider {public static final String API_URI = "/v3/api-docs";private final RouteLocator routeLocator;private final GatewayProperties gatewayProperties;/*** 这个类是核心,这个类封装的是SwaggerResource,即在swagger-ui.html页面中顶部的选择框,选择服务的swagger页面内容。* RouteLocator:获取spring cloud gateway中注册的路由* RouteDefinitionLocator:获取spring cloud gateway路由的详细信息* RestTemplate:获取各个配置有swagger的服务的swagger-resources*/@Overridepublic List<SwaggerResource> get() {List<SwaggerResource> resources = new ArrayList<>();List<String> routes = new ArrayList<>();//取出gateway的routerouteLocator.getRoutes().subscribe(route -> routes.add(route.getId()));//结合配置的route-路径(Path),和route过滤,只获取有效的route节点gatewayProperties.getRoutes().stream().filter(routeDefinition -> routes.contains(routeDefinition.getId())).forEach(routeDefinition -> routeDefinition.getPredicates().stream().filter(predicateDefinition -> ("Path").equalsIgnoreCase(predicateDefinition.getName())).forEach(predicateDefinition -> resources.add(swaggerResource(routeDefinition.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("3.0.0");return swaggerResource;}
SwaggerGatewayFilterFactory
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;/*** @program: hy-cloud* @description: swagger filter* @author: loren* @Description: TODO* @create: 2023-02-07 09:59**/
@Component
public class SwaggerGatewayFilterFactory extends AbstractGatewayFilterFactory {private static final String HEADER_NAME = "X-Forwarded-Prefix";@Overridepublic GatewayFilter apply(Object config) {return (exchange, chain) -> {ServerHttpRequest request = exchange.getRequest();String path = request.getURI().getPath();if (!StringUtils.endsWithIgnoreCase(path, SwaggerProvider.API_URI)) {return chain.filter(exchange);}String basePath = path.substring(0, path.lastIndexOf(SwaggerProvider.API_URI));ServerHttpRequest newRequest = request.mutate().header(HEADER_NAME, basePath).build();ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();return chain.filter(newExchange);};}
}
SwaggerGlobalFilter
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;/*** 类说明: 处理gateway集成knife4j后接口请求没带上服务名称问题**/
@Slf4j
@Component
public class SwaggerGlobalFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {String path=exchange.getRequest().getPath().toString();if (!path.endsWith(SwaggerProvider.API_URI)){return chain.filter(exchange);}String[] pathArray=path.split("/");String basePath=pathArray[1];ServerHttpResponse originalResponse = exchange.getResponse();// 定义新的消息头HttpHeaders headers = new HttpHeaders();headers.putAll(exchange.getResponse().getHeaders());ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {@Overridepublic Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {if (Objects.equals(getStatusCode(), HttpStatus.OK) && body instanceof Flux) {Flux<? extends DataBuffer> fluxBody = Flux.from(body);return super.writeWith(fluxBody.buffer().map(dataBuffers -> {List<String> list = new ArrayList<String>();dataBuffers.forEach(dataBuffer -> {byte[] content = new byte[dataBuffer.readableByteCount()];dataBuffer.read(content);DataBufferUtils.release(dataBuffer);list.add(new String(content, StandardCharsets.UTF_8));});String s = listToString(list);int length = s.getBytes().length;headers.setContentLength(length);JSONObject jsonObject= JSONUtil.parseObj(s);jsonObject.set("basePath",basePath);s=jsonObject.toString();return bufferFactory().wrap(s.getBytes());}));}return super.writeWith(body);};@Overridepublic HttpHeaders getHeaders() {HttpHeaders httpHeaders = new HttpHeaders();httpHeaders.putAll(super.getHeaders());//由于修改了请求体的body,导致content-length长度不确定,因此使用分块编码httpHeaders.remove(HttpHeaders.CONTENT_LENGTH);httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");return httpHeaders;}private String listToString(List<String> list){StringBuilder stringBuilder=new StringBuilder();for (String s:list){stringBuilder.append(s);}return stringBuilder.toString();}};return chain.filter(exchange.mutate().response(decoratedResponse).build());}@Overridepublic int getOrder() {return -2;}
}
gateway yml配置
除了网关服务外,所有需要swagger的项目yml都需要配置上:
最后访问:
这篇关于springcloud alibaba gateway方式集成swagger3.0的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!