Java ORM实体类自动生成工具:MySQL表映射到Java实体

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:本文介绍了一个为Java企业级应用设计的工具,该工具能够自动将MySQL数据库中的表结构转换为Java实体类,利用ORM技术如Hibernate或MyBatis,简化开发流程。实体类通过JDBC连接数据库后,自动获取表结构并生成对应的源代码,包括属性的CRUD操作方法、添加ORM框架注解、序列化支持、主键处理等。工具的可配置性和异常处理确保了其灵活性和稳定性,社区参与和持续更新则保证了工具的不断完善。
mysql数据库表映射实体生成

1. 数据库表映射到Java实体类

在现代Java开发中,将数据库表映射到Java实体类是一个基础且至关重要的过程。这不仅涉及将数据表的结构转换为对象模型,还包括理解数据库的schema和Java代码之间的关系。映射过程为ORM(对象关系映射)框架提供了基础,使得能够以面向对象的方式来操作关系型数据库中的数据。

1.1 基本映射原则

实体类通常对应数据库中的一个表,而类中的每个属性则映射到表中的一个字段。数据库表的主键在Java实体类中通常表现为一个ID字段,并且有时会通过注解或XML映射文件来显式地定义这种关系。例如,使用JPA注解时,可以通过 @Entity @Table 注解来声明一个类为实体类并映射到特定的表:

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "students")
public class Student {
    @Id
    private Long id;
    private String name;
    private int age;
    // getters and setters
}

1.2 字段映射的细节

除了基本的映射关系,还可以映射更多复杂的数据库特性,比如外键关系、索引、唯一性约束等。对于这些复杂的映射关系,可能需要额外的注解和配置来精确控制映射过程。例如,使用JPA的 @ManyToOne 注解可以映射多对一的外键关系:

import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.ManyToOne;
import javax.persistence.JoinColumn;

@Entity
@Table(name = "grades")
public class Grade {
    @Id
    private Long id;
    @ManyToOne
    @JoinColumn(name = "student_id")
    private Student student;
    private String subject;
    private float score;
    // getters and setters
}

映射过程是建立在Java开发者对数据库设计和ORM框架有深刻理解的基础上的。合理利用这些映射机制,可以提高开发效率、降低数据库操作的复杂性,同时为代码的可维护性打下坚实基础。

2. ORM技术的应用与实践

在深入理解了数据库表映射到Java实体类之后,接下来将探讨ORM(Object Relational Mapping,对象关系映射)技术的应用与实践。ORM技术作为Java企业级应用中不可或缺的一部分,它提供了数据库与对象模型之间的映射机制,使得开发者能够更加便捷地操作数据库。

2.1 ORM技术概述

2.1.1 ORM技术的定义和优势

ORM技术允许开发者通过使用普通的Java对象来实现数据库的CRUD(创建Create、读取Retrieve、更新Update、删除Delete)操作。对象和数据库表之间通过映射关系相互转换,极大地简化了数据库操作的代码量和复杂性。

优势主要体现在:

  • 面向对象的操作 :开发者不再编写复杂的SQL语句,而是通过操作Java对象来实现对数据库的操作。
  • 数据库无关性 :通过ORM框架,可以方便地切换不同的数据库,因为操作对象与数据库的具体实现解耦。
  • 性能优化 :ORM框架通常会进行SQL语句的优化,提高查询效率。
  • 数据一致性和完整性 :通过ORM框架,可以利用其提供的事务管理功能来保证数据的一致性和完整性。

2.1.2 Hibernate和MyBatis的比较

在众多的ORM框架中,Hibernate和MyBatis是两个非常流行的选择。它们各有特点,适合不同的应用场景。

  • Hibernate 是一个全自动化ORM框架。它提供了一套完整的映射机制,通过注解或XML来配置对象与数据库表之间的映射关系,可以实现几乎不用编写SQL语句就能完成所有数据库操作。

  • MyBatis 则是一种半自动化的ORM框架。它提供了一种更加灵活的方式来编写SQL语句,并允许开发者自由地编写SQL。MyBatis通过XML或注解将SQL语句和Java对象进行映射,使开发者能更好地控制SQL执行。

在选择上,如果项目需要更少的配置和代码,优先考虑Hibernate;如果需要更高的灵活性和控制力,MyBatis会是更好的选择。

2.2 Hibernate应用

2.2.1 Hibernate的基本操作

要使用Hibernate,首先需要在项目中引入Hibernate的依赖库,并配置好Hibernate的配置文件(hibernate.cfg.xml)。基本的操作流程通常包括以下几个步骤:

  1. 创建实体类并映射数据库表。
  2. 创建映射文件或使用注解指定映射关系。
  3. 创建SessionFactory。
  4. 使用SessionFactory获取Session。
  5. 开启事务,进行数据操作。
  6. 提交事务或回滚事务。
  7. 关闭Session。

下面是一个使用注解映射的简单例子:

import javax.persistence.*;
import java.io.Serializable;

@Entity
@Table(name="EMPLOYEE")
public class Employee implements Serializable {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="ID")
    private int id;
    @Column(name="FIRST_NAME")
    private String firstName;
    @Column(name="LAST_NAME")
    private String lastName;
    // 省略getter和setter方法
}

2.2.2 Hibernate的高级特性

Hibernate除了基本操作外,还提供了一系列高级特性:

  • 缓存机制 :Hibernate提供了两级缓存:一级缓存是Session级别的,不可配置,随Session生命周期而存在;二级缓存是可配置的,可以跨多个Session共享数据,提高性能。
  • HQL(Hibernate Query Language) :是一种对象查询语言,允许执行复杂的查询操作,其语法类似SQL,但操作的是对象。
  • 乐观锁和悲观锁 :Hibernate支持通过版本号或时间戳等机制实现乐观锁,通过锁机制实现悲观锁,保证并发时数据的一致性。

使用HQL查询例子:

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
String hql = "FROM Employee e WHERE e.firstName = :firstName";
Query query = session.createQuery(hql);
query.setParameter("firstName", "John");
List<Employee> employees = query.list();
tx.commit();
session.close();

2.3 MyBatis应用

2.3.1 MyBatis的基本操作

MyBatis需要在项目中引入MyBatis的依赖库,并配置好mybatis-config.xml配置文件。其基本操作步骤与Hibernate类似,但提供了更灵活的SQL操作能力。一个典型的操作流程是:

  1. 配置MyBatis。
  2. 创建Mapper接口和映射文件。
  3. 获取SqlSessionFactory。
  4. 获取SqlSession。
  5. 通过SqlSession调用Mapper接口方法操作数据库。
  6. 提交或回滚事务。
  7. 关闭SqlSession。

下面是一个简单的Mapper接口和映射文件的例子:

public interface EmployeeMapper {
    Employee selectEmployee(int id);
}
<mapper namespace="com.example.mapper.EmployeeMapper">
    <select id="selectEmployee" resultType="com.example.domain.Employee">
        SELECT * FROM EMPLOYEE WHERE ID = #{id}
    </select>
</mapper>

2.3.2 MyBatis的高级特性

MyBatis的高级特性主要包括:

  • 动态SQL :MyBatis支持动态SQL的构建,能够根据不同的条件动态生成SQL语句。
  • 插件机制 :MyBatis允许开发者自定义插件来拦截Mapper接口方法的调用,以实现性能监控、日志记录等功能。
  • 缓存机制 :除了使用一级缓存外,MyBatis也可以配置使用第三方缓存框架如Ehcache,进一步提升性能。

使用动态SQL和插件的例子:

<select id="selectEmployee" resultType="com.example.domain.Employee">
    SELECT * FROM EMPLOYEE
    <where>
        <if test="id != null">
            AND ID = #{id}
        </if>
        <if test="firstName != null">
            AND FIRST_NAME = #{firstName}
        </if>
    </where>
</select>

本章节的介绍仅涉及了Hibernate和MyBatis应用的基础知识。要深入掌握这些框架,还需要通过实际项目来实践和深入学习它们的高级特性。接下来的章节将讲述JDBC数据库连接与表信息获取,为深入探讨ORM技术的应用与实践打下坚实的基础。

3. JDBC数据库连接与表信息获取

3.1 JDBC基础

3.1.1 JDBC的定义和基本操作

JDBC(Java Database Connectivity)是一种Java API,它定义了客户端如何连接和操作数据库。JDBC为Java开发者提供了一种统一的方式来访问多种数据库管理系统(DBMS)。

要使用JDBC,首先需要包含相应的驱动库在项目中,然后加载驱动类,建立到数据库的连接。以下是一个简单的例子,展示了如何使用JDBC连接到MySQL数据库:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class JdbcExample {
    public static void main(String[] args) {
        // 定义数据库连接URL
        String url = "jdbc:mysql://localhost:3306/mydatabase";
        String user = "username";
        String password = "password";

        Connection conn = null;
        try {
            // 加载并注册JDBC驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            // 建立数据库连接
            conn = DriverManager.getConnection(url, user, password);
            System.out.println("连接数据库成功!");
        } catch (ClassNotFoundException e) {
            System.out.println("找不到JDBC驱动");
            e.printStackTrace();
        } catch (SQLException e) {
            System.out.println("数据库连接失败");
            e.printStackTrace();
        }
        // 使用完毕记得关闭连接
        finally {
            try {
                if (conn != null) conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

以上代码段说明了如何通过JDBC连接数据库的基本步骤:
1. 导入JDBC相关的类。
2. 使用 Class.forName() 来加载并注册数据库驱动。
3. 使用 DriverManager.getConnection() 获取数据库连接。
4. 使用连接进行数据库操作。
5. 使用完毕后关闭连接。

3.1.2 JDBC的高级特性

JDBC不仅提供了基本的数据库连接和执行SQL语句的功能,它还支持许多高级特性,例如连接池、事务控制和批处理操作等。

连接池的引入可以显著减少连接数据库的开销,因为数据库连接是一种稀缺资源,频繁地打开和关闭连接会导致性能下降。JDBC提供的连接池功能可以在多个请求之间共享和重用数据库连接。

事务控制允许用户定义一个或多个操作作为一个执行单元,保证数据的一致性和完整性。通过调用 Connection 对象的 setAutoCommit(false) commit() 方法,可以控制事务的开始和提交。

批处理操作允许将多个SQL语句组合成一个批次,一次性发送给数据库执行。这减少了网络传输次数,提高了执行效率。

try (Connection conn = DriverManager.getConnection(url, user, password)) {
    conn.setAutoCommit(false); // 关闭自动提交,开始一个事务
    PreparedStatement pstmt = conn.prepareStatement("INSERT INTO table_name (column1, column2) VALUES (?, ?)");
    for (int i = 0; i < data.size(); i++) {
        pstmt.setString(1, data.get(i).getColumn1());
        pstmt.setString(2, data.get(i).getColumn2());
        pstmt.addBatch(); // 添加到批处理
    }
    pstmt.executeBatch(); // 执行批处理
    conn.commit(); // 提交事务
} catch (SQLException e) {
    conn.rollback(); // 出现异常时回滚事务
    e.printStackTrace();
}

3.2 数据表信息获取

3.2.1 获取表结构信息的方法

JDBC提供了一种简单的方法来获取数据库表的结构信息,即通过 DatabaseMetaData 接口。它提供了一组丰富的元数据方法,可以用来获取关于数据库的各种信息,包括数据库表的信息。

下面的代码展示了如何使用 DatabaseMetaData 获取指定表的所有列信息:

try (Connection conn = DriverManager.getConnection(url, user, password)) {
    DatabaseMetaData metaData = conn.getMetaData();
    ResultSet rs = metaData.getColumns(null, null, "table_name", null);
    while (rs.next()) {
        String columnName = rs.getString("COLUMN_NAME");
        String columnType = rs.getString("TYPE_NAME");
        int columnSize = rs.getInt("COLUMN_SIZE");
        System.out.println("列名: " + columnName + ", 类型: " + columnType + ", 长度: " + columnSize);
    }
} catch (SQLException e) {
    e.printStackTrace();
}

3.2.2 处理表信息的策略

在实际开发中,对于表结构信息的获取和处理,通常可以采用以下策略:

  • 动态生成实体类 :根据表结构信息,可以动态地生成对应的Java实体类。
  • 表信息缓存 :避免每次查询都去数据库获取表信息,可以将获取到的表信息进行缓存,从而提升性能。
  • 元数据更新监听 :监控数据库表结构的变更,动态地更新Java实体类或数据访问层代码。

例如,可以构建一个表信息的缓存结构,利用 ConcurrentHashMap 进行线程安全的存储,配合定时任务来更新缓存,减少对数据库的查询次数,如下代码所示:

ConcurrentHashMap<String, TableInfo> tableInfoCache = new ConcurrentHashMap<>();

// 使用定时任务或在表结构变更时更新缓存
public void refreshTableInfo(String tableName) {
    try (Connection conn = DriverManager.getConnection(url, user, password)) {
        DatabaseMetaData metaData = conn.getMetaData();
        ResultSet rs = metaData.getColumns(null, null, tableName, null);
        TableInfo tableInfo = new TableInfo();
        while (rs.next()) {
            // 读取列信息并填充到tableInfo对象中
        }
        tableInfoCache.put(tableName, tableInfo);
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

// 供其他部分调用缓存的信息
public TableInfo getTableInfo(String tableName) {
    return tableInfoCache.get(tableName);
}

在本章节中,我们详细了解了JDBC基础,包括其定义、基本操作、以及高级特性。此外,我们还探讨了获取数据库表信息的方法和处理策略,展示了代码示例和具体的实现细节。通过这些内容,读者可以更加深入地理解和应用JDBC来操作数据库,为后文的实体类自动生成和CRUD操作方法奠定了基础。

4. 实体类自动生成与CRUD操作方法

随着软件开发的自动化和智能化发展,开发人员不再需要手动编写大量模板代码,尤其是在数据持久层的操作中。实体类自动生成工具的出现,极大地提高了开发效率,而CRUD(Create、Read、Update、Delete)操作是数据库操作中最常见的功能。本章将深入探讨实体类自动生成工具的使用方法,以及如何实现高效的CRUD操作。

4.1 实体类自动生成工具

在复杂的数据库结构映射到Java实体类时,开发者通常会依赖实体类生成工具来简化这一过程。这些工具可以自动扫描数据库表,根据数据库的元数据生成对应的Java实体类。

4.1.1 常见的实体类生成工具

在Java生态中,常见的实体类自动生成工具包括MyBatis Generator、JOOQ等。MyBatis Generator是一个专门为MyBatis框架设计的生成器,能够生成数据库表对应的实体类、Mapper接口和XML映射文件。JOOQ则是一个更为全面的数据库交互库,它不仅可以生成实体类,还可以执行类型安全的SQL查询。开发者可以根据项目需求和个人偏好选择合适的工具。

4.1.2 实体类生成工具的使用方法

以MyBatis Generator为例,以下是使用该工具的基本步骤:

  1. 在项目中引入MyBatis Generator的依赖。
  2. 配置 generatorConfig.xml 文件,指定数据库连接信息以及生成的实体类存放位置等。
  3. 执行Generator提供的命令或接口,自动生成实体类代码。
<!-- generatorConfig.xml 配置示例 -->
<generatorConfiguration>
    <context id="DB2Tables" targetRuntime="MyBatis3">
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                         connectionURL="jdbc:mysql://localhost:3306/your_database"
                         userId="your_username"
                         password="your_password">
        </jdbcConnection>
        <!-- 其他配置... -->
    </context>
</generatorConfiguration>

配置完成后,可以通过以下Maven命令来生成代码:

mvn mybatis-generator:generate

执行完毕后,相应的实体类将被创建在指定位置,同时生成Mapper接口及XML配置文件。这些工具通常还支持自定义生成模板,以便满足更复杂的生成需求。

4.2 CRUD操作方法

CRUD操作是数据库持久层的基本操作,代表创建、读取、更新和删除数据的能力。在Java中,这些操作通常由ORM框架或者JDBC提供支持。

4.2.1 CRUD操作的定义和重要性

CRUD操作的重要性在于它们是构建业务逻辑层的基础。任何对数据的处理和操作,最终都可以分解为这些基本操作。良好的CRUD实现,能够提高代码的可读性、可维护性和可扩展性。

4.2.2 CRUD操作的具体实现

在MyBatis中,CRUD操作主要通过Mapper接口和XML映射文件来实现。以下是一个简单的CRUD操作实现示例:

// Mapper接口
public interface UserMapper {
    int insert(User user);
    User selectByPrimaryKey(Integer id);
    int updateByPrimaryKey(User user);
    int deleteByPrimaryKey(Integer id);
}
<!-- Mapper XML文件 -->
<mapper namespace="com.example.mapper.UserMapper">
    <insert id="insert" parameterType="com.example.domain.User">
        INSERT INTO user (name, age) VALUES (#{name}, #{age})
    </insert>
    <select id="selectByPrimaryKey" parameterType="int" resultType="com.example.domain.User">
        SELECT * FROM user WHERE id = #{id}
    </select>
    <update id="updateByPrimaryKey">
        UPDATE user SET name = #{name}, age = #{age} WHERE id = #{id}
    </update>
    <delete id="deleteByPrimaryKey" parameterType="int">
        DELETE FROM user WHERE id = #{id}
    </delete>
</mapper>

在上述示例中,定义了一个User实体类对应的Mapper接口和XML映射文件。通过这些定义,就可以执行具体的CRUD操作了。实际应用中,开发者可以根据业务需求定制更复杂的SQL语句,并通过接口方法进行调用。

在更高级的实践中,可以结合MyBatis的注解特性,使得Mapper接口的实现更加简洁。例如,可以在Mapper接口的方法上使用 @Select @Insert @Update @Delete 注解直接定义SQL语句。

// 使用注解简化Mapper接口
public interface UserMapper {
    @Insert("INSERT INTO user (name, age) VALUES (#{name}, #{age})")
    int insert(User user);
    @Select("SELECT * FROM user WHERE id = #{id}")
    User selectByPrimaryKey(Integer id);
    @Update("UPDATE user SET name = #{name}, age = #{age} WHERE id = #{id}")
    int updateByPrimaryKey(User user);
    @Delete("DELETE FROM user WHERE id = #{id}")
    int deleteByPrimaryKey(Integer id);
}

通过注解的方式,可以减少XML映射文件的编写工作,使代码更加简洁。不过,在一些项目中,由于对SQL语句的复杂控制和版本控制的需求,可能仍需使用XML映射文件的方式。

CRUD操作的实现是开发过程中最基础,同时也是最关键的部分。熟练掌握这些操作,并能够灵活地应用到不同的应用场景中,是每个Java后端开发者的基本技能。随着框架和工具的不断进步,CRUD操作的方法也在不断进化,合理利用这些工具和服务可以大大提高开发效率和系统的健壮性。

5. 高级特性与社区参与

随着Java开发的深入,开发者们常常需要处理更加复杂的业务需求。在ORM(对象关系映射)框架的使用过程中,我们不仅需要掌握基础的操作,更应该利用其高级特性来优化我们的代码和提高开发效率。此外,社区的力量不可小觑,通过积极参与社区和持续学习,可以帮助我们不断更新知识库,保持技能的前沿性。

5.1 ORM注解添加与序列化支持

5.1.1 ORM注解的定义和作用

ORM注解是Java语言中对ORM框架提供了一种声明式的映射机制。通过在Java类中的字段上添加注解,我们可以简洁明了地告诉ORM框架如何将Java对象映射到数据库的表结构中。例如,Hibernate和MyBatis都支持使用注解来简化映射配置。

@Entity
@Table(name="student")
public class Student {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;
    private String name;
    private Integer age;
    // getters and setters
}

在上述代码中, @Entity 注解标明该类为一个实体类, @Table 注解指定了数据库中的表名,而 @Id @GeneratedValue 注解则定义了主键及生成策略。

5.1.2 序列化的基本知识和应用

序列化是将对象状态转换为可存储或传输格式的过程。在Java中,任何实现了Serializable接口的对象都可以被序列化。序列化在ORM框架中尤为重要,尤其是在Web应用和微服务架构中,对象可能会在不同的系统间传输。

import java.io.Serializable;

public class User implements Serializable {
    private static final long serialVersionUID = 1L;
    // class members
}

在上面的代码中, User 类实现了 Serializable 接口,这样就可以被序列化了。

5.2 主键处理与源码保存

5.2.1 主键生成策略

主键是数据库中用来唯一标识一条记录的字段。在ORM中,我们可以使用注解来指定主键的生成策略。通常有自然主键和代理主键之分,而在ORM框架中,推荐使用代理主键,因为它不依赖于业务,更容易维护。

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

以上注解表示主键 id 将由数据库自动生成。

5.2.2 源码保存的方法和工具

为了便于版本控制和团队协作,源代码必须被保存在代码仓库中。现代的版本控制系统如Git,提供了分布式架构,支持大型团队进行有效的代码管理。

# Git commit message
[feature] Add ORM annotations to Student entity

Add Hibernate annotations to the Student entity for better database mapping.
- Use @Entity to define a persistent entity.
- Add @Table(name="student") to define the mapped table.
- Include @Id and @GeneratedValue to define primary key and its strategy.

Signed-off-by: Your Name <your.email@example.com>

有效的提交消息能帮助其他开发者理解代码变更的意图。

5.3 工具配置性与异常处理

5.3.1 工具配置性的理解和应用

工具的配置性是指工具根据使用者的不同需要进行个性化设置的能力。例如,ORM框架通常拥有强大的配置文件(XML或注解),允许开发者配置诸如缓存策略、连接池细节等高级特性。

<!-- example of hibernate configuration in hibernate.cfg.xml -->
<property name="hibernate.cache.provider_class">org.hibernate.cache.NoCacheProvider</property>

在配置文件中,我们可以定义缓存提供者,以便控制Hibernate的缓存行为。

5.3.2 异常处理的策略和方法

异常处理在任何软件开发中都是关键组成部分。ORM框架可能会抛出各种异常,如数据访问异常、连接异常等。合理地处理这些异常不仅可以提高代码的健壮性,还可以提升用户体验。

try {
    // data access logic
} catch (DataAccessException e) {
    // handle exception, possibly log it and give user a friendly message
    logger.error("Data access exception occurred", e);
    throw new RuntimeException("An error occurred while accessing the database.");
}

在代码中使用try-catch块来捕获异常,并进行适当的处理。

5.4 社区参与与持续更新

5.4.1 社区参与的意义和方式

社区参与对于个人成长和项目成功至关重要。开发者可以通过社区贡献代码、分享经验、提供反馈以及参与讨论来促进项目的改进和个人技能的提高。

5.4.2 持续更新的策略和方法

在IT行业,技术更新迭代非常快。为了跟上时代的步伐,开发者需要不断地学习新技术,更新自己的知识体系。

flowchart LR
    A[开始学习] --> B[确定学习路径]
    B --> C[获取学习资源]
    C --> D[动手实践]
    D --> E[分享学习成果]
    E --> F[持续反馈与改进]

持续学习的流程图显示了从开始到不断改进的过程。通过这样循环的步骤,开发者可以持续更新自己的技能。

总的来说,本章节我们讨论了通过使用ORM注解来优化映射关系,处理主键和源码保存的策略,理解工具的配置性,以及如何处理异常。同时,我们也强调了社区参与的重要性以及如何通过各种方法来持续学习和更新。这些高级特性和社区支持,将帮助开发者更好地适应变化,提高开发效率和质量。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:本文介绍了一个为Java企业级应用设计的工具,该工具能够自动将MySQL数据库中的表结构转换为Java实体类,利用ORM技术如Hibernate或MyBatis,简化开发流程。实体类通过JDBC连接数据库后,自动获取表结构并生成对应的源代码,包括属性的CRUD操作方法、添加ORM框架注解、序列化支持、主键处理等。工具的可配置性和异常处理确保了其灵活性和稳定性,社区参与和持续更新则保证了工具的不断完善。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值