66、SpringCloudAlibaba 基礎環境搭建 gateway Swagger SpringBoot、SpringCloud、SpringCloudAlibaba選擇版本依次是2.2.2.RELEASE、Hoxton.SR1、2.0.1.RELEASE
阿新 • • 發佈:2022-03-03
1、建立父工程
<properties> <java.version>1.8</java.version> <maven.compiler.source>${java.version}</maven.compiler.source> <maven.compiler.target>${java.version}</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <junit.version>4.12</junit.version> <log4.version>1.2.17</log4.version> <lombok.version>1.16.18</lombok.version> <druid.version>1.1.18</druid.version> <mybatis-plus.version>3.3.1</mybatis-plus.version> <generator.version>3.0.6</generator.version> <moredatasource.version>3.3.2</moredatasource.version> <hutool.version>5.3.9</hutool.version> <!-- Projects --> <jackson.version>2.9.6</jackson.version> <fastjson.version>1.2.12</fastjson.version> <swagger.version>2.9.2</swagger.version> <swagger-bootstrap-ui.version>1.9.6</swagger-bootstrap-ui.version> <spring-boot.version>2.2.2.RELEASE</spring-boot.version> <spring-cloud.version>Hoxton.SR1</spring-cloud.version> <cloud-alibaba.version>2.0.1.RELEASE</cloud-alibaba.version> </properties> <dependencyManagement> <dependencies> <!-- Spring Boot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring-boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- Spring Cloud --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- Spring Cloud Alibaba --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${cloud-alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>${druid.version}</version> </dependency> <!-- mybatis-plus的依賴 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatis-plus.version}</version> </dependency> <!-- mybatis-plus的自動生成依賴 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>${generator.version}</version> </dependency> <!-- mybatis-plus多資料來源 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>dynamic-datasource-spring-boot-starter</artifactId> <version>${moredatasource.version}</version> </dependency> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>2.1</version> </dependency> <!-- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </dependency> <!-- HuTool --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>${hutool.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>${fastjson.version}</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>${swagger.version}</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>${swagger.version}</version> </dependency> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>swagger-bootstrap-ui</artifactId> <version>${swagger-bootstrap-ui.version}</version> </dependency> </dependencies> </dependencyManagement> <!-- Maven 多環境配置 --> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <fork>true</fork> <source>${java.version}</source> <target>${java.version}</target> <skip>true</skip> <encoding>${project.build.sourceEncoding}</encoding> </configuration> </plugin> </plugins> </build>
2、建立通用模組shop-common
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>springcloud-alibaba</artifactId> <groupId>com.itheima</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>shop-common</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.56</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> </dependency> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>swagger-bootstrap-ui</artifactId> </dependency> </dependencies> </project>
3、通用模組中編寫Swagger配置BaseSwaggerConfig類
package com.itheima.config; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.ApiKey; import springfox.documentation.service.AuthorizationScope; import springfox.documentation.service.Contact; import springfox.documentation.service.Parameter; import springfox.documentation.service.SecurityReference; import springfox.documentation.spi.service.contexts.SecurityContext; import java.util.ArrayList; import java.util.List; import static com.google.common.collect.Lists.newArrayList; public class BaseSwaggerConfig { public List<Parameter> pars = new ArrayList<Parameter>(); public BaseSwaggerConfig(){ } public ApiInfo apiInfo(String title, String description, String version, String name, String url, String email) { return new ApiInfoBuilder() .title(title) .description(description) .contact(new Contact("edwin", "", "[email protected]")) .version(version) .build(); } public List<ApiKey> securitySchemes() { return newArrayList( new ApiKey("Authorization", "api-token", "header")); } public List<SecurityContext> securityContexts() { return newArrayList( SecurityContext.builder() .securityReferences(defaultAuth()) .forPaths(PathSelectors.regex("^(?!auth).*$")) .build() ); } public List<SecurityReference> defaultAuth() { AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; authorizationScopes[0] = authorizationScope; return newArrayList( new SecurityReference("Authorization", authorizationScopes)); } }
4、通用模組中編寫Swagger配置 SwaggerConfig類
package com.itheima.config; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; @Configuration @EnableSwagger2 public class SwaggerConfig { @Value("${spring.application.name:}") private String name; @Value("${swagger.title:}") private String title; @Value("${swagger.description:}") private String description; private static final String email = "[email protected]"; @Bean public Docket createRestApi() { BaseSwaggerConfig baseSwagger = new BaseSwaggerConfig(); return new Docket(DocumentationType.SWAGGER_2) .apiInfo(baseSwagger.apiInfo(title,description,"2.0",name,"",email)).select() .apis(RequestHandlerSelectors.withClassAnnotation(Api.class)) .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) .paths(PathSelectors.any()) .build().globalOperationParameters(baseSwagger.pars).securitySchemes(baseSwagger.securitySchemes()) .securityContexts(baseSwagger.securityContexts()); } }
5、建立shop-openfeign做服務的遠端呼叫
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>springcloud-alibaba</artifactId> <groupId>com.itheima</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>shop-openfeign</artifactId> <dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>com.itheima</groupId> <artifactId>shop-common</artifactId> <version>1.0-SNAPSHOT</version> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </exclusion> <exclusion> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </exclusion> </exclusions> </dependency> </dependencies> </project>
7、建立服務提供者以shop-user為例
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>springcloud-alibaba</artifactId> <groupId>com.itheima</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>shop-user</artifactId> <dependencies> <dependency> <groupId>com.itheima</groupId> <artifactId>shop-common</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>com.itheima</groupId> <artifactId>shop-openfeign</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> </dependencies> </project>
建立UserApplication主啟動類
@SpringBootApplication @EnableDiscoveryClient @EnableFeignClients(basePackages = {"com.itheima"}) @ComponentScan(basePackages = {"com.itheima"}) public class UserApplication { public static void main(String[] args) { SpringApplication.run(UserApplication.class, args); } }
建立application.yml配置檔案
server: port: 8087 spring: application: name: shop-user datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/shop?serverTimezone=CTT&characterEncoding=utf8&useUnicode=true&useSSL=false&autoReconnect=true&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true username: root password: 123456 jpa: hibernate: ddl-auto: update show-sql: true cloud: nacos: discovery: server-addr: 42.194.158.212:8848 feign: sentinel: enabled: true swagger: title: "Swagger2 API文件" description: "使用者管理微服務"
建立controller類做測試
@RestController @RequestMapping(value = "/user") @Api(tags = "使用者管理") public class UserController { @ApiOperation(value = "計算+", notes = "加法") @ApiImplicitParams({ @ApiImplicitParam(name = "a", paramType = "path", value = "數字a", required = true, dataType = "Long"), @ApiImplicitParam(name = "b", paramType = "path", value = "數字b", required = true, dataType = "Long") }) @GetMapping("/{a}/{b}") public Integer get(@PathVariable Integer a, @PathVariable Integer b) { return a + b; } }
建立JPA的dao類
import com.itheima.domain.User; import org.springframework.data.jpa.repository.JpaRepository; public interface UserRepository extends JpaRepository<User,Integer> { }
建立JPA的實體類,啟動專案會把對應的表自動建立,訪問http://localhost:8080/swagger-ui.html SwaggerApi
@Data @Entity @Table(name = "shop_user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String username; private String password; private String telephone; }
8、建立服務閘道器微服務shop-gateway
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>springcloud-alibaba</artifactId> <groupId>com.itheima</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>shop-gateway</artifactId> <dependencies> <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.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> </dependency> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>swagger-bootstrap-ui</artifactId> </dependency> </dependencies> </project>
建立application.yml
server: port: 7001 spring: application: name: shop-gateway cloud: nacos: discovery: server-addr: 42.194.158.212:8848 gateway: discovery: locator: enabled: true #開啟動態路由 routes: - id: shop-order uri: lb://shop-order predicates: ##如果滿足這個條件就會轉發到shop-order微服務 - Path=/order_service/order/** filters: # 1表示回刪除一層路徑之後轉發到shop-order微服務 # http://localhost:7001/order_service/order/create/2 會變成 => http://localhost:8081/order/create/2 - StripPrefix=1 - id: shop-product uri: lb://shop-product predicates: - Path=/product/** # http://localhost:7001/shop-user/v2/api-docs 這個是錯的 # http://localhost:8087/v2/api-docs 這個是對的 - id: shop-user uri: lb://shop-user predicates: - Path=/shop-user/** filters: - StripPrefix=1
建立主啟動類
@SpringBootApplication public class GatewayApplication { public static void main(String[] args) { SpringApplication.run(GatewayApplication.class,args); } }
建立SwaggerProvider對Swagger進行配置
@Component @Primary @AllArgsConstructor public class SwaggerProvider implements SwaggerResourcesProvider { public static final String API_URI = "/v2/api-docs"; private final RouteLocator routeLocator; private final GatewayProperties gatewayProperties; @Override public List<SwaggerResource> get() { List<SwaggerResource> resources = new ArrayList<>(); List<String> routes = new ArrayList<>(); //取出gateway的route routeLocator.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("2.0"); return swaggerResource; } }
建立SwaggerHandler 對Swagger資源做處理
@RestController @RequestMapping("/swagger-resources") 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("/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))); } }
建立SwaggerHeaderFilter
public class SwaggerHeaderFilter extends AbstractGatewayFilterFactory { private static final String HEADER_NAME = "X-Forwarded-Prefix"; @Override public 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); }; } }