当前位置:   article > 正文

Apollo安装和基本使用_安装apollo

安装apollo

Apollo的搭建和基本使用

1.Apollo安装

Apollo架构

首先看一下阿波罗的架构图,留个印象,具体的功能可以看下面连接地址

https://bbs.csdn.net/topics/605023699

Apollo 架构图 by 宋顺

如图主要分为三个模块

ConfigService、AdminService、Portal,围绕着三个进行环境搭建

Jar包及脚本准备

搭建版本为Apollo 2.0.0-RC1 Release版本 ,其余版本自行下载

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lSXV62pS-1679584749847)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323174641362.png)]

Apollo依赖于数据库,准备好脚本文件,直接上gitee搜索apollo

脚本文件所在目录

scripts/sql
  • 1

下载 apolloconfigdb.sql和apolloportaldb.sql,导入到数据库

修改配置文件

adminservice配置

根据自己存放的位置进行查找

首先是adminservice的配置文件,目录地址: apollo-adminservice-2.0.0-RC1-github\config\application-github.properties

添加数据库连接配置

spring.datasource.url = jdbc:mysql://localhost:3306/ApolloConfigDB?characterEncoding=utf8
spring.datasource.username = root
spring.datasource.password = 123456
  • 1
  • 2
  • 3
configservice配置
spring.datasource.url = jdbc:mysql://localhost:3306/ApolloConfigDB?characterEncoding=utf8
spring.datasource.username = root
spring.datasource.password = 123456
  • 1
  • 2
  • 3
protal
spring.datasource.url = jdbc:mysql://localhost:3306/ApolloPortalDB?characterEncoding=utf8
spring.datasource.username = root
spring.datasource.password = 123456

server.port=8070
  • 1
  • 2
  • 3
  • 4
  • 5

启动jar包

admin默认占用8090

config默认占用8080

protal占用8070

启动命令,在对应的目录

# admin
java -jar apollo-adminservice-2.0.0-RC1.jar

# config
java -jar apollo-configservice-2.0.0-RC1.jar

# protal  这里的-Ddev_meta=http://localhost:8080 开发环境获取数据位置 -Dserver.port指定端口
java -Ddev_meta=http://localhost:8080 -Dserver.port=8070 -jar apollo-portal-2.0.0-RC1.jar

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

protal当然也可以直接修改一下配置,在protal的config文件夹下面有 apollo-env.properties,自带了几个地址,稍微修改一下就可以

local.meta=http://localhost:8080
dev.meta=http://localhost:8080
fat.meta=http://fill-in-fat-meta-server:8080
uat.meta=http://fill-in-uat-meta-server:8080
lpt.meta=${lpt_meta}
pro.meta=http://fill-in-pro-meta-server:8081
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

修改完执行运行命令, 照样正常启动

java -jar apollo-portal-2.0.0-RC1.jar
  • 1

启动之后访问

访问8070端口

用户名 apollo

密码 admin

初始是没有应用的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LGlmEoON-1679584749848)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323182230240.png)]

在创建应用之前可以先看一下系统的一些配置参数信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A3YNXIPa-1679584749848)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323182928848.png)]

如图输入组织信息查询,如果要修改只需要在value里面写入值 进行覆盖就可以,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XxTB8spI-1679584749849)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323182907627.png)]

能查询那些key 我们可以看数据库, apolloportaldb的serverconfig表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VPd5uhqH-1679584749849)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323183136061.png)]

可以不做修改继续进行创建,下面的应用负责人及应用管理员可以自行在管理员工具 那里添加,这里就不演示了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VrqepDbE-1679584749850)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323183300290.png)]

提交之后新增配置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H996GSHk-1679584749850)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323183529483.png)]

新增的配置需要进过发布才能使用,点击发布

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mmogsYuG-1679584749851)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323183613000.png)]

2.java基本使用

maven依赖
    <dependencies>
        <!-- https://mvnrepository.com/artifact/com.ctrip.framework.apollo/apollo-client -->
        <dependency>
            <groupId>com.ctrip.framework.apollo</groupId>
            <artifactId>apollo-client</artifactId>
            <version>2.0.0-RC1</version>
        </dependency>

    </dependencies>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
项目结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g1XdNRRd-1679584749851)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323183809543.png)]

编写配置和代码运行

app.properties 内容,这些我们也可以在启动的时候通过运行参数添加

# 指定应用id  上面创建时候的
app.id=liuhuan-appid
# 指定访问数据的地址 上面配置的
apollo.meta=http://localhost:8080
  • 1
  • 2
  • 3
  • 4

编写测试代码

public class MyApolloDemo {

    public static void main(String[] args) {
        Config appConfig = ConfigService.getAppConfig();
        // 这里可以获取指定namespace下面的配置,目前我们没有配置
        // Config config = ConfigService.getConfig("liuhuan-application");
        while (true){
            SleepUtils.sleepSeconds(1);
            String property = appConfig.getProperty("liuhuan.spring-boot", "zs");
            System.out.println(property);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

查看运行结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SR9Is7Sj-1679584749851)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323184353004.png)]

app.peoperties的内容也可以在启动的时候,由java运行参数来定义

-Dapp.id=liuhuan-appid -Denv=dev -Ddev_meta=http://localhost:8080
  • 1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t9tuRMEA-1679584749852)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323184927703.png)]

查看运行结果,一样能获取到数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VwK27Thm-1679584749852)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323184909288.png)]

3.apollo的集群和namespace功能

新建集群

新建一个SHAJQ集群

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YrlvmEvA-1679584749853)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323191549257.png)]

新建namespace

新建一个spring-boot

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JUetfe4n-1679584749853)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323191450673.png)]

可以看到多了一个SHAJQ的集群,同时也多了一个spring-boot的namespace

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-udSi1813-1679584749854)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323193727811.png)]

同步配置功能

可以将本集群下面的数据同步到其余集群,也可以把其余的配置同步到本集群

点击SHAJQ集群,在application的namespace下面创建几个新的配置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ujCpnuDR-1679584749854)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323194028970.png)]

点击SHAJQ下面的application下面的同步配置,将其同步到Dev下面

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gFteyzsS-1679584749855)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323191836437.png)]

同步完成,同步完之后,dev环境的配置也需要发布才能使用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UOH1Q4Gz-1679584749855)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323194104991.png)]

4.springboot使用方式

发布配置

基于上面创建的集群演示,在SHAJQ的spring-boot的namespace下面添加测试配置并发布

spring.source = SHAJQ spring-boot
spring.name = SHAJq  spring-boot name
spring.age = 28

  • 1
  • 2
  • 3
  • 4

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xu0dEf62-1679584749856)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323192638906.png)]

项目结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5rJ4iRRE-1679584749856)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323185354852.png)]

pom依赖
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>2.6.5</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.6.5</version>
        </dependency>

        <dependency>
            <groupId>com.ctrip.framework.apollo</groupId>
            <artifactId>apollo-client</artifactId>
            <version>2.0.0-RC1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-context</artifactId>
            <version>3.1.3</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.24</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <version>2.6.5</version>
        </dependency>

        <dependency>
            <groupId>org.liuhuan</groupId>
            <artifactId>commons</artifactId>
            <version>0.1.0</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.6.5</version>
                <configuration>
                    <!-- 指定该Main Class为全局的唯一入口 -->
                    <mainClass>com.liuhuan.apollo.ApolloApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal><!--可以把依赖的包都打包到生成的Jar包中-->
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
配置文件

apollo-env.properties 测试证明这里的配置并没有啥鸟用 只是看了官方的代码发现有这么个配置 加上再说,主要起作用的配置还是下面application.properties的apollo.meta,估计只是为了让我们知道有哪些地址,不行自己测试

# 使用的环境
env=dev
# 设置访问的开发数据的地址
dev.meta=http://localhost:8080/
# 设置访问的生产数据地址 用于等下演示环境
pro.meta=http://localhost:8081/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

application.peoperties

server.port=7987
# app.id 需要和apollo配置的一直
app.id=liuhuan-demo
# 取apollo配置
apollo.bootstrap.enabled=true
# 将 Apollo 加载提到初始化日志系统之前,如果设置为 false,
# 那么将打印出 Apollo 的日志信息,但是由于打印 Apollo 日志信息需要日志先启动,
# 启动后无法对日志配置进行修改,所以 Apollo 不能管理应用的日志配置,如果设置为 true,
# 那么 Apollo 可以管理日志的配置,但是不能打印出 Apollo 的日志信息
apollo.bootstrap.eagerLoad.enabled=true
apollo.bootstrap.namespaces=spring-boot
# 使用哪个集群配置
apollo.cluster=SHAJQ
spring.application.name=apollo-springboot
# Spring应用通常会使用 Placeholder 来注入配置,如${someKey:someDefaultValue},
# 冒号前面的是 key,冒号后面的是默认值。如果想关闭 placeholder 在运行时自动更新功能,可以设置为 false
apollo.autoUpdateInjectedSpringProperties=true
apollo.meta= http://localhost:8080
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
启动类及演示代码
@SpringBootApplication
// 使用apollo
@EnableApolloConfig
// 支持@ConfigurationProperties 配置
@EnableConfigurationProperties
public class ApolloApplication {

    public static void main(String[] args) {
        SpringApplication.run(ApolloApplication.class,args);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

配置类

@Component("apolloConfig")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ApolloConfig {

    @Value("${spring.source}")
    private String source;
    @Value("${spring.name}")
    private String name;
    @Value("${spring.age}")
    private Integer age;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

controller

@RestController
@RequestMapping("/apollo")
public class ApolloController {

    @Value("${name:aaa}")
    private String old;

    @Autowired
    private ApolloConfig apolloConfig;

    @GetMapping("/config")
    public String getApolloConfig(){
        return apolloConfig.toString();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

postman测试

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kdbWK0ZP-1679584749856)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323195532903.png)]

5.动态刷新

问题

apollo整合完成之后,并不能完成动态的刷新,在控制台页面将spring.age 改成30,再次访问发现还是29,重启之后再次访问,才会变成30,修改成31也必须重启

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AxT6kZhG-1679584749857)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323200324263.png)]

访问结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kKDO6MH4-1679584749857)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323200333576.png)]

解决

方式一

基于EnvironmentChangeEvent结合@ApolloConfigChangeListener实现

代码如下

@Component
@Slf4j
public class SpringBootApolloRefreshConfig implements ApplicationContextAware {
    private ApplicationContext applicationContext;
    // interestedKeyPrefixes = {"redis.cache."}
    @ApolloConfigChangeListener(value = "spring-boot.properties")
    public void onChange(ConfigChangeEvent changeEvent) {
      boolean propertiesChanged = false;

      for (String changedKey : changeEvent.changedKeys()) {
        ConfigChange change = changeEvent.getChange(changedKey);
        log.info("Change-key: {}, oldValue: {}, newValue: {}, changeType: {}",
                change.getPropertyName(),change.getOldValue(),
                change.getNewValue(), change.getChangeType());
        //jobinfo的key发生了改变
        if (changedKey.startsWith("spring.")) {
          propertiesChanged = true;
        }
      }
      //更新jobinfo的值
      if (propertiesChanged) {
        refreshProperties(changeEvent);
      }
    }

  private void refreshProperties(ConfigChangeEvent changeEvent){
    long startTime = System.currentTimeMillis();
    // 更新配置
    this.applicationContext.publishEvent(new EnvironmentChangeEvent(changeEvent.changedKeys()));
    long finishTime = System.currentTimeMillis() - startTime;
    log.info("更新数据完成!耗时:" + finishTime + "ms");
  }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
      this.applicationContext = applicationContext;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
方式二

修改配置类

@Component("apolloConfig")
@ConfigurationProperties(prefix = "spring")
@RefreshScope
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ApolloConfig {

    private String source;

    private String name;

    private Integer age;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

动态修改代码

@Component
@Slf4j
public class ApolloRefreshConfig2 {
    @Resource
    private RefreshScope refreshScope;

    @ApolloConfigChangeListener(value = "spring-boot.properties")
    public void onChange(ConfigChangeEvent changeEvent) {
        boolean propertiesChanged = false;
        for (String changedKey : changeEvent.changedKeys()) {
            ConfigChange change = changeEvent.getChange(changedKey);
            log.info("Change-key: {}, oldValue: {}, newValue: {}, changeType: {}",
                    change.getPropertyName(),change.getOldValue(),
                    change.getNewValue(), change.getChangeType());
            //jobinfo的key发生了改变
            if (changedKey.startsWith("spring.")) {
                propertiesChanged = true;
//                break;
            }
        }
        //更新jobinfo的值
        if (propertiesChanged) {
            refreshProperties(changeEvent);
        }
    }

    private void refreshProperties(ConfigChangeEvent changeEvent){
        long startTime = System.currentTimeMillis();
        // 更新配置
        refreshScope.refresh("apolloConfig");
        long finishTime = System.currentTimeMillis() - startTime;
        log.info("更新数据完成!耗时:" + finishTime + "ms");
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

6.灰度发布

创建灰度版本

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dRanK8vF-1679584749858)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323203457629.png)]

修改灰度配置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IkYChr7V-1679584749859)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323203559465.png)]

新增灰度规则

选择对应的机器ip,然后发布配置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EFwoT7d6-1679584749860)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323203634549.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-B68RWLcC-1679584749860)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323203710442.png)]

访问

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EbgKEUZZ-1679584749861)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323203737885.png)]

7. 两套环境

Pro环境

还是使用apolloconfigdb.sql

修改数据库名 原数据库名称为ApolloConfigDB 修改为ApolloProConfigDB,其余不变,运行sql

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A4pK0SjU-1679584749863)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20230323223914086.png)]

还是原来的jar包 ,可以选择运行的时候指定数据库地址和启动端口,也可以选择直接在配置文件中修改好地址和端口

修改配置文件

configservice、adminservice

spring.datasource.url = jdbc:mysql://localhost:3306/ApolloProConfigDB?characterEncoding=utf8
spring.datasource.username = root
spring.datasource.password = 123456
  • 1
  • 2
  • 3

修改数据库地址

ApolloProConfigDB下面的serverconfig表

修改eureka的地址端口为8081

update serverconfig set `Value` =  'http://localhost:8081/eureka/' where `Key` = 'eureka.service.url';
  • 1

启动config、admin的jar包

java -Dserver.port=8091 -jar apollo-adminservice-2.0.0-RC1.jar

java -Dserver.port=8081 -jar apollo-configservice-2.0.0-RC1.jar
  • 1
  • 2
  • 3

关闭protal服务,重新启动

java -Dapollo_profile=github,auth -Ddev_meta=http://localhost:8080/ -Dpro_meta=http://localhost:8081 -Dserver.port=8070 -jar apollo-portal-2.0.0-RC1.jar
  • 1

启动成功之后访问

http://localhost:8070/
  • 1

修改环境配置 apollo.portal.envs 加上pro

[外链图片转存中...(img-fD28O7Ij-1679584749863)]

刷新页面,随便点击上面创建好的应用,右边会提示补全环境和namespace

[外链图片转存中...(img-u1eoWvJZ-1679584749864)]

最终效果

[外链图片转存中...(img-U5aFsUE4-1679584749864)]

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/733478
推荐阅读
  

闽ICP备14008679号