mybatis-配置文件方式+spring整合


mybatis 持久层框架,内部封装了JDBC,屏蔽了JDBC API底层访问细节,采用ORM(Object Relational Mapping)思想解决了实体和数据库映射的问题,应用程序访问数据库更方便。

1 单表操作

1.1 创建表

创建一个用户表:

--用户表
create table tb_user (
    id int auto_increment primary key,
    user_name varchar(50) not null,
    make_time datetime,
    update_time datetime
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ;

1.2 引入依赖

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.8</version>
</dependency>
<!--用于类中自动生成get、set、构造方法等-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.22</version>
    <scope>provided</scope>
</dependency>

1.3 创建实体类

//用户类,@Data注解用来自动生成set、get等方法
@Data
public class User {
    private int  id ;
    private String  userName ;
    private Timestamp makeTime;
    private Timestamp updateTime;
}

1.4 添加配置

1.4.1 主配置文件

主配置文件主要用来配置需要加载的外部文件路径(properties)、设置数据类型别名(typeAliases)、配置自定义类型处理器(typeHandlers)、配置第三方的插件来进行功能扩展(plugins)、数据源环境配置(environments)、映射文件配置(mappers)等。

mybatis.xml文件:

<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--注意:标签有顺序-->
    <!--加载外部的properties文件-->
    <properties resource="jdbc.properties"/>
    <!--为数据类型设置别名,基本数据类型已为默认设置-->
    <typeAliases>
        <typeAlias type="com.test.entity.User" alias="user"/>
    </typeAliases> 
    <!--配置第三方的插件来进行功能扩展-->
    <plugins>
        <plugin interceptor="com.github.pagehelper.PageInterceptor">
        </plugin>
    </plugins>
    <!--数据源环境配置-->
    <environments default="dev">
        <!--指定当前环境为dev-->
        <environment id="dev">
            <!--指定事务管理类型为JDBC,直接使用JDBC的提交和回滚设置,依赖于从数据源得到的连接来管理事务作用域-->
            <transactionManager type="JDBC"/>
            <!--指定数据源类型为数据库连接池-->
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--加载映射文件-->
    <mappers>
        <mapper resource="mapper/UserMapper.xml"/>
    </mappers>
</configuration>

1.4.2 映射文件

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">
<!--namespace为接口类全路径-->
<mapper namespace="com.test.dao.UserDao">
    <!--表字段和类字段进行映射-->
    <!--user为com.test.entity.User的别名-->
    <resultMap id="userMap" type="user">

        <result column="id" property="id"/>
        <result column="user_name" property="userName"/>
        <result column="make_time" property="makeTime"/>
        <result column="update_time" property="updateTime"/>

    </resultMap>

    <!--抽取共同的sql片段-->
    <sql id="selectUser">select * from tb_user</sql>

    <select id="findAll" resultMap="userMap">
        <include refid="selectUser"/>
    </select>
    <select id="findByUserName" resultMap="userMap">
        <include refid="selectUser"/>
        <where>
            <if test="userName != null">
                and user_name=#{userName}
            </if>
        </where>
    </select>
    <select id="findByUserNames" resultMap="userMap" parameterType="list">
        <include refid="selectUser"/>
        <where>
            <foreach collection="list" item="userName" open="user_name in (" close=")" separator=",">
                #{userName}
            </foreach>
        </where>
    </select>
    <select id="findById" resultMap="userMap">
        <include refid="selectUser"/>
        <where>
            <if test="id != null">
                id = #{id}
            </if>
        </where>
    </select>
    <insert id="addUser" parameterType="user">
            insert into tb_user(user_name,make_time) values (#{userName},#{makeTime})
    </insert>
    <update id="updateUser" parameterType="user">
            update tb_user set user_name=#{userName} , update_time=#{updateTime} where id=#{id}
    </update>
    <delete id="deleteUser" parameterType="int">
            delete from tb_user where id=#{id}
    </delete>
</mapper>

映射文件说明:

标签属性说明
mappernamespace只有mapper映射文件,不创建相关接口类时,一般设置为mapper文件名,如userMap,与select、update、delete、insert标签中的id组成sql唯一标志,用于sql语句执行。 如:sqlSession.select("userMap.findAll");
创建相关接口类,通过jdk动态代理方式,完成sql执行时,设置为相关接口类的全路径,如:com.test.dao.UserDao,上述配置文件采用该种方式。
resultMaptype用于类中属性与表字段进行映射,填写需要映射类的全路径,如果在主配置文件中已配置类别名,则填写别名即可。如:主配置文件中标签typeAlias设置com.test.entity.User的别名为user,则此type可设置为user。
selectresultMap设置返回值类型为映射后的结果,属性值为resultMap标签中的id值。
resultType设置返回值类型为非映射后的结果
sqlid提取的相同sql的id值,在sql语句中导入标签中使用,作为include标签中refid属性值。
foreachcollection要遍历的集合元素:array数组,arg0, collection, list
item遍历集合的每个元素,生成的变量名,相当于for(String str:List<String> list) 中的str。
open语句的开始部分
close语句的结束部分
separator每个元素之间的分隔符

1.4.3 接口类

public interface UserDao {
    List<User> findAll();
    List<User> findByUserName(@Param("userName") String userName);
    List<User> findByUserNames(List<String> users);
    User findById(int id);
    void addUser(User user);
    void updateUser(User user);
    void deleteUser(int id);
}

接口类与映射文件(上述mapper/UserMapper.xml)关系说明:
①接口类的全限定名需与映射文件中的namespace相同;
②接口类中的方法名需与映射文件中的每个statement的id相同;
③接口类中的方法输入参数类型需与映射文件中的每个statement的parameterType的类型相同,@Param注解中的名称与映射文件中接收到的参数名称对应;
④接口类中的方法返回类型需与映射文件中的每个statement的resultType的类型相同

1.4.4 测试

执行方法前获取接口,执行后关闭sqlsession:

//通过代理方式获取接口
public class UserTest {

    private UserDao userDao;
    private SqlSession sqlSession;

     @Before
    public void before() throws IOException {
        //从类路径下、文件系统或url加载资源文件
        InputStream inputStream = Resources.getResourceAsStream("mybatis.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        //openSession()默认开启事务,需要手动提交事务
        //openSession(boolean autoCommit)参数为true,则自动提交事务,否则需要手动提交
        //SqlSession中有所有执行sql语句、提交或回滚事务和获取映射器实例的方法
        sqlSession = sqlSessionFactory.openSession(true);
        //jdk动态代理方式获得UserDao接口的实现类对象(目标对象)
        userDao = sqlSession.getMapper(UserDao.class);
    }
    
    @After
    public void after(){
        sqlSession.close();
    }
}
1.4.4.1 添加数据
@Test
public void testAdd() throws IOException {

    for(int i=0 ; i < 10 ; i++) {
        User user = new User();
        user.setUserName("小草"+i);
        user.setMakeTime(new Timestamp(new Date().getTime()));
        userDao.addUser(user);
    }

}

测试结果:
在这里插入图片描述

1.4.4.2 查询全部
@Test
public void testFindAll() throws IOException {

    //非代理方式执行查询语句:
    //sqlSession.select("userMap.findAll");
    //参数为:namespace.id
    List<User> list = userDao.findAll();

    for(User User:list){
        System.out.println(User);
    }

}

测试结果:
在这里插入图片描述

1.4.4.3 分页查询
@Test
public void testPage() throws IOException {
    //从第二页开始,每页2条数据
    PageHelper.startPage(2,2);
    List<User> list = userDao.findAll();
    PageInfo<User> pageInfo = new PageInfo<User>(list);
    int pages = pageInfo.getPages();//总页数
    System.out.println("总页数:"+pages);
    for(User user:list){
        System.out.println(user);
    }
}

测试结果:
在这里插入图片描述

1.4.4.4 更新数据
@Test
    public void testUpdate() throws IOException {

        User user = new User();
        user.setId(2);
        user.setUserName("小静");
        user.setUpdateTime(new Timestamp(new Date().getTime()));
        userDao.updateUser(user);

    }

测试结果:
在这里插入图片描述

1.4.4.5 根据用户名查询
@Test
public void testFindByUserName() throws IOException {
    List<User> list = userDao.findByUserName("小静");
    for(User User:list){
        System.out.println(User);
    }
}

测试结果:
在这里插入图片描述

1.4.4.6 删除数据
@Test
public void testDelete() throws IOException {
     userDao.deleteUser(2);//删除id为2的数据
 }

测试结果:在这里插入图片描述

1.4.5 补充

1.4.5.1 分页查询

需要引入分页插件:

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.3.0</version>
</dependency>

主配置文件mybatis.xml中添加插件配置:

<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor/">
</plugins>
1.4.5.2 日志输出

为了实现控制台sql输出,需要引入日志框架,设置日志输出级别等。

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

添加log4j.properties配置文件:

log4j.rootLogger=DEBUG,Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n

2 多表查询

2.1 创建多张表

分析用户、账户、角色、权限之间的关系,创建表,E-R图如下:
在这里插入图片描述
根据E-R图,分析可以得出,还需要创建用户角色表tb_user_role,角色权限表tb_role_privilege,用户表同第1章节的tb_user。

--账户表
create table tb_account (
    id int auto_increment primary key,
    account_name varchar(50) not null,
    user_id int not null,
    money decimal(19,4),
    make_time datetime,
    update_time datetime
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ;

--角色表
create table tb_role(
    id int auto_increment primary key,
    role_name varchar(50) not null,
    make_time datetime,
    update_time datetime
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ;
--权限表
create table tb_privilege(
    id int auto_increment primary key,
    privilege_name varchar(50) not null,
    make_time datetime,
    update_time datetime
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ;
--用户角色表
create table tb_user_role(
    id int auto_increment primary key,
    role_id int not null,
    user_id int not null,
    make_time datetime,
    update_time datetime
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ;
--角色权限表
create table tb_role_privilege(
    id int auto_increment primary key,
    role_id int not null,
    privilege_id int not null,
    make_time datetime,
    update_time datetime
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ;

2.2 创建实体类

//用户类
@Data
public class User {
    private int  id ;
    private String  userName ;
    private Timestamp makeTime;
    private Timestamp updateTime;
    private List<Role> roles;
    private List<Account> accounts;
}
//账户类
@Data
public class Account {

    private int    id;
    private String    accountName;
    private BigDecimal money;
    private Timestamp makeTime;
    private Timestamp updateTime;
    private User user;
}
//角色类
@Data
public class Role {
    private int  id ;
    private String  roleName ;
    private Timestamp makeTime;
    private Timestamp updateTime;
    private List<Privilege> privilege;
    private List<User> users;
}
//权限类
@Data
public class Privilege {
    private int  id ;
    private String  privilegeName ;
    private Timestamp makeTime;
    private Timestamp updateTime;
    private List<Role> roles;
}

2.3 一对一查询

一个账户只能属于一个人,查询账户所属的用户信息。

2.3.1 配置文件

主配置文件mybatis.xml中增加别名:

<typeAlias type="com.test.entity.Account" alias="account"/>

映射文件AccountMapper.xml文件中增加:

<!--表字段和类字段进行映射-->
<resultMap id="accountMap" type="account">
    <result column="id" property="id"/>
    <result column="account_name" property="accountName"/>
    <result column="money" property="money"/>
    <result column="make_time" property="makeTime"/>
    <result column="update_time" property="updateTime"/>
    <association property="user" javaType="com.test.entity.User">
        <result column="uid" property="id"/>
        <result column="user_name" property="userName"/>
        <result column="make_time" property="makeTime"/>
        <result column="update_time" property="updateTime"/>
    </association>
</resultMap>
<!--根据用户名查询账户信息,如果无用户名,则查询全部账户所属的用户信息-->
<select id="selectByUserName" resultMap="accountMap">
    select * , u.id as uid from tb_account a,tb_user u
    <where>
       a.user_id=u.id
       <if test="userName != null">
       and u.user_name=#{userName}
       </if>
    </where>
</select>

association标签说明:

标签/属性说明
association描述只能有一个的关系,如一个账户只能属于一个用户。
property传值为主类中某个属性名,如Account类中的user属性。

result标签说明:

属性说明
column传值为查询sql结果中的字段,如果查询结果中涉及多个表相同的字段名,要设置别名,此处填字段别名
property传值为当前要映射类的属性

2.3.2 接口类

接口类中增加相应的接口方法:

List<Account> selectByUserName(@Param("userName") String userName);

2.3.3 测试

 @Test
 public void testSelectByUserName(){
     List<Account> list = accountDao.selectByUserName(null);
     for(Account account:list){
         System.out.println(account);
     }
 }

测试结果:
在这里插入图片描述

2.4 一对多查询

一个人可以有多个账户,查询某个用户的所有账户信息。

表中数据如下:
在这里插入图片描述
在这里插入图片描述

2.4.1 配置文件

<!--表字段和类字段进行映射-->
<!--user为com.test.entity.User的别名-->
<resultMap id="userMap" type="user">
    <result column="id" property="id"/>
    <result column="user_name" property="userName"/>
    <result column="make_time" property="makeTime"/>
    <result column="update_time" property="updateTime"/>
    <collection property="accounts" ofType="com.test.entity.Account">
        <result column="aid" property="id"/>
        <result column="account_name" property="accountName"/>
        <result column="money" property="money"/>
        <result column="make_time" property="makeTime"/>
        <result column="update_time" property="updateTime"/>
    </collection>
</resultMap>
<!--根据用户名进行模糊查询-->
<select id="selectUserAccountByUserName" resultMap="userMap">
        select * , a.id as aid from tb_user u
        left join tb_account a  on a.user_id = u.id
        <where>
            <if test="userName != null">
               and u.user_name like concat('%',#{userName},'%')
            </if>
        </where>
</select>

2.4.2 接口类

List<User> selectUserAccountByUserName(@Param("userName") String userName);

2.4.3 测试

@Test
public void testSelectUserAccountByUserName(){
      List<User> list = userDao.selectUserAccountByUserName("小草");
      for(User user:list){
          System.err.println(String.format("用户:id %s ,用户名%s ,账户如下:",user.getId(),user.getUserName() ) );
          List<Account> accounts = user.getAccounts();
          for(Account account:accounts){
              System.err.println(account);
          }
      }
 }

测试结果:
在这里插入图片描述

2.5 多对多查询

某个用户可以有多个角色,某个角色可以属于多个用户,某个角色可以有多个权限,某个权限可以属于多个用户,查询某个用户下的权限。

各表数据如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

tb_role_privilege插入数据:

insert into tb_role_privilege(role_id,privilege_id,make_time) values(1,1,CURRENT_TIMESTAMP());
insert into tb_role_privilege(role_id,privilege_id,make_time) values(1,2,CURRENT_TIMESTAMP());
insert into tb_role_privilege(role_id,privilege_id,make_time) values(1,3,CURRENT_TIMESTAMP());
insert into tb_role_privilege(role_id,privilege_id,make_time) values(2,1,CURRENT_TIMESTAMP());

tb_user_role插入数据:

insert into tb_user_role(role_id,user_id,make_time) values(1,1,CURRENT_TIMESTAMP());
insert into tb_user_role(role_id,user_id,make_time) values(1,2,CURRENT_TIMESTAMP());
insert into tb_user_role(role_id,user_id,make_time) values(2,3,CURRENT_TIMESTAMP());

2.5.1 配置文件

  <resultMap id="userMap" type="user">

     <result column="id" property="id"/>
     <result column="user_name" property="userName"/>
     <result column="make_time" property="makeTime"/>
     <result column="update_time" property="updateTime"/>
     <collection property="accounts" ofType="com.test.entity.Account">
         <result column="aid" property="id"/>
         <result column="account_name" property="accountName"/>
         <result column="money" property="money"/>
         <result column="make_time" property="makeTime"/>
         <result column="update_time" property="updateTime"/>
     </collection>
     <collection property="roles" ofType="com.test.entity.Role">
         <result column="rid" property="id"/>
         <result column="role_name" property="accountName"/>
         <result column="make_time" property="makeTime"/>
         <result column="update_time" property="updateTime"/>
         <collection property="privileges" ofType="com.test.entity.Privilege">
             <result column="pid" property="id"/>
             <result column="privilege_name" property="privilegeName"/>
             <result column="make_time" property="makeTime"/>
             <result column="update_time" property="updateTime"/>
         </collection>
     </collection>
 </resultMap>
 <!--根据用户名,查询用户权限-->
 <select id="selectUserPrivilegeByUserName" resultMap="userMap">
    select * , p.id as pid, ur.role_id as rid from tb_user u
    left join tb_user_role ur on ur.user_id=u.id
    inner join tb_role_privilege rp on rp.role_id=ur.role_id
    inner join tb_privilege p on p.id=rp.privilege_id
    <where>
        <if test="userName != null">
            and u.user_name like concat('%',#{userName},'%')
        </if>
    </where>
</select>

collection标签说明:

标签/属性说明
collection描述有多个的关系,如一个用户可以有多个角色,一个角色可以有多个权限
ofType区别于javaType,传值类中包含集合类型需使用这个属性

2.5.2 接口类

List<User> selectUserPrivilegeByUserName(@Param("userName") String userName);

2.5.3 测试

 @Test
 public void testSelectUserPrivilegeByUserName(){
     List<User> list = userDao.selectUserPrivilegeByUserName("小草0");
     for(User user:list){
         System.err.println(String.format("用户:id %s ,用户名%s ,权限如下:",user.getId(),user.getUserName() ) );
         List<Role> roles = user.getRoles();
         for(Role role:roles){
             List<Privilege> privileges = role.getPrivileges();
             for(Privilege privilege:privileges){
                 System.err.println(privilege);
             }
         }
     }
 }

测试结果:
在这里插入图片描述

3 spring整合mybatis

spring整合mybatis,其实就是将使用mybatis生成mapper接口实现类对象的工作交由spring容器来完成,事务控制也由spring来完成。

3.1 引入依赖

数据源依赖:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.8</version>
</dependency>

数据库驱动依赖:

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.49</version>
</dependency>

mybatis依赖:

<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.6</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.8</version>
</dependency>

spring依赖:

 <dependency>
   <groupId>org.springframework</groupId>
     <artifactId>spring-context</artifactId>
     <version>5.3.13</version>
 </dependency>
 <!--spring-jdbc依赖-->
 <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-jdbc</artifactId>
     <version>5.3.13</version>
 </dependency>
 <!--aop织入依赖-->
 <dependency>
     <groupId>org.aspectj</groupId>
     <artifactId>aspectjweaver</artifactId>
     <version>1.8.13</version>
 </dependency>

3.2 配置文件

mybatis主配置文件mybatis.xml中删除environments中数据源相关的配置。
applicationContext.xml中配置如下:

<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"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       ">
    <context:component-scan base-package="com.test"/>

    <context:property-placeholder location="classpath:jdbc.properties"/>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    <!--mybatis sqlSessionFactory-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:mybatis.xml"/>
    </bean>
    <!--动态代理方式生成mapper实现类对象-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.test.dao"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>
    <!--事务相关配置-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <aop:pointcut id="myPointcut" expression="execution(* com.test.service.impl.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut"></aop:advisor>
    </aop:config>
</beans>

3.3 测试

@Service("userService")
public class UserServiceImp implements UserService {

    @Resource
    private UserDao userDao;

    public void addUser(User user) {
        userDao.addUser(user);
        int i=1/0;
    }
}

@ContextConfiguration("classpath:applicationContext.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class MybatisTest {

    @Autowired
    private UserService userService;
    @Test
    public void testAdd(){
        User user = new User();
        user.setUserName("华盛顿");
        user.setMakeTime(new Timestamp(new Date().getTime()));
        userService.addUser(user);
    }
}

测试结果:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值