Spring框架之IOC、AOP详解

Spring 框架之IOC、AOP

spring概念

spring是项目中对象的容器.用来管理项目中的所有对象.

  1. 创建对象,并维护对象间的关系AOP
  2. 整合代理技术,实现AOP思想
  3. spring可以整合几乎任何第三方框架,作为项目中的粘合剂.

IOC&DI概念

  • IOC:反转控制,创建对象的方式被反转,从我们自己创建变为程序创建.
  • DI:依赖注入,是技术,可以将依赖属性注入到对象.构造注入|set方法注入.IOC的实现需要依赖DI技术.

BeanFactory&ApplicationContext

  • BeanFactory接口
    BeanFactory是spring框架初代接口.
    BeanFactory是ApplicationContext父接口.
    BeanFactory是获得对象时才创建对象.

  • ApplicationContext接口
    ApplicationContext是后期发展出的接口.
    ApplicationContext的功能要更加强大.
    ApplicationContext是启动时默认立刻创建容器中所有对象,获得时直接返回

AOP思想

  • 纵向重复,横向抽取.
  • spring封装了代理技术,通过代理技术来体现aop思想.我们使用代理体现aop时,不需要我们自己书写代理代码.spring帮我们完成.

spring框架搭建

导包

  • 4个核心包,core、bean、context、exception
  • 2个日志包,apache.commons.loggin、apache.log4j

准备对象

创建一个类

创建spring配置文件

在src目录下创建applicationContext.xml
导入4个约束(schema)beans、context、tx、aop

<!--将User对象交给spring管理-->
<bean name="user" class="cn.it.domain.User"></bean>

<!--配置dao-->
<bean name="userDao" class="cn.it.dao.impl.UserDao"></bean>

<!--配置service-->
<bean name="userService" class="cn.it.service.impl.UserService">
    <property name="userDao" ref="userDao"></property>
</bean>

配置spring容器随项目启动

原则:一个web项目启动只创建一个spring容器.
操作:
方案一:将spring容器的创建放入静态代码块中.该访问属于自己手动创建容器,容器与web项目没有关联,不推荐.
方案二:spring利用监听器(ServletContext对象创建与销毁监听器)来创建容器.

<!--配置spring容器随项目启动-->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--指定spring配置文件位置-->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>

原理:ContextLoaderListener继承了ServletContextListener,ServletContextListener监听ServletContext的创建与销毁。

代码测试

SE环境测试

//1.创建spring容器
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//2.获取User对象
User user = ac.getBean("user");
获得spring容器及容器中对象

Web环境下

//1.获得Application域对象
ServletContext sc = ServletActionContext.getServletContext();
//2.调用工具方法从域中取出对象
ApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(sc);
//3.获得CustomerService
us = (UserService) ac.getBean("userService");

spring配置详解(xml)

基础配置

bean元素:将对象交给spring容器管理

  • name属性:对象的名字,spring根据该名字获得。
  • id属性:对象的名字,spring根据该名字获得。

    name属性与id属性区别:
        1.id出现时间较早.
        2.id属性必须符合id规范:唯一不能使用特殊字符.
        3.name属性:可以重复(不推荐重复),也可以使用特殊字符.
    
  • class属性:对象的完整类名。
  • scope属性:决定对象的作用域,生命周期。

    singleton(默认值):单例,容器启动时创建单例对象,容器销毁时才销毁单例对象.
    prototype:原型多例,启动时不会创建,每次获得时都会创建新的对象,对象不会放入容器的管理.
    request:web环境下的属性,对象的生命周期为一次请求.
    session:web环境下的属性,对象的生命周期为一次会话.
    
  • init-method|desotory-method属性:指定对象的生命周期。

    init-method:指定对象的初始化方法,会在构造方法调用之后调用.
    destory-method:指定对象的销毁方法,会在容器销毁对象之前调用.
    

    xml配置

    <bean name="user" class="cn.it.domain.User" scope="prototype" init-method="init" destory-method="destory"></bean>
    

sping创建对象方法

静态工厂
//静态工厂
public class UserFactory{
    public static User getUser(){
        return new User();
    }
}

xml配置文件

<bean name="user2" class="cn.it.factory.UserFactory" factory-method="getUser"></bean>
动态工厂
//动态工厂
public class UserFactory{
    public User getUser2(){
        return new User();
    }
}

xml配置文件

<bean name="userFactory" class="cn.it.factory.UserFactory"></bean>
<bean name="user3" factory-bean="userFactory" factory-method="getUser2"></bean>
构造方法(推荐)
<bean name="user" class="cn.it.domain.User"></bean>

spring中的DI(依赖注入)

构造方法注入

constructor-arg:指定构造参数

  • 定位属性:
    name属性:参数名
    index属性:指定参数在参数列表中的索引
    type属性:指定参数类型
  • 注入属性:
    value属性:参数值
    ref属性:注入引用类型

    <bean name="user" class="cn.it.domain.User">
        <constructor-arg name="name" index="0" value="张三"></constructor-arg>
        <constructor-arg name="age" type="java.lang.Integer" value="22"></constructor-arg>
        <constructor-arg name="car" ref="car"></constructor-arg>  
    </bean>
    
set方法注入
  • property标签

    <bean name="user" class="cn.it.domain.User">
        <!--一个property属性代表调用一次set方法-->
        <property name="name" value="James"></property>
        <property name="age" value="22"></property>
        <property name="car" ref="car"></property>
    </bean>
    
  • p名称空间

导入p名称空间

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

p:属性名= | p:属性名-ref=

    <bean name="user" class="cn.it.domain.User" p:name="curry" p:age="27" p:car-ref="car"></bean>
SPEL表达式

SPEL:spring expression language spring 表达式语言,只能引用属性,不能引用对象.
在配置文件中使用#{spel}来引用其他Bean的属性值.

<bean name="user" class="cn.it.domain.User" >
    <property name="age" value="user.age"></property>
    <property name="name" value="curry"></property>
</bean>

复杂类型注入

Array

1.只有一个值可以直接使用value|ref

    <property name="arr" value="product"></property>

2.如果多个值,元素

<property name="arr">
    <array>
        <value>pro</value>
        <ref bean="product" />
    </array>
</property>
List

1.只有一个值可以直接使用value|ref

    <property name="list" value="car"></property>

2.如果多个值,元素
|-
|-

    <property name="list">
        <list>
            <value>c</value>
            <ref bean="car"></bean>
        </list>
    </property>
Map


|-填写键值对

    <property name="map">
        <map>
            <entry key="" value=""></entry>
            <entry key="" value-ref=""><entry>
            <entry key-ref="" value-ref=""></entry>
        <map>
    </property>
Properties


|-填写键值对

    <property name="prop">
        <props>
            <prop key="jdbc.driver" value="com.mysql.jdbc.Driver"></prop>
            <prop key="jdbc.username" value="root"></prop>
        </props>
    </property>

spring配置详解(注解)

准备工作

导包

|4+2
|spring-aop

导入约束

spring-context-4.2.xsd

开启注解配置
<!--指定扫描哪个包中的注解,指定的包以及子孙包都会扫描-->
<context:component-scan base-package="cn.it"></context:component-scan>

注解

注册对象

@component(“user”)
@controller(“user”)
@service(“user”)
@Repository(“user”)

指定对象域作用域

@Scope(“singleton”)

指定对象生命周期

@PostConstruct 初始化
@PreDestory 销毁

值注入

@value
1.成员变量,直接为成员变量赋值
2.set方法,调用set方法赋值

注入引用类型

1.@AutoWired根据类型自动装配
2.@AutoWired和@Qulifier配合,@Qualifier(“car”)
3.@Resource直接指定注入的对象名,@Resource(name=”car”)

spring整合JDBC(JDBCTemplate)

spring框架提供一个可以完成jdbc操作的对象,该对象可以放置到spring容器中.
spring准备的操作数据库的类,与QueryRunner类的设计与使用几乎完全相同.

导包

  • 4+2
  • spring-jdbc、spring-tx
  • 数据库驱动、c3p0连接池

JDBCTemplate工具类

  • jt.update(String sql,Object…params)增删改

    public void save(User u){
        String sql ="insert into t_user value(null,?) ";
        getJdbcTemplate().update(sql,user.getName);
    }
    
  • jt.queryForObject(sql,class,params),查询单个值,并指定返回值类型

    //查询总数
    public Integer getTotalCount(){
        String sql = "select Count(*) from t_user ";
        getJdbcTemplate().queryForObject(sql,Integer.class);
    }
    
  • jt.queryForObject(sql,rowMapper,params),执行查询,并手动封装结果到对象中.返回单个对象

    //根据id查对象
    public User getById(Integer id){
        String sql = "select * from t_user where id=?";
        return getJdbcTemplate().QueryForObject(sql,new RowMapper<User>(){
            public User mapRow(ResultSet rs,int index ) throws SQLException{
                User user = new User();
                user.setId(rs.getInt("id"));
                user.setName(rs.getString("name"));
                return user;    
            }
        },id);
    }
    
  • jt.query(sql,rowMapper,params),执行查询,手动封装结果,返回List

    //查询所有的User
    public List<User> getAll(){
        String sql = "select * from t_user";
        return getJdbcTemplate().QueryForObject(sql,new RowMapper<User>(){
            public User mapRow(ResultSet rs,int index) throws SQLException{
                User user = new User();
                user.setId(rs.getInt("id"));
                user.setName(rs.getString("name"));
                return user;
            }
        });
    }
    

JdBCDaoSupport

继承JdbcDaoSupport,减少一层依赖关系.源码中已经帮我们接收JdbcTemplate
好处:可以减少一级依赖关系.直接将连接池对象注入给Dao即可。

使用DB.properties管理连接信息

  1. 在src下创建properties文件,文件配置数据库信息
  2. spring配置文件中读取:
  3. 在配置中引用,${key}






spring中aop开发

aop&代理

spring中封装的代理技术
  • 动态代理

    局限性:生成代理类时必须基于接口.生成的代理对象实际上就是接口的实现类.
    spring中的aop是希望能够对所有对象生成代理的.基于该动态代理原则会导致
    项目中很多类无法生成代理.

  • CGLib代理

    spring为了能够对项目中所有类生成代理.所以引入了cglib这个第三方代理技术.该代理技术的特点是.对目标对象生成代理时,代理对象是被代理对象的子类.
    hibernate中应用了CGLib代理,懒加载技术中返回的就是cglib代理对象.

aop中的名称解释

aop联盟制定规范

  • 连接点 join point:目标对象中所有可以增强的方法.
  • 切点 point cut:已经或即将增加的方法.
  • 通知 advice:我们需要对目标方法增强的代码.
  • 目标对象 target:我们需要增强的对象
  • 代理对象 proxy:将通知应用到目标对象生成的对象
  • 织入 weaving:将通知织入到目标对象的过程.
  • 切面 aspect|advistor:切点+通知

springAOP开发步骤(注解)

  • 导包
  • 目标对象
  • 通知对象
  • 配置注解

注解详解

xml中配置
  1. 注册目标对象

    <bean name="userService" class="cn.it.service.impl.UserService"></bean>
    
  2. 注册通知对象

    <bean name="myAdvice" class="cn.it.test.MyAdvice"></bean>
    
  3. 开启使用注解配置aop

    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    
代码中配置注解
  • @Aspect 表示该类是通知类

    @Aspect 
    pbublic class MyAdvice{}
    
  • @Before(“execution(表达式)”) 前置通知
  • @Around(“execution(表达式)”) 环绕通知
  • @AfterRunner(“execution(表达式)”) 后置通知
  • @After(“execution(表达式)”) 后置通知,不管是否抛异常,都执行
  • @AfterThrowing(“execution(表达式)”) 异常拦截通知

    //注册切点
    @Pointcut(execution(* cn.it.service.impl.*ServiceImpl.*(..)))
    public void myPc(){}
    
    //前置通知
    @Before("MyAdvice.myPc()")
    public void before(){}
    

springAOP开发步骤(xml)

  • 导包
  • 目标对象
  • 通知对象
  • 配置xml

xml配置详解

<aop:config>
    <!--1.注册目标对象-->
    <bean name="userService" class="cn.it.service.impl.UserServiceImpl"></bean>
    <!--2.注册通知对象-->
    <bean name="myAdvice" class="cn.it.test.MyAdvice"></bean>
    <!--3.配置切面-->
    <!--注册切点-->
    <aop:pointcut id="myPc" exception="execution(* cn.it.service.*serviceImpl.*(..))" />
    <!--配置切面,method对应要增强的方法,pointcut-ref对应切点-->
    <aop:aspect ref="myAdvice">
        <aop:before method="before" pointcut-ref="myPc"/>
        <aop:around method="around" pointcut-ref="myPc"/>
        <aop:after method="after" pointcut-ref="myPc"/>
        <aop:after-returning method="afterReturning" pointcut-ref="myPc"/>
        <aop:after-throwing method="afterThrowing" poingcut-ref="myPc"/>
    </aop:aspect>
</aop:config>

Spring中的aop事务管理

事务属性

  • 传播行为(PROPAGATION)默认选择REQUIRED
  • 是否只读(only-read)true|false
  • 隔离级别

springAOP事务管理(XML) ###

  • 导包
  • 创建Dao层对象
  • 创建Service层对象
  • 创建Spring配置文件

spring文件配置详解

<!--指定读取properties文件-->
<context:property-placeholder location="classpath:db.properties" />
<!--配置连接池-->
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="${jdbc.driverClass}" />
    <property name="jdbcUrl" value="${jdbc.jdbcUrl}" />
    <property name="user" value="${jdbc.user}" />
    <property name="password" value="${jdbc.password}" />
</bean>

<!--配置dao-->
<bean name="userDao" class="cn.it.dao.impl.UserDao" >
    <property name="dataSource" ref="dataSource"></property>
</bean>

<!--配置service-->
<bean name="userService" class="cn.it.service.impl.UserService">
    <property name="userDao" ref="userDao"></property>
</bean>
  • 配置事务

引入tx约束

<!--配置核心事务管理器-->
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>

<!--事务通知&事务属性-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <!--配置事务属性-->
    <tx:attributes>
        <tx: method="before" propagation="REQUIRED" read-only="false" isolaction="REPEATABLE_READ" />
        <tx: method="around" propagation="REQUIRED" read-only="false" isolaction="REPEATABLE_READ" />
    </tx:attributes>
</tx:advice>

<!--配置切面完成织入-->
<aop:config>
    <!--配置切点-->
    <aop:pointcut exception="execution(* cn.it.test.*serviceImpl.*(..))" id="txPc"/>
    <!--配置切面-->
    <aop:aspect advice-ref="txAdvice" pointcut-ref="txPc" />
</aop:config>

springAOP事务管理(注解) ###

  • 导包
  • 创建Dao层对象
  • 创建Service层对象
  • 创建Spring配置文件

spring文件配置详解

<!--指定读取properties文件-->
<context:property-placeholder location="classpath:db.properties" />
<!--配置连接池-->
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass" value="${jdbc.driverClass}" />
    <property name="jdbcUrl" value="${jdbc.jdbcUrl}" />
    <property name="user" value="${jdbc.user}" />
    <property name="password" value="${jdbc.password}" />
</bean>

<!--配置dao-->
<bean name="userDao" class="cn.it.dao.impl.UserDao" >
    <property name="dataSource" ref="dataSource"></property>
</bean>

<!--配置service-->
<bean name="userService" class="cn.it.service.impl.UserService">
    <property name="userDao" ref="userDao"></property>
</bean>
  • 配置注解





    //使用注解管理事务
    @Transactional(paragation=Paragation.REQUIRED,readOnly=false,isolaction=Isolaction.REPEATABLE_READ)
    public class UserServiceImpl implements UserService{

    @Transactional(paragation=Paragation.REQUIRED,readOnly=true,isolaction=Isolaction.REPEATABLE_READ)
    public void transaction()
    

    }

spring整合hibernate、struts2

导包

  • hibernate lib下required
  • struts2 apps下struts2-blank(删除与hibernate相同的包)
  • spring
    1. core、context、bean、exception、log4j、logging
    2. spring-jdbc、spring-tx、spring-orm
    3. 数据库驱动、c3p0连接池
    4. spring-aop、spring-aspect
    5. aspectj织入、aop联盟
    6. spring-web
    7. spring-test、junit4
  • web jstl

整合spring到web项目

配置监听器,让spring随项目的启动而创建容器
<listener>
    <listener>org.springframework.web.context.ContextLoaderListener</listener>
</listener>
<!--指定容器配置文件位置-->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
</context-param>

准备spring配置文件

在src目录下创建applicationContext.xml,导入4个约束,bean、context、tx、aop

<!--配置dao-->
<bean name="userDao" class="cn.it.dao.impl.UserDaoImpl">

</bean>
<!--配置service-->
<bean name="userService" class="cn.it.service.impl.UserServiceImpl" >
    <property name="ud" ref="userDao"></property>
</bean>
<!--配置Action-->
<bean name="userAction" class="cn.it.web.action.UserAction">
    <property name="us" ref="userService"></property>
</bean>

整合struts2到web项目

创建Action
  • 创建Action的三种方式
    1. pojo(普通java对象,不需要实现任何接口|任何类)
    2. 实现Action
    3. 继承ActionSupport
  • 获取表单数据的三种方式
    1. 属性驱动
    2. 对象驱动
    3. 模型驱动
创建配置文件
<struts>
    <package name="crm" namespace="/" extends="struts-default">
        <action name="userAction_*" class="cn.it.web.action.UserAction" method="{1}">
            <result="success">/login.jsp</result>
        </action>
    </package>
</struts>
配置入口过滤器
<filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

spring整合struts2

配置整合spring常量
<context-param>
    <param-name>struts.objectFactory</param-name>
    <param-value>spring</param-value>
</context-param>
方案1:Action对象仍然由struts2创建,spring负责组装依赖.
<!--配置常量,指定由spring完成属性注入-->
<context-param>
    <param-name>struts.objectFactory.spring.autoWire</param-name>
    <param-value>name</param-value>
</context-param>

在action中准备依赖属性 

<!--在spring中配置依赖属性-->
<bean name="us" class="cn.it.service.impl.UserServiceImpl" ></bean>
方案2:Action对象创建与依赖注入全都由spring完成
将Action配置到spring容器中
<bean name="userAction" class="cn.it.web.action.UserAction">
    <property name="us" ref="userService"></property>
</bean>

在Action配置中的class属性,填写对象的BeanName
<action name="userAction_*" class="userAction" method="{1}">
    <result name="success" >/login.jsp</result>
</action>

搭建Hibernate框架

准备实体与映射文件

准备实体

映射文件 User.hbm.xml

<hibernate-mapping package="cn.it.domain">
    <class name="User" table="tb_user">
        <!--配置主键-->
        <id name="u_id" column="u_id">
            <generator class="native"></generator>
        </id>
        <!--配置普通属性-->
        <property name="u_name" column="u_name"></property>
        <property name="u_age" column="u_age"></property>
        <property name="u_gender" column="u_gender"></property>
    </class>
</hibernate-mapping>
准备主配置文件

在src目录下创建hibernate.cfg.xml

<hibernate-configuration>
    <session-factory>
        <!--配置5个必选-->

        <!--配置3个可选-->

        <!--配置映射文件-->
        <mapping resource="cn/it/domain/User.hbm.xml"></mapping>
    </session-factory>
</hibernate-configuration>

整合spring与hibernate

整合方式1:使用原生Hibernate配置文件
<!--配置sessionFactory-->
<bean name="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean" >
    <property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
</bean>
整合方式2:将hibernate中的配置转移到spring中
<!--将hibernate中的配置转移到spring中-->
<bean name="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean" >
    <!--指定可选|必选属性-->
    <property name="hibernateProperties">
        <props>
            <!--必选-->
            <prop key=""></prop>    
            <!--可选-->
            <prop key=""></prop>
        </props>
    </property>
    <!--引入映射文件-->
    <property name="mappingDirectoryLocations" value="classpath:cn/it/domain"></property>
</bean>

将c3p0连接池配置到spring

1.准备DB.properties
2.读取db.properties
<context:property-placeholder loaction="classpath:db.properties" />
3.配置连接池对象,并注入连接配置
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="jdbcUrl" value="${jdbc.jdbcUrl}"><property>
    <property name="driverClass" value="${jdbc.driverClass}"><property>
    <property name="user" value="${jdbc.user}"><property>
    <property name="password" value="${jdbc.password}"><property>
</bean>
4.将连接池对象注入到sessionFactory中
<bean name="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean" >
    <!--将连接池对象注入到sessionFactory中-->
    <property name="dataSource" ref="dataSource"></property>
    <!--指定可选|必选属性-->
    <property name="hibernateProperties">
        <props>
            <!--必选,其中4个没用了,只保留数据库方言-->
            <prop key=""></prop>    
            <!--可选-->
            <prop key=""></prop>
        </props>
    </property>
    <!--引入映射文件-->
    <property name="mappingDirectoryLocations" value="classpath:cn/it/domain"></property>
</bean>

将Dao&Hibernate模板配置到spring

书写Dao类
配置hibernate模板到spring
<bean name="hibernateTemplate" class="org.springframework.orm.hibernate5.HibernateTemplate">
    <property name="sessionFactory" ref="sessionFactory"></property>
</bean>
配置dao到spring
<bean name="userDao" class="cn.it.dao.impl.UserDaoImpl">
    <property name="ht" ref="hibernateTemplate"></property>
</bean>

整合AOP事务

1.完成Service
<!--配置service-->
<bean name="userService" class="cn.it.service.impl.UserServiceImpl">
    <property name="ud" ref="userDao"></property>
</bean>
2.配置核心事务管理器
<bean name="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory"></property>
</bean>

XML|注解事务配置

xml配置

<!--配置事务通知-->
<tx:advice name="myAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="save*" progation="REQUIRED" read-only="false" isolaction="REPEATABLE_READ" />
    </tx:attributes>
</tx:advice>

<!--配置切面-->
<aop:config>
    <aop:pointcut expression="execution(* cn.it.service.*serviceImpl.*(..))" id="myPc" />
    <aop:advisor advice-ref="adAdvice" pointcut-ref="myPc" />
</aop:config>

注解

<!--开启注解管理事务"开关"-->
<tx:annotation-driven transaction-manager="transactionManager" />

service中使用注解
@Transaction(progation=Progation.REQUIRED,readOnly=true,isolaction=Isolaction.REPEATABLE_READ)
publlic class UserServiceImpl implments UserService{

}

解决no-session问题

配置扩大session作用范围的过滤器

<filter>
    <filter-name>OpenSessionInViewFilter</filter-name>
    <filter-class>org.springframework.orm.hibernate5.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>OpenSessionInViewFilter<filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值