Spring新手入门笔记 纯手打

Spring

IOC原理

  1. 控制反转,把创建对象和对象之间的调用过程交给spring处理

  2. 目的:降低耦合度

  3. 案例

    1. beans.xnl

      <?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">
          <!--配置 User 对象创建-->
          <bean id="user" class="cn.mucd.entity.User"/>
      </beans>
      
      
    2. User.java

    3. public class User {
          public void add(){
              System.out.println("add init ....");
          }
      }
      
      
    4. 测试

    5.    @Test
      public  void test01() {
          //读取配置文件
          ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("beans.xml");
          User user = (User) classPathXmlApplicationContext.getBean("user");
          user.add();
      }
      
    6. 输出 add init ....

  4. IOC底层使用到了 xml 解析、工厂模式、反射

BeanFactory接口

  1. IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
  2. IOC容器实现的两种方式
    1. BeanFactory:IOC 容器基本实现,是 Spring 内部的使用接口,不提供开发人员进行使用 * 加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象
    2. ApplicationContext:BeanFactory 接口的子接口,提供更多更强大的功能,一般由开发人 员进行使用
  3. ApplicatoinContext接口有实现类[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S8QfhBZJ-1647920780409)(C:\Users\mucd\AppData\Roaming\Typora\typora-user-images\1647910899933.png)]

IOC操作Bean管理

  1. Bean管理是指两个操作

  2. spring创建对象

  3. spring注入属性

  4. 操作的两种方式

    1. 基于xml实现

      1. <bean id="user" class="cn.cn.mucd.entity.User"></bean>
        
      2. 在bean标签里添加对应的属性,就能实现对象穿件

      3. id属性: 唯一标识

      4. class属性: 类路径,包括包名

    2. 基于xml注入属性

      1. DI: 依赖注入,就是注入属性

      2. 使用set方法进行注入

        1. public class Book {
              //创建属性 
              private String bookName;
              private String email;
          
              //创建set方法
              public void setBookName(String bookName) {
                  this.bookName = bookName;
              }
          
              public void setEmail(String email) {
                  this.email = email;
              }
          }
          
        2. <!--set 方法进行属性注入-->
          <bean id="book" class="cn.mucd.entity.Book">
              <property name="bookName" value="爱情故事"/>
              <property name="email" value="213123@qq.com"/>
          </bean>
          
      3. 使用有参构造进行注入

        1. 创建类,定义属性,创建属性对应有参数构造方法

        2. public class Book {
              private String bookName;
              private String email;
          
              public Book() {
              }
          
              public Book(String bookName, String email) {
                  this.bookName = bookName;
                  this.email = email;
              }
          }
          
        3. <bean id="book" class="cn.mucd.entity.Book">
              <constructor-arg name="bookName" value="隔山打牛"/>
              <constructor-arg name="email" value="12312@qq.com"/>
          </bean>
          
      4. 注入外部Bean

        1. 创建类service 类和 dao 类

          1. //service
            public class UserService{
                //创建 UserDao 类型属性,生成 set 方法
                private UserDao userDao;
                public void setUserDao(UserDao userDao) {
                    this.userDao = userDao;
                }
                public void add() {
                    System.out.println("service add...............");
                    userDao.update();
                }
            }
            //dao接口和实现
            public interface UserDao {
                int update();
            }
            
            public class UserDaoImpl implements UserDao{
            
                @Override
                public int update() {
                    System.out.println(" dao update .... ");
                    return 1;
                }
            }
            
            
            
        2. 在 service 调用 dao 里面的方法

        3. 在 spring 配置文件中进行配置

        4. <bean id="userDao" class="cn.mucd.dao.UserDaoImpl"/>
          <bean id="userService" class="cn.mucd.servicew.UserService">
              <property name="userDao" ref="userDao"/>
          </bean>
          
        5. 运行测试

        6. @Test
          public void test02(){
              ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
              UserService userService = (UserService) context.getBean("userService");
              userService.add();
          }
          
      5. 注入属性,内部bean

        1. 创建类

          1. //部门
            public class Dept {
                private String dname;
            
                public void setDname(String dname) {
                    this.dname = dname;
                }
            }
            
            //员工
            public class Emp {
                private String ename;
                private Dept  dept;
            
                public void setEname(String ename) {
                    this.ename = ename;
                }
            
                public void setDept(Dept dept) {
                    this.dept = dept;
                }
            }
            
          2. <!--注入 内部bean-->
            <bean id="emp" class="cn.mucd.entity.Emp">
                <property name="ename" value="女员工"/>
                <!--设置内部属性-->
                <property name="dept">
                    <bean class="cn.mucd.entity.Dept">
                        <property name="dname" value="人事部"/>
                    </bean>
                </property>
            </bean>
            
          3. 运行

          4. @Test
            public void test03(){
                ApplicationContext text = new ClassPathXmlApplicationContext("beans.xml");
                Emp emp = (Emp) text.getBean("emp");
                System.out.println("emp = " + emp);
            }
            
      6. 级联赋值

        1. <!--注入属性 级联赋值-->
          <bean id="emp2" class="cn.mucd.entity.Emp">
              <property name="dept" ref="dept2"/>
              <property name="ename" value="anan"/>
          </bean>
          
          <bean id="dept2" class="cn.mucd.entity.Dept">
              <property name="dname" value="美女部门"/>
          </bean>
          
      7. 集合注入

        1. @ToString
          public class Coll {
              private List<String> list;
              private Set<String> set;
              private Map<String, Object> map;
              private String[] strs;
          
              public void setList(List<String> list) {
                  this.list = list;
              }
          
              public void setSet(Set<String> set) {
                  this.set = set;
              }
          
              public void setMap(Map<String, Object> map) {
                  this.map = map;
              }
          
              public void setStrs(String[] strs) {
                  this.strs = strs;
              }
          }
          
        2. 
          <!--注入集合属性-->
          <bean class="cn.mucd.entity.Coll" id="coll">
              <property name="strs">
                  <array>
                      <value>arr1</value>
                      <value>arr2</value>
                      <value>arr3</value>
                  </array>
              </property>
              <property name="list">
                  <list>
                      <value>list1</value>
                      <value>list2</value>
                      <value>list3</value>
                  </list>
              </property>
              <property name="set">
                  <set>
                      <value>set1</value>
                      <value>set2</value>
                      <value>set3</value>
                  </set>
              </property>
              <property name="map">
                  <map>
                      <entry key="name" value="zangsan"/>
                      <entry key="addr" value="bj"/>
                  </map>
              </property>
          </bean>
          
    3. IOC操作bean管理 FactoryBean

      1. Spring 有两种类型 bean,一种普通 bean,另外一种工厂 bean(FactoryBean)

      2. 普通 bean:在配置文件中定义 bean 类型就是返回类型

      3. 工厂 bean:在配置文件定义 bean 类型可以和返回类型不一样

        1. 第一步 创建类,让这个类作为工厂 bean,实现接口 FactoryBean
        2. 第二步 实现接口里面的方法,在实现的方法中定义返回的 bean 类型
      4. 代码实现

        1. public class MyBean implements FactoryBean<Course> {
           //定义返回 bean
           @Override
           public Course getObject() throws Exception {
           Course course = new Course();
           course.setCname("abc");
           return course;
           }
           @Override
           public Class<?> getObjectType() {
           return null;
           }
           @Override
           public boolean isSingleton() {
           return false;
           }
          }
          
        2. <bean id="myBean" class="com.spring5.factorybean.MyBean">
          </bean>
          
        3. @Test
          public void test3() {
           ApplicationContext context =
           new ClassPathXmlApplicationContext("bean3.xml");
           Course course = context.getBean("myBean", Course.class);
           System.out.println(course);
          }
          
      5. bean的作用域

        1. spring的bean默认是单例对象

        2. 设置bean标签的scope属性改变作用域

          1. 默认值,singleton,表示是单实例对象

          2. prototype表示多例对象

          3. <bean id="user" class"com.spring5.factorybean.user" scope="prototype"/>
            
      6. bean的生命周期

        1. 生命周期: 从创建到销毁的过程

        2. 周期

          1. 通过构造器创建bean的实例(无参构造)

          2. bean的属性设置值和对其他bean引用(调用set )

          3. 调用bean的初始化方法

          4. 使用bean(已经获取到的对象)

          5. public class Orders {
             //无参数构造
             public Orders() {
             System.out.println("第一步 执行无参数构造创建 bean 实例");
             }
             private String oname;
             public void setOname(String oname) {
             this.oname = oname;
             System.out.println("第二步 调用 set 方法设置属性值");
             }
             //创建执行的初始化的方法
             public void initMethod() {
             System.out.println("第三步 执行初始化的方法");
             }
             //创建执行的销毁的方法
             public void destroyMethod() {
             System.out.println("第五步 执行销毁的方法");
             }
            }
            
            ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("bean4.xml");
            Orders orders = context.getBean("orders", Orders.class);
            System.out.println("第四步 获取创建 bean 实例对象");
            System.out.println(orders);
            //手动让 bean 实例销毁
            context.close();
            
          6. bean后置处理器

            1. bean 的后置处理器,bean 生命周期有七步
            2. 通过构造器创建 bean 实例(无参数构造)
            3. 为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
            4. 把 bean 实例传递 bean 后置处理器的方法 postProcessBeforeInitialization
            5. 调用 bean 的初始化的方法(需要进行配置初始化的方法)
            6. 把 bean 实例传递 bean 后置处理器的方法 postProcessAfterInitialization
            7. bean 可以使用了(对象获取到了)
            8. 当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
        3. 创建类,实现接口 BeanPostProcessor,创建后置处理器

        4. public class MyBeanPost implements BeanPostProcessor {
           @Override
           public Object postProcessBeforeInitialization(Object bean, String beanName)
          throws BeansException {
           System.out.println("在初始化之前执行的方法");
           return bean;
           }
           @Override
           public Object postProcessAfterInitialization(Object bean, String beanName)
          throws BeansException {
           System.out.println("在初始化之后执行的方法");
           return bean;
           }
          }
          
        5. <!--配置后置处理器-->
          <bean id="myBeanPost" class="com.atguigu.spring5.bean.MyBeanPost"></bean>
          
      7. xml自动装配

        1. 根据指定装配规则(属性名称或者属性类型),Spring 自动将匹配的属性值进行注入

        2. <!--实现自动装配
           bean 标签属性 autowire,配置自动装配
           autowire 属性常用两个值:
           byName 根据属性名称注入 ,注入值 bean 的 id 值和类属性名称一样
           byType 根据属性类型注入
          -->
          <bean id="emp" class="com.atguigu.spring5.autowire.Emp" autowire="byName">
           <!--<property name="dept" ref="dept"></property>-->
          </bean>
          <bean id="dept" class="com.atguigu.spring5.autowire.Dept"></bean>
          
      8. 外部属性配置文件

        1. <!--直接配置连接池-->
          <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
              <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
              <property name="url"
                        value="jdbc:mysql://localhost:3306/userDb"></property>
              <property name="username" value="root"></property>
              <property name="password" value="root"></property>
          </bean>
          
          
      9. 引入外部文件

        1. <beans xmlns="http://www.springframework.org/schema/beans" 
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:p="http://www.springframework.org/schema/p"
           xmlns:util="http://www.springframework.org/schema/util"
           xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/util
          http://www.springframework.org/schema/util/spring-util.xsd
           http://www.springframework.org/schema/context
          http://www.springframework.org/schema/context/spring-context.xsd">
          
          <!--引入外部属性文件-->
          <context:property-placeholder location="classpath:jdbc.properties"/>
          <!--配置连接池-->
          <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
           <property name="driverClassName" value="${prop.driverClass}"></property>
           <property name="url" value="${prop.url}"></property>
           <property name="username" value="${prop.userName}"></property>
           <property name="password" value="${prop.password}"></property>
          </bean>
          
    4. 基于注解实现

      1. 简化xml配置

      2. 使用在类上,方法上,属性上

      3. 针对创建对象提供注解

        1. @Component
        2. @Service
        3. @Controller
        4. @Repository
        5. 以上功能一样, 都可以用来创建 bean 实例
      4. 实现对象创建

        1. 引入aop依赖

        2. 开启组件扫描

        3. <context:annotation-config />

          1. 进行注解驱动注册,从而使注解生效

          2. 用于激活那些已经在spring容器里注册过的bean上面的注解,也就是显示的向Spring注册

          3. 如果不扫描包,就需要手动配置bean

          4. 如果不加注解驱动,则注入的值为null!

          5. <!--开启组件扫描
             1 如果扫描多个包,多个包使用逗号隔开
             2 扫描包上层目录
            -->
            <context:component-scan base-package="cn.spring"></context:component-scan>
            <context:annotation-config />
            
  5. 创建类,在类上添加注解

      ```java
            //如果不写值,默认就是把类名首字母小写的驼峰命名,如Book->book , UserInfo->userInfo
      @Component("person")
            public class Person {
                public void addPerson(){
                    System.out.println("add person ....");
                }
            }
            
            @Test
            public void test06(){
                ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
                //这里填写@Component里的值就可以
                Person person = (Person) app.getBean("person");
                person.addPerson();
            }
            ```
      
      5. 作用域注解 `@Scope`
      
         1. singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。
      
         2. prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收
      
         3. ```java
            @Component("user")
            @Scope("prototype")
            public class User{}
            ```
    
    1. 基于Java类进行配置

    2. JavaConfig原本是spring的子项目,通过Java类的方式提供Bean的定义信息,在Spring4版本JavaConfig已经正式成为Spring的核心功能

    3. //创建SpringConfig.java
      @Configuration("springAnno")
      public class SpringAnno {
          @Bean
          public Pet pet(){
              return new Pet();
          }
      }
      //创建Pet.java
      @ToString
      public class Pet {
          //给属性赋值
          @Value("小猫")
          private String pname;
      
          //给方法赋值
          @Value("小狗")
          public void setPname(String pname) {
              this.pname = pname;
          }
      }
      
      //测试运行
      @Test
      public void  test07(){
          //这里要newAnnotationConfigApplicationContext,不要再写new ClassPathXmlApplicationContext了
          ApplicationContext context = new AnnotationConfigApplicationContext(SpringAnno.class);
          Pet pet = (Pet) context.getBean("pet");
          System.out.println("pet = " + pet);//pet = Pet(pname=小狗)
      
      }
      
    4. 这里Pet.java里写了两个@Value,运行的时候输出的是方法的@Value()

    5. 导入其他配置类

      1. 使用@Import(),这里就类似include标签导入

      2. @Configuration("springAnno")
        @Import(SpringCnfig.class)
        public class SpringAnno {
        
            @Bean
            public Pet pet(){
                return new Pet();
            }
        
        }
        
    6. 关于Java类的配置方式以后会在SpringBoot中大量的用到.

AOP

  1. 什么是AOP?

    1. AOP(As[ect Oriented Programming) 面向切面编程
    2. 通过预编译和运行时动态代理实现程序功能的统一维护的一种技术
    3. 图片
  2. 在Spring中的作用

    1. 提供声明是事务,允许用户自定义切面
  3. 重点:

    1. 横切关注点:
      1. 跨越应用程序多个模块的方法或功能. 与我们的业务逻辑无关,但是需要关注横切. 如日志,安全,缓存,事务等…
    2. 切面(ASPECT):
      1. 横切关注点,被模块化的特殊对象. 即他是一个类
    3. 通知(Advice):
      1. 切面必须要完成的工作
    4. 目标(Target):
      1. 被通知对象
    5. 代理(Proxy):
      1. 向目标对象应用通知之后创建的对象
    6. 切入点(PointCut):
      1. 切面通知执行的"地点"的定义
    7. 连接点(JointPoint):
      1. 与切入点匹配的执行点
  4. 5种类型的通知(Advice):

    1. 图片
    2. Aop可以在不改变原有代码的情况下,去增加新的功能.
  5. 实现AOP

    1. 使用AOP前,还需要导一个依赖

    2. <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
      <dependency>
         <groupId>org.aspectj</groupId>
         <artifactId>aspectjweaver</artifactId>
         <version>1.9.4</version>
      </dependency>
      
    3. 第一种实现方式

      1. //创建接口和实现类
        public interface UserService {
            void add();
            void del();
            void update();
            void findAll();
        }
        //实现类
        public class UserServiceImpl implements UserService{
            @Override
            public void add() {
                System.out.println("add user ...");
            }
        
            @Override
            public void del() {
                System.out.println("del user ...");
            }
        
            @Override
            public void update() {
                System.out.println("upd user ...");
            }
        
            @Override
            public void findAll() {
                System.out.println("find user ...");
            }
        }
        
        
      2. 创建增强类,一个前置增强一个后置增强

      3. //前置增强类
        public class BeforeLog implements MethodBeforeAdvice {
            /**
             * @param method 要执行的目标对象的方法
             * @param args   被调用的方法参数
             * @param target 目标对象
             * @throws Throwable 异常
             */
            @Override
            public void before(Method method, Object[] args, Object target) throws Throwable {
                System.out.println("前置方法===============");
                System.out.println("methodName = " + method.getName());
                System.out.println(Arrays.toString(args));
                System.out.println("className = " + target.getClass().getName());
        
            }
        }
        //后置增强类
        public class AfterLog implements AfterReturningAdvice {
           //returnValue 返回值
           //method被调用的方法
           //args 被调用的方法的对象的参数
           //target 被调用的目标对象
           @Override
           public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
               System.out.println("执行了" + target.getClass().getName()
               +"的"+method.getName()+"方法,"
               +"返回值:"+returnValue);
          }
        }
        
      4. 最后去application.xml注册实现aop

      5. <?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:aop="http://www.springframework.org/schema/aop"
               xsi:schemaLocation="http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans.xsd
               http://www.springframework.org/schema/aop
               http://www.springframework.org/schema/aop/spring-aop.xsd">
        
            <bean class="cn.mucd.aop.advice.AfterLog" id="afterLog"/>
            <bean class="cn.mucd.aop.advice.BeforeLog" id="beforeLog"/>
            <bean class="cn.mucd.aop.service.UserServiceImpl" id="userService"/>
        
            <!--aop 配置-->
            <aop:config>
                <!--expresssion表达式匹配要执行的方法-->
                <aop:pointcut id="pointcut" expression="execution(* cn.mucd.aop.service.UserServiceImpl.*(..))"/>
                <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
                <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
            </aop:config>
        </beans>
        
      6. <!--execution(返回值 类.方法(方法参数)) *代表所有-->

      7. 运行

      8. @Test
        public void test01() {
            ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
            UserService userService = (UserService) context.getBean("userService");
            userService.findAll();
        }
        //输出
        前置方法===============
        methodName = findAll
        []
        className = cn.mucd.aop.service.UserServiceImpl
        find user ...
        后置方法=================
        methodName = findAll
        []
        className = cn.mucd.aop.service.UserServiceImpl
        
    4. aop就是将公共的业务(安全,日志等)和领域业务结合起来,当执行领域业务时将公共业务也加进来,实现公共业务重复利用!本质还是动态代理.

    5. 第二种实现方式

      1. 自定义类来实现aop

      2. 写一个自己的切入类

      3. public class MyPointCut {
            public void before(){
                System.out.println("---------方法执行前---------");
            }
            public void after(){
                System.out.println("---------方法执行后---------");
            }
        
        }
        
      4. xml配置

      5.     <bean class="cn.mucd.aop.service.UserServiceImpl" id="userService"/>
            <bean class="cn.mucd.aop.pointcut.MyPointCut" id="myPointCut"/>
        
            <aop:config>
                <aop:aspect ref="myPointCut">
                    <aop:pointcut id="cut" expression="execution(* cn.mucd.aop.service.UserServiceImpl.*(..))"/>
                    <!--自己类里面的方法 before and after-->
                    <aop:before method="before" pointcut-ref="cut"/>
                    <aop:before method="after" pointcut-ref="cut"/>
                </aop:aspect>
            </aop:config>
        
      6. 运行

      7. @Test
        public void test02() {
            ApplicationContext context = new ClassPathXmlApplicationContext("mypointcut.xml");
            UserService userService = (UserService) context.getBean("userService");
            userService.findAll();
        }
        
    6. 第三种方式

      1. 使用注解实现aop

      2. 编写一个注解实现的增强类

      3. @Aspect
        public class AnnoPointcut {
        
            @Before("execution(* cn.mucd.aop.service.UserServiceImpl.*(..))")
            public void before(){
                System.out.println("anno 前置");
            }
        
            @After("execution(* cn.mucd.aop.service.UserServiceImpl.*(..))")
            public void after(){
                System.out.println("anno 后置");
            }
        
            @SneakyThrows
            @Around("execution(* cn.mucd.aop.service.UserServiceImpl.*(..))")
            public void around(ProceedingJoinPoint pj){
                System.out.println("环绕前-------");
                System.out.println("签名 = " + pj.getSignature());;
        
                //执行目标方法
                Object proceed = pj.proceed();
        
                System.out.println("环绕后-------");
                System.out.println("proceed = " + proceed);
            }
        
        }
        
      4. 配置xml文件

      5. <?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:aop="http://www.springframework.org/schema/aop"
               xsi:schemaLocation="http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans.xsd
               http://www.springframework.org/schema/aop
               http://www.springframework.org/schema/aop/spring-aop.xsd">
        
            <bean class="cn.mucd.aop.pointcut.AnnoPointcut" id="pointcut"/>
            <bean class="cn.mucd.aop.service.UserServiceImpl" id="service"/>
        
            <aop:aspectj-autoproxy/>
        
        </beans>
        
      6. 运行

      7. @Test
        public void test03() {
            ApplicationContext context = new ClassPathXmlApplicationContext("anno.xml");
            UserService userService = (UserService) context.getBean("service");
            userService.findAll();
        }
        //结果
        环绕前-------
        签名 = void cn.mucd.aop.service.UserService.findAll()
        anno 前置
        find user ...
        anno 后置
        环绕后-------
        proceed = null
        

    持续更新中 …

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值