spring cloud

目录

1.系统架构演变

1.1.单体应用架构

1.2.微服务架构

1.3. 单体应用架构和微服务架构的区别

1.3.1.单体应用架构的优点

1.3.2.单体应用架构的缺点

1.3.3.微服务架构的优点

1.3.4.微服务架构的缺点

2.什么是springCloud

3.微服务出现的问题

4.微服务架构的常见概念

4.1.服务治理

4.1.1.服务注册

4.1.2.服务发现

4.1.3.服务剔除

4.2.服务调用

4.2.1.RESTful接口

4.2.2.RPC协议

4.2.3.RESTful接口和RPC协议的区别

4.3.服务网关

4.4. 服务容错

4.5.链路追踪

5.微服务架构的解决方案

5.1.SpringCloud-Netflix

5.2. SpringCloud Alibaba 

6.搭建微服务

6.1.准备条件

6.1.1.技术选型

6.1.2.模块设计

6.2.创建父工程

6.2.3.依赖

6.2.4.隐藏java中的文件--在另一篇博客中

6.3.公共模块代码

6.3.1.创建公共模块

6.3.2.添加依赖

6.4.商品微服务--对商品的各种操作

6.4.1.创建商品微服务--省略

6.4.2.添加依赖

6.4.3.创建配置并在配置文件中写入数据源

6.4.4.添加主启动类

6.4.5.controller

6.4.6.dao

6.4.7. ProductService

6.4.8.service

6.4.9.运行

6.5.订单微服务

6.5.1.创建订单微服务--省略

6.5.2.添加依赖

6.5.3.创建配置文件,并且写入数据源

6.5.4.创建主启动类

6.5.5.controller

6.5.6.service

6.5.7.serviceImpl

6.5.8.dao

6.5.9.运行

7.服务治理

7.1.为什使用服务治理

7.2.什么是服务治理

7.2.1.服务注册

7.2.2.服务发现

7.3.常见的注册中心

7.3.1.Zookeeper

7.3.2.Eureka

7.3.3.Consul

7.3.4.Nacos (服务治理  配置中心)

8.nacos

8.1.什么是nacos

8.2.搭建Nacos 的环境

8.2.1.下载Nacos

8.2.2.安装Nacos --解压就可以

8.2.3.启动Nacos

8.2.4.访问Nacos

 8.3. 将商品微服务注册到nacos

8.3.1.添加依赖

8.3.2.在配置文件中指定路径和微服务的名称

8.3.3.启动服务

8.4.订单微服务拉取商品微服务

8.4.1.添加依赖

8.4.2.在配置文件中指定那个服务和拉取微服务的名称

8.4.3.修改controller层里面的代码

9.负载均衡

9.1.什么是负载均衡

9.2.自定义负载均衡

9.2.1.启动多个商品微服务

9.2.2.controller层代码

9.2.3.访问

9.3.基于Ribbon实现负载均衡 ---组件

9.3.1.什么是Ribbon

9.3.2.Ribbon的主要作用

9.3.3.使用Ribbon完成负载均衡

9.3.4.Ribbon支持的负载均衡策略

9.3.5.通过修改配置来调整Ribbon的负载均衡策略

10.基于OpenFeign实现服务调用

10.1.什么使用openFeign

10.2.什么是openFeign

10.3.使用openFeign

10.3.1.添加openFeign的依赖

10.3.2.创建openFeign的接口

10.3.3.在主类上开启openFeign注解

10.3.4.修改controller层的代码

10.3.5.访问

11.nacos集群

11.1.如何使用nacos集群

11.1.1创建一个数据库

11.1.2.创建表,添加数据

11.1.3.指定使用mysql作为数据存储

11.1.4.配置集群文件

11.1.5.停止nacos并复制三份

11.1.6.修改每一份的端口号

11.1.7.启动三个nacos

11.1.8.访问nacos

11.2.搭建nginx代理上面三个nacos

11.2.1.启动nginx

11.2.2.访问

 11.3.将微服务注册到nacos集群上

12.gateway网关

12.1.什么是网关

12.2.常见的网关

12.2.1.Ngnix+lua

12.2.2.kong

12.2.3.Zuul 1.0(慢 servlet 2.0 ) zuul2.0 没出来

12.2.4.Spring Cloud Gateway

12.3.什么是Gateway网关

12.3.1.Gateway网关优点

12.3.2.Gateway网关缺点

13.4.如何使用gateway网关

13.4.1.创建一个gateway微服务模块--此步骤省略

13.4.2.加入相关的依赖

13.4.3.配置文件

13.4.4.创建主启动类

13.4.5.访问

13.5.优化--让gateway网关从注册中心拉取服务

 13.5.1.加入依赖

 13.5.2.配置文件中指定注册中心的地址

13.6.gateway自动路由

13.6.1.修改配置文件

13.6.2.访问

 13.7.Gateway断言

13.7.1.基于Datetime类型的断言工厂

13.7.2.基于远程地址的断言工厂

13.7.3.基于Cookie的断言工厂

13.7.4.基于Header的断言工厂

13.7.5.基于Host的断言工厂

13.7.6.基于Method请求方法的断言工厂

13.7.7.基于Path请求路径的断言工厂

13.7.8.基于路由权重的断言工厂

13.8.过滤器

13.8.1.过滤器的作用

13.8.2.过滤器的生命周期

13.8.3.过滤器的分类

13.8.4.自定义全局过滤器

14.配置文件

14.1.为什么使用配置文件

14.2.如何使用配置文件

14.2.1.在配置中心创建一个配置文件

14.2.2.添加配置文件依赖

14.2.3.创建一个配置文件--名字是bootstrap.properties

14.2.4.写一个方法进行测试

14.2.5.将application配置文件的内容复制到配置中心

14.2.6.配置文件实时刷新

14.3.命名空间

14.3.1.创建命名空间

14.3.2.将public里面的配置克隆到dev(开发环境下)

14.3.3.运行项目

14.4.1.新建配置

14.4.2.将product和order的数据源剪切到新建的配置中

14.4.3.修改bootstrap.properties文件

14.5.4.访问--测试

15.Sleuth--链路追踪

15.1.什么是链路追踪

15.2.常见的链路追踪

15.2.1.cat

15.2.2.zipkin 

15.2.3.pinpoint

15.2.4.skywalking 【未来企业会使用的多】

15.2.5.Sleuth

15.3.什么是Sleuth

15.4.如何使用Sleuth

15.4.1.在父工程添加依赖

15.5.Zipkin

15.5.1.什么是Zipkin

15.6. ZipKin安装

15.6.1.下载成功--输入命令就可以用

15.6.2.启动ZipKin--找到自己下载的位置

15.6.3.访问zipken

15.7.如何使用zipkin

15.7.1.在父类中添加依赖

15.7.2.修改配置文件

15.7.3.重启项目并且访问


1.系统架构演变

        随着互联网的发展,网站应用的规模也在不断的扩大,进而导致系统架构也在不断的进行变化。   从互联网早起到现在,系统架构大体经历了下面几个过程: 单体应用架构--->垂直应用架构--->分布式架构--->SOA架构--->微服务架构,当然还有悄然兴起的Service Mesh(服务网格化)

1.1.单体应用架构

        互联网早期,一般的网站应用流量较小,只需一个应用,将所有功能代码都部署在一起就可以,这样可以减少开发、部署和维护的成本。比如说一个电商系统,里面会包含很多用户管理,商品管理,订单管理,物流管理等等很多模块,  我们会把它们做成一个web项目,然后部署到一台tomcat服务器上。

1.2.微服务架构

        把一个项目拆分成若干个工程,而每一个工程是可以独立运行和部署的,物理进行了拆分,逻辑上还是一个整体---->必须要springboot(独立的系统) 必须依赖于springboot技术。Springcloud如果没有springboot 那么springcloud也无法使用。 springboot可以独立使用。因为springboot里面内置了tomcat

1.3. 单体应用架构和微服务架构的区别

1.3.1.单体应用架构的优点

(1)项目架构简单,小型项目的话,开发成本低。

(2)项目部署在一个节点上,维护方便

1.3.2.单体应用架构的缺点

(1)全部功能集成在一个工程中,对于大型项目来讲不易开发和维护[修改代码]。

(2)项目模块之间紧密耦合,单点容错率低。

(3)无法针对不同模块进行针对性优化和水平扩展

1.3.3.微服务架构的优点

(1)服务原子化拆分,独立打包、部署和升级,保证每个微服务清晰的任务划分,利于扩展

(2)微服务之间采用Restful等轻量级http协议相互调用

1.3.4.微服务架构的缺点

(1)小型项目----微服务架构不合适。仓库系统---微服务。

(2)微服务系统开发的技术成本高《高》(容错、分布式事务等)

2.什么是springCloud

        Spring Cloud就是微服务系统架构的一站式解决方案,是各个微服务架构落地技术的集合体,俗称微服务全家桶,在平时我们构建微服务的过程中需要做如服务发现注册、配置中心、负载均衡、断路器、数据监控等操作,而Spring Cloud 为我们提供了一套简易的编程模型,使我们能在 Spring Boot 的基础上轻松地实现微服务项目的构建

3.微服务出现的问题

3.1.这么多小服务,如何管理他们? --概念:服务治理 

3.2.这么多小服务,他们之间如何通讯?调用 --概念:服务调用 

3.3.这么多小服务,客户端怎么访问他们?前端 --概念:服务网关

3.4.这么多小服务,一旦出现问题了,应该如何自处理? --概念:服务容错

3.5.这么多小服务,一旦出现问题了,应该如何排错? --概念:链路追踪

4.微服务架构的常见概念

4.1.服务治理

服务治理就是进行服务的自动化管理,其核心是服务的自动注册与发现。

4.1.1.服务注册

服务实例将自身服务信息注册到注册中心。

4.1.2.服务发现

服务实例通过注册中心,获取到注册到其中的服务实例的信息,通过这些信息去请求它们提供的服务。

4.1.3.服务剔除

服务注册中心将出问题的服务自动剔除到可用列表之外,使其不会被调用到。

4.2.服务调用

在微服务架构中,通常存在多个服务之间的远程调用的需求。目前主流的远程调用技术有基于HTTP的RESTful接口以及基于TCP的RPC协议。

4.2.1.RESTful接口

这是一种HTTP调用的格式,更标准,更通用,无论哪种语言都支持http协

4.2.2.RPC协议

 @Autowire Bservice  bservice.方法()

一种进程间通信方式。允许像调用本地服务一样调用远程服务。RPC框架的主要目标就是让远程服务调用更简单、透明。RPC框架负责屏蔽底层的传输方式、序列化方式和通信细节。开发人员在使用的时候只需要了解谁在什么位置提供了什么样的远程服务接口即可,并不需要关心底层通信细节和调用过程。

4.2.3.RESTful接口和RPC协议的区别

 4.3.服务网关

        随着微服务的不断增多,不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信可能出现:

1.客户端需要调用不同的url地址,增加难度

2.在一定的场景下,存在跨域请求的问题

3.每个微服务都需要进行单独的身份认证

        针对这些问题,API网关顺势而生。API网关直面意思是将所有API调用统一接入到API网关层,由网关层统一接入和输出。一个网关的基本功能有:统一接入、安全防护、协议适配、流量管控、长短链接支持、容错能力。有了网关之后,各个API服务提供团队可以专注于自己的的业务逻辑处理,而API网关更专注于安全、流量、路由等问题。

4.4. 服务容错

        在微服务当中,一个请求经常会涉及到调用几个服务,如果其中某个服务不可用,没有做服务容错的话,极有可能会造成一连串的服务不可用,这就是雪崩效应。 我们没法预防雪崩效应的发生,只能尽可能去做好容错。服务容错的三个核心思想是:

1.不被外界环境影响

2.不被上游请求压垮

3.不被下游响应拖垮

4.5.链路追踪

        随着微服务架构的流行,服务按照不同的维度进行拆分,一次请求往往需要涉及到多个服务。互联网应用构建在不同的软件模块集上,这些软件模块,有可能是由不同的团队开发、可能使用不同的编程语言来实现、有可能布在了几千台服务器,横跨多个不同的数据中心。因此,就需要对一次请求涉及的多个服务链路进行日志记录,性能监控即链路追踪

5.微服务架构的解决方案

5.1.SpringCloud-Netflix

springcloud 很多组件都是拿的是Netflix公司,这家公司这些组件停止维护和更新)

Eureka组件解决服务治理

Feign组件解决服务调用的问题

zuul组件解决客户端调用微服务的问题

hystrix组件解决容错

sleuth组件链路追踪

        Spring Cloud是一系列框架的集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署.Spring Cloud并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。已经停更了。Euruka(注册中),feign远程调用,hystrix 容错,zuul网关   

5.2. SpringCloud Alibaba 

引入springcloud很多组件都更新了-springcloud alibaba

        Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。

nacos组件解决服务治理

openfeign组件解决服务调用

gateway[spring公司]主件解决api网关

sentinel主件解决服务容错

sleuth组件链路追踪--Netflix

6.搭建微服务

本次是使用的电商项目中的商品微服务订单微服务为案例

6.1.准备条件

6.1.1.技术选型

maven3.5.0+

数据库:MySQL 5.7 以上

持久层: Mybatis-plus /《Mybatis  Mapper Mybatis-plus》

其他: SpringCloud Alibaba /技术栈 / druid

6.1.2.模块设计

创建父工程 ----jar的版本管理  公共jar的引入

创建公共模块【实体类】 《实体类,公共依赖,工具类。》

创建商品微服务 【端口: 8080~8089  搭建集群

创建订单微服务 【端口: 8090~8099  搭建集群

6.2.创建父工程

6.2.3.依赖

将自动生成的依赖删除一下,还有他们的版本号要对应,下面地址是其他博客的写的版本对应

springboot,springCloud,springCloudAlibaba各版本之间的对应关系_lwdbcy的博客-CSDN博客

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <modules>
        <module>springcloud-comment</module>
    </modules>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.12.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.guan</groupId>
    <artifactId>springboot-springcloud</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-springcloud</name>
    <description>Demo project for Spring Boot</description>

    <!--如果你的工程为父工程那么它的打包方式为pom-->
    <packaging>pom</packaging>
    <!--定义版本号-->
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF- 8</project.reporting.outputEncoding>
        <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
        <spring-cloud-alibaba.version>2.2.3.RELEASE</spring-cloud-alibaba.version>
    </properties>

    <!--dependencyManagement:它只负责jar的版本号管理,不负责jar的下载,交于子模块,子模块在使用时无需指定版本号
          :springboot springcloud  springcloudalibaba之间版本一定要匹配
    -->
    <dependencyManagement>
        <dependencies>
            <!--springcloud的版本管理-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--springcloudalibaba的版本管理-->

            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

 6.2.4.隐藏java中的文件--在另一篇博客中

可以将父工程的src给删除,我们不在父工程写代码,其他的不要删除要不然可能会报错

6.3.公共模块代码

6.3.1.创建公共模块

 

6.3.2.添加依赖

  <!--引入lombok依赖-->
    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
      
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>
    </dependencies>

6.3.3.添加实体类

@Data
@TableName(value="shop_product")
public class Product {
    @TableId(type= IdType.AUTO)
    private Integer pid;
    private String pname;//商品名称
    private Double pprice;//商品价格
    private Integer stock;//库存
}
@Data
@TableName("shop_order")
public class Order {
    @TableId(type = IdType.AUTO)
    private Long oid; //订单id
    private Integer uid;//用户id
    private String username;//用户名
    private Integer pid;//商品id
    private String pname;//商品名称
    private Double pprice;//商品价格
    private Integer number;//购买数量
}

6.4.商品微服务--对商品的各种操作

如果其他微服务也要用到商品的操作,让其他服务调用商品微服务,不要再其他服务在写对商品的操作

6.4.1.创建商品微服务--省略

6.4.2.添加依赖

<dependencies>
        <!--引入公共模块-->
        <dependency>
            <groupId>com.guan</groupId>
            <artifactId>springcloud-comment</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <!--引入mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--引入web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

6.4.3.创建配置并在配置文件中写入数据源

#为了后期扩展方便微服务的端口号设置为8080-8090之间
server.port=8081
#数据源
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.password=grt081141
spring.datasource.username=root
spring.datasource.url=jdbc:mysql://localhost:3306/springcloud?serverTimezone=Asia/Shanghai
#日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

6.4.4.添加主启动类

package guan;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringcloudApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringcloudApplication.class, args);
    }

}

6.4.5.controller

@RestController
@RequestMapping("product")
public class ProductController {
    @Autowired
    private ProductService productService;
    @GetMapping("/getById/{pid}")
    public Product product(@PathVariable Integer pid){
        return productService.findById(pid);
    }
}

6.4.6.dao

@Mapper
public interface ProductMapper extends BaseMapper<Product> {

}

6.4.7. ProductService

public interface ProductService {

    Product findById(Integer pid);
}

6.4.8.service

@Service
public class ProductServiceImpl implements ProductService {
    @Autowired
    private ProductMapper productMapper;
    @Override
    public Product findById(Integer pid) {

        return productMapper.selectById(pid);
    }
}

6.4.9.运行

可能会出现的错误

6.5.订单微服务

6.5.1.创建订单微服务--省略

6.5.2.添加依赖


        <!--引入公共模块-->
        <dependency>
            <groupId>com.guan</groupId>
            <artifactId>springcloud-comment</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <!--引入价格模块-->
        <dependency>
            <groupId>com.guan</groupId>
            <artifactId>springcloud-product</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

6.5.3.创建配置文件,并且写入数据源

#为了后期扩展方便订单微服务的端口号设置为8090-8099之间
server.port=8091
#数据源
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.password=grt081141
spring.datasource.username=root
spring.datasource.url=jdbc:mysql://localhost:3306/springcloud?serverTimezone=Asia/Shanghai
#日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

6.5.4.创建主启动类

@SpringBootApplication
public class SpringcloudOrderApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringcloudOrderApplication.class, args);


    }
    //将RestTemplate交于容器管理
    @Bean
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

}

 6.5.5.controller

@RestController
@RequestMapping("order")
public class OrderController {
    @Autowired
    private OrderServiceImpl orderService;
    //注入工具类 --这个工具类没有交于容器管理,需要自己手动交于容器
    @Autowired
    private RestTemplate restTemplate;
    @GetMapping("buy/{pid}/{num}")
    public String buy(@PathVariable Integer pid,@PathVariable Integer num){
        System.out.println("=======购买开始===========");
        Order order=new Order();
        //设置购买的数量
        order.setNumber(num);
        //设置购买人的名字
        order.setUsername("东方青苍");
        //设置id
        order.setUid(1);
        //设置订单中商品的信息
        //由于商品的信息在商品微服务中,如果想要用,得调用
        //远程调用有两种方法1.http协议的restful风格的调用--适合微服务2.基于TCp协议的RPC--适合SOA分布式
        //所以我们用http协议--1.自己写代码完成http的调用
        // 2springboot提供一个工具类RestTemplate--属于http协议完成的调用
        Product forObject = restTemplate.getForObject("http://localhost:8081/product/getById/" + pid, Product.class);
        //获取商品的id
        order.setPid(pid);
        order.setPprice(forObject.getPprice());
        order.setPname(forObject.getPname());
        orderService.saveOrder(order);
        System.out.println("==========购买结束=========");
        return "下单成功";
    }
}

 6.5.6.service

public interface OrderService {
    public int saveOrder(Order order);
}

 6.5.7.serviceImpl

@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderMapper orderMapper;
    @Override
    public int saveOrder(Order order) {
        //添加,将订单的信息添加到order中
        return orderMapper.insert(order);
    }
}

6.5.8.dao

@Mapper
public interface OrderMapper extends BaseMapper<Order> {
}

6.5.9.运行

7.服务治理

7.1.为什使用服务治理

上面的代码,因为我们生产者的ip和端口号都写死了,会出现一下的问题

1.如果商品微服务部署的地址发生改变,订单微服务也要跟着修改

2.没有办法使用负载均衡

3.一旦服务变得越来越多,人工维护调用关系困难

解决的方法:使用服务治理主件--所有的微服务都会自动的把自己的信息注册到该主件

7.2.什么是服务治理

        服务治理是微服务架构中最核心最基本的模块。用于实现各个微服务的自动化注册与发现

7.2.1.服务注册

        在服务治理框架中,都会构建一个注册中心,每个服务单元向注册中心登记自己提供服务的详细信息。并在注册中心形成一张服务的清单,服务注册中心需要以心跳30s  90s的方式去监测清单中 的服务是否可用,如果不可用,需要在服务清单中剔除不可用的服务

7.2.2.服务发现

        服务调用方向服务注册中心咨询服务,并获取所有服务的实例清单,实现对具体服务实例的访问。

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值