JavaWeb、Maven与Mybatis框架

目录

一、Maven

1、Maven简介

2、Maven的特点

2.1、Maven提供了一套标准化的的项目结构

2.2、提供了一套标准化构建流程

2.3、提供了一套依赖管理机制

        3、安装Maven

4、Maven常用命令

5、Maven生命周期

6、在IDEA中配置Maven

6.1、配置Maven环境

 6.2、了解Maven坐标​编辑

 6.3、创建Maven项目

6.4、导入Maven项目

7、依赖管理

 7.1、导入依赖

 7.2、依赖范围

二、MyBatis

1、Mybatis定义

2、JDBC的缺点

3、Mybatis简化JDBC

4、Mybatis快速入门

 1、创建user表,添加数据

 2、创建Maven模块,导入坐标

 3、编写Mybatis核心配置文件 mybatis-config.xml

 4、编写SQL映射文件:SQL语句代码UserMapper.xml

 5、创建User类

 6、编写主程序

 5、IDEA集成操作Navicat

 6、使用Mapper代理方式完成入门案例

 1、定义同名的Mapper接口,并放置在同一目录下

 2、设置SQL映射文件的namespace为接口的全限定名

 3、在Mapper接口中定义方法

4、编码

7、Mybatis核心配置文件详解

8、Mybatis实战案例(使用配置文件实现增删改查)

1、查询所有数据

2、查看商品详情

3、多条件查询

        方法一:散装参数

        方法二:传入对象参数

        方法三:map集合做参数(HashMap)

4、多条件动态查询

5、单条件动态查询

 6、添加数据

        直接添加数据

         添加数据--主键返回

7、修改数据

         修改全部字段

         修改动态字段

8、删除数据

        删除一个

        批量删除

9、Mybatis使用注解完成增删改查


一、Maven

1、Maven简介

pom 就是 project object moudle 项目对象模型

配置完pom.xml文件之后,相对应的jar包就会出现在项目中,不需要再手动导包,而实际在maven中有一个本地仓库,仓库中存放有相对应的jar包,它只是通过本地仓库将jar包导入项目。

 由于中央仓库是由maven团队维护,由于仓库位置在国外,在国内访问速度较慢,所以一般公司会搭建自己的私服,将中央仓库的jar包同步下来,通过访问私服速度更快,中央仓库中存放的都是开源的jar包,带版权的jar只能在私服中

仓库工作流程:

项目1中需要某个jar包,向本地仓库申请,本地仓库中没有再向中央仓库中申请,并将相对应的jar包保存在本地仓库,然后导入项目1中,这时项目2需要用到该jar包时直接向本地仓库申请后导入。但如果架设了私服,本地仓库会先向私服请求,私服没有才会向中央仓库请求,然后将jar包下载到私服,再保存到本地仓库。

2、Maven的特点

2.1、Maven提供了一套标准化的的项目结构

2.2、提供了一套标准化构建流程

2.3、提供了一套依赖管理机制

 maven通过核心配置文件直接导包,不需要再下载后右键导包。

3、安装Maven

在setting文件中指定本地仓库

<localRepository>D:\2ProgramTool\Intellij idea\apache\maven cangku</localRepository>

4、Maven常用命令

compile编译,将代码编译成 字节码文件,生成目标文件target文件

clean清理,将目标文件删除

test测试,执行test文件夹下的测试代码,输出测试结果

package打包,将该maven项目打包成jar文件

install安装,将该maven项目的jar包下载进本地仓库

使用Maven可以将项目打包!!

 5、Maven生命周期

Maven对项目构建的生命周期分为3套 :clean、default、site

6、在IDEA中配置Maven

6.1、配置Maven环境

 6.2、了解Maven坐标

 6.3、创建Maven项目

6.4、导入Maven项目

 7、依赖管理

        7.1、导入依赖

 

    <!--导入当前需要的依赖包-->
    <!--dependencies 依赖,复数形式,多个依赖-->
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <!--选择版本后会标红,说明本地仓库没有这个版本信息,点击右侧Maven标志,刷新就会自动下载-->
            <version>5.1.34</version>
        </dependency>

        <dependency>
            <!--设置IDEA,修改立即生效就不需要点击侧边Maven-->
            <!--也可使使用快捷键Alt+Ins然后搜索,快速导入相关依赖-->
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.12</version>
        </dependency>

    </dependencies>

         7.2、依赖范围

 运行环境不存在说明这个依赖不会存在打包好的jar包中。

二、MyBatis

1、Mybatis定义

 与数据库进行操作的代码称为持久层。三层框架:表现层,业务层,持久层 -> 前端、后端、数据库

2、JDBC的缺点

3、Mybatis简化JDBC

将数据库连接和数据库操作都写在依赖中

4、Mybatis快速入门

  •  1、创建user表,添加数据

CREATE DATABASE mybatis;
USE mybatis;

DROP TABLE  IF EXISTS tb_user;

CREATE TABLE tb_user(
	id INT PRIMARY KEY AUTO_INCREMENT,
	username VARCHAR(10),
	password VARCHAR(10),
	gender CHAR(1),
	addr VARCHAR(30)
	);
	
INSERT INTO tb_user(username,password,gender,addr) 
		VALUES
		('张三','12345','男','安徽'),
		('李四','14335','男','芜湖'),
		('王五','16745','女','南京');
  • 2、创建Maven模块,导入坐标

  • 3、编写Mybatis核心配置文件 mybatis-config.xml

<?xml version="1.0" encoding="UTF-8" ?>


<!--Mybatis核心配置文件-->
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <!--数据库连接信息-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="12345"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--加载SQL映射文件-->
        <mapper resource="UserMapper.xml"/>
    </mappers>
</configuration>
  •  4、编写SQL映射文件:SQL语句代码UserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!--SQL映射文件-->
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!--mapper根标签  namespace必须要指定名称-->
<mapper namespace="test">
    <!--id 表示SQL语句的唯一标识
        resultType 表示SQL执行后返回结果的类型-->
    <select id="selectAll" resultType="com.itheima.pojo.User">
        select * from tb_user;
    </select>
    
</mapper>
  • 5、创建User类

public class User {
    private Integer id;
    private String username;
    private String password;
    private String gender;
    private String addr;
  • 6、编写主程序

public class MybatisDemo {
    public static void main(String[] args) throws Exception {
        //1、加载Mybatis核心配置文件,获取SqlSessionFactory
        String resource = "mybatis-config.xml";
        //Mybatis提供了资源加载类Resource,通过静态方法getResourceAsStream将字符串返回成一个字节输入流
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //再通过SqlSessionFactoryBuilder对象的build方法获取字节输入流创建一个sqlSessionFactory
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2、用sqlSessionFactory获取对应sqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        //3、执行sql
        //传入SQL语句的唯一标识需要跟上名称空间
        List<User> users = sqlSession.selectList("test.selectAll");

        System.out.println(users);

        //4、释放资源
        sqlSession.close();
    }
}

5、IDEA集成操作Navicat

点击右侧DataBase点击加号,创建一个数据库连接,再点击🖊进行SQL语法编写,代码会自动补全

6、使用Mapper代理方式完成入门案例

由于入门案例中的Mybatis简化后仍然存在硬编码问题,代码不灵活,所以使用Mapper代理方式进一步解决硬编码问题

  •  1、定义同名的Mapper接口,并放置在同一目录下

 右键单击resources新建文件,文件格式与Mapper接口的包名一致,中间用 / 做分隔符

文件创建成功后,将Mapper映射文件拖入文件夹中

 编译Maven项目查看class文件,Mapper接口与映射文件在同一文件夹下

  •  2、设置SQL映射文件的namespace为接口的全限定名

<!--mapper根标签  namespace必须要指定名称-->
包名.类名
<mapper namespace="com.itheima.mapper.UserMapper">
    <!--id 表示SQL语句的唯一标识
        resultType 表示SQL执行后返回结果的类型-->
    <select id="selectAll" resultType="com.itheima.pojo.User">
        select * from tb_user;
    </select>

</mapper>
  •  3、在Mapper接口中定义方法

public interface UserMapper {
    //定义一个与SQL映射文件id同名的方法
    //返回SQL映射文件中对应的返回值类型,还要根据SQL语义判断具体返回值类型
    List<User> selectAll();
}

 注意:由于Mapper映射文件位置已经更改,所以在Mybatis核心配置文件中修改映射文件的位置

 <mappers>
        <!--加载SQL映射文件-->
        <mapper resource="com/itheima/mapper/UserMapper.xml"/>
    </mappers>
  • 4、编码

//3、执行sql
//获取UserMapper接口的代理对象
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> userList = mapper.selectAll();

System.out.println(userList);

7、Mybatis核心配置文件详解

<?xml version="1.0" encoding="UTF-8" ?>

<!--Mybatis核心配置文件-->
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <!--
    使用typeAliases再进行包扫描,给该包下的所有实体类起别名,直接使用不区分大小写的类名
    例如SQL映射文件下的返回值类型可以直接使用user,而不是com.itheima.pojo.user
    -->
    <typeAliases>
        <package name="com.itheima.pojo"/>
    </typeAliases>

    <!--environments:配置数据库连接环境信息,可以配置多个environment,通过default属性切换不同的environment-->
    <environments default="development">
        <environment id="development">
            <!--事物的管理方式-->
            <transactionManager type="JDBC"/>
            <!--数据库连接池,默认为POOLED-->
            <dataSource type="POOLED">
                <!--数据库连接信息-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false"/>
                <property name="username" value="root"/>
                <property name="password" value="12345"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--加载SQL映射文件-->
        <mapper resource="com/itheima/mapper/UserMapper.xml"/>
    </mappers>
</configuration>

8、Mybatis实战案例(使用配置文件实现增删改查)

1、查询所有数据

 发现问题:在查询数据并对数据进行输出时发现,从数据库中查找的数据不能很好的封装成User类存储的值是null。

 由于数据库中列名为user_name,而User实体类中对应的用户名为userName,两者名称不同对应不上无法自动的封装数据。

三种修改方式:

<!--
        数据库表的字段名称 和 实体类的属性名称不一样 ,则不能自动封装数据
            *第一种方式:起别名  使两个名称相同  缺点:每次查询都要定义一次别名
            *第二种方式 使用Sql片段     缺点:不灵活
            *第三种方式 使用resultMap映射
    -->
<!--<select id="selectAll" resultType="User">
    <!--第一种起别名  缺点:每次查询都要定义一次别名-->
        select
            id, user_name as userName, password, gender, addr
        from tb_user;
    </select>
<sql id="user_column">
     id, user_name as userName, password, gender, addr
</sql>

<select id="selectAll" resultType="User">
<!--第二种方式:sql片段, 缺点:对部分列名查询时要重写一个sql片段-->
     select
       <include refid="user_column"></include>
     from tb_user;
</select>
<resultMap id="userResultMap" type="user">
        <!--resultMap有两个常用属性 id:设置主键字段的映射  result:设置一般字段的映射-->
        <!--column 表的列名 property 实体类的属性名-->
        <result column="user_name" property="username"></result>
</resultMap>

<select id="selectAll" resultMap="userResultMap">
    <!--第三种方式:使用resultMap映射,select标签中要记得修改为resultMap-->
        select
        *
        from tb_user;
    </select>

数据成功封装

2、查看商品详情

<!--
         *参数占位符
         1、#{}: 会将其替换成?,为了防止SQL注入
         2、${}: 字符串拼接,直接将参数拼到字符串,会存在SQL注入问题
                使用时机:*参数传递的时候:#{}
                        *表名或者列名不固定 ${}
         3、特殊字符: xml文件中的一些比较运算符不能直接使用,要适应注意字符 &lt
    -->
    <select id="selectById" resultMap="userResultMap">
        select  *
        from tb_user where id = #{id};
    </select>
public interface UserMapper {
    //1、查询所有
    List<User> selectAll();

    //2、查看详情,根据id查询
    User selectById(int id);

3、多条件查询

多条件查询,传入多个参数有三种传参方式 :

方法一:散装参数

public interface UserMapper {
    //1、查询所有
    List<User> selectAll();

    //2、查看详情,根据id查询
    User selectById(int id);

    //3、多条件查询
    //三种方式的参数接收
    //1、散装参数,存在多个参数使用@Param("占位符名称")注解
    List<User> selectByFields(@Param("username") String username,@Param("gender") String gender,@Param("addr") String addr);
 <select id="selectByFields" resultMap="userResultMap">
        select
        *
        from tb_user
        where
          user_name = #{username}
          and gender = #{gender}
          and addr like #{addr};
    </select>
    //接收参数
            String username = "张三";
            String gender = "男";
            String addr = "徽";
            //处理参数 模糊查询
            addr = "%" + addr;

        //4、执行接口方法(执行SQL语句) 通过接口方法执行SQL语句
        List<User> user = usermapper.selectByFields(username,gender,addr);
        System.out.println(user);

方法二:传入对象参数

 //接口
// 2、对象参数:传入一个对象,对象的属性名称要与参数占位符名称一致
    List<User> selectByFields(User user);
 //接收参数
            String username = "张三";
            String gender = "男";
            String addr = "徽";
            //处理参数
            addr = "%" + addr;

            //封装对象
            User user = new User();
            user.setUsername(username);
            user.setGender(gender);
            user.setAddr(addr);
        //4、执行接口方法(执行SQL语句) 通过接口方法执行SQL语句 
        List<User> users = usermapper.selectByFields(user);

方法三:map集合做参数(HashMap)

//接口
//3、传入Map集合
    List<User> selectByFields(Map map);
//接收参数
            String username = "张三";
            String gender = "男";
            String addr = "徽";
            //处理参数
            addr = "%" + addr;

            //添加Map集合
            Map map = new HashMap();
            //键:xml中的占位符名称,值:传入的参数
            map.put("username",username);
            map.put("gender",gender);
            map.put("addr",addr);
        //4、执行接口方法(执行SQL语句) 通过接口方法执行SQL语句
        List<User> users = usermapper.selectByFields(map);

多条件查询当前存在的弊端:如果用户只输入其中一个数据就进行查询结果会查不到任何数据,所以需要采用动态查询方式

4、多条件动态查询

 使用if实现动态查询

<select id="selectByFields" resultMap="userResultMap">
        select
            *
        from tb_user
        where
              /*test中判断的值是传入的占位符的值,判断占位符是否为空字符串或者空字符,不能使用表名*/
              /*多条件的and不能丢*/
            <if test="username != null and username != ''">
                user_name = #{username}
            </if>

            <if test="gender != null and gender != ''">
                and gender = #{gender}
            </if>

            <if test="addr != null and addr != ''">
                and addr like #{addr};
            </if>

    </select>
//接收参数
            String username = "张三";
            String gender = "男";
            String addr = "徽";
            //处理参数
            addr = "%" + addr;

            //添加Map集合 
            // 只输入两个数据
            Map map = new HashMap();
            //键:xml中的占位符名称,值:传入的参数
            map.put("username",username);
            map.put("gender",gender);
           
            //map.put("addr",addr);
        //4、执行接口方法(执行SQL语句) 通过接口方法执行SQL语句
        List<User> users = usermapper.selectByFields(map);

当前问题:仅仅使用if语句会有bug,如果多条件查询中,用户没有输入第一个条件,而选择了后面的条件,此时第二条语句就会变成第一条语句使得SQL语句变成了

select * from tb_user where and gender=?

解决问题:在where后面加上恒等式1=1,并在每条语句前都加上and就可以解决问题

<select id="selectByFields" resultMap="userResultMap">
        select
            *
        from tb_user
        where 1 = 1
              /*test中判断的值是传入的占位符的值,判断占位符是否为空字符串或者空字符,不能使用表名*/
              /*多条件的and不能丢*/
            <if test="username != null and username != ''">
                and user_name = #{username}
            </if>

            <if test="gender != null and gender != ''">
                and gender = #{gender}
            </if>

            <if test="addr != null and addr != ''">
                and addr like #{addr};
            </if>

    </select>

 也可以使用Mybatis提供的<where>标签来代替where语句,满足其中的条件就能执行

<select id="selectByFields" resultMap="userResultMap">
        select
            *
        from tb_user
        <where>
                
              <!--test中判断的值是传入的占位符的值,判断占位符是否为空字符串或者空字符,不能使用表名-->
              <!--多条件的and不能丢-->
            <if test="username != null and username != ''">
                and user_name = #{username}
            </if>

            <if test="gender != null and gender != ''">
                and gender = #{gender}
            </if>

            <if test="addr != null and addr != ''">
                and addr like #{addr};
            </if>
         </where>
    </select>

5、单条件动态查询

 使用choose实现单条件动态查询

choose就相当于switch  when某个条件成立 执行代码  otherwise相当于default 恒等式

<select id="selectByFild" resultMap="userResultMap">
        select
        *
        from tb_user
        <!--where不能丢-->
        where
        <choose>

            <when test="username != null and username != ''">
                 user_name = #{username}
            </when>

            <when test="gender != null and gender != ''">
                 gender = #{gender}
            </when>

            <when test="addr != null and addr != ''">
                 addr like #{addr}
            </when>

            <otherwise>
                1 = 1
            </otherwise>
        </choose>
    </select>

使用<where>标签代替where语句,可以省略1=1

<select id="selectByField" resultMap="userResultMap">
        select
        *
        from tb_user
        <where><!--满足其中的条件就能执行-->
        <choose>
            <when test="username != null and username != ''">
                 user_name = #{username}
            </when>

            <when test="gender != null and gender != ''">
                 gender = #{gender}
            </when>

            <when test="addr != null and addr != ''">
                 addr like #{addr}
            </when>

        </choose>
        </where>
    </select>

 6、添加数据

直接添加数据

<insert id="add">
        insert
        into tb_user(user_name,password,gender,addr)
        values
        (#{username},#{password},#{gender},#{addr});
</insert>
//测试类
//接收参数
        String username = "赵六";
        String password = "123789";
        String gender = "男";
        String addr = "滁州";

        User user = new User(username,password,gender,addr);

        //4、执行接口方法(执行SQL语句) 通过接口方法执行SQL语句
        usermapper.add(user);

发现问题:代码运行正常,但是数据库中却没有显示添加的数据

 解决问题:执行完后需要手动提交事务

//提交事务
sqlSession.commit();

可以在建立SqlSession对象时设置自动提交事务

//1、加载mybatis核心配置文件获取SqlSessionFactory
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //2、获取SqlSession对象
        //设置参数 true 自动提交事务,默认手动提交
        SqlSession sqlSession = sqlSessionFactory.openSession(true);

使用此方式添加数据的缺点: 数据添加后无法通过封装的数据访问到数据库中的id值

 添加数据--主键返回

 只需要对SQL语句设置两个属性就能获取到对应的id值

在Mybatis中useGeneratedKeys属性只针对insert语句生效,默认为false,当设置为true时,表示插入的表以自增列为主键,则允许JDBC自动生成主键(对主键字段对应的实体类属性进行赋值)并可将此主键值返回,前提是主键必须自增。

keyProperty属性中必须填写的是主键字段对应的实体类属性名称,以确保实体类对象通过Mybatis增加到数据库之后得到的id增长值会被设置在实体类对应的属性值上。

public class User {
    //实体类属性值
    private Integer id;
    private String username;
    private String password;
    private String gender;
    private String addr;
<insert id="add" useGeneratedKeys="true" keyProperty="id">
        insert
        into tb_user(user_name,password,gender,addr)
        values
        (#{username},#{password},#{gender},#{addr});
</insert>

7、修改数据

 修改全部字段

 <update id="updateAll" >
        update tb_user
        set user_name = #{username},
            password = #{password},
            gender = #{gender},
            addr = #{addr}
        where id = #{id};
    </update>
//接收参数
        String username = "张明杨";
        String password = "124589";
        String gender = "女";
        String addr = "广西";
        Integer id = 7;

        //封装新的对象
        User user = new User(id,username,password,gender,addr);
        //4、执行接口方法(执行SQL语句) 通过接口方法执行SQL语句
        int count = usermapper.updateAll(user);

修改动态字段

使用Mybatis提供的<set标签>   只修改部分字段

 <update id="updatePart">
        update tb_user
        <set>
            <if test="username != null and username != ''">
                user_name = #{username},
            </if>

            <if test="password != null and password != ''">
                password = #{password},
            </if>

            <if test="gender != null and gender != ''">
                gender = #{gender},
            </if>

            <if test="addr != null and addr != ''">
                addr = #{addr},
            </if>

        </set>
        where id = #{id};
    </update>
//接收参数
        String username = "张明杨";
        String password = "124589";
        String gender = "女";
        String addr = "广西";
        Integer id = 8;

        //封装新的对象
        User user = new User();
        user.setUsername(username);
        //user.setPassword(password);
        //user.setGender(gender);
        user.setId(id);
        user.setAddr(addr);

        //4、执行接口方法(执行SQL语句) 通过接口方法执行SQL语句
        int count = usermapper.updatePart(user);
        System.out.println(count);

8、删除数据

删除一个

批量删除

    //9、批量删除
    //使用@Param注解将这个ids数组命名,传到sql语句中
    int deleteByIds(@Param("ids") int[] ids);
<!--
        在Mybatis中会将数组参数封装成一个Map集合
        键:数组    值:数组参数id对应的实体类对象
        *默认key的名称为 array
        *通过@Param注解可以改变map集合的默认key的名称
    -->
    <delete id="deleteByIds">
        delete from tb_user where id
        in
         <!--根据数组内容生成对应数量的占位符-->
        <!--collection:对应的数组名称 item:相当于循环中获取到的元素 separator:元素之间的分隔符 open:以什么开头 close:以什么结尾-->
        <foreach collection="ids" item="id" separator="," open="(" close=");">
            #{id}
        </foreach>

    </delete>
//3、获取Mapper接口的代理对象
        UserMapper usermapper = sqlSession.getMapper(UserMapper.class);

        //接收参数
        int[] ids = {6};

        //4、执行接口方法(执行SQL语句) 通过接口方法执行SQL语句
        int count = usermapper.deleteByIds(ids);
        System.out.println(count);

9、Mybatis使用注解完成增删改查

定义接口时使用注解,注解中写入sql语句

//注解开发简单SQL语句
//注解添加数据
    @Insert("insert into tb_user(user_name,password,gender,addr) values (#{username},#{password},#{gender},#{addr})")
    int addAll2(User user);
 //接收参数
        String username = "张三";
        String password = "1221421";
        String gender = "男";
        String addr = "徽";


        User user = new User(username,password,gender,addr);
        //4、执行接口方法(执行SQL语句) 通过接口方法执行SQL语句
        int count = usermapper.addAll2(user);

        sqlSession.commit();
        System.out.println(count);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值