Maven实战指南 09

  6.3.2 实现Hibernate DAO模块

在实际项目中,我们一般会使用面向接口编程,从而实现调用者和被调用者的完全解耦,方便项目的团队开发和后期的扩展。鉴于这样的考虑,关于Hibernate的持久层的实现,分两步进行:第一步定义公共接口和类,第二步基于Hibernate实现接口,详细介绍如下:

 

第一步:定义公共DAO接口和类

1、创建一个普通的Maven工程:MvnBookSSHDemo.DAO。目录结构如下:

 

 

pom.xml也没有太特别的,内容如下:

<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

  <modelVersion>4.0.0</modelVersion>

 

  <groupId>cn.com.mvnbook.ssh.demo</groupId>

  <artifactId>MvnBookSSHDemo.DAO</artifactId>

  <version>0.0.1-SNAPSHOT</version>

  <packaging>jar</packaging>

 

  <name>MvnBookSSHDemo.DAO</name>

  <url>http://maven.apache.org</url>

 

  <properties>

    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

  </properties>

 

  <dependencies>

    <dependency>

      <groupId>junit</groupId>

      <artifactId>junit</artifactId>

      <version>4.7</version>

      <scope>test</scope>

    </dependency>

  </dependencies>

    <distributionManagement>

     <repository>

        <id>archivaServer</id>

        <url>http://localhost:8080/repository/internal</url>

     </repository>

     <snapshotRepository>

        <id>archivaServer</id>

        <url>http://localhost:8080/repository/snapshots</url>

     </snapshotRepository>

  </distributionManagement>

</project>

 

2、编写公共接口和代码

在这里有两类代码,一类是实体类(MvnUser),另一类是实体DAO接口(IMvnUserDAO)。因为MvnUser里面有个状态(status)属性,配合它,定义了一个枚举状态类(Status)。具体代码如下:

Status.java

package cn.com.mvnbook.ssh.demo.entity;

 

public enum Status {

ACTIVE("Active"),

    INACTIVE("Inactive"),

    DELETED("Deleted"),

    LOCKED("Locked");

    private String status;

private Status(final String status){

this.status = status;

}

public String getStatus() {

return status;

}

public void setStatus(String status) {

this.status = status;

}

public String toString(){

return this.status;

}

}

 

MvnUser.java

package cn.com.mvnbook.ssh.demo.entity;

 

public class MvnUser {

private int urId;

    private String urUserName;

    private String urPassword;

    private int urAge;

    private String urStatus = Status.ACTIVE.getStatus();//Active

public int getUrId() {

return urId;

}

public void setUrId(int urId) {

this.urId = urId;

}

public String getUrUserName() {

return urUserName;

}

public void setUrUserName(String urUserName) {

this.urUserName = urUserName;

}

public String getUrPassword() {

return urPassword;

}

public void setUrPassword(String urPassword) {

this.urPassword = urPassword;

}

public int getUrAge() {

return urAge;

}

public void setUrAge(int urAge) {

this.urAge = urAge;

}

public String getUrStatus() {

return urStatus;

}

public void setUrStatus(String urStatus) {

this.urStatus = urStatus;

}

}

 

IMvnUserDAO.java

package cn.com.mvnbook.ssh.demo.dao;

 

import java.util.List;

 

import cn.com.mvnbook.ssh.demo.entity.MvnUser;

/**

 * MvnUser实体对象的持久层代码,封装了对MvnUser实体对象的CRUD方法

 *

 * @author Noble

 * @version 1.0

 * */

public interface IMvnUserDAO {

/**

 * 在数据库中,添加一个新的MvnUser对象

 *

 * @param user 需要添加的用户实体对象,该对象需要有用户名、密码、年龄和状态属性

 *

 * @return void

 * @throws RuntimeException 添加失败或出现其它意外

 * */

public void addUser(MvnUser user) ;

 

/**

 * 更新MvnUser对象。该对象中需要设置年龄、状态和id属性,属性和状态是要更新的新值,id为条件

 *

 * @param user 需要更新的MvnUser对象

 *

 * @return void

 * @throws RuntimeException 更新失败或出现其它意外

 * */

public void update(MvnUser user) ;

    /**

     * 删除MvnUser对象,该对象中需要有要删除对象的id属性,id属性为删除条件

     *

     * @param user 要删除的MvnUser对象

     *

     * @return void

     * @throws RuntimeException 删除失败或出现其它意外

     * */

public void deleteUser(MvnUser user) ;

 

/**

 * 根据id查询对应的MvnUser对象

 *

 * @param id 要查询的MvnUser对象的id

 * @return MvnUser id对应的MvnUser对象,如果没有对象,返回null

 * @throws RuntimeException 出现意外情况

 * */

public MvnUser findUserById(int id) ;

/**

 * 根据用户名查询对应的MvnUser对象

 *

 * @param userName 要查询的MvnUser对象的用户名

 * @return MvnUser 用户对应的MvnUser对象,如果没有对象,返回null

 * @throws RuntimeException 出现意外情况

 * */

public MvnUser findUserByUserName(String userName) ;

 

/**

 * 查找数据库中所有的用户对象,以List集合的形式返回

 *

 * @return List<MvnUser> 所有用户对象的集合

 * @throws RuntimeException 出现意外情况

 * */

public List<MvnUser> findUsers() ;

}

 

3、安装发布

在工程上鼠标右键 Run As->Maven install,Eclipse会自动将工程代码编译打包,如果没有错误的话,最后以构件的形式,安装在本地仓库中。参考效果图如下:

 

 

为了方便公司其它开发人员可以使用,我们接下来将该项目以构件的形式,发布到前面搭建好的私服上去,为了发布成功,请按前面的私服介绍,搭建并且启动私服,同时在当前工程的pom.xml中,添加distributionManagement配置,详细参考前面的pom.xml。具体操作和效果图如下。

1)操作

   工程右键选择Run As -> Maven build...

   Goals中输入deploy,点击Run按钮

2)Archiva上关于发布的构件效果图

 

 

第二步:基于Hibernate完成DAO接口的实现

团队商量确定好接口,接下来就是对接口的实现和基于接口上的开发工作了。因为有共同的接口,所以这两个工作可以同步进行。这现象同我们现实生活中的电脑的配件一样(硬盘、内存条、CPU、显卡等等),事先定义好标准(插口),不同厂商就可以按同样的标准各自生产,出来后就可以顺利的组装在一起,不用管有哪个厂家,在哪里,用那个流水线生产的。

接下来我们开始研究DAO接口的实现。大概分如下四步进行:

 

第一步:创建工程,添加相关依赖

这个步骤比较简单,创建工程的方式同以前一样。具体创建的过程,在这里就不重复了。目录结构如下:

 

 

虽然不重复说明项目的创建过程,但是要注意如下两点:

1、因为前面我们有创建了公共的Hibernate POM工程,里面有描述好了Hibernate相关的依赖(目的是让所有开发人员重用,不要自己再重复编写),并且有以构件的形式安装发布好了。这里我们要体现的是怎么样继承前面定义好的pom

2、同样的,因为我们新工程里面要实现MvnBookSSHDemo.DAO中定义的接口,并且使用到它里面定义的公共类,而且根据前面的介绍,MvnBookSSHDemo.DAO,我们也以构件的形式安装发布到私服了。在这里,我们要体现一下怎么样在自己的工程里面,设置我们团队内部自己发布的构件。

这两点注意事项,主要体现在pom.xml中,pom.xml内容如下:

<?xml version="1.0"?>

<project

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"

xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<modelVersion>4.0.0</modelVersion>

<parent>

<groupId>cn.com.mvnbook.pom</groupId>

<artifactId>Hibernate4MySQLPOM</artifactId>

<version>0.0.1-SNAPSHOT</version>

</parent>

<groupId>cn.com.mvnbook.ssh.demo.dao.hibernate</groupId>

<artifactId>MvnBookSSHDemo.DAO.Hibernate</artifactId>

<name>MvnBookSSHDemo.DAO.Hibernate</name>

<url>http://maven.apache.org</url>

<properties>

<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

</properties>

<dependencies>

<dependency>

<groupId>cn.com.mvnbook.ssh.demo</groupId>

<artifactId>MvnBookSSHDemo.DAO</artifactId>

<version>0.0.1-SNAPSHOT</version>

</dependency>

<dependency>

<groupId>cn.com.mvnbook.pom</groupId>

<artifactId>SpringPOM</artifactId>

<version>0.0.1-SNAPSHOT</version>

<type>pom</type>

</dependency>

</dependencies>

  <distributionManagement>

     <repository>

        <id>archivaServer</id>

        <url>http://localhost:8080/repository/internal</url>

     </repository>

     <snapshotRepository>

        <id>archivaServer</id>

        <url>http://localhost:8080/repository/snapshots</url>

     </snapshotRepository>

  </distributionManagement>

</project>

 

说明:

1 <parent>

<groupId>cn.com.mvnbook.pom</groupId>

<artifactId>Hibernate4MySQLPOM</artifactId>

<version>0.0.1-SNAPSHOT</version>

</parent>

这是pom.xml中的第一个粗体内容,它描述的是当前的pom.xml,继承了Hibernate4MySQLPOM构件中定义的pom内容,其中groupId,artifactIdversion共同形成构件的坐标。当我们的pom需要继承别人定义好的pom的话,只需要使用如上parent配置指定就行,不过这里的继承,同java中继承一样,只能单继承,而且只能继承packaging类型为pom的构件(这点可以看Hibernate4MySQLPOM中的pom.xml文件,里面的packagingpom)。

 

2 <dependency>

<groupId>cn.com.mvnbook.ssh.demo</groupId>

<artifactId>MvnBookSSHDemo.DAO</artifactId>

<version>0.0.1-SNAPSHOT</version>

</dependency>

<dependency>

<groupId>cn.com.mvnbook.pom</groupId>

<artifactId>SpringPOM</artifactId>

<version>0.0.1-SNAPSHOT</version>

<type>pom</type>

</dependency>

这是在我们pom.xml中第二个粗体内容,描述的是两个依赖。第一个依赖是我们前面定义的DAO接口和公共类的构件依赖,通过查看代码,其实同使用我们从网上找的其它依赖一样。第二个虽然也是使用的我们前面定义的spring的公共pom依赖,但是有点点不同,里面包含了一个<type>pom</type>,这个元素指定的是依赖的packaging类型。依赖的packaging类型默认是jar(我们前面所有pom.xml中没有指定type的情况,都是这样),如果我们pom引用的依赖是pom类型的,就需要在dependency中添加type元素,指定是类型pom,形同这里用到的第二个依赖,否则构建的时候会报错。

 

第二步:编写实现代码

基于HibernateDAO实现代码,主要有如下几个类:

MvnUser4Hibernate.java 该类继承MvnUser类,里面用注解描述了实体信息

AbstractDAO.java        该类定义了实体的公共持久化方法,所有的DAO实现类就继承它

MvnUserDAOImpl.java    该类实现MvnUser实体类的所有持久化方法

HibernateConfiguration.java   Hibernate的配置类,描述Hibernate的配置信息,代替
                        hibernate.cfg.xml

db.properties          描述数据库连接信息和hibernate的一些配置信息

 

各个代码如下:

MvnUser4Hibernate.java

package cn.com.mvnbook.ssh.demo.entity.hibernate;

 

import javax.persistence.Column;

import javax.persistence.Entity;

import javax.persistence.GeneratedValue;

import javax.persistence.GenerationType;

import javax.persistence.Id;

import javax.persistence.Table;

 

import cn.com.mvnbook.ssh.demo.entity.MvnUser;

@Entity

@Table(catalog="mvn_db",name="mvn_user")

public class MvnUser4Hibernate extends MvnUser {

@Id

    @GeneratedValue(strategy=GenerationType.IDENTITY)

    @Column(name="ur_id")

public int getUrId() {

// TODO Auto-generated method stub

return super.getUrId();

}

 

@Column(name="ur_user_name",length=20,unique=true,nullable=false)

public String getUrUserName() {

// TODO Auto-generated method stub

return super.getUrUserName();

}

 

@Column(name="ur_password",length=10,nullable=false)

public String getUrPassword() {

// TODO Auto-generated method stub

return super.getUrPassword();

}

 

@Column(name="ur_age")

public int getUrAge() {

// TODO Auto-generated method stub

return super.getUrAge();

}

 

@Column(name="ur_status",length=20,nullable=true)

public String getUrStatus() {

// TODO Auto-generated method stub

return super.getUrStatus();

}

}

 

AbstractDAO.java

package cn.com.mvnbook.ssh.demo.dao.hibernate;

 

import java.io.Serializable;

import java.lang.reflect.ParameterizedType;

import java.util.List;

 

import org.hibernate.Criteria;

import org.hibernate.Session;

import org.hibernate.SessionFactory;

import org.springframework.beans.factory.annotation.Autowired;

 

import cn.com.mvnbook.ssh.demo.entity.MvnUser;

import cn.com.mvnbook.ssh.demo.entity.hibernate.MvnUser4Hibernate;

 

public abstract class AbstractDAO<PK extends Serializable, T> {

    

    private final Class<T> persistentClass;

     

    @SuppressWarnings("unchecked")

    public AbstractDAO(){

        this.persistentClass =(Class<T>) (

         (ParameterizedType) this.getClass().getGenericSuperclass()

         ).getActualTypeArguments()[1];

    }

     

    @Autowired

    private SessionFactory sessionFactory;

 

    protected Session getSession(){

        return sessionFactory.getCurrentSession();

    }

 

    @SuppressWarnings("unchecked")

    public T getByKey(PK key) {

        return (T) getSession().get(persistentClass, key);

    }

 

    public void persist(T entity) {

        getSession().persist(entity);

    }

 

    public void delete(T entity) {

        getSession().delete(entity);

    }

    

    public void update(T entity){

     getSession().merge(entity);

    }

    

    public List<T> findAll(){

     Criteria cri = this.createEntityCriteria();

     cri.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);//消除重复对象

     return cri.list();

    }

     

    protected Criteria createEntityCriteria(){

        return getSession().createCriteria(persistentClass);

    }

}

 

MvnUserDAOImpl.java

package cn.com.mvnbook.ssh.demo.dao.hibernate.impl;

 

import java.util.List;

 

import org.hibernate.Criteria;

import org.hibernate.criterion.Restrictions;

import org.springframework.stereotype.Repository;

import org.springframework.transaction.annotation.Transactional;

 

import cn.com.mvnbook.ssh.demo.dao.IMvnUserDAO;

import cn.com.mvnbook.ssh.demo.dao.hibernate.AbstractDAO;

import cn.com.mvnbook.ssh.demo.entity.MvnUser;

import cn.com.mvnbook.ssh.demo.entity.hibernate.MvnUser4Hibernate;

@Repository("userDAO")

@Transactional// 标记使用事务,为了方便DAO设置,是临时的,正式事务应该设置在服务层

public class MvnUserDAOImpl extends AbstractDAO<Integer, MvnUser4Hibernate> implements IMvnUserDAO {

 

public void addUser(MvnUser user) {

MvnUser4Hibernate u = this.convertToMvnUser4Hibernate(user);

super.persist(u);

}

 

public void update(MvnUser user) {

MvnUser4Hibernate u = this.convertToMvnUser4Hibernate(user);

super.update(u);

}

 

public void deleteUser(MvnUser user) {

MvnUser4Hibernate u = this.convertToMvnUser4Hibernate(user);

super.delete(u);

}

 

public MvnUser findUserById(int id) {

return super.getByKey(id);

}

 

public MvnUser findUserByUserName(String userName) {

Criteria criteria = super.createEntityCriteria();

criteria.add(Restrictions.eq("urUserName", userName));

return (MvnUser)criteria.uniqueResult();

}

 

public List<MvnUser> findUsers() {

Criteria criteria = super.createEntityCriteria();

return criteria.list();

}

private MvnUser4Hibernate convertToMvnUser4Hibernate(MvnUser user){

MvnUser4Hibernate u = (MvnUser4Hibernate) this.findUserById(user.getUrId());

// 这里不要轻易new一个同已经存在的一样的对象,否则会抛

//org.hibernate.NonUniqueObjectException:

//a different object with the same identifier value was

//already associated withthe session异常

if (u == null) {

u = new MvnUser4Hibernate();

u.setUrId(user.getUrId());

}

u.setUrAge(user.getUrAge());

u.setUrPassword(user.getUrPassword());

u.setUrStatus(user.getUrStatus());

u.setUrUserName(user.getUrUserName());

return u;

    }

}

 

HibernateConfiguration.java

package cn.com.mvnbook.ssh.demo.dao.hibernate.config;

 

import java.util.Properties;

 

import javax.sql.DataSource;

 

import org.hibernate.SessionFactory;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.ComponentScan;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.PropertySource;

import org.springframework.core.env.Environment;

import org.springframework.jdbc.datasource.DriverManagerDataSource;

import org.springframework.orm.hibernate4.HibernateTransactionManager;

import org.springframework.orm.hibernate4.LocalSessionFactoryBean;

import org.springframework.transaction.annotation.EnableTransactionManagement;

 

//配置类

@Configuration

@EnableTransactionManagement// 要支持事务管理

@ComponentScan({ "cn.com.mvnbook.ssh.demo.dao.hibernate.config" })

@PropertySource(value = { "classpath:db.properties" })// 自动读入的属性文件

public class HibernateConfiguration {

// 自动注入 Spring的环境对象(上下文)

    @Autowired

    private Environment environment;

 

    // 创建一个SessionFactory

    @Bean(name="sessionFactory")

    public LocalSessionFactoryBean sessionFactory() {

        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();

        // 数据源

        sessionFactory.setDataSource(dataSource());

        // 指定数据实体类的包

        sessionFactory.setPackagesToScan(new String[]
                                   { "cn.com.mvnbook.ssh.demo.entity.hibernate" });

        // hibernate的属性信息

        sessionFactory.setHibernateProperties(hibernateProperties());

        return sessionFactory;

     }

    // 初始化数据源对象

    @Bean(name="dataSource")// 将当前方法返回的对象,当成普通Bean对象,放入IOC容器中

    public DataSource dataSource() {

        DriverManagerDataSource dataSource = new DriverManagerDataSource();

        // 设置连接数据库的四要素

        dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));

        dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));

        dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));

        dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));

        return dataSource;

    }

    // Hibernate除连接数据库之外的配置,封装到Properties

    private Properties hibernateProperties() {

        Properties properties = new Properties();

        properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));

        properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));

        properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));

        properties.put("hibernate.hbm2ddl.auto", environment.getRequiredProperty("hibernate.hbm2ddl.auto"));

        return properties;        

    }

     

    @Bean

    @Autowired

    public HibernateTransactionManager transactionManager(SessionFactory s) {

       HibernateTransactionManager txManager = new HibernateTransactionManager();

       txManager.setSessionFactory(s);

       return txManager;

    }

}

 

db.properties(存放在工程的 src/main/resources目录下)

jdbc.username=root

jdbc.password=root

jdbc.url=jdbc:mysql://localhost:3306/mvn_db

jdbc.driverClassName=com.mysql.jdbc.Driver

hibernate.dialect = org.hibernate.dialect.MySQLDialect

hibernate.show_sql = true

hibernate.format_sql = true

hibernate.hbm2ddl.auto = update

 

第三步:编写测试代码

测试代码是基于jUnit的,相对比较简单,只有一个类,针对MvnUserDAOImpl.java进行测试,另外有一个spring的配置文件,applicationContext.xml

需要注意的是,测试的所有代码和资源文件,都是分别放在src/test目录下对应的子目录中的,参考前面提供的工程目录结构图。在Maven中具体文件的存放位置,是有固定约束的(规定死了的)。测试代码和配置文件的内容如下:

 

TestMvnUserDAOImpl.java

package cn.com.mvnbook.ssh.demo.dao.hibernate.impl;

 

import org.junit.After;

import org.junit.Before;

import org.junit.Test;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

 

import cn.com.mvnbook.ssh.demo.dao.IMvnUserDAO;

import cn.com.mvnbook.ssh.demo.entity.MvnUser;

import cn.com.mvnbook.ssh.demo.entity.Status;

import junit.framework.Assert;

 

public class TestMvnUserDAOImpl {

private IMvnUserDAO userDAO;

private ApplicationContext ctx = null;

 

@Before

public void init() {

ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

userDAO = (IMvnUserDAO)this.ctx.getBean("userDAO");

//userDAO = (IMvnUserDAO) this.ctx.getBean(MvnUserDAOImpl.class);

}

@Test

public void testAddUser(){

MvnUser user= new MvnUser();

user.setUrAge(11);

user.setUrPassword("11");

user.setUrStatus(Status.ACTIVE.getStatus());

user.setUrUserName("userName11");

this.userDAO.addUser(user);

MvnUser u = this.userDAO.findUserByUserName("userName11");

Assert.assertTrue(u != null && u.getUrAge()==11);

this.userDAO.deleteUser(u);

}

@Test

public void testFindUserById(){

MvnUser user = this.userDAO.findUserById(1);

Assert.assertEquals("zhangsan", user.getUrUserName());

}

@Test

public void testUpdate(){

MvnUser user = this.userDAO.findUserById(1);

user.setUrAge(99);

this.userDAO.update(user);

user = this.userDAO.findUserById(1);

Assert.assertEquals(99, user.getUrAge());

}

@After

public void destory(){

this.userDAO = null;

this.ctx = null;

}

}

 

applicationContext.xml

<?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:mvc="http://www.springframework.org/schema/mvc"

xmlns:context="http://www.springframework.org/schema/context"

xsi:schemaLocation="http://www.springframework.org/schema/beans

    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd

http://www.springframework.org/schema/mvc

http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd

http://www.springframework.org/schema/context

" >http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <!--spring自动扫描组件类的包,包括子包和子子包等-->

<context:component-scan

base-package="cn.com.mvnbook.ssh.demo"></context:component-scan>

</beans>

 

第四步:测试安装发布

测试:

鼠标右击工程 Run As->Maven test

Maven自动会对jUnit写的测试代码进行测试,并且显示测试结果,如图:

 

 

安装:

鼠标右击工程 Run As ->Maven install

Maven会自动将工程代码编译,运行完测试代码,所有通过后,打包成构件,发布到本地仓库。结果如图:

 

 

发布:

鼠标右击工程 Run As -> Maven build...

在弹出框的Goals输入框中输入deploy,点击Run按钮,Maven会自动将工程构件,发布到指定的私服仓库中,效果图如下显示,但是要注意,一定要在pom.xml中配置distributionManagement,指定发布的位置。

 

 

版权所有,转载请注明。 同类视频请参考 http://cyedu.ke.qq.com
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值