SpringBoot配置和使用

springboot和spring一样,是和其他技术进行整合的一种技术。

一、SpringBoot简介

1.1 原有Spring优缺点分析

1.1.1 Spring的优点分析

Spring是Java企业版的轻量级代替品。Spring为企业级Java开发提供了一种相对简单的方法,通过依赖注入和面向切面编程,用简单的Java对象实现了EJB的功能。

spring在开发过程中可以把相应的bean配置到配置文件当中,通过IOC让spring容器来进行管理Java对象。减少代码的工作,还能减少层与层之间的耦合。

1.1.2 Spring的缺点分析

虽然Spring的组件代码是轻量级的,但它的配置却是重量级的。一开始,Spring用XML配置,而且是很多XML配置。
Spring 2.5引入了基于注解的组件扫描,这消除了大量针对应用程序自身组件的显式XML配置。
Spring 3.0引入了基于Java的配置,这是一种类型安全的可重构配置方式,可以代替XML,全注解的配置方式。

所有这些配置都代表了开发时的损耗。因为在思考Spring特性配置和解决业务问题之间需要进行思维切换,所以编写配置挤占了编写应用程序逻辑的时间。和所有框架一样,Spring实用,但与此同时它要求的回报也不少。

除此之外,项目的依赖管理也是一件耗时耗力的事情。在环境搭建时,需要分析要导入哪些库的坐标,而且还需要分析导入与之有依赖关系的其他库的坐标,一旦选错了依赖的版本,随之而来的不兼容问题就会严重阻碍项目的开发进度。

1.2 SpringBoot的概述

1.2.1 SpringBoot解决上述Spring的缺点

SpringBoot对上述Spring的缺点进行的改善和优化,基于约定优于配置的思想,也就是说在spring开发的过程中,需要人告诉这个框架需要怎么做,但是告诉框架需要做的事情有时候都是一样的,这样的话就需要把这些配置设置为默认的,这样在开发的过程中不需要开发人员过多的关注配置文件的配置,只需要进行业务逻辑代码的编写就行。

1.2.2 SpringBoot的特点

  • 为基于Spring的开发提供更快的入门体验
  • 开箱即用,没有代码生成,也无需XML配置。同时也可以修改默认值来满足特定的需求
  • 提供了一些大型项目中常见的非功能性特性,如嵌入式服务器、在平常开发项目的时候可能我们需要把代码配置Tomcat,把代码放到Tomcat服务器上才能运行,但是在springboot中内置了这些服务器不需要额外的配置,springboot中还提供了一些关于安全和各种指标的配置。
  • SpringBoot不是对Spring功能上的增强,而是提供了一种快速使用Spring的方式

1.2.3 SpringBoot的核心功能

其实springBoot的核心功能就是上面提到的所有的springBoot 的特点。

  • 起步依赖

    起步依赖本质上是一个Maven项目对象模型(Project Object Model,POM),定义了对其他库的传递依赖,这些东西加在一起即支持某项功能。

    简单的说,起步依赖就是将具备某种功能的坐标打包到一起,并提供一些默认的功能。

  • 自动配置

    Spring Boot的自动配置是一个运行时(更准确地说,是应用程序启动时)的过程,考虑了众多因素,才决定Spring配置应该用哪个,不该用哪个。该过程是Spring自动完成的。在程序中我们需要使用一个sessionFactory的时候我们需要在我们的spring中配置一个sessionFactory,mybaties和hibernate都有相关的配置,但是sessionfactory配置的时候需要一个数据源datasource,按照spring的做法,这个数据源需要配置,需要的时候再注入DataSource ,但是springboot提供了一种可以自动的把数据源注入到DataSource当中,这样可以让你直接的使用。

关于起步依赖和自动配置的具体用法在下面的代码中会进一步的详细讲解。

1.2.3 SpringBoot的角色

springboot的底层抵赖与spring framework ,spring framework是一种Javaee的框架,springboot是一种快速构建spring应用的框架,然后spring cloud 是一种构建spring boot的分布式的应用 底层依赖于springboot 三个角色相互相成 ,spring boot起到一个承上启下的作用。

springboot2.0的新特性

编程语言需要用 Java8 底层的框架时spring framework 5.0X

二、SpringBoot快速入门

2.1 代码实现

2.1.1 创建Maven工程

使用idea工具创建一个maven工程,该工程为普通的java工程即可

2.1.2 添加SpringBoot的起步依赖

SpringBoot要求,项目要继承SpringBoot的起步依赖spring-boot-starter-parent
也就是在创建springboot工程的时候,所有的项目都需要是parent的子才行。

  <parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.0.1.RELEASE</version>
  </parent>

SpringBoot要集成SpringMVC进行Controller的开发,所以项目要导入web的启动依赖
我们需要在这里需要在页面上看到效果,所以需要导入一个web项目的起步依赖,我们需要开发web工程只需要导入这个起步依赖就可以。

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

这个坐标的底层负责导入spring和springMVC的各种坐标,所以我们只需要导入这一个就可以了。

导入之后在项目中完整的pom文件如下:

     <?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">
        <modelVersion>4.0.0</modelVersion>
        
        <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
        </parent>
        
        <groupId>cn.zzu</groupId>
        <artifactId>springboot_quick</artifactId>
        <version>1.0-SNAPSHOT</version>
        
        <dependencies>
        <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        </dependencies>
        
        </project>

到这配置完事了
但是还缺少一个引导类的编写。
编写引导类:名字任意

  package cn.zzu;
  
  import org.springframework.boot.SpringApplication;
  import org.springframework.boot.autoconfigure.SpringBootApplication;
  
  @SpringBootApplication
  //标注一下这个类是springboot的引导类
  public class MyspringBootApplication {
  public static void main(String[] args) {
  SpringApplication.run(MyspringBootApplication.class);
  }
  }

SpringBootApplication注解在哪个类上哪个类就是引导类。假如我们在另一个类中加上 @SpringBootApplication注解,那么这个xxx类就是引导类。
例如我们在run方法中写入字节码文件就可以,SpringApplication.run(xxx.class);
这样也能正确的加载引导类。

  • @SpringBootApplication:标注SpringBoot的启动类,该注解具备多种功能
  • SpringApplication.run(MySpringBootApplication.class) 代表运行SpringBoot的启动类,参数为SpringBoot启动类的字节码对象
  • main是Java程序的主入口
  • run方法,表示运行SpringBoot的引导类,run参数就是springBoot引导类的字节码对象

运行之后打印出spring以及一片的日志信息

.   ____  ___ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::(v2.0.1.RELEASE)

2019-09-07 10:12:33.953  INFO 136952 --- [   main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''


2019-09-07 10:12:33.956  INFO 136952 --- [   main] cn.zzu.MyspringBootApplication   : Started MyspringBootApplication in 4.653 seconds (JVM running for 7.3)

从这一段日志中我们可以发现,Tomcat的端口已经启动了,端口是8080 说明是已经内置了Tomcat 项目的访问路径是空的

我们通过localhost:8080访问Tomcat,然后会打印出一下的信息

Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.

说明我们还没有配置任何项目

下面我们写一个controller来进行测试一下

编写controller

QuickController.Java

    package cn.zzu.controller;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    @Controller
    public class QuickController {
    
    @RequestMapping("/quick")
    @ResponseBody
    public  String quick(){
    return "hello springboot";
    }
    }

这个时候运行我们的项目。 然后访问 localhost:8080/quick

这个时候就会显示出我们编写的一个简单的输出 hello springboot

到这里我们就可以发现,一个简单的springboot项目的跑通,一种经历了三步,添加起步依赖,编写引导类,然后编写controller
我们没有编写任何配置文件,没有做任何关于springMVC和spring的配置我们就可以直接使用注解的方式来创建一个简单的springboot的程序。

我么可以发现我们添加的起步依赖帮我们添加了一个springMVC的坐标,如果没有添加,上面的注解是无法使用的。

在上面的配置文件中,所有的springboot工程都必须依赖 spring-boot-starter-parent

我们导入web的起步依赖spring-boot-starter-web会帮我们自动的添加关于spring以及springMVC的各项依赖。

2.2.3 SpringBoot工程热部署

我们在开发中反复修改类、页面等资源,每次修改后都是需要重新启动才生效,这样每次启动都很麻烦,浪费了大量的时间,我们可以在修改代码后不重启就能生效,在 pom.xml 中添加如下配置就可以实现这样的功能,我们称之为热部署。

    <!--热部署配置-->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    </dependency>

注意:这样在工程中设置过之后,可能还是会出现无法进行热部署的原因,我们需要在idea中进行设置,开启热部署

出现这种情况,并不是热部署配置问题,其根本原因是因为Intellij IEDA默认情况下不会自动编译,需要对IDEA进行自动编译的设置
勾选setting中 build auto。。选项
然后按 ALT+SHIFT+CTRL+/ 选择 register 勾选 compiler.automake.allow.running 选项就可以进行热部署了

2.2.4 使用idea快速创建SpringBoot项目

我们可以在创建项目的时候选择 Spring Initializr 来进行springBoot项目的自动创建
然后会自动把工程需要的坐标全都导入项目中,而且还会在项目文件夹下自动创建引导类

三、SpringBoot原理分析

3.1 起步依赖原理分析

3.1.1 分析spring-boot-starter-parent

starter-parent的底层主要是对版本控制之类的坐标配置

从spring-boot-starter-dependencies的pom.xml中我们可以发现,一部分坐标的版本、依赖管理、插件管理已经定义好,所以我们的SpringBoot工程继承spring-boot-starter-parent后已经具备版本锁定等配置了。所以起步依赖的作用就是进行依赖的传递。

3.1.2 分析spring-boot-starter-web

按住Ctrl点击pom.xml中的spring-boot-starter-web,跳转到了spring-boot-starter-web的pom.xml,xml配置如下(只摘抄了部分重点配置):

    <?xml version="1.0" encoding="UTF-8"?>
    <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      	<modelVersion>4.0.0</modelVersion>
      	<parent>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-starters</artifactId>
    	<version>2.0.1.RELEASE</version>
      	</parent>
      	<groupId>org.springframework.boot</groupId>
      	<artifactId>spring-boot-starter-web</artifactId>
      	<version>2.0.1.RELEASE</version>
      	<name>Spring Boot Web Starter</name>
      
      	<dependencies>
    	<dependency>
      		<groupId>org.springframework.boot</groupId>
      		<artifactId>spring-boot-starter</artifactId>
      		<version>2.0.1.RELEASE</version>
      		<scope>compile</scope>
    	</dependency>
    	<dependency>
      		<groupId>org.springframework.boot</groupId>
      		<artifactId>spring-boot-starter-json</artifactId>
      		<version>2.0.1.RELEASE</version>
      		<scope>compile</scope>
    	</dependency>
    	<dependency>
      		<groupId>org.springframework.boot</groupId>
      		<artifactId>spring-boot-starter-tomcat</artifactId>
      		<version>2.0.1.RELEASE</version>
      		<scope>compile</scope>
    	</dependency>
    	<dependency>
      		<groupId>org.hibernate.validator</groupId>
      		<artifactId>hibernate-validator</artifactId>
      		<version>6.0.9.Final</version>
      		<scope>compile</scope>
    	</dependency>
    	<dependency>
      		<groupId>org.springframework</groupId>
      		<artifactId>spring-web</artifactId>
      		<version>5.0.5.RELEASE</version>
      		<scope>compile</scope>
    	</dependency>
    	<dependency>
      		<groupId>org.springframework</groupId>
      		<artifactId>spring-webmvc</artifactId>
      		<version>5.0.5.RELEASE</version>
      		<scope>compile</scope>
    	</dependency>
      	</dependencies>
    </project>

从上面的spring-boot-starter-web的pom.xml中我们可以发现,spring-boot-starter-web就是将web开发要使用的spring-web、spring-webmvc等坐标进行了“打包”,这样我们的工程只要引入spring-boot-starter-web起步依赖的坐标就可以进行web开发了,同样体现了依赖传递的作用。

四、SpringBoot的配置文件

4.1 SpringBoot配置文件类型

4.1.1 SpringBoot配置文件类型和作用

SpringBoot是基于约定的,所以很多配置都有默认值,但如果想使用自己的配置替换默认配置的话,就可以使用application.properties或者application.yml(application.yaml)进行配置。

SpringBoot默认会从Resources目录下加载application.properties或application.yml(application.yaml)文件

其中,application.properties文件是键值对类型的文件,之前一直在使用,所以此处不在对properties文件的格式进行阐述。除了properties文件外,SpringBoot还可以使用yml文件进行配置,下面对yml文件进行讲解。

4.1.2 application.yml配置文件

4.1.2.1 yml配置文件简介

YML文件格式是YAML (YAML Aint Markup Language)编写的文件格式,YAML是一种直观的能够被电脑识别的的数据数据序列化格式,并且容易被人类阅读,容易和脚本语言交互的,可以被支持YAML库的不同的编程语言程序导入,比如: C/C++, Ruby, Python, Java, Perl, C#, PHP等。YML文件是以数据为核心的,比传统的xml方式更加简洁。

YML文件的扩展名可以使用.yml或者.yaml。

4.1.2.2 yml配置文件的语法

主要讲解两种配置方式,一种是配置普通数据,一种是配置对象数据。

4.1.2.2.1 配置普通数据
  • 语法: key: value

  • 示例代码:

  • name: haohao
    
  • 注意:value之前有一个空格,空格后面才能写value

    server:
    port: 8081

    注意:如果我们在这里配置了两个一个是application.properties一个是application.yml文件。加载的顺序是先加载application.yml文件

4.1.2.2.2 配置对象数据
  • 语法:

    ​ key:

    ​ key1: value1

    ​ key2: value2

    ​ 或者:

    ​ key: {key1: value1,key2: value2}

示例代码:

#对象的配置
yaml
person:
name: xiaoming
age: 31
addr: beijing

#或者

person: {name: haohao,age: 31,addr: beijing}

- 注意:key1前面的空格个数不限定,在yml语法中,相同缩进代表同一个级别



##### 4.1.2.2.2 配置Map数据 

同上面的对象写法

##### 4.1.2.2.3 配置数组(List、Set)数据

  - 语法: 
  
    ​	key: 
  
    ​		- value1
  
    ​		- value2
  
    或者:
  
    ​	key: [value1,value2]
  
  - 示例代码:
  
  - ```yaml
    city:
  - beijing
  - tianjin
  - shanghai
  - chongqing
  
#或者

    city: [beijing,tianjin,shanghai,chongqing]
  
    #集合中的元素是对象形式
    student:
  - name: zhangsan
    age: 18
    score: 100
  - name: lisi
    age: 28
    score: 88
  - name: wangwu
    age: 38
    score: 90
    ```

- 注意:value1与之间的 - 之间存在一个空格



**
我们在以上的问价中我们配置properties文件或者是yml文件时,像我们配置的server这些端口数据,配置文件会自动的识别的,但是配置的student数据,或者其他的对象数据配置文件是不会自动识别的,所以就需要我们进行文件的识别映射**



## 4.2 配置文件与配置类的属性映射方式
配置类的属性映射我们可以通过@Value 映射 来进行获取

### 4.2.1 使用注解@Value映射

我们可以通过@Value注解将配置文件中的值映射到一个Spring管理的Bean的字段上


例如:

application.properties配置如下:

  ```properties
  person:
    name: zhangsan
    age: 18
  ```

或者,application.yml配置如下:

  ```yaml
  person:
    name: zhangsan
    age: 18****
  ```

实体Bean代码如下:

```java

  package cn.zzu.Controller;
  
  import org.springframework.beans.factory.annotation.Value;
  import org.springframework.stereotype.Controller;
  import org.springframework.web.bind.annotation.RequestMapping;
  import org.springframework.web.bind.annotation.ResponseBody;
  
  @Controller
  public class Quick2Controller {
  
  @Value("${person.name}")
  private String name;
  @Value("${person.age}")
  private Integer age;
  
  @RequestMapping("/quick3")
  @ResponseBody
  public String quick(){
  return "springboot 访问成功! name="+name+",age="+age;
  }
  }
  

浏览器访问地址:http://localhost:8080/quick3 既可以进行结果的输出

我们使用这种方式获取值的时候优点是获取的值比较精确,可以获取到我们想获取的信息,但是缺点是比较繁琐,如果只有几个信息的时候可以通过这种方式获取,但是如果信息比较多的时候,就比较耗费时间。这时,我们可以使用,使用注解@ConfigurationProperties映射

4.2.2 使用注解@ConfigurationProperties映射

通过注解@ConfigurationProperties(prefix=“配置文件中的key的前缀”)可以将配置文件中的配置自动与实体进行映射

application.properties配置如下:

```properties
person:
  name: zhangsan
  age: 18
```

或者,application.yml配置如下:

```yaml
person:
  name: zhangsan
  age: 18
```

JavaBean代码如下:

    package cn.zzu.Controller;
    
    
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    @Controller
    @ConfigurationProperties(prefix = "person")
    
    public class Quick3Controller {
    
    private String name;
    private Integer age;
    
    public void setName(String name) {
    this.name = name;
    }
    
    public void setAge(Integer age) {
    this.age = age;
    }
    
    @RequestMapping("/quick4")
    @ResponseBody
    public String quick(){
    return "springboot 访问成功! name="+name+",age="+age;
    }
    }

这个时候如果没有配置ConfigurationProperties会提示一个 错误,我们需要添加依赖消除这种错误提示

    <!--@ConfigurationProperties执行器的配置-->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
    </dependency>

注意:使用@ConfigurationProperties方式可以进行配置文件与实体字段的自动映射,但需要字段必须提供set方法才可以,而使用@Value注解修饰的字段不需要提供set方法

五、SpringBoot与整合其他技术

5.1 SpringBoot整合Mybatis

5.1.1 添加Mybatis的起步依赖

    <!--mybatis起步依赖-->
    <dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.1.1</version>
    </dependency>

这个起步依赖是mybaties提供的

5.1.2 添加数据库驱动坐标


    <!-- MySQL连接驱动 -->
    <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    </dependency>

5.1.3 添加数据库连接信息

在application.properties中添加数据量的连接信息

#DB Configuration:
spring.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=123456

我们在配置文件中添加数据库的连接信息。

5.1.4 创建user表

在test数据库中创建user表

    -- ----------------------------
    -- Table structure for `user`
    -- ----------------------------
    DROP TABLE IF EXISTS `user`;
    CREATE TABLE `user` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `username` varchar(50) DEFAULT NULL,
      `password` varchar(50) DEFAULT NULL,
      `name` varchar(50) DEFAULT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
    
    -- ----------------------------
    -- Records of user
    -- ----------------------------
    INSERT INTO `user` VALUES ('1', 'zhangsan', '123', '张三');
    INSERT INTO `user` VALUES ('2', 'lisi', '123', '李四');
    

5.1.5 创建实体Bean

package cn.zzu.springboot_mybaties.domain;


public class User {

    // 主键
    private Long id;
    // 用户名
    private String username;
    // 密码
    private String password;
    // 姓名
    private String name;

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", name='" + name + '\'' +
                '}';
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

我们把数据库和我们的实体对应起来, 需要编写mapper

5.1.6 编写Mapper

@Mapper
public interface UserMapper {
	public List<User> queryUserList();
}

注意:@Mapper标记该类是一个mybatis的mapper接口,可以被spring boot自动扫描到spring上下文中

5.1.7 配置Mapper映射文件

在src\main\resources\mapper路径下加入UserMapper.xml配置文件"

    <?xml version="1.0" encoding="utf-8" ?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    <mapper namespace="cn.zzu.springboot_mybaties.mapper.UserMapper">
    <select id="queryUserList" resultType="user">
    select * from user
    </select>
    </mapper>

5.1.8 在application.properties中添加mybatis的信息


    #spring集成Mybatis环境
    #pojo别名扫描包
    mybatis.type-aliases-package=cn.zzu.springboot_mybaties.domain
    #加载Mybatis映射文件
    mybatis.mapper-locations=classpath:mapper/*Mapper.xml
    

5.1.9 编写测试Controller

    package cn.zzu.springboot_mybaties.controller;
    
    import cn.zzu.springboot_mybaties.domain.User;
    import cn.zzu.springboot_mybaties.mapper.UserMapper;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    import java.util.List;
    
    public class MybatiesController {
    
    @Autowired
    private UserMapper userMapper;
    
    @RequestMapping("/query")
    @ResponseBody
    public List<User> queryUser(){
    List<User> users = userMapper.queryUserList();
    return users;
    }
    
    }
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值