spring5

1、Spring 框架概述

1.1 spring简介

Spring 是一个分层的 JavaSE/EEfull-stack(一站式) 轻量级开源框架。
轻量级:一个应用是否属于轻量级还是重量级,主要看它使用了多少服务.使用的服务越多,容器要为普通java对象做的工作就越多,必然会影响到应用的发布时间或者是运行性能.对于spring容器,它提供了很多服务,但这些服务并不是默认为应用打开的,应用需要某种服务,还需要指明使用该服务,如果应用使用的服务很少,如:只使用了spring核心服务,那么我们可以认为此时应用属于轻量级的,如果应用使用了spring提供的大部分服务,这时应用就属于重量级。
一站式:不仅对其他框架都进行了整合还能帮其他框架管理对象(因为spring框架的性质是容器性质:管理项目中的对象,装什么对象就有什么功能)。
分层的:

  • WEB 层:Spring MVC。
  • 业务层:Bean 管理:(IOC)。
  • 持久层:Spring 的 JDBC 模板。

1.2 spring中的核心概念

DI(dependency injection)依赖注入:属性值的注入,实现IOC思想需要DI做支持
IOC(Inverse of Control)反转控制:将由我们管理的对象交由sping容器管理
AOP(Aspect Oriented Programming):面向切面编程思想(纵向重复,横向抽取)将应用程序中的商业逻辑同对其提供支持的通用服务进行分离。

1.3 spring的特点

  • 方便解耦简化开发
    通过spring提供的IOC容器将对象之间的依赖关系交由spring控制,避免硬编码造成的过度程序耦合,用户也不用为了单例模式类,属性文件解析这些很底层的需求编码,可以更专注于上层的应用。
  • AOP功能的支持
  • 方便程序的测试通过注解方便的测试spring程序。
  • 方便集成各种优秀框架
  • 方便进行事务操作
  • 降低 API 开发难度
    对jdbc,JavaMail等进行了简单的封装

1.4简单的spring入门案例

  • 创建普通java工程

  • 创建lib文件夹将spring基础包放入lib中
    在这里插入图片描述

  • 导入jar包:选中刚刚的放入lib文件的五个jar包
    在这里插入图片描述

  • 导入spring的核心jar包
    在这里插入图片描述
    spring核心包:
    spring-beans-5.2.6.RELEASE.jar
    spring-context-5.2.6.RELEASE.jar
    spring-core-5.2.6.RELEASE.jar
    spring-core-5.2.6.RELEASE.jar
    spring-expression-5.2.6.RELEASE.jar
    日志包:
    commons-logging-1.1.1.jar
    导入junit测试需要使用的包:
    junit-4.10.jar
    hamcrest-core-1.3.jar

  • 新建User类
    在这里插入图片描述

  • 创建 Spring 配置文件,在配置文件配置创建的对象
    -

  • 创建test类并启动单元测试
    在这里插入图片描述

2、IOC 容器

2.1 IOC 概念和底层原理*****

  • 什么是ioc:控制反转,把对象创建和对象之间的调用过程,交给 Spring 进行管理
  • 使用 IOC 目的:为了耦合度降低。
  • 原理:xml的解析,工厂模式,反射技术

在这里插入图片描述
调用方法
在这里插入图片描述

2.2 IOC 接口(BeanFactory)

  1. IOC 思想是基于 IOC 容器完成,而IOC 容器底层就是对象工厂

  2. Spring 提供创建IOC 容器的两种方式:(两个接口)
    (1)BeanFactory:IOC 容器基本实现,是 Spring 内部的使用接口,不提供开发人员进行使用,加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象
    (2)ApplicationContext:BeanFactory 接口的子接口,提供更多更强大的功能,一般由开发人员进行使用加载配置文件时候就会把在配置文件中的对象进行创建

  3. ApplicationContext 接口典型的实现类
    (1)ClassPathXmlApplicationContext:从类路径下加载配置文件
    (2)FileSystemXmlApplicationContext:从硬盘绝对路径下加载配置文件

2.3 IOC 操作 Bean 管理的两种方式

概念:操作 Bean 管理即spring创建对象和对象属性注入的方式

2.3.1基于xml 管理

2.3.1.1基于xml方式创建对象

在这里插入图片描述
创建对象时候,默认执行无参数构造方法完成对象创建

2.3.1.2基于xml方式注入属性

DI依赖注入,就是给IOC容器创建的对象的属性注入值

  1. 使用set方法注入属性
    创建类,定义属性和对应的 set 方法
    在这里插入图片描述
    在 spring 配置文件配置对象创建,配置属性注入
    在这里插入图片描述
  2. 使用有参数构造创建对象并注入属性
    在book类中加入有参构造
    在这里插入图片描述
    在bean标签中添加如下标签,可以在constructor-arg标签中使用type属性指定当前注入参数的类型
    在这里插入图片描述
  3. P名称空间注入(基本不用)
    使用 p 名称空间注入,可以简化基于 xml 配置方式
    添加 p 名称空间在配置文件中
    在这里插入图片描述
    进行属性注入,在 bean 标签里面进行操作
    在这里插入图片描述
2.3.1.3xml方式注入其它类型属性
  1. 字面量
    null 值(bean标签内部使用property标签)
    在这里插入图片描述
    属性值包含特殊符号用指定格式包裹含有特殊符号的属性值 <![CDATA[ 属性值 ]]>
    在这里插入图片描述

  2. 注入属性-外部bean
    将UserDaoImpl注入到UserService的userDao属性中
    在这里插入图片描述

  3. 注入属性-内部bean和级联赋值
    给员工类的部门属性注入值
    在这里插入图片描述

  4. 级联赋值:在引入外部bean时对外部bean进行属性赋值
    第一种写法
    在这里插入图片描述
    第二种写法
    在这里插入图片描述

  5. 注入复杂类型属性
    (1)创建类,定义数组、list、map、set 类型属性,生成对应 set 方法
    在这里插入图片描述
    (2)在 spring 配置文件进行配置
    在这里插入图片描述

6 .在集合里设置对象类型的属性

  • 下面说到courseList是Stu类的一个属性 类型为List
    在这里插入图片描述
  • 把集合注入部分提取出来
    (1)在 spring 配置文件中引入名称空间 util 只需将原有的xml文件中的两行文件拷贝并粘贴一份将修改即可
    添加前
    在这里插入图片描述
    添加前后在这里插入图片描述
    (2)使用util标签完成集合注入提取
    下面的books是Book类的属性,类型为List
    在这里插入图片描述
2.3.1.4FactoryBean

Spring 有两种类型 bean,一种普通 bean上面我们使用到的都是普通bean,另外一种工厂 bean(FactoryBean)

  • 普通bean与工厂bean的区别
    普通 bean:在配置文件中定义 bean 类型就是返回类
    工厂 bean:在配置文件定义 bean 类型可以和返回类型不一样
    第一步 创建类,让这个类作为工厂 bean,实现接口 FactoryBean
    第二步 实现接口里面的方法,在实现的getObject()方法中定义返回的 bean 类型
    在这里插入图片描述
    在这里插入图片描述
2.3.1.5bean的作用域

xml指定scope作用域
在这里插入图片描述

  1. singleton
    IOC容器仅创建一个Bean实例,singleton也是bean默认的作用域,加载 spring 配置文件时候就会创建单实例对象。
  2. prototype
    IOC容器可以创建多个Bean实例,每次返回的都是一个新的实例,在调用getBean 方法时候才会创建对象。
  3. request
    该属性仅对HTTP请求产生作用,使用该属性定义Bean时,每次HTTP请求都会创建一个新的Bean,适用于WebApplicationContext环境。
  4. session
    该属性仅用于HTTP Session,同一个Session共享一个Bean实例。不同Session使用不同的实例。
  5. global-session
    该属性仅用于HTTP Session,同session作用域不同的是,所有的Session共享一个Bean实例。
2.3.1.6生命周期

对象从创建到销毁的过程

  • bean 生命周期
    (1)实例化bean对象
    (2)设置对象属性 (可能会出现循环依赖问题)
    (3)对bean实例做前置处理并执行postProcessBeforeInitialization 方法
    (4)对bean进行初始化(需要进行配置初始化的方法)
    (5)对bean实例做后置处理 并执行postProcessAfterInitialization方法
    (6)bean 可以使用了(对象获取到了)
    (7)调用 bean 的销毁的方法
    后置处理器的概念:若配置后置处理器则在当前ioc容器中所有的bean对象调用初始化方法前后会执行postProcessBeforeInitialization和postProcessAfterInitialization方法

1.创建实体类
在这里插入图片描述
2.创建后置管理器类
在这里插入图片描述
3. XML 配置后置处理器和实体类bean
在这里插入图片描述
4.测试
在这里插入图片描述

2.3.1.7xml自动装配(基本不用都使用注解形式实现)

根据指定装备规则(属性名称或者属性类型),Spring 自动将匹配的属性值进行注入
在这里插入图片描述

2.3.1.8引入外部属性配置文件(这里以配置数据源为例)
  • 引入德鲁伊(Druid)连接池依赖 jar 包 druid-1.1.9.jar

  • 创建外部配置文件
    在这里插入图片描述

  • 引入命名空间
    在这里插入图片描述

  • 在xml中引用外部配置文件的属性
    在这里插入图片描述

2.3.2基于注解管理

2.3.2.1Spring 针对 Bean 管理中创建对象提供注解

(1)@Component
(2)@Service
(3)@Controller
(4)@Repository
上面四个注解功能是一样的,都可以用来创建 bean 实例

2.3.2.2基于注解方式实现对象创建
  1. 第一步 引入注解支持依赖
    spring-aop-5.2.6.RELEASE.jar
  2. 导入命名空间
    在这里插入图片描述
  3. 开启组件扫描
    在这里插入图片描述
  4. 创建类,在类上面添加创建对象注解;//创建的bean的名称默认值是类名称首字母小写
    在这里插入图片描述
2.3.2.3基于注解方式实现属性注入
  • @Autowired:根据属性类型进行自动装配
  • @Qualifier:根据名称进行注入
    @Qualifier 注解的使用,需要和@Autowired 一起使用意为注入那个类型的那个名称的bean
  • @Resource:可以根据类型注入,也可以根据名称注入
    @Resource根据类型注入,@Resource(name = “userDaoImpl1”)根据属性名称注入
  • @Value:注入普通类型属性 此种方式是通过反射赋值破坏了封装性
2.3.2.4完全注解开发,使用注解类代替xml配置文件
  1. 创建service类并使用注解创建bean对象
    在这里插入图片描述
  2. 创建配置类,替代 xml 配置文件
    在这里插入图片描述
  3. 编写测试类
    在这里插入图片描述

3、Aop

3.1AOP概念*****

  • 什么是 AOP
    (1)面向切面编程(方面),利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得
    业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
    (2)通俗描述:不通过修改源代码方式,将应用程序中的商业逻辑同对其提供支持的通用服务进行分离

3.2AOP的底层原理*****

AOP 底层使用动态代理

  • 第一种 有接口情况,使用 JDK 动态代理
    被代理对象类需要实现接口,代理对象类需要实现InvocationHandler接口,使用代理对象,增强类的方法
    1.创建接口、实现类
    在这里插入图片描述
    在这里插入图片描述
    2.创建代理类实现InvocationHandler接口
    在这里插入图片描述
    3.编写测试类
    在这里插入图片描述
    4.执行结果
    在这里插入图片描述

  • 第二种 没有接口情况,使用 CGLIB 动态代理
    cglib动态代理是通过继承被代理类,生成的动态代理类是被代理类的子类,然后通过重写业务方法来实现代理。

3.3AOP的术语和相关概念

3.3.1术语

下图的左边的UserServiceImpl为被代理对象类 右边为代理类
在这里插入图片描述

3.3.2通知的类型 引自更详细的通知介绍

  • 前置通知在目标方法执行之前执行执行的通知。
    前置通知方法,可以没有参数,也可以额外接收一个JoinPoint,Spring会自动将该对象传入,代表当前的连接点,通过该对象可以获取目标对象 和 目标方法相关的信息。
  • 后置通知:在目标方法执行之后执行的通知。常用在记录日志(方法已经成功调用)
  • 环绕通知在目标方法执行之前和之后都可以执行额外代码的通知,常用在控制事务 权限控制
    在环绕通知中必须显式的调用目标方法,目标方法才会执行,这个显式调用时通过ProceedingJoinPoint来实现的,可以在环绕通知中接收一个此类型的形参,spring容器会自动将该对象传入只有环绕通知可以接收ProceedingJoinPoint,其他通知只能接收JoinPoint。环绕通知需要返回返回值,否则真正调用者将拿不到返回值,只能得到一个null。环绕通知有控制目标方法是否执行、有控制是否返回值、有改变返回值的能力。
    慎用环绕通知,会破坏了软件分层的“高内聚 低耦合”的目标。
  • 异常通知:在目标方法抛出异常时执行的通知,常用在异常处理 控制事务
  • 最终通知:是在目标方法执行之后执行的通知,常用在记录日志(方法已经调用,但不一定成功)
    和后置通知不同之处在于,后置通知是在方法正常返回后执行的通知,如果方法没有正常返-例如抛出异常,则后置通知不会执行。
    而最终通知无论如何都会在目标方法调用过后执行,即使目标方法没有正常的执行完成。

3.3.3 切入点表达式

切入点表达式作用:知道对哪个类里面的哪个方法进行增强
切入点表达式的格式:execution([权限修饰符] 返回类型 [声明类型].方法名(参数列表) )
一个完成的写法:execution(public void com.walkwind.spring5.UserServiceImpl.add())
权限修饰符:可以省略
返回值:可使用通配符
包名:可使用通配符✳有几层就写几个
类名和方法名:都可以使用通配符✳
参数类型:可以用通配符✳表示前提是必须有参数,…表示有无参数均可,有参数时可以是任意类型

3.4实现AOP操作

3.4.1AspectJ 注解实现

Spring 框架一般都是基于 AspectJ 实现 AOP 操作AspectJ 不是 Spring 组成部分,独立 AOP 框架,一般把 AspectJ 和 Spirng 框架一起使用,进行 AOP 操作,AspectJ支持xml和注解两种方式。
通用步骤

  1. 准备jar包
    com.springsource.net.sf.cglib-2.2.0.jar
    com.springsource.org.aopalliance-1.0.0.jar
    com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
    commons-logging-1.1.1.jar
    hamcrest-core-1.3.jar
    junit-4.10.jar
    spring-aop-5.2.6.RELEASE.jar
    spring-beans-5.2.6.RELEASE.jar
    spring-context-5.2.6.RELEASE.jar
    spring-core-5.2.6.RELEASE.jar
    spring-expression-5.2.6.RELEASE.jar

  2. 创建目标类,在类里面定义方法
    在这里插入图片描述

  3. 在 spring 配置文件中导入aop和context命名空间;开启注解扫描;生成代理对象
    在这里插入图片描述

  4. 创建增强类(编写增强逻辑,声明通知类型)
    在增强类上面添加注解 @Aspect;在增强类的里面,在作为通知方法上面添加通知类型注解,使用切入点表达式配置
    在这里插入图片描述

  5. 相同的切入点的抽取
    第四步中用到了很多的相同的切入点我们可以把它提取成公共的切入点使用引入的方法定义通知的切入点
    在这里插入图片描述

  6. 定义增强类优先级
    有多个增强类多同一个方法进行增强,设置增强类优先级
    在增强类上面添加注解 @Order(数字类型值),数字类型值越小优先级越高
    在这里插入图片描述

  7. 完全使用注解开发
    使用配置类代替xml文件
    在这里插入图片描述
    在这里插入图片描述

3.4.2使用xml配置实现aop

在这里插入图片描述

4、JdbcTemplate

4.1相关概念

  • jdbc:JDBC(JavaDataBase Connectivity)就是Java数据库连接,就是用Java语言来操作数据库。Spring 框架对 JDBC 进行封装,使用 JdbcTemplate 方便实现对数据库操作。
  • 数据库驱动:java应用程序与数据库建立连接时,先通过jdbc与数据库厂商提供的驱动程序通信,而驱动程序再与数据库通信。
  • 数据库连接池(c3p0,druid):包装JDBC的接口,但是却作用在JDBC的具体实现上使用连接池的时候,你需要配置特定的数据库驱动包。

4.2jdbc操作数据库(批量新增数据)

  1. 引入相关 jar 包
    在这里插入图片描述

  2. 在 spring 配置文件配置数据库连接池;配置 JdbcTemplate 对象;注入 DataSource
    db.properties
    在这里插入图片描述

application.xml
在这里插入图片描述

  1. 创建 service 类,创建 dao 类,在 dao 注入 jdbcTemplate 对象
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  2. 编写测试类
    在这里插入图片描述

5、事务管理

事务就是对一系列的数据库操作进行统一的提交或回滚操作,比如说做一个转账功能,要更改帐户两边的数据,这时候就必须要用事务才能算是严谨的做法。要么成功,要么失败,保持数据一致性。如果中间有一个操作出现异常,那么回滚之前的所有操作。

5.1事务概念

  • 事务特性
    ①原子性(Atomicity):事务的中的操作要么全部成功要么全部失败
    ②一致性(Consistency):事务必须使数据库从一个一致性状态到另一个一致性状态,例:A和B一起来有5000块,无论两者之间如何转账最后总量都必须为5000
    ③隔离性(Isolation):同时开启的两个事务之间互不干扰
    ④持久性(Durability):指一个事务一旦提交,那么对数据库的保存都是以永久的

5.2事务操作(Spring 事务管理介绍)

  • 事务添加到 JavaEE 三层结构里面 Service 层(业务逻辑层)
  • 在 Spring 进行事务管理操作
    两种方式:编程式事务管理和声明式事务管理(使用)
  • 声明式事务管理
    (1)基于注解方式(使用)
    (2)基于 xml 配置文件方式
  • Spring 进行声明式事务管理,底层使用 AOP 原理
  • Spring 事务管理 API提供一个接口,代表事务管理器,这个接口针对不同的框架提供不同的实现类
    在这里插入图片描述

5.3注解声明式事务管理

  1. 创建实体类及service,dao模拟转账
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  2. 在 spring 配置文件配置事务管理器;引入名称空间 tx;开启事务注解;
    在这里插入图片描述
  3. 在 service 类上面(或者 service 类里面方法上面)添加事务注解

5.4注解声明式事务管理参数配置(@Transactional)

  • 在 service 类上面添加注解@Transactional,在这个注解里面可以配置事务相关参数
  • @Transactional 只能被应用到public方法上, 对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能.
  • Spring团队的建议是你在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。

5.4.1事务传播行为(propagation)*****

propagation:多事务方法直接进行调用,这个过程中事务 是如何进行管理的

  • REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
  • SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
  • MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。
  • REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
  • NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  • NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
  • NESTED:支持当前事务,新增Savepoint点,与当前事务同步提交或回滚。

5.4.2事务隔离级别(ioslation)*****

事务有特性成为隔离性,多事务操作之间不会产生影响。不考虑隔离性产生很多问题

  • 事务并发问题
    ①脏读:一个事务读取过程中,读取到了另一个事务未提交的数据
    ②不可重复读:一个事务内多次查询同一数据却返回了不同的值,这是因为在查询间隔,数据被另一个数据修改并提交了.
    ③虚读|幻读:例事务A删除了表中的全部数据的同时事务B在表中又插了一条数据,当操作事务A 的用户再查看时发现库里还有条数据,就像产生了幻觉一样
    注: 幻读和不可重复读都是读取了另一条已经提交的事务,不同的是不可重复读查询的都是同一个数据项,而幻读针对的是一批数据整体(比如数据的个数)
  • 事务的隔离级别
    ①读未提交(read uncommited):最低级别,事务并发(①②③)都可能发生
    ②读已提交(read commited):可避免脏读的发生,事务并发(②③)可能发生
    ③可重复度(repeatable read):可避免脏读和不可重复读,事务并发(③)可能发生
    ④串行化(serialiable):事务排队一个接着一个进行,可避免事务并发问题

5.4.3超时时间(timeout)

事务需要在一定时间内进行提交,如果不提交进行回滚
默认值是 -1 :表示永不超时,设置时间以秒单位进行计算

5.4.4是否只读(readOnly)

读:查询操作,写:添加修改删除操作
readOnly 默认值 false,表示可以查询,可以添加修改删除操作
设置 readOnly 值是 true,设置成 true 之后,只能查询

5.4.5回滚(rollbackFor)

设置出现哪些异常进行事务回滚
指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})

5.4.6不回滚(noRollbackFor)

设置出现哪些异常不进行事务回滚
指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})

5.5完全使用注解开发(配置类代替application.xml文件)

在这里插入图片描述
在这里插入图片描述

5.5XML 声明式事务管理

配置文件配置事务管理器,事务通知,切入点和切面
在这里插入图片描述
<aop:advisor >大多用于事务管理。
<aop:aspect >大多用于日志、缓存。

6、Spring5 新特性

7、面试题

7.1spring架构执行流程*****

在这里插入图片描述

  1. 用户发送请求至前端控制器DispatcherServlet
  2. DispatcherServlet收到请求调用HandlerMapping处理器映射器。
  3. 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。
  4. DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
  5. 执行处理器(Controller,也叫后端控制器)。
  6. Controller执行完成返回ModelAndView
  7. HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
  8. DispatcherServlet将ModelAndView传给ViewReslover视图解析器
  9. ViewReslover解析后返回具体View
  10. DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)。
  11. DispatcherServlet响应用户

7.2spring如何解决循环依赖问题(待补充)*****

spring是如何解决的:先创建出A对象和B对象,这时并没有对属性进行注入,而是将生成的对象标记为一个半成品,在被依赖的对象创建之后再进行值的注入;

  1. 使用context.getBean(A.class),旨在获取容器内的单例A(若A不存在,就会走A这个Bean的创建流程),显然初次获取A是不存在的,因此走A的创建之路~
  2. 实例化A(注意此处仅仅是实例化),并将它放进缓存(此时A已经实例化完成,已经可以被引用了)
  3. 初始化A:@Autowired依赖注入B(此时需要去容器内获取B)
  4. 为了完成依赖注入B,会通过getBean(B)去容器内找B。但此时B在容器内不存在,就走向B的创建之路~
  5. 实例化B,并将其放入缓存。(此时B也能够被引用了)
  6. 初始化B,@Autowired依赖注入A(此时需要去容器内获取A)
  7. 此处重要:初始化B时会调用getBean(A)去容器内找到A,上面我们已经说过了此时候因为A已经实例化完成了并且放进了缓存里,所以这个时候去看缓存里是已经存在A的引用了的,所以getBean(A)能够正常返回
  8. B初始化成功(此时已经注入A成功了,已成功持有A的引用了),return(注意此处return相当于是返回最上面的getBean(B)这句代码,回到了初始化A的流程中~)。
  9. 因为B实例已经成功返回了,因此最终A也初始化成功
  10. 到此,B持有的已经是初始化完成的A,A持有的也是初始化完成的B,完美~

7.4三级缓存

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值