springboot与swagger与zuul整合


title: springboot与swagger与zuul整合
copyright: true
categories: springmvc和springboot
tags: swagger
password:


  • 1、项目结构:
    涉及到的服务有:
    api-gateway、userservice、taskservice,项目由Springboot-springcloud-jpa-fegin-consul-zuul构成微服务
  • 2、网关服务:
    其中 api-gateway 是网关服务 ,负责url的分发到各个微服务,用的是zuul,通过url匹配,在consul中找到并分发到不同服务,服务注册发现容器用的是consul,还可以用于配置项目key-value
    consul配置如下:
spring: 
cloud: 
inetutils: 
ignoredInterfaces: 
- docker0 
- veth.* 
- VMware.* 
- VPN.* 
consul: 
host: consul.zhibi.config 
#port: 8500 
discovery: 
healthCheckInterval: 15s #服务中心健康检查间隔 
preferIpAddress: true#使用外部IP注册服务,默认使用的是主机名 
health-check-critical-timeout: 5m #5分钟没有恢复服务的从服务注册中心移除 
instanceId: ${spring.cloud.client.hostname}:${spring.application.name}:${server.port} 
config: 
prefix: config 
defaultContext: xiuba-apigateway 
profileSeparator: ',' 
format: PROPERTIES 
 

服务分发用的是cloud全家桶中的zuul服务
配置如下:


spring: 
   application: 
      name: apigateway 
zuul: 
     ignoredServices: '*' 
    routes: 
         user-api: 
             path: /user/** 
           stripPrefix: false 
           serviceId: userservice 
        task-api: 
          path: /task/** 
           stripPrefix: false 
           serviceId: taskservice 
      debug: 
           request: true 
           include-debug-header: true 
 
      host: 
          connect-timeout-millis: 10000 
          socket-timeout-millis: 60000 
          max-total-connections: 1000 
         max-per-route-connections: 200 
      ribbon: 
          ReadTimeout: 10000 
          #开启饥饿模式,启动时创建好对应服务的client 
          eager-load: 
                 enabled: true 
          clients: userservice,taskservice,orderservice,payservice,searchservice 

以/user开始的url会被分配到userservice服务中,

以/task开始的url会被分派到taskservice服务中,

stripPrefix: true的时候,访问相应服务的时候会去掉前面的/user、/task前缀

  • 3、task、user服务
    cloud配置:
spring: 
cloud: 
inetutils: 
ignoredInterfaces: 
- docker0 
- veth.* 
- VMware.* 
- VPN.* 
consul: 
 host: consul.zhibi.config 
 #port: 8500 

 
discovery: 
 healthCheckInterval: 15s #服务中心健康检查间隔 
 
preferIpAddress: true#使用外部IP注册服务,默认使用的是主机名 
 
health-check-critical-timeout: 5m #5分钟没有恢复服务的从服务注册中心移除 
 
instanceId: ${spring.cloud.client.hostname}:${spring.application.name}:${server.port} 
 config: 
 prefix: config 
 defaultContext: xiuba-task 
 profileSeparator: ',' 
 format: PROPERTIES 
 
  • 4、swagger的maven依赖如下:
 
    io.springfox 
    springfox-swagger2 
    RELEASE 

 
 
    io.springfox 
    springfox-swagger-ui 
    RELEASE 
 
 
  • 5、zuul-swagger配置

①、SwaggerConfig.java:

package com.zhibi.xiuba.config; 
 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import springfox.documentation.builders.ApiInfoBuilder; 
import springfox.documentation.service.ApiInfo; 
import springfox.documentation.service.Contact; 
import springfox.documentation.spi.DocumentationType; 
import springfox.documentation.spring.web.plugins.Docket; 
import springfox.documentation.swagger.web.UiConfiguration; 
import springfox.documentation.swagger2.annotations.EnableSwagger2; 
 
/** 
* Created by qinhe_admin on 2017/9/20. 
*/ 
@Configuration 
@EnableSwagger2 
public class SwaggerConfig { 
 
@Bean 
public Docket createRestApi() { 
return new Docket(DocumentationType.SWAGGER_2) 
.apiInfo(apiInfo()); 
} 
 
private ApiInfo apiInfo() { 
return new ApiInfoBuilder() 
.title("白拿拿系统") 
.description("白拿拿系统接口文档说明") 
.termsOfServiceUrl("http://www.xiuba365.com") 
.contact(new Contact("秦贺", "", "[email protected]")) 
.version("1.0") 
.build(); 
} 
 
@Bean 
UiConfiguration uiConfig() { 
return new UiConfiguration(null, "list", "alpha", "schema", 
UiConfiguration.Constants.DEFAULT_SUBMIT_METHODS, false, true); 
} 
} 
 

②、DocumentationConfig


package com.zhibi.xiuba.config; 
 
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; 
 
/** 
* Created by qinhe_admin on 2017/9/20. 
*/ 
@Component 
@Primary 
public class DocumentationConfig implements SwaggerResourcesProvider { 
@Override 
public List get() { 
List resources = new ArrayList<>(); 
resources.add(swaggerResource("活动task模块API", "/task/v2/api-docs", "2.0")); 
resources.add(swaggerResource("用户账户user模块API", "/user/v2/api-docs", "2.0")); 
return resources; 
} 
 
private SwaggerResource swaggerResource(String name, String location, String version) { 
SwaggerResource swaggerResource = new SwaggerResource(); 
swaggerResource.setName(name); 
swaggerResource.setLocation(location); 
swaggerResource.setSwaggerVersion(version); 
return swaggerResource; 
} 
} 
 
  • 6、task和user服务的swagger配置

配置:


    xiuba: 
    swagger: 
    title: 活动task模块API 
    description: 活动模块接口文档说明 
    termsOfServiceUrl: http://www.xiuba365.com/ 
    version: 1.0 
    basePackage: com.zhibi.xiuba.controller 
    module: task 
    xiuba: 
    swagger: 
    title: 用户账户user模块API 
    description: 用户账户模块接口文档说明 
    termsOfServiceUrl: http://www.xiuba365.com/ 
    version: 1.0 
    basePackage: com.zhibi.xiuba.controller 
    module: user 

SwaggerConfig.java:

package com.zhibi.xiuba.configers; 
 
import org.springframework.boot.context.properties.ConfigurationProperties; 
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; 
import springfox.documentation.swagger.web.UiConfiguration; 
 
/** 
* Created by qinhe_admin on 2017/9/20. 
*/ 
@Configuration 
@ConfigurationProperties(prefix = "xiuba.swagger") 
public class SwaggerConfig { 
 
private String title; 
 
private String description; 
 
private String termsOfServiceUrl; 
 
private String version; 
 
private String basePackage; 
 
public String getTitle() { 
return title; 
} 
 
public void setTitle(String title) { 
this.title = title; 
} 
 
public String getDescription() { 
return description; 
} 
 
public void setDescription(String description) { 
this.description = description; 
} 
 
public String getTermsOfServiceUrl() { 
return termsOfServiceUrl; 
} 
 
public void setTermsOfServiceUrl(String termsOfServiceUrl) { 
this.termsOfServiceUrl = termsOfServiceUrl; 
} 
 
public String getVersion() { 
return version; 
} 
 
public void setVersion(String version) { 
this.version = version; 
} 
 
public String getBasePackage() { 
return basePackage; 
} 
 
public void setBasePackage(String basePackage) { 
this.basePackage = basePackage; 
} 
 
@Bean 
public Docket createRestApi() { 
return new Docket(DocumentationType.SWAGGER_2) 
.apiInfo(apiInfo()) 
.select() 
.apis(RequestHandlerSelectors.basePackage(basePackage)) 
//                .apis(RequestHandlerSelectors.withClassAnnotation(Api.class)) 
//                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) 
.paths(PathSelectors.any()) 
.build(); 
} 
 
private ApiInfo apiInfo() { 
return new ApiInfoBuilder() 
.title(title) 
.description(description) 
.termsOfServiceUrl(termsOfServiceUrl) 
.contact(new Contact("秦贺", "", "[email protected]")) 
.version(version) 
.build(); 
} 
 
@Bean 
UiConfiguration uiConfig() { 
return new UiConfiguration(null, "list", "alpha", "schema", UiConfiguration.Constants.DEFAULT_SUBMIT_METHODS, false, true); 
} 
} 
 

修改源代码的url:

Swagger2Controller.java:

package com.zhibi.xiuba.configers; 
 
import com.google.common.base.Optional; 
import com.google.common.base.Strings; 
import io.swagger.models.Swagger; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.boot.context.properties.ConfigurationProperties; 
import org.springframework.core.env.Environment; 
import org.springframework.http.HttpStatus; 
import org.springframework.http.ResponseEntity; 
import org.springframework.stereotype.Controller; 
import org.springframework.web.bind.annotation.*; 
import org.springframework.web.util.UriComponents; 
import springfox.documentation.annotations.ApiIgnore; 
import springfox.documentation.service.Documentation; 
import springfox.documentation.spring.web.DocumentationCache; 
import springfox.documentation.spring.web.PropertySourcedMapping; 
import springfox.documentation.spring.web.json.Json; 
import springfox.documentation.spring.web.json.JsonSerializer; 
import springfox.documentation.spring.web.plugins.Docket; 
import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper; 
 
import javax.servlet.http.HttpServletRequest; 
 
import static com.google.common.base.Strings.isNullOrEmpty; 
import static com.zhibi.xiuba.configers.HostNameProvider.componentsFrom; 
import static org.springframework.util.MimeTypeUtils.APPLICATION_JSON_VALUE; 
 
@Controller 
@ApiIgnore 
@ConfigurationProperties(prefix = "xiuba.swagger") 
public class Swagger2Controller { 
 
private String module; 
private static final String HAL_MEDIA_TYPE = "application/hal+json"; 
 
private final String hostNameOverride; 
private final DocumentationCache documentationCache; 
private final ServiceModelToSwagger2Mapper mapper; 
private final JsonSerializer jsonSerializer; 
 
public String getModule() { 
return module; 
} 
 
public void setModule(String module) { 
this.module = module; 
} 
 
@Autowired 
public Swagger2Controller( 
Environment environment, 
DocumentationCache documentationCache, 
ServiceModelToSwagger2Mapper mapper, 
JsonSerializer jsonSerializer) { 
 
this.hostNameOverride = environment.getProperty("springfox.documentation.swagger.v2.host", "DEFAULT"); 
this.documentationCache = documentationCache; 
this.mapper = mapper; 
this.jsonSerializer = jsonSerializer; 
} 
 
@RequestMapping(value = "/{module}/v2/api-docs", method = RequestMethod.GET, produces = {APPLICATION_JSON_VALUE, HAL_MEDIA_TYPE}) 
@PropertySourcedMapping( 
value = "${springfox.documentation.swagger.v2.path}", 
propertyKey = "springfox.documentation.swagger.v2.path") 
@ResponseBody 
public ResponseEntity getDocumentation( 
@RequestParam(value = "group", required = false) String swaggerGroup, 
@PathVariable(value = "module", required = true) String module, 
HttpServletRequest servletRequest) { 
 
if (org.apache.commons.lang3.StringUtils.isNotBlank(module) && module.equalsIgnoreCase(this.module)) { 
String groupName = Optional.fromNullable(swaggerGroup).or(Docket.DEFAULT_GROUP_NAME); 
Documentation documentation = documentationCache.documentationByGroup(groupName); 
if (documentation == null) { 
return new ResponseEntity(HttpStatus.NOT_FOUND); 
} 
Swagger swagger = mapper.mapDocumentation(documentation); 
UriComponents uriComponents = componentsFrom(servletRequest, swagger.getBasePath()); 
swagger.basePath(Strings.isNullOrEmpty(uriComponents.getPath()) ? "/" : uriComponents.getPath()); 
if (isNullOrEmpty(swagger.getHost())) { 
swagger.host(hostName(uriComponents)); 
} 
return new ResponseEntity(jsonSerializer.toJson(swagger), HttpStatus.OK); 
}else { 
return new ResponseEntity(HttpStatus.NOT_FOUND); 
} 
} 
 
private String hostName(UriComponents uriComponents) { 
if ("DEFAULT".equals(hostNameOverride)) { 
String host = uriComponents.getHost(); 
int port = uriComponents.getPort(); 
if (port > -1) { 
return String.format("%s:%d", host, port); 
} 
return host; 
} 
return hostNameOverride; 
} 
} 
 

HostNameProvider.java:

package com.zhibi.xiuba.configers; 
 
 
import org.springframework.http.server.ServletServerHttpRequest; 
import org.springframework.web.servlet.support.ServletUriComponentsBuilder; 
import org.springframework.web.util.UriComponents; 
import org.springframework.web.util.UriComponentsBuilder; 
import org.springframework.web.util.UrlPathHelper; 
 
import javax.servlet.http.HttpServletRequest; 
 
import static org.springframework.util.StringUtils.hasText; 
import static org.springframework.web.servlet.support.ServletUriComponentsBuilder.fromContextPath; 
 
public class HostNameProvider { 
 
public HostNameProvider() { 
throw new UnsupportedOperationException(); 
} 
 
static UriComponents componentsFrom( 
HttpServletRequest request, 
String basePath) { 
 
ServletUriComponentsBuilder builder = fromServletMapping(request, basePath); 
 
UriComponents components = UriComponentsBuilder.fromHttpRequest( 
new ServletServerHttpRequest(request)) 
.build(); 
 
String host = components.getHost(); 
if (!hasText(host)) { 
return builder.build(); 
} 
 
builder.host(host); 
builder.port(components.getPort()); 
 
return builder.build(); 
} 
 
private static ServletUriComponentsBuilder fromServletMapping( 
HttpServletRequest request, 
String basePath) { 
 
ServletUriComponentsBuilder builder = fromContextPath(request); 
 
builder.replacePath(prependForwardedPrefix(request, basePath)); 
if (hasText(new UrlPathHelper().getPathWithinServletMapping(request))) { 
builder.path(request.getServletPath()); 
} 
 
return builder; 
} 
 
private static String prependForwardedPrefix( 
HttpServletRequest request, 
String path) { 
 
String prefix = request.getHeader("X-Forwarded-Prefix"); 
if (prefix != null) { 
return prefix + path; 
} else { 
return path; 
} 
} 
} 

  • 7、访问

访问api-gateway微服务的swagger-ui,通过此服务的ui间接访问其他服务的接口文档数据
http://{ip}:{port}/swagger-ui.html

你可能感兴趣的:(springboot与swagger与zuul整合)