Spring学习总结

简介与特点

Spring 是一个轻量级的IOCAOP一站式 Java 开发框架。

  1. 轻量级的
    Spring 框架使用的 jar 都比较小,一般在 1M 以下或者几百 kb。Spring 核心功能的所需的 jar 总共在 3M 左右。 Spring 框架运行占用的资源少,运行效率高

  2. IOC
    Inversion of Control,缩写为 IOC,是由 Spring 管理对象,而非传统实现中由程序代码直接操控,是一种设计思想 ,可以在不修改原来代码的前提下,为业务代码添加功能。(同一个功能添加给多个方法)

  3. AOP
    Aspect Oriented Programming 直译过来就是面向切面编程。AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。面向对象编程将程序抽象成各个层次的对象,而面向切面编程是将程序抽象成各个切面.

  4. 一站式框架
    Spring 本身也提供了 数据访问功能web功能 ,以及可以很好的 管理其他框架

Maven项目集成Spring

Spring基础依赖配置

   <!-- spring-context spring最核心基础的jar-->
 <dependency>
  <groupId>org.springframework</groupId>
   <artifactId>spring-context</artifactId>
  <version>5.2.2.RELEASE</version>
 </dependency>

IOC的实现方式

将原本在程序中手动创建的对象的控制权,交给spring

具体管理内容(对象的创建 初始化 以及对象功能的增强 以及对象与对象之间的依赖关系 对象的销毁)

正控:若要使用某个对象,需要自己去负责对象的创建

反控:若要使用某个对象,只需要从Spring 容器中获取需要使用的对象,不关心对象的创建过程,也就是把创建对象的控制权反转给了 Spring 框架.

bean : 是指spring创建的对象,与自己直接创建的对象有区别

基于XML

关于bean的scope属性

若是 singleton :单例(默认值) 所有创建返回同一个对象并且在为容器引入XML配置时创建对象

prototype: 原型(例列) 每次创建都会创建一个新对象

request : 每 次http请求都会创建一个bean, 仅 用 于WebApplicationContext 环境

ref 属性

  1. resources包下创建 xml文件

XML文件配置内容

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">


   <!--   为 spring 声明需要管理的类           -->
   <!-- 创建时的标识名   类的路径                        别名 创建可以使用                    -->
    <bean id="student" class="com.spring.model.Student" name="student2 student3" scope="singleton"> </bean>
</beans>
  1. 为容器引入XML配置 ClassPathXmlApplicationContext(“XML文件名”)

ClassPathXmlApplicationContext( ) spring 实现的具体类 :可以理解为一个容器(生产并管理对象) 别名 IOC容器 spring容器

ApplicationContext applicationContext=new ClassPathXmlApplicationContext("spring.xml");

3.创建对象的方法

方法一:向下转型

Student student=(Student) applicationContext.getBean("student");

方法二: 传入Class类对象

Student stu=applicationContext.getBean("student",Student.class);
  1. 依赖注入:指 Spring 创建对象的过程中,将对象依赖属性(简单值,集合,对象)通过配置设置给该对象

方法一:set方法注入 必须在实体类为相应属性设置set方法

name 被注入类属性的名字

ref :被注入属性是Spring管理的的类 填对应被管理类 的 bean 中 id (唯一标识符) 值
//后文案例中应用

<bean id="student" class="com.spring.model.Student" name="student2 student3" scope="prototype">
        <property name="id" value="100"></property>
        <property name="name" value="name"></property>
        <property name="gender" value=""></property>
</bean>

方法二:依靠构造方法注入 利用实体类中的有参构造方法设置初始值

有几个 constructor-arg 就应有 相应数量参数 的构造方法

 <bean id="student" class="com.spring.model.Student" name="student2 student3" scope="prototype">
       <constructor-arg name="name" value="liming"></constructor-arg>
       <constructor-arg name="gender" value=""></constructor-arg>
</bean>

bean实现管理案例

目录结构
在这里插入图片描述

  1. dao数据访问层 对数据库数据进行增删改查

    该类需要交给spring管理

public class StudentDao {
    public void save(){
        //获取链接对象
        System.out.println("保存学生信息");
        //提交事务
        //关闭链接
    }
    public void delete(){
        //获取链接对象
        System.out.println("删除学生信息");
        //提交事务
        //关闭链接
    }
}
  1. web层 将dao层的封装成功能

    该类也交给spring管理 并通过依赖注入 创建StudentDao

public class StudentServlet {
    //依赖注入的方法创建对象
    StudentDao studentDao;

    public StudentDao getStudentDao() {
        return studentDao;
    }

    public void setStudentDao(StudentDao studentDao) {
        this.studentDao = studentDao;
    }


    public void saveStudent(){
        studentDao.save();
    }

    public void deleteStudent(){
        studentDao.delete();
    }
}

  1. Spring的XML配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">

    

    <bean id="StudentDao" class="com.spring.dao.StudentDao" scope="singleton"></bean>
     
    <bean id="StudentServlet" class="com.spring.web.StudentServlet" scope="singleton">
        <property name="studentDao" ref="StudentDao"></property>
    </bean>
</beans>

测试:

//测试bean案例
//获取IOC容器
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("spring.xml");
//获取功能类
StudentServlet studentServlet=applicationContext.getBean("StudentServlet",StudentServlet.class);

//保存学生信息
studentServlet.saveStudent();
//删除学生信息
studentServlet.deleteStudent();

基于注解标签(常用)

添加注解扫描

开启注解扫描,对指定包下面的类进行扫描,检查添加有spring注解的类

<context:component-scan base-package="包名"> </context:component-scan>

注解方式XML文件配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd ">

      <!--开启注解扫描-->
<context:component-scan base-package="com.spring"></context:component-scan>

</beans>

在案例使用注解

以下三种注解功能一致,只是为了区分不同功能而命名不同

  1. model包 模型类(获其他类)中使用 @Component

    @Component(value = “引入后的名字”) 交给spring管理

    @Scope(value = “singleton”) singleton / prototype 单列或原型

@Component(value = "Student")
@Scope(value = "singleton")
public class Student{
...
}
  1. dao包 数据访问层 数据操作类中使用 @Repository
@Repository(value = "StudentDao")
public class StudentDao {
...
}
  1. web包 业务逻辑层 类中使用 @Service
@Service(value = "StudentServlet")
public class StudentServlet {

//   类型注入
    @Autowired(required = false) //  required 是否能不为空 默认为true(不能为空)
    StudentDao studentDao;       //注入注释也可以加在set方法上 ,加在属性上不需要定义set方法
...
}

注解方式注入

注入分为两种方法,对象名注入类型注入。 并且有两种注解能实现注入,一种是spring提供的 @Autowired,另一种为 JDK 提供的注解 @Resource

1.对象名注入:
使用 @Aotuwired

@Qualifier(value=“要注入类的名字”) 确定注入类型的来源

   @Repository(value = "StudentDao")  //读取处有名字
//-----------------------------------------------------------
       @Autowired
       @Qualifier(value = "StudentDao")   
       StudentDao studentDao;

使用 @Resource

   @Repository(value = "StudentDao")  //读取处有名字
//-----------------------------------------------------------
     @Resource(name="StudentDao")
     StudentDao studentDao;

2.类型注入
使用 @Aotuwired
在spring读取被控制类时。会记录他的类型。所以读取处没有命名 只使用 @Autowired 会根据 需要注入的类型 在已读取的类型中查找获取。

@Repository     //读取处没有名字
//-----------------------------------------------------------
     
       @Autowired   
       StudentDao studentDao;

使用 @Resource

   @Repository  //读取处没有名字
//-----------------------------------------------------------
     @Resource
     StudentDao studentDao;

测试方法:

 ApplicationContext applicationContext=new ClassPathXmlApplicationContext("springs.xml");

        Student student=applicationContext.getBean("Student",Student.class);
        System.out.println(student);

        Student student1=applicationContext.getBean("Student",Student.class);
        
        System.out.println(student);
        System.out.println(student1);

Spring管理数据连接对象

功能:为管理案例的Dao类添加具体的操作数据库功能

阿里数据源依赖配置

 <!-- spring-jdbc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.2.2.RELEASE</version>
    </dependency>
   
    
    <!--   使用的是阿里巴巴提供的     数据库连接管理组件    -->
    <!--   提供了  连接数据库功能     数据库连接池功能-->
    <!-- 阿里数据源 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.10</version>
    </dependency>

Spring管理数据源

Spring 自身也提供了 web 层的 SpringWeb 和 持久层的 Spring JdbcTemplate

在spring配置文件中添加数据源配置数据源

方式一:在注解扫描下填入(静态填入)缺点:修改不方便

 <!--   Spring管理连接对象-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/dormdb?serverTimezone=Asia/Shanghai"></property>
        <property name="username" value="root"></property>
        <property name="password" value="root"></property>
        <property name="initialSize" value="10"></property><!--初始化连接数量-->
        <property name="maxActive" value="20"></property><!--最大连接数量-->
    </bean>

方式二: properties 属性文件配置

创建 properties 文件 给文件填入 键值关系

#把配置文件的值 统一集中管理
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/dormdb?serverTimezone=Asia/Shanghai
uname=root
pwd=root
initialSize=10
maxActive=20
<!--添加配置文件-->
  <context:property-placeholder location="config.properties"></context:property-placeholder>

 <!--   Spring管理连接对象-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${driverClassName}"></property>
        <property name="url" value="${url}"></property>
        <property name="username" value="${uname}"></property>
        <property name="password" value="${pwd}"></property>
        <property name="initialSize" value="${initialSize}"></property><!--初始化连接数量-->
        <property name="maxActive" value="${maxActive}"></property><!--最大连接数量-->
    </bean>

Spring管理 JdbcTemplate

JdbcTemplate 提供了许多 访问数据库的方法

    <!--  创建spring对jdbc进行封装的一个类 Jdbctemplate -->
 <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--   给 JdbcTemplate 加入 spring已管理的阿里数据源   -->
        <property name="dataSource" ref="dataSource"></property>
 </bean>

如此一来便能对数据库实现存储等操作。

@Repository(value = "StudentDao")
public class StudentDao {
    @Autowired
    JdbcTemplate jdbcTemplate;
    public void save(){
        //获取链接对象
        System.out.println("保存学生信息");
        jdbcTemplate.execute("INSERT INTO student(NAME,gender) VALUES('李明','男')");
        System.out.println("成功");
        //提交事务
        //关闭链接
    }
}

Spring集成Mybatis

Spring集成 Mybatis 的核心是将SqlSessionFactory 交由 Spring 管理,并由Spring 管理对 dao 接口的代理实现。

以下操作简介: 利用Mybatis 替代掉 JdbcTemplate利用 Spring 管理数据连接对象的功能取代 Mybatis 全局配置中的数据库连接池

相关依赖

    <!--spring 结合mybatis 的插件包-->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>1.3.1</version>
    </dependency>

  <!-- spring-context -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.2.RELEASE</version>
    </dependency>

   <!--    mysql    -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.16</version>
    </dependency>

  <!--   mybatis   -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.2</version>
    </dependency>

    <!-- spring-jdbc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.2.2.RELEASE</version>
    </dependency>
    
    <!-- 阿里数据源 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.10</version>
    </dependency>

集成过程

dao包 和映射文件 与mybatis使用没有不同

model包
添加将 Student 类交给 spring 管理

@@Repository(value = "Student")
public class Student{
...
}

service包

@Service(value = "StudentServlet")
public class StudentServlet {

     @Autowired
     StudentDao studentDao;

   public  void saves(Student student){
         studentDao.save(student);
     }
}
mybatis 全局配置
  1. spring 已有阿里数据源管理连接对象, 所以 mybatis全局配置文件中不需要连接数据库
  2. spring 会加载 Mapper 映射文件,所以 mybatis全局配置文件中不加载
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <settings>
        <setting name="logImpl" value="STDOUT_LOGGING"/>         <!--开启日志   -->
        <setting name="mapUnderscoreToCamelCase" value="true"/>  <!-- 对象映射   下划线和驼峰命名 转化 -->
        <setting name="cacheEnabled" value="true"/>  <!--二级缓存-->
    </settings>


    <!-- 为类型配置别名 -->
    <typeAliases>
        <!-- 为单个类配置别名 -->
        <!-- <typeAlias type="com.ffyc.mybatis.model.Admin" alias="admin"></typeAlias> -->
        <package name="com.myAndSpring.model"/>       <!-- 导入包中所有实体 -->
    </typeAliases>

     <!--连接数据库-->

     <!--配置sql映射文件-->
  

</configuration>
spring全局配置

使用 mybatis 替代 JdbcTemplate

配置核心:

  • spring管理生成sqlSessionFactory:

    1. 注入数据源
    2. 加入mybatis的 全局配置文件
    3. 加入 Mapper 映射文件
  • spring 管理生成接口代理对象:
    对 dao 包扫描(web层注入dao中的类使用)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd ">


    <context:component-scan base-package="com.myAndSpring"></context:component-scan>

    <context:property-placeholder location="config.properties"></context:property-placeholder>
    <!--   Spring管理连接对象-->

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${driverClassName}"></property>
        <property name="url" value="${url}"></property>
        <property name="username" value="${uname}"></property>
        <property name="password" value="${password}"></property>
        <property name="initialSize" value="${initialSize}"></property><!--初始化连接数量-->
        <property name="maxActive" value="${maxActive}"></property><!--最大连接数量-->
    </bean>


<!--   !!!!  spring管理生成sqlSessionFactory           -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
         <!--         1.注入数据源      -->
        <property name="dataSource" ref="dataSource"></property>

        <!--          2.mybatis 全局配置文件         -->
        <property name="configLocation" value="classpath:mybatis2.xml"></property>

            <!--      3.指定映射文件地址                           Student2 不能用 *代替          -->
        <property name="mapperLocations" value="classpath:mappers/*2Mapper.xml"></property>
    </bean>


<!--  !!!!  spring 管理生成接口代理对象-->
    <bean id="mapperFactory" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
             <!--     对指定包下的接口进行扫描     并生成接口的代理对象     -->
        <property name="basePackage" value="com.myAndSpring.dao"></property>
   <!--                                                          不用ref     -->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory">
        </property>
    </bean>


</beans>

测试类

 public static void main(String[] args) {
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("spring2.xml");

        Student student=applicationContext.getBean("Student",Student.class);

        student.setName("李明2");
        student.setGender("男");

        StudentServlet studentServlet=applicationContext.getBean("StudentServlet",StudentServlet.class);

        studentServlet.saves(student);

    }

Spring AOP实现

AOP概述

AOP 意为:面向切面编程,通过 预编译方式运行期间动态代理 实现 程序功能的统一维护 的一种技术。,是 java 开发中的一个重要内容。
利用 AOP 可以对 业务逻辑非业务逻辑进行隔离,从而使得各部分之间的 耦合度降低 ,提高程序的 可重用性 ,同时提高了开发的效率。

不需要修改代码,通过动态代理技术,把要添加的功能横切进来。

面向切面编程的好处就是: 减少重复 , 专注业务
注意:面向切面编程只是面向对象编程的一种补充。

使用案例:
事务处理:开启事务,关闭事务,出现异常后回滚事务
权限判断:在执行方法前,判断是否具有权限
日志:在执行前进行日志处理

AOP 思想不是 spring 中特有的,是Java中的动态代理模式,spring只是使用了这一思想。

AOP 基本概念

连接点(Joinpoint):类中可以被增强的方法

切入点(pointcut):类中有实际被增强的方法 (实际实现的连接点)

通知(Advice) : 通知是指一个切面在特定的连接点要做的事情(增强的功能)。通知分为方法执行前通知,方法执行后通知,环绕通知等.

目标(Target) : 代理的目标对象(连接点,切入点所在类)

代理(Proxy) :向目标对象应用通知时创建的代理对象

AOP 相关依赖

AspectJ 是一个基于 Java 语言的 AOP 框架,它提供了强大的 AOP 功能,且其实现方式更为简捷,使用更为方便, 而且还支持 注解式开发 。所以,Spring 又将 AspectJ 的对于 AOP 的实现也引入到了自己的框架中。

<!-- AOP 相关依赖 -->
<dependency>
  <groupId>org.springframework</groupId>
   <artifactId>spring-aspects</artifactId>
  <version>5.2.2.RELEASE</version>
</dependency>

<!-- 仍要使用 spring 基础包-->
<dependency>
  <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
  <version>5.2.2.RELEASE</version>
</dependency>

spring 全局配置配置AOP

xmlns:aop="http://www.springframework.org/schema/aop"

http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd

<!--   启动 AspectJ 支持   -->
<aop:aspectj-autoproxy/>

创建通知类

@Aspect // 此标签类中的方法就是代理对象要使用的

@Component   //必须交给spring代理
@Aspect      // 此标签类中的方法就是代理对象要使用的
public class CommonUtil {

    @Before("execution(* com.ffyc.aop.dao.StudentDaoclass.*(..))")
    public  void savelog(){
        System.out.println("执行成功");
    }

    @Before("execution(* com.aop.dao.StudentDaoclass.save(String))")
    public  void savelog2(){
        System.out.println("执行成功 字符串参数");
    }

    public  void commit(){
        System.out.println("提交事务");
    }
}

通知 注解

aop 使用前提是 切入点对象为spring 代理的对象

   //        返回值类型               类名 *         函数名 参数类型 ..    .. / *(全部)
@Before("execution(* com.aop.dao.StudentDaoclass.*(..))")

前三种使用方法基本一致

  1. @Before 前置通知:前置通知函数执行前执行

  2. @After 后置通知:切入函数执行后 必然执行(即使出现异常也会执行)

  3. @AfterReturnning 返回通知:方法成功执行之后通知出现异常不执行

  4. @AfterThrowing 异常通知:抛出异常之后执行
    传入异常的顶尖类。
    多个属性需要标上 value

 @AfterThrowing(value = "execution(* com.aop.dao.StudentDaoclass.save(String))",throwing = "e")
    public  void savelog2(Throwable e){
        System.out.println("执行成功后 字符串参数"+e.getMessage());
    }

@Around 环绕通知

在需要同时使用两种以上通知时,可以使用环绕通知。

 @Around("execution(* com.aop.dao.StudentDaoclass.*(..))")
   public void around(ProceedingJoinPoint joinPoint) {
        try {
            System.out.println("打印日志");  // 前置通知
            joinPoint.proceed();           //执行目标函数
            System.out.println("返回通知");
        } catch (Throwable e) {
            System.out.println("异常通知");
        }
        System.out.println("后置通知");
   }

数据库事务管理

数据库事务概念

数据库事务是 一次对数据库执行的若干操作 的管理,这一操作的若干条sql语句,应该是一个整体单元。数据库事务能保证数据的完整性,不能一半保存成功,一半没有成功

在 jdbc 中每次执行完sql后,事务自动提交 (风险性高)

在 mybatis 中是通过 SqlSession,commit( ) 手动提交 (麻烦)

spring 事务管理

Spring 中的事务管理分为两种形式:

编程式事务声明式事务

编程式事务:在项目中很少使用,这种方式需要在我们代码中需要提交事务或回滚事务时自己写代码实现.

声明式事务管理:建立在AOP 基础上,本质是对方法前后进行拦截,所以声明式事务是方法级别的。

Spring 声明式事物管理方式有两种:

基于 xml 配置

基于注解实现

spring 基于注解实现事务管理

xmlns:tx="http://www.springframework.org/schema/tx"

http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
<!-- 配置 spring 事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
   <property name="dataSource" ref="dataSource"></property>
</bean>

<!-- 开启注解事务管理 -->
<tx:annotation-driven transaction-manager="transactionManager"/>

在类或方法上使用 @Transactional 标签即(必须为spring中管理生成的

声明式事务失效场景

  1. @Transactional 应用在非 public 修饰的方法上
  2. 异常被 catch 捕获导致失效
  3. 出现编译期异常
@Transactional(rollbackFor = RuntimeException.class)    
// 默认 只捕获运行期异常 触发事务管理

@Transactional(rollbackFor = Exception.class)
//改成 Exception.class 使得编译期异常  也能捕获
  1. 数据库引擎不支持事务 MySQL中只有 innodb支持事务
  • 25
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浩然缭绕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值