为了账号安全,请及时绑定邮箱和手机立即绑定

SpringCloud微服务学习:从入门到实践

概述

SpringCloud微服务学习涵盖了Spring Cloud的基本概念、主要组件及其功能介绍,包括服务注册与发现、负载均衡、服务容错处理及集中化配置管理等内容。本文还详细讲解了如何搭建Spring Cloud项目,创建服务提供者和消费者,并通过实际案例演示了服务注册发现与负载均衡的实现。此外,还深入探讨了服务容错处理与配置管理的最佳实践,帮助开发者掌握Spring Cloud微服务的核心技术。

SpringCloud简介

什么是SpringCloud

Spring Cloud 是一个基于 Spring Boot 的开发工具,它提供了快速构建分布式系统的中间层支持。它包括一系列微服务框架的集合,如配置管理、服务发现、断路器、路由、微服务间的负载均衡、声明式 REST 客户端、数据流的聚合、服务到服务的通信等。Spring Cloud 旨在简化分布式系统中的常见模式,并为开发者提供一系列工具和技术来简化分布式系统开发。

SpringCloud的主要组件及其作用

  1. Eureka:提供服务注册与发现。Eureka 服务端(也叫服务注册中心)是一个高可用的服务,客户端(服务提供者和消费者)通过心跳机制向服务端发送自己的地址信息,服务端接收到信息后将其存储并提供给需要调用服务的客户端。
  2. Ribbon:客户端负载均衡工具,它通过在客户端实现负载均衡的算法,直接调用服务,而不需要借助中间件。
  3. Feign:声明式的服务调用。Feign 提供了一个简单的 HTTP 客户端接口进行 HTTP 请求,使用 Feign 可以声明式地定义 HTTP 客户端。
  4. Hystrix:断路器,用于服务容错处理。当服务调用出现故障时,断路器会开启熔断机制,避免进一步调用失效服务,防止故障扩散。
  5. Config Server:集中式的配置管理,它提供了一个中心化的配置服务器,可以将配置信息集中管理,并将配置信息同步到各个服务。
  6. Zuul:API 网关,路由请求到不同服务,还提供过滤器支持,可以进行权限验证、日志记录、监控等功能。
  7. Spring Cloud Gateway:新的微服务网关,基于 Spring Boot 2.0 以上版本,支持多种路由策略,提供了强大的路由支持。
  8. Spring Cloud Stream:消息驱动的微服务,与 Spring Cloud Data Flow 结合,可以实现微服务之间的异步通信。
  9. Spring Cloud Sleuth:全链路监控,用于跟踪服务请求,收集和分析服务请求的时间、响应时间和异常信息。

SpringCloud的安装与配置

安装 Spring Cloud 需要先安装 Java 开发环境和 Maven 或 Gradle 等构建工具。下面以 Maven 为例,介绍如何配置 Spring Cloud 项目。

  1. 环境配置

    • 安装 Java 开发环境(建议使用 Java 8 或更高版本)。
    • 安装 Maven(建议版本 3.6+)。
  2. 创建 Maven 项目

    • 使用命令行创建 Maven 项目:
      mvn archetype:generate -DgroupId=com.example -DartifactId=springcloud-demo -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
    • 进入项目目录:
      cd springcloud-demo
  3. 添加依赖

    • 编辑 pom.xml 文件,添加 Spring Boot 和 Spring Cloud 依赖:

      <parent>
       <groupId>org.springframework.boot</groupId>
      .
       .
       .
      </parent>
      
      <dependencies>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
           <version>2.2.6.RELEASE</version>
       </dependency>
      </dependencies>
      
      <dependencyManagement>
       <dependencies>
           <dependency>
               <groupId>org.springframework.cloud</groupId>
               <artifactId>spring-cloud-dependencies</artifactId>
               <version>Hoxton.SR12</version>
               <type>pom</type>
               <scope>import</scope>
           </dependency>
       </dependencies>
      </dependencyManagement>
  4. 配置文件

    • src/main/resources 目录下创建 application.yml 文件,定义 Spring Cloud 配置:

      spring:
      application:
       name: eureka-client
      
      eureka:
      client:
       service-url:
         defaultZone: http://localhost:8761/eureka/
      instance:
       prefer-ip-address: true
    • spring.application.name 用于定义服务名称。
    • eureka.client.service-url.defaultZone 配置服务注册中心地址。
    • eureka.instance.prefer-ip-address 是否使用IP地址注册服务。
  5. 启动类

    • 创建启动类 SpringCloudDemoApplication.java

      package com.example;
      
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      
      @SpringBootApplication
      public class SpringCloudDemoApplication {
       public static void main(String[] args) {
           SpringApplication.run(SpringCloudDemoApplication.class, args);
       }
      }

通过以上步骤,一个简单的 Spring Cloud 项目就搭建完成了。接下来可以继续进行更深入的学习。

创建第一个SpringCloud微服务项目

使用IDE创建SpringBoot项目

在开始构建第一个 Spring Cloud 微服务前,我们先使用 IntelliJ IDEA 创建一个 Spring Boot 项目。

  1. 打开 IntelliJ IDEA,选择 File -> New -> Project,选择 Spring Initializr
  2. 选择Spring Boot版本,这里选择 Spring Boot 2.7.13
  3. 填写项目信息,如 GroupArtifact,例如:
    • Group: com.example
    • Artifact: springcloud-demo
  4. 选择依赖,选择 WebSpring Cloud 依赖,例如 Spring Cloud Netflix Eureka
  5. 创建项目,点击 Finish

通过以上步骤,一个简单的 Spring Boot 项目就创建完成了。

添加SpringCloud依赖

pom.xml 文件中添加 Spring Cloud 依赖,如下所示:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        <version>2.2.6.RELEASE</version>
    </dependency>
</dependencies>

此外,还需要在 pom.xml 文件中定义 Spring Cloud 依赖管理:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Hoxton.SR12</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

实现简单的服务

接下来,我们将实现一个简单的 REST 服务。在 src/main/java/com/example/springclouddemo 目录下创建一个 HelloController.java 文件,如下:

package com.example.springclouddemo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class HelloController {
    @GetMapping("/hello")
    public String sayHello() {
        return "Hello Spring Cloud!";
    }
}

运行项目

执行 mvn spring-boot:run 命令启动项目,访问 http://localhost:8080/api/hello,可以看到返回信息 "Hello Spring Cloud!"

服务注册与发现

使用Eureka构建服务注册中心

Eureka 是 Spring Cloud 中的核心组件之一,用于服务注册与发现。Eureka 服务端作为服务注册中心,服务提供者(Provider)和消费者(Consumer)注册到 Eureka 服务端,实现服务的注册与发现。

  1. 创建Eureka服务端

    • 创建一个新的 Spring Boot 项目,名为 EurekaServer
    • pom.xml 文件中添加 Eureka 服务端依赖:
      <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
       <version>2.2.6.RELEASE</version>
      </dependency>
    • application.yml 文件中配置 Eureka 服务端:

      server:
       port: 8761
      
      eureka:
       instance:
           hostname: localhost
       client:
           register-with-eureka: false
           fetch-registry: false
           server: true
    • 创建启动类 EurekaServerApplication.java

      package com.example.eurekaserver;
      
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
      
      @SpringBootApplication
      @EnableEurekaServer
      public class EurekaServerApplication {
       public static void main(String[] args) {
           SpringApplication.run(EurekaServerApplication.class, args);
       }
      }
  2. 创建Eureka客户端

    • 修改之前创建的服务项目 springcloud-demo,使其注册到 Eureka 服务端。
    • pom.xml 文件中添加 Eureka 客户端依赖:
      <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
       <version>2.2.6.RELEASE</version>
      </dependency>
    • application.yml 文件中配置 Eureka 客户端:

      spring:
       application:
           name: eureka-client
       cloud:
           nacos:
               discovery:
                   server-addr: localhost:8848
      eureka:
       client:
           service-url:
               defaultZone: http://localhost:8761/eureka/
       instance:
           prefer-ip-address: true
    • 创建启动类 SpringCloudDemoApplication.java

      package com.example;
      
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      
      @SpringBootApplication
      public class SpringCloudDemoApplication {
       public static void main(String[] args) {
           SpringApplication.run(SpringCloudDemoApplication.class, args);
       }
      }

服务提供者与消费者

  1. 服务提供者

    • HelloController.java 文件中定义 REST 服务,如下:

      package com.example.springclouddemo.controller;
      
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      
      @RestController
      @RequestMapping("/api")
      public class HelloController {
       @GetMapping("/hello")
       public String sayHello() {
           return "Hello Spring Cloud!";
       }
      }
  2. 服务消费者

    • 创建一个新的 Spring Boot 项目,名为 EurekaConsumer
    • pom.xml 文件中添加 Eureka 客户端依赖:
      <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
       <version>2.2.6.RELEASE</version>
      </dependency>
    • application.yml 文件中配置 Eureka 客户端:

      spring:
       application:
           name: eureka-consumer
       cloud:
           nacos:
               discovery:
                   server-addr: localhost:8848
      eureka:
       client:
           service-url:
               defaultZone: http://localhost:8761/eureka/
       instance:
           prefer-ip-address: true
    • HelloService.java 文件中定义服务调用:

      package com.example.eurekaconsumer.service;
      
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.cloud.client.ServiceInstance;
      import org.springframework.cloud.client.loadBalancer.LoadBalancerClient;
      import org.springframework.web.client.RestTemplate;
      
      import org.springframework.stereotype.Service;
      
      @Service
      public class HelloService {
       @Autowired
       private RestTemplate restTemplate;
      
       @Autowired
       private LoadBalancerClient loadBalancer;
      
       public String sayHello() {
           ServiceInstance serviceInstance = loadBalancer.choose("eureka-client");
           String serviceUrl = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/api/hello";
           return restTemplate.getForObject(serviceUrl, String.class);
       }
      }
    • HelloController.java 文件中调用 sayHello 方法:

      package com.example.eurekaconsumer.controller;
      
      import com.example.eurekaconsumer.service.HelloService;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      
      @RestController
      @RequestMapping("/api")
      public class HelloController {
       @Autowired
       private HelloService helloService;
      
       @GetMapping("/hello")
       public String sayHello() {
           return helloService.sayHello();
       }
      }

运行项目

启动 Eureka 服务端,访问 http://localhost:8761/,可以看到注册中心界面。启动服务提供者和消费者,访问 http://localhost:8080/api/hello,可以看到返回信息 "Hello Spring Cloud!"

服务的负载均衡

使用Ribbon实现服务的客户端负载均衡

Ribbon 是 Spring Cloud 提供的客户端负载均衡工具,它可以与 Eureka 结合使用,实现在客户端进行服务调用的负载均衡。

  1. 创建服务提供者

    • 创建一个新的 Spring Boot 项目,名为 RibbonProvider
    • pom.xml 文件中添加 Eureka 客户端依赖:
      <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
       <version>2.2.6.RELEASE</version>
      </dependency>
    • application.yml 文件中配置 Eureka 客户端:
      spring:
       application:
           name: ribbon-provider
       cloud:
           nacos:
               discovery:
                   server-addr: localhost:8848
      eureka:
       client:
           service-url:
               defaultZone: http://localhost:8761/eureka/
       instance:
           prefer-ip-address: true
  2. 创建服务消费者

    • 修改之前的 EurekaConsumer 项目,在 application.yml 文件中配置 Ribbon:
      spring:
       application:
           name: ribbon-consumer
       cloud:
           nacos:
               discovery:
                   server-addr: localhost:8848
      eureka:
       client:
           service-url:
               defaultZone: http://localhost:8761/eureka/
       instance:
           prefer-ip-address: true
      ribbon:
       eureka:
           enabled: true
  3. 在服务消费者中使用Ribbon

    • HelloService.java 文件中使用 Ribbon 实现负载均衡:

      package com.example.ribbonconsumer.service;
      
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.cloud.client.ServiceInstance;
      import org.springframework.cloud.client.loadBalancer.LoadBalancerClient;
      import org.springframework.web.client.RestTemplate;
      
      import org.springframework.stereotype.Service;
      
      import java.util.List;
      
      @Service
      public class HelloService {
       @Autowired
       private LoadBalancerClient loadBalancer;
      
       private List<ServiceInstance> instances;
       private int index = -1;
      
       public String sayHello() {
           instances = loadBalancer.getInstances("ribbon-provider");
           index = (index + 1) % instances.size();
           ServiceInstance instance = instances.get(index);
           String serviceUrl = "http://" + instance.getHost() + ":" + instance.getPort() + "/api/hello";
           return new RestTemplate().getForObject(serviceUrl, String.class);
       }
      }

运行项目

启动 Eureka 服务端,启动两个服务提供者实例,启动服务消费者,访问 http://localhost:8080/api/hello,可以看到负载均衡效果。

使用Feign实现声明式的服务调用

  1. 创建Feign服务消费者

    • 修改之前的 EurekaConsumer 项目,在 pom.xml 文件中添加 Feign 依赖:
      <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-openfeign</artifactId>
       <version>2.2.6.RELEASE</version>
      </dependency>
    • HelloService.java 文件中定义 Feign 客户端接口:

      package com.example.eurekaconsumer.service;
      
      import org.springframework.cloud.openfeign.FeignClient;
      import org.springframework.web.bind.annotation.GetMapping;
      
      @FeignClient(name = "ribbon-provider", url = "http://ribbon-provider")
      public interface RibbonProviderClient {
      
       @GetMapping("/api/hello")
       String sayHello();
      }
    • HelloService.java 文件中实现 Feign 客户端调用:

      package com.example.eurekaconsumer.service;
      
      import com.example.eurekaconsumer.service.RibbonProviderClient;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Service;
      
      @Service
      public class HelloService {
       @Autowired
       private RibbonProviderClient ribbonProviderClient;
      
       public String sayHello() {
           return ribbonProviderClient.sayHello();
       }
      }

运行项目

启动 Eureka 服务端,启动服务提供者和消费者,访问 http://localhost:8080/api/hello,可以看到通过 Feign 客户端实现的服务调用。

服务的容错处理

使用Hystrix实现服务的熔断与降级

Hystrix 是 Spring Cloud 提供的断路器库,用于实现服务的熔断与降级。它可以防止服务调用故障扩散,提高系统的健壮性。

  1. 创建服务提供者

    • 创建一个新的 Spring Boot 项目,名为 HystrixProvider
    • pom.xml 文件中添加 Hystrix 依赖:
      <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
       <version>2.2.6.RELEASE</version>
      </dependency>
    • HelloController.java 文件中添加 Hystrix 调用:

      package com.example.hystrixprovider.controller;
      
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
      import org.springframework.cloud.client.loadBalancer.LoadBalancerClient;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      import org.springframework.web.client.RestTemplate;
      
      import javax.annotation.Resource;
      import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
      
      @RestController
      @RequestMapping("/api")
      @EnableCircuitBreaker
      public class HelloController {
       @Autowired
       private LoadBalancerClient loadBalancer;
      
       @HystrixCommand(fallbackMethod = "fallback")
       @GetMapping("/hello")
       public String sayHello() {
           List<ServiceInstance> instances = loadBalancer.getInstances("hystrix-provider");
           ServiceInstance instance = instances.get(0);
           String serviceUrl = "http://" + instance.getHost() + ":" + instance.getPort() + "/api/hello";
           return new RestTemplate().getForObject(serviceUrl, String.class);
       }
      
       public String fallback() {
           return "Service Temporarily Unavailable";
       }
      }
  2. 创建服务消费者

    • 修改之前的 EurekaConsumer 项目,在 pom.xml 文件中添加 Hystrix 依赖:
      <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
       <version>2.2.6.RELEASE</version>
      </dependency>
  3. 在服务消费者中使用Hystrix

    • HelloService.java 文件中使用 Hystrix 实现容错处理:

      package com.example.eurekaconsumer.service;
      
      import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
      import org.springframework.cloud.client.loadBalancer.LoadBalancerClient;
      import org.springframework.web.client.RestTemplate;
      import org.springframework.stereotype.Service;
      
      @Service
      @EnableCircuitBreaker
      public class HelloService {
       @Autowired
       private LoadBalancerClient loadBalancer;
      
       @Autowired
       private RestTemplate restTemplate;
      
       @HystrixCommand(fallbackMethod = "fallback")
       public String sayHello() {
           ServiceInstance serviceInstance = loadBalancer.choose("hystrix-provider");
           String serviceUrl = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/api/hello";
           return restTemplate.getForObject(serviceUrl, String.class);
       }
      
       public String fallback() {
           return "Service Temporarily Unavailable";
       }
      }

运行项目

启动 Eureka 服务端,启动服务提供者和消费者,模拟服务提供者故障(如关闭服务提供者),访问 http://localhost:8080/api/hello,可以看到返回信息 "Service Temporarily Unavailable"

服务的超时控制与重试机制

Hystrix 还提供超时控制和重试机制,增强服务调用的健壮性。

  1. 设置超时控制

    • HelloService.java 文件中设置超时时间:
      @HystrixCommand(fallbackMethod = "fallback", timeoutInMilliseconds = 2000)
      public String sayHello() {
       ServiceInstance serviceInstance = loadBalancer.choose("hystrix-provider");
       String serviceUrl = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/api/hello";
       return restTemplate.getForObject(serviceUrl, String.class);
      }
  2. 设置重试机制
    • HelloService.java 文件中设置重试次数:
      @HystrixCommand(fallbackMethod = "fallback", commandProperties = {
           @HystrixProperty(name = "retry.enabled", value = "true"),
           @HystrixProperty(name = "retry.maxAttempts", value = "3")
      })
      public String sayHello() {
       ServiceInstance serviceInstance = loadBalancer.choose("hystrix-provider");
       String serviceUrl = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/api/hello";
       return restTemplate.getForObject(serviceUrl, String.class);
      }

运行项目

启动 Eureka 服务端,启动服务提供者和消费者,模拟网络延迟或服务不稳定情况,访问 http://localhost:8080/api/hello,可以看到服务调用的超时控制和重试机制。

服务的配置与管理

使用Config Server集中化管理配置

Config Server 是 Spring Cloud 提供的集中化配置管理工具,它可以通过 Git、SVN 等仓库集中管理配置信息。

  1. 创建Config Server项目

    • 创建一个新的 Spring Boot 项目,名为 ConfigServer
    • pom.xml 文件中添加 Config Server 依赖:
      <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-config-server</artifactId>
       <version>2.2.6.RELEASE</version>
      </dependency>
    • application.yml 文件中配置 Config Server:

      server:
       port: 8888
      
      spring:
       cloud:
           config:
               server:
                   git:
                       uri: https://github.com/example/config-repo
                       username: your-username
                       password: your-password
  2. 创建配置仓库

    • 在 GitHub 上创建一个新的仓库 config-repo
    • 在仓库中创建配置文件,如 application.yml,内容如下:
      spring:
       application:
           name: config-client
  3. 创建配置客户端

    • 修改之前的 EurekaConsumer 项目,在 pom.xml 文件中添加 Config Client 依赖:

      <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-config</artifactId>
       <version>2.2.6.RELEASE</version>
      </dependency>
    • bootstrap.yml 文件中配置 Config Client:
      spring:
       cloud:
           config:
               uri: http://localhost:8888/
       application:
           name: config-client

如何更新配置并使服务端自动获取更新

  1. 更新配置文件

    • 在 GitHub 上更新配置仓库中的配置文件,如修改 application.yml 文件中的值:
      spring:
       application:
           name: config-client
           profile: dev
  2. 刷新配置

    • 在服务端启动后,可以通过发送 POST 请求刷新配置:

      curl -X POST http://localhost:8080/actuator/refresh
    • HelloController.java 文件中添加刷新配置的方法:

      package com.example.eurekaconsumer.controller;
      
      import org.springframework.beans.factory.annotation.Value;
      import org.springframework.cloud.context.config.annotation.RefreshScope;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      
      @RestController
      @RequestMapping("/api")
      public class HelloController {
       @Value("${spring.application.name}")
       private String appName;
      
       @GetMapping("/hello")
       public String sayHello() {
           return "Hello " + appName;
       }
      }

运行项目

启动 Config Server,访问 http://localhost:8888/config-client,可以看到配置信息。更新配置仓库中的配置文件,发送刷新请求,可以在服务端看到配置更新效果。

通过以上步骤,我们完成了从 Spring Cloud 微服务入门到实践的全过程,介绍了 Spring Cloud 的基本概念、组件、配置、服务发现、负载均衡、容错处理以及配置管理等关键知识点。希望这些内容能帮助开发者更好地理解和使用 Spring Cloud。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消