Ibatis开发要点

 

        Ibatis提供了一种半自动化的O/R Mapping实现框架。它以牺牲工作量和移植性的代价换取了SQL语句设计的自由性和可优化性。

典型Ibatis配置文件

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

<!DOCTYPE sqlMapConfig PUBLIC"-//iBATIS.com//DTD SQL Map Config 2.0//EN""http://www.ibatis.com/dtd/sql-map-config-2.dtd">

 

<sqlMapConfig>

 <settingscacheModelsEnabled="true"           //是否开启缓存

 enhancementEnabled="false"          //是否开启字节码增强,提高get/set调用性能

 lazyLoadingEnabled="true"                            //是否开启延迟加载

 errorTracingEnabled="true"                            //是否启用错误日志

 maxRequests="32"                                         //最大并发请求

 maxSessions="10"                         //最大允许并发SqlMapClient数

 maxTransactions="5"                                      //最大并发事务数

 useStatementNamespaces="false" />            //是否使用statment命名空间

 

 <transactionManagertype="JDBC">               //传统JDBC事务支持

 <dataSource type="SIMPLE">        //简单数据库连接池,对应SimpleDataSourceFactory

  <property name="JDBC.Driver"value="com.mysql.jdbc.Driver" />

  <property name="JDBC.ConnectionURL"value="jdbc:mysql://localhost:3306/mysql" />

  <property name="JDBC.Username" value="root" />

  <property name="JDBC.Password" value="password"/>

 <propertyname="Pool.MaximumActiveConnections" value="10"/>//数据库连接池最大连接数

 

  <property name="Pool.MaximumIdleConnections"value="5" />    //允许挂起连接数

<propertyname="Pool.MaximumCheckoutTime" value="120000"/>//连接任务允许占用最大时间

  <property name="Pool.TimeToWait" value="500"/>          //允许等待最长时间

 

  <property name="Pool.PingQuery" value="select 1 fromACCOUNT"/> //连接状态检测语句

 

  <property name="Pool.PingEnabled" value="false"/>       //是否开启连接状态检测

 

  <property name="Pool.PingConnectionsOlderThan"value="1" />  //连接状态检测时间设定

 

  <property name="Pool.PingConnectionsNotUsedFor"value="1" />//空闲状态检测时间设定

 </dataSource>

 </transactionManager>

 

 <!-- JNDI

 <transactionManagertype="JDBC">

 <dataSource type="JNDI">    //使用J2EE容器实现DataSource,对应实现类JndiDataSourceFactory

  <property name="DataSource"value="java:comp/env/jdbc/myDataSource" />

 </dataSource>

 </transactionManager>-->

 <!-- JTA

 <transactionManagertype="JTA">       //使用容器提供的JTA服务实现全局事务管理

 <property name="UserTransaction"value="java:/ctx/con/UserTransaction" />

 <dataSource type="JNDI">

  <property name="DataSource"value="java:comp/env/jdbc/myDataSource" />

 </dataSource>

 </transactionManager> -->

 

 <sqlMapresource="com/ibatis/ao/User.xml" />

</sqlMapConfig>

 

User模型类

 

public class User implements Serializable{

 private Integer id;

 private String name;

 private Integer sex;

 

 public User(){}

 

 public User(Integer id,String name,Integersex){

 this.id=id;

 this.name=name;

 this.sex=sex;

 }

 

 public Integer getId() {

 return id;

 }

 

 public void setId(Integer id) {

 this.id = id;

 }

 

 public String getName() {

 return name;

 }

 

 public void setName(String name) {

 this.name = name;

 }

 

 public Integer getSex() {

 return sex;

 }

 

 public void setSex(Integer sex) {

 this.sex = sex;

 }

}

 

模型类映射文件

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

<!DOCTYPE sqlMap PUBLIC"-//iBATIS.com//DTD SQL Map 2.0//EN""http://toolkit.alibaba-inc.com/dtd/ibatis/sql-map-2.dtd">

<sqlMap namespace="User">

 <typeAlias alias="user"type="com.ibatis.ao.User" />      //设置映射路径

 

 <!-- 模块配置 -->

 <cacheModel id="userCache"type="LRU">               //设置缓存类型

 <flushInterval hours="24" />                                     //设置缓存有效期

 <flushOnExecute statement="updateUser" />          //执行特定statment是清空缓存

 <property name="size" value="1000" />                  //设置缓存大小

 </cacheModel>

 

 <resultMap id="userResult"class="user">               //resultMap结果映射

 <result property="id" column="id" />

 <result property="name" column="name" />

 <result property="sex" column="sex" />

 </resultMap>

 

 <!-- Statement配置 -->

 <select id="getUser"resultMap="userResult" parameterClass="string">   //parameterClass参数类

   <![CDATA[

       select

            name,

            sex

       from

            t_user

       where

            name=#name#

   ]]>

 </select>

 

 <select id="getUserById"resultClass="user" parameterClass="Integer">  //resultClass结果类

 <![CDATA[

       select

            name,

            sex

       from

            t_user

       where

            id=#id#

    ]]>

 </select>

 

 <insert id="insertUser"parameterClass="user">

       <![CDATA[

       INSERT INTO t_user (

        name,

        sex

       ) values (

  #name#,

  #sex#

       )

   ]]>

 </insert>

 <delete id="deleteUser"parameterClass="Integer">

    <![CDATA[

    delete from t_user

    WHERE id=#id#

    ]]>

 </delete>

 <update id="updateUser"parameterClass="user">

    <![CDATA[

    update t_user

     set

      name=#name#,

      sex=#sex#

    WHERE id=#id#

    ]]>

 </update>

 

</sqlMap>

 

测试类

 public void testIbatisSqlMap() throwsSQLException{

 String resource="sqlmap-config.xml";

  try{

  Reader reader=Resources.getResourceAsReader(resource);

  SqlMapClient sqlMap =SqlMapClientBuilder.buildSqlMapClient(reader);    //SqlMapClient核心类

  try{

   sqlMap.startTransaction();

 

//   User user=new User();

//   user.setId(new Integer(1));

//   user.setName("Samantha");

//   user.setSex(new Integer(11));

//   sqlMap.insert("insertUser",user);

 

   Integer key=new Integer(2);

    Useruser1=(User)sqlMap.queryForObject("getUserById",key);

   

   sqlMap.commitTransaction();

   System.out.println(user1.getName());

   }catch (SQLException e) {

   e.printStackTrace();

  }finally{

   sqlMap.endTransaction();

   }

  }catch (IOException e) {

  e.printStackTrace();

  }

}

 

Ibatis高级特性:

 

1.数据关联:(一对多关联)

 

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

<!DOCTYPE sqlMap PUBLIC"-//iBATIS.com//DTD SQL Map 2.0//EN""http://toolkit.alibaba-inc.com/dtd/ibatis/sql-map-2.dtd">

<sqlMap namespace="User">

 <typeAlias alias="user"type="com.ibatis.ao.User" />

 <typeAlias alias="address"type="com.ibatis.ao.Address" />

 

 <resultMap id="get-user-result"class="user">

 <result property="id" column="id" />

 <result property="name" column="name" />

 <result property="sex" column="sex" />

 <result property="addresses" column="id"select="User.getAddressByUserId" />

 </resultMap>

 

 <select id="User.getUsers"parameterClass="java.lang.String"

 resultMap="get-user-result">

 <![CDATA[

 select

  id,

  name,

  sex

 from t_user

 where id = #id#

 ]]>

 </select>

 

 <selectid="User.getAddressByUserId" parameterClass="int"

 resultClass="address">

 <![CDATA[

 select

  address,

  zipcode

 from t_address

 where user_id = #userid#

 ]]>

 </select>

</sqlMap>

 

对应代码:

 

public void testIbatisSqlMap() throwsSQLException, IOException {

 String resource = "sqlmap-config.xml";

 Reader reader = Resources.getResourceAsReader(resource);

 SqlMapClient sqlMap = SqlMapClientBuilder.buildSqlMapClient(reader);

  //sqlMap系统初始化完毕

 List userList = sqlMap.queryForList("User.getUsers","2");

  for(int i = 0; i < userList.size(); i++) {

  User user = (User) userList.get(i);

  System.out.println("==>" + user.getName());

  for (int k = 0; k < user.getAddresses().size(); k++) {

   Address addr = (Address)user.getAddresses().get(k);

   System.out.println(new String(addr.getAddress()));

   }

  }

 }

 

这种对应在大数据量的情况下会产生性能问题

 

如果是一对一关系:

 

<resultMap >

 <result property="id" column="id"/>

 <result property="name" column="name"/>

 <result property="sex" column="sex"/>

 <result property="address"column="t_address.address"/>

 <result property="zipCode" column="t_address.zipcode"/>

</resultMap>

<selectparameterClass="string"

 resultMap="get-user-result">

 <![CDATA[

   select

      *

   from t_user,t_address

   where t_user.id=t_address.user_id

 ]]>

</select>

 

2.延迟加载:当真正访问对象时才执行SQL语句,提高了系统性能。

 

3.动态映射

 

<dynamic prepend="WHERE">

 <isNotEmpty prepend="AND" property="name">

   (name like #name#)

 </isNotEmpty>

 <isNotEmpty prepend="AND" property="address">

   (address like #address#)

 </isNotEmpty>

</dynamic>

 

一元判定:is(Not)PropertyAvailable,is(Not)Null,is(Not)Empty

 

二元判定:is(Not)Equal,isGreatThan,isGreatEqual,isLessThan,isLessEqual

 

4.事务管理

 

传统JDBC事务:

 

try{

 

 sqlMap.startTransaction();

 

  ...

 

 sqlMap.commitTransaction();

 

}finally{

 

 sqlMap.endTransaction();

 

}

 

JTA事务管理:提供了跨数据库事务管理能力

 

外部事务管理:<transactionManagertype="EXTERNAL">

 

UserTransaction tx=newInitialContext().lookup("...");

 

...

 

tx.commit();

 

5.Cache

 

readonly、serialize(全局数据缓存)特性

 

Type:MEMORY、LRU、FIFO、OSCACHE

 

SoftReference、WeakReference、PhantomReference

 

<cacheModel type="MEMORY">

 <flushInterval hours="24"/>

 <flushOnExecute statement="updateUser"/>

 <property value="WEAK" />

</cacheModel>

 

Ibatis in Spring:

 

接口:

 

public interface IUserDAO {

 public void insertUser(User user);

}

 

实现类:

 

public class UserDao extendsSqlMapClientDaoSupport implements IUserDAO{

 

 public void insertUser(User user){

 getSqlMapClientTemplate().update("insertUser",user);

 }

}

 

模型类配置文件:

 

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

<!DOCTYPE sqlMap PUBLIC"-//iBATIS.com//DTD SQL Map 2.0//EN" "http://toolkit.alibaba-inc.com/dtd/ibatis/sql-map-2.dtd">

<sqlMap namespace="User">

 <typeAlias alias="user"type="com.ibatis.ao.User" />

 <insert id="insertUser"parameterClass="user">

 INSERT INTO users(username,password) VALUES (#username#,#password#)

 </insert>

</sqlMap>

 

拦截器:

 

public class SqlInterceptor extendsSqlMapClientDaoSupport implements MethodInterceptor{

 

 public Object invoke(MethodInvocationinvocation) throws Throwable {

 

   //可以doSomething

 Object returnValue=null;

 

  //可以doSomething

 returnValue=invocation.proceed();

 return returnValue;

 }

}

ibatis配置文件:

 

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

<!DOCTYPE sqlMapConfig PUBLIC"-//iBATIS.com//DTD SQL Map Config 2.0//EN""http://www.ibatis.com/dtd/sql-map-config-2.dtd">

<sqlMapConfig>

 <sqlMap resource="com/ibatis/ao/User.xml"/>

</sqlMapConfig>

 

Spring配置文件:

 

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

<!DOCTYPE beans PUBLIC"-//SPRING//DTD BEAN//EN""http://www.springframework.org/dtd/spring-beans.dtd">

<beans>

 <description>SpringIbatis</description>

 <bean id="dataSource"

 

       class ="org.apache.commons.dbcp.BasicDataSource"destroy-method="close"> //DBCP连接数据库

 <property name="driverClassName">

  <value>com.p6spy.engine.spy.P6SpyDriver</value>            //利用P6Spy来显示执行的SQL语句

 

 </property>

<property name="url">

  <value>jdbc:mysql://localhost:3306/mysql</value>

 </property>

 <property name="username">

  <value>root</value>

 </property>

 <property name="password">

  <value>password</value>

 </property>

 </bean>

 

 <bean id="sqlMapClient"class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">

 <property name="configLocation">

  <value>sqlmap-config.xml</value>

 </property> 

 </bean>

 

 <bean id="sqlInterceptor"class="com.taobao.ibatis.dao.SqlInterceptor">      //实现一个拦截器

 <property name="sqlMapClient">

  <ref local="sqlMapClient"/>

 </property>

 <property name="dataSource">

  <ref local="dataSource"/>

 </property>

 </bean>

 

 <bean id="myPointcutAdvisor"class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">      //设置切点

 <property name="advice">

  <ref local="sqlInterceptor"/>

 </property>

 <property name="patterns">

  <list>

   <value>.*insert.*</value>

  </list>

 </property>

 </bean>

 

 <bean id="userDAO"class="com.taobao.ibatis.dao.UserDao">

 <property name="dataSource">

  <ref local="dataSource"/>

 </property>

 <property name="sqlMapClient">

  <ref local="sqlMapClient"/>

 </property>

 </bean>

 

 <bean id="userDAOProxy"class="org.springframework.aop.framework.ProxyFactoryBean"> //设置代理类

 <property name="proxyInterfaces">

  <value>com.ibatis.ao.IUserDAO</value>

 </property>

 <property name="target">

  <ref local="userDAO"/>

 </property>

 <property name="interceptorNames">

  <value>myPointcutAdvisor</value>

 </property>

 </bean>

</beans>

 

附:p6spy.properties配置文件

 

module.log=com.p6spy.engine.logging.P6LogFactory

realdriver=com.mysql.jdbc.Driver

deregisterdrivers=true

executionthreshold=

outagedetection=false

outagedetectioninterval=

filter=false

include    =

exclude    =

sqlexpression =

autoflush  = true

dateformat=

includecategories=

excludecategories=info,debug,result,batch

stringmatcher=

stacktrace=false

stacktraceclass=

reloadproperties=false

reloadpropertiesinterval=60

useprefix=false

appender=com.p6spy.engine.logging.appender.StdoutLogger

append=true

log4j.appender.STDOUT=org.apache.log4j.ConsoleAppender

log4j.appender.STDOUT.layout=org.apache.log4j.SimpleLayout

log4j.appender.STDOUT.layout.ConversionPattern=p6spy

log4j.logger.p6spy=DEBUG,STDOUT

 

测试类:

 

public void testIbatisSqlMap(){

 ApplicationContext ctx=newFileSystemXmlApplicationContext("ibatiscontext.xml");

 IUserDAO userdao=(IUserDAO)ctx.getBean("userDAOProxy");

 User user=new User();

 user.setUsername("Samantha");

 user.setPassword("miss");

 userdao.insertUser(user);

 }

 

对dao配置文件

举例说明:
1.来一个Person类

package com.Jdnis.ibatis.model;

import java.io.Serializable;

import java.sql.Date;

public class Person implements Serializable {

        privatestatic final long serialVersionUID = 1L;

        private intid ;

        privateString firstName ;

        privateString lastName ;

        private DatebirthDate = new Date(1900,1,1);;

        privatedouble weight ;

        privatedouble height ;

        public intgetId() {

               returnid;

        }

        public voidsetId(int id) {

               this.id= id;

        }

        publicString getFirstName() {

               returnfirstName;

        }

        public voidsetFirstName(String firstName) {

               this.firstName= firstName;

        }

        publicString getLastName() {

               returnlastName;

        }

        public voidsetLastName(String lastName) {

               this.lastName= lastName;

        }

        public DategetBirthDate() {

               returnbirthDate;

        }

        public voidsetBirthDate(Date birthDate) {

               this.birthDate= birthDate;

        }

        publicdouble getWeight() {

               returnweight;

        }

        public voidsetWeight(double weight) {

               this.weight= weight;

        }

        publicdouble getHeight() {

               returnheight;

        }

        public voidsetHeight(double height) {

               this.height= height;

        }

}


2.oop编程中,面向接口编程是一种很好的编程风格。在这一步骤中,定义Person实例的一个操作接口:

package com.Jdnis.ibatis.interfaces;

import java.util.List;

import com.ibatis.dao.client.Dao;

import com.Jdnis.ibatis.model.Person;

public interface PersonInterface extends Dao{

    public voidinsertPerson(Person p);

    public voidupdatePerson(Person p);

    public ListselectAllPerson( );

}


3.对接口的实现类

package com.Jdnis.ibatis.interfaces;

import java.sql.SQLException;

import java.util.List;

import com.ibatis.dao.client.DaoManager;

import com.ibatis.dao.client.template.SqlMapDaoTemplate;

import com.Jdnis.ibatis.model.Person;

public class PersonImpl extends SqlMapDaoTemplateimplements PersonInterface {

        publicPersonImpl(DaoManager daoManager) {

               super(daoManager);

               //TODO Auto-generated constructor stub

        }

        public voidinsertPerson(Person p) {

               //TODO Auto-generated method stub

               try {

                       this.getSqlMapExecutor().insert("insertPerson",p);

                       System.out.println("数据插入成功!");

               }catch (SQLException e) {

                       //TODO Auto-generated catch block

                       System.out.println("插入出错,主键冲突!");

               }

        }

        public voidupdatePerson(Person p) {

               //TODO Auto-generated method stub

               try {

                       this.getSqlMapExecutor().update("updatePerson",p);

               }catch (SQLException e) {

                       //TODO Auto-generated catch block

                       e.printStackTrace();

               }

        }

        public ListselectAllPerson() {

               //TODO Auto-generated method stub

               returnqueryForList("selectAllPerson",null);

        }

}


4.配置person.xml文件:实现对象与数据库的映射

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

<!DOCTYPE sqlMap PUBLIC "-//iBATIS.com//DTD SQLMap 2.0//EN" "http://www.ibatis.com/dtd/sql-map-2.dtd">

<sqlMap namespace="Person">

   <!-- 缓存 -->

   <typeAliasalias="person" type="com.Jdnis.ibatis.model.Person" />

   <parameterMapid="insert_person" class="person">

      <parameterproperty="id" jdbcType="int" />

      <parameterproperty="firstName" jdbcType="varchar"/>

      <parameterproperty="lastName" jdbcType="varchar"/>

      <parameterproperty="birthDate" jdbcType="Date"/>

      <parameterproperty="weight" jdbcType="double" />

      <parameterproperty="height" jdbcType="double" />

  </parameterMap>

   <resultMapid="allPersons" class="person">

      <result property="id"column="per_id" />

      <resultproperty="firstName" column="per_first_name" />

      <resultproperty="lastName" column="per_last_name" />

      <resultproperty="birthDate" column="per_birth_date" />

      <resultproperty="weight" column="weightInKilograms" />

      <resultproperty="height" column="heightInMeters" />

  </resultMap>

  

   <statementid="insertPerson" parameterMap="insert_person">

     INSERT INTOpersons VALUES(?,?,?,?,?,?)

  </statement>

   <statementid="selectAllPerson" resultMap="allPersons">

    <![CDATA[select * from persons]]>

  </statement>

   <statementid="updatePerson" parameterClass="person">

    <![CDATA[update persons setper_first_name=#firstName#,per_last_Name=#lastName#,per_birth_date=#birthDate#,weightInKilograms=#weight#,heightInMeters=#height#where per_id=#id#]]>

  </statement>

</sqlMap>


5.SqlMapConfig.xml文件的配置:配置数据源

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

<!DOCTYPE sqlMapConfig PUBLIC "-//iBATIS.com//DTDSQL Map Config 2.0//EN" "http://www.ibatis.com/dtd/sql-map-config-2.dtd">

<sqlMapConfig>

  <!-- 地方i -->

  <settingscacheModelsEnabled="true"

             enhancementEnabled="true"

             lazyLoadingEnabled="true"

             errorTracingEnabled="true"

             maxRequests="32"

              maxSessions="10"

             maxTransactions="5"

             useStatementNamespaces="false"

    />

   <transactionManager type="JDBC">

       <dataSource type="SIMPLE">

           <property name="JDBC.Driver"value="com.mysql.jdbc.Driver" />

           <property name="JDBC.ConnectionURL"value="jdbc:mysql://localhost/person" />

           <property name="JDBC.Username" value="root" />

           <property name="JDBC.Password" value="root" />

           <property name="Pool.MaximumActiveConnections"value="10" />

           <property name="Pool.MaximumIdleConnections"value="5" />

           <property name="Pool.MaximumCheckoutTime"value="120000" />

           <property name="Pool.TimeToWait" value="500"/>

           <property name="Pool.PingQuery" value="select 1 fromsample" />

           <property name="Pool.PingEnabled" value="false"/>

           <property name="Pool.PingConnectionsOlderThan"value="1" />

           <property name="Pool.PingConnectionsNotUsedFor"value="1" />

       </dataSource>

   </transactionManager>  

   <sqlMapresource="com/Jdnis/ibatis/map/person.xml" />

</sqlMapConfig>


6.ibatis的dao.xml文件的配置

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

<!DOCTYPE daoConfig PUBLIC"-//ibatis.apache.org//DTD DAO Configuration 2.0//EN""http://ibatis.apache.org/dtd/dao-2.dtd">

<daoConfig>

  <context>

   <transactionManager type="SQLMAP">

      <propertyname="SqlMapConfigResource"value="com/neusoft/ibatis/map/SqlMapConfig.xml" />

   </transactionManager>

    <dao interface="com.neusoft.ibatis.interfaces.PersonInterface"implementation="com.Jdnis.ibatis.interfaces.PersonImpl" />

  </context>

</daoConfig>


该文件的<transactionManager>元素将刚才的SqlMapConfig.xml相关联起来,使得三个配置文件都联系到了一起,<dao>元素的配置是将dao接口与其实现类关联起来。
7.dao.xml文件的解析

package com.Jdnis.ibatis.dao;

import java.io.IOException;

import java.io.Reader;

import java.util.Properties;

import com.ibatis.common.resources.Resources;

import com.ibatis.dao.client.DaoManager;

import com.ibatis.dao.client.DaoManagerBuilder;

public class DAOConfig {

        privatestatic final String resource="com/Jdnis/ibatis/map/dao.xml";

        privatestatic final DaoManager daoManager;

        static{

               daoManager= newDaoManager(null);

        }

        publicstatic DaoManager getDaoManager(){

               returndaoManager;

        }

        public staticDaoManager newDaoManager(Properties props){

               try {

                       Readerreader = Resources.getResourceAsReader(resource);

                       returnDaoManagerBuilder.buildDaoManager(reader,props);

               }catch (Exception e) {

                       //TODO Auto-generated catch block

                       newRuntimeException("Could not initialize DaoConfig.  Cause: " + e, e);

               }

               returnnull;  

        }

}


8.测试类

package com.Jdnis.ibatis.dao;

import java.sql.Date;

import com.ibatis.dao.client.DaoManager;

import com.Jdnis.ibatis.interfaces.PersonInterface;

import com.Jdnis.ibatis.model.Person;

public class TestCase {

   DaoManagerdaoManager;

        protectedvoid setUp()throws Exception{

               daoManager= DAOConfig.getDaoManager();

        }

        public voidtestInsertPerson(){

               PersonInterfacepi = (PersonInterface)daoManager.getDao(PersonInterface.class);

               Personp = new Person();

               p.setId(2);

               p.setFirstName("firstName");

               p.setLastName("lastName");

               //p.setBirthDate(newDate(21,12,25));

               p.setHeight(172);

               p.setWeight(125);

               pi.insertPerson(p);

        }

        publicstatic void main(String[] args){

               TestCasetc = new TestCase();

               try {

                       tc.setUp();

               }catch (Exception e) {

                       //TODO Auto-generated catch block

                       e.printStackTrace();

               }

               tc.testInsertPerson();

        }

}


ibatis通过

PersonInterface pi =(PersonInterface)daoManager.getDao(PersonInterface.class);


这种反射的机制,来实例化一个接口的实现类(dao.xml文件中接口与实现类的关联)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值