Spring框架学习

目录

1.Spring框架的概述

1.1 spring框架的概念

1.2Spring框架的特点

1.3 体系结构图

2.Spring框架的IOC核心功能快速入门

2.1. 什么是IOC的功能?

2.2下载Spring框架的开发包

2.3创建JavaWEB项目,引入Spring的开发包

2.4 创建对应的包结构,编写Java的类,要注意:以后使用Spring框架做开发,都需要来编写接口与实现类!!

2.5 想把UserServiceImpl实现类的创建交给Spring框架来管理,需要创建Spring框架的配置文件,完成配置

2.5编写测试程序,采用Spring框架的工厂方式来获取到UserService接口的具体实现类!!

3.入门总结之Spring框架中的工厂

3.1 ApplicationContext接口

3.2 BeanFactory工厂(是Spring框架早期的创建Bean对象的工厂接口)(不推荐)

3.3BeanFactory和ApplicationContext的区别

4.入门总结之配置Spring框架编写XML的提示

5.Spring框架中标签的配置

5.1 id属性和name属性的区别

5.2 class属性

5.3scope属性

5.4Bean对象的创建和销毁的两个属性配置

6.依赖注入(DI)

6.1IOC和DI的概念

6.2 DI(依赖注入)

6.3注意:Junit的类起名字不能为Test

7.Spring框架的属性注入(依赖注入的方式)

7.1类成员变量常用的注入方式:    构造函数

 

7.2类成员变量常用的注入方式:    setter方法

7.3类成员变量常用的注入方式(属性是另一个Java的类)

   value替换成ref(注意这用的是构造方法)

7.4p名称空间的注入(了解)

7.5 SpEL注入方式(了解)

7.6数组,集合(List,Set,Map),Properties等的注入

8.Spring框架的配置文件分开管理

9.Spring框架的IOC之注解方式的快速入门

9.1注解方式的过程:

9.2 注解方式的实现:

步骤一:导入注解开发所有需要的jar包

 步骤二:创建对应的包结构,编写Java的类

步骤三:在src的目录下,创建applicationContext.xml的配置文件

     注意:因为现在想使用注解的方式,那么引入的约束发生了变化

需要引入context的约束,具体的约束如下

步骤四:在applicationContext.xml配置文件中加入开启组件扫描

    * 注意:也可以采用如下配置  

步骤五:在UserServiceImpl的实现类上添加注解

步骤六:编写测试代码

10.Spring框架中Bean管理的常用注解

10.1Spring中提供@Component的三个衍生注解:(功能目前来讲是一致的)

        * @Controller        -- 作用在WEB层        * @Service            -- 作用在业务层        * @Repository(仓库)        -- 作用在持久层

* 说明:这三个注解是为了让标注类本身的用途清晰,Spring在后续版本会对其增强

10.2注入的过程分析

10.3注入的属性的类型

属性注入的注解(说明:使用注解注入的方式,可以不用提供set方法)

 如果是注入的普通类型,可以使用value注解

如果注入的是对象类型,使用如下注解

@Resource    =@Autowired  +@Qualifier

注意:假如在service层注入完后,service层就可以调用dao层的内容的

比如说:在service层就可调用dao层的save方法

eg:

11.Bean的作用范围和生命周期的注解

12.Spring框架整合JUnit单元测试

具体步骤:



1.Spring框架的概述

 

1.1 spring框架的概念

  • Spring是一个开源框架
  • 2003 年兴起的一个轻量级的Java开发框架
  • 为了解决企业应用开发的复杂性而创建,不仅限于服务器端的开发,任何Java应用都可以(简单性、可测试性和松耦合的角度而言)
  • 核心是控热制反转(IoC)和面向切面(AOP)
  •  简单来说,Spring是一个分层的JavaSE/EEfull-stack(一站式) 轻量级开源框架。为什么说它是一站式呢?

我们来看一下EE开发分成三层结构

 WEB层        -- Spring MVC

 业务层         -- Bean管理:(IOC)

 持久层        -- Spring的JDBC模板.ORM模板用于整合其他的持久层框架
    

1.2Spring框架的特点

  • 方便解耦,简化开发

       Spring就是一个大工厂,可以将所有对象创建和依赖关系维护,交给Spring管理

  • AOP编程的支持

      Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能

  • 声明式事务的支持

      只需要通过配置就可以完成对事务的管理,而无需手动编程

  • 方便程序的测试

     Spring对Junit4支持,可以通过注解方便的测试Spring程序

  • 方便集成各种优秀框架

     Spring不排斥各种优秀的开源框架,内部提供了对各种优秀框架(如:Struts2、Hibernate、MyBatis、Quartz等)直接支持.

  • 降低JavaEE API的使用难度

Spring 对JavaEE开发中非常难用一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低

1.3 体系结构图

 

 

2.Spring框架的IOC核心功能快速入门

2.1. 什么是IOC的功能?

IoC  (Inverse of Control  )控制反转,将对象的创建权反转给Spring!!

2.2下载Spring框架的开发包

下载Spring框架的开发包
        * 官网:http://spring.io/
        * 下载地址:http://repo.springsource.org/libs-release-local/org/springframework/spring解压:(Spring目录结构:)
            * docs        -- API和开发规范
            * libs        -- jar包和源码
            * schema    -- 约束

2.3创建JavaWEB项目,引入Spring的开发包

  • 引入Spring框架IOC核心功能需要的具体的jar包
  • Spring框架的IOC的功能,那么根据Spring框架的体系结构图能看到,只需要引入如下的jar包(对应体系结构图的最下面)
  • Spring框架也需要引入日志相关的jar包

 

2.4 创建对应的包结构,编写Java的类,要注意:以后使用Spring框架做开发,都需要来编写接口与实现类!!

UserService            -- 接口
UserServiceImpl        -- 具体的实现类

2.5 想把UserServiceImpl实现类的创建交给Spring框架来管理,需要创建Spring框架的配置文件,完成配置

  • 在src目录下创建applicationContext.xml的配置文件,名称是可以任意的,但是一般都会使用默认名称!!
  • 引入spring的约束,需要先找到具体的约束头信息!!
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
  • 完成UserService的配置
<bean id="UserService" class="com.spring.demo1.UserServiceImpl" init-method="init">

 

2.5编写测试程序,采用Spring框架的工厂方式来获取到UserService接口的具体实现类!!

	@Test
	public void run1()
	{
		//创建工厂,获取核心配置文件
		ApplicationContext ac =new ClassPathXmlApplicationContext("applicationContext.xml");
	   //从工厂中获取对象
		UserServiceImpl usi=(UserServiceImpl) ac.getBean("UserService");
	   //上面传入id值,正常返回的是id中多对应的对象(com.spring.demo1.UserServiceImpl)
	   //调用方法执行
		usi.SayHello();
		
		
	}

 

3.入门总结之Spring框架中的工厂

3.1 ApplicationContext接口

使用ApplicationContext工厂的接口,使用该接口可以获取到具体的Bean对象

该接口下有两个具体的实现类

  • ClassPathXmlApplicationContext            加载类路径下的Spring配置文件
  • FileSystemXmlApplicationContext           加载本地磁盘下的Spring配置文件

3.2 BeanFactory工厂(是Spring框架早期的创建Bean对象的工厂接口)(不推荐)

从例子中可以看到他是被拉黑线的

3.3BeanFactory和ApplicationContext的区别

  • BeanFactory    

BeanFactory采取延迟加载,第一次getBean时才会初始化Bean

  • ApplicationContext

在加载applicationContext.xml时候就会创建具体的Bean对象的实例,还提供了一些其他的功能

4.入门总结之配置Spring框架编写XML的提示

 

1. 步骤一:先复制, http://www.springframework.org/schema/beans/spring-beans.xsd    

2. 步骤二:搜索XML Catalog,点击Add按钮

3. 步骤三:先选择Location的schema的约束地址

步骤四:注意:Key type要选择:Schema location

步骤五:Key把http://www.springframework.org/schema/beans/spring-beans.xsd复制上

 

5.Spring框架中<bean>标签的配置

5.1 id属性和name属性的区别

  • id

Bean起个名字,在约束中采用ID的约束,唯一

取值要求:必须以字母开始,可以使用字母、数字、连字符、下划线、句话、冒号    id:不能出现特殊字符

  • name    

Bean起个名字,没有采用ID的约束(了解)

取值要求:name:出现特殊字符.如果<bean>没有id的话 , name可以当做id使用,但开发一般不用

Spring框架在整合Struts1的框架的时候,Struts1的框架的访问路径是以/开头的,例如:/bookAction

 

5.2 class属性

Bean对象的全路径  eg:

 <bean id="CustomDao" class="com.spring.demo2.CustomerDaoImpl"/>

5.3scope属性

scope属性代表Bean的作用范围

  • ①singleton            -- 单例(默认值)
  • ②prototype            -- 多例,在Spring框架整合Struts2框架的时候,Action类也需要交给Spring做管理,配置把Action类配置成多例!!
  • ③request            -- 应用在Web项目中,每次HTTP请求都会创建一个新的Bean
  • ④session               -- 应用在Web项目中,同一个HTTP Session 共享一个Bean
  • ⑤globalsession        -- 应用在Web项目中,多服务器间的session(一个地方登陆成功其他地方就可以用了)

5.4Bean对象的创建和销毁的两个属性配置

Spring初始化bean或销毁bean时,有时需要作一些处理工作,因此spring可以在创建和拆卸bean的时候调用bean的两个生命周期方法

  • init-method          当bean被载入到容器的时候调用init-method属性指定的方法
  • destroy-method   当bean从容器中删除的时候调用destroy-method属性指定的方法

注:

想查看destroy-method的效果,有如下条件
 scope= singleton有效
 web容器中会自动调用,但是main函数或测试用例需要手动调用(需要使用ClassPathXmlApplicationContext的close()方法)

 

6.依赖注入(DI)

6.1IOC和DI的概念

IOC  :Inverse of Control,控制反转,将对象的创建权反转给Spring!!

DI    : Dependency Injection,依赖注入,在Spring框架负责创建Bean对象时,动态的将依赖对象注入到Bean组件中

6.2 DI(依赖注入)

例如:如果UserServiceImpl的实现类中有一个属性,那么使用Spring框架的IOC功能时,可以通过依赖注入把该属性的值传入进来!!

具体的配置如下

  <bean id="us" class="com.itheima.demo1.UserServiceImpl">
                <property name="uname" value="小苍老师"/>
            </bean>
  •             原来的话必须先new好(new UserServiceImpl),然后自己设置name的值setname
  •             现在依靠容器中,不用自己管,在注入可以得到:
  •             当在获取配置文件中就会创建UserServiceIml这个对象,同时就会把property里面的内容赋值给name

6.3注意:Junit的类起名字不能为Test

假如说这个类名字为Test的话就会报错

7.Spring框架的属性注入(依赖注入的方式)

7.1类成员变量常用的注入方式:    构造函数

  •    编写Java的类,提供构造方法

public class Car 
{

	private String name;
        private double money;
	public Car(String name, double money) {
		this.name = name;
		this.money = money;
	}
	@Override
	public String toString() {
	return "Car [name=" + name + ", money=" + money + "]";
	}
}
  • 编写配置文件
	<bean id="car" class="com.spring.demo1.Car">
	<constructor-arg name="name" value="苍老师"/>
	<constructor-arg name="money" value="100"/>
	</bean>

	<constructor-arg index="0" value="小泽老师"/>
	<constructor-arg index="1" value="100"/>
  • DemoTest
@Test
	public void run1()
	{
		ApplicationContext ac= new ClassPathXmlApplicationContext("applicationContext.xml");
		Car1 c1=(Car1) ac.getBean("car1);
		System.out.println(c1);
		
	}   

注意:当car这个类创建好之后,交给容器去管理,现在不需要自己去new创建对象了,容器会帮我们创建这个对象,但是这个对象没有空的构造方法,有参数的就一个,所以你在创建对象的时候需要传入两个参数

写配置文件的时候:

  • id的值是随便写的,class是全路径
  • 注意是两个值需要两个constructor-arg

 

7.2类成员变量常用的注入方式:    setter方法

  • 编写Java的类,提供属性和对应的set方法即可
package com.spring.demo2;

public class Car2 {
	
	private String cname;
	private Double price;
	
	public String getCname() {
		return cname;
	}
	public void setCname(String cname) {
		this.cname = cname;
	}
	public Double getPrice() {
		return price;
	}
	public void setPrice(Double price) {
		this.price = price;
	}
	@Override
	public String toString() {
		return "Car2 [cname=" + cname + ", price=" + price + "]";
	}
}

 

  • 编写配置文件
 	<bean id="car2" class="com.spring.demo2.Car2">
   		<property name="cname" value="范老师"/>
   		<property name="price" value="1000"/>
   	</bean> 
  • DemoTest
@Test
	public void run2()
	{
		ApplicationContext ac= new ClassPathXmlApplicationContext("applicationContext.xml");
		Car2 c2=(Car2) ac.getBean("car2);
		System.out.println(c1);
		
	}   

7.3类成员变量常用的注入方式(属性是另一个Java的类)

   value替换成ref(注意这用的是构造方法)

package com.spring.demo3;

public class Person {
	
	private String pname;
	private Car1 car1;
	
	public Person(String pname, Car1 car1) {
		this.pname = pname;
		this.car1 = car1;
	}

	@Override
	public String toString() {
		return "Person [pname=" + pname + ", car1=" + car1 + "]";
	}
}
 	<bean id="car2" class="com.spring.demo3.Car2">
   		
   	</bean>

 

7.4p名称空间的注入(了解)

 

  • 需要先引入 p 名称空间

配置文件中加入:xmlns:p="http://www.springframework.org/schema/p"

  • 使用p名称空间的语法

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

  • DemoTest
<bean id="person" class="com.spring.demo4.Person" p:pname="老王" p:car2-ref="car2"/>

7.5 SpEL注入方式(了解)

  •  SpEL:Spring Expression Language是Spring的表达式语言,有一些自己的语法
  •   语法 :#{SpEL}  数字直接写 字符串的话加单引号
  •  例如如下的代码
	<!-- SpEL的方式 -->
	<bean id="car2" class="com.spring.demo5.Car2">
   	<property name="cname" value="#{'马云'}"/>
   	<property name="price" value="20000"/>
   	</bean> 
  • SpEL还支持调用类中的属性或者方法
public class CarInfo 
{
    public String getCarname(){
	     return "奔驰";
	}
}
value="#{CarInfo.getname}“

7.6数组,集合(List,Set,Map),Properties等的注入

package com.spring.demo4;

import java.util.Arrays;
import java.util.Map;

public class User {
	private String [] arr;

	public void setArr(String[] arr) {
		this.arr = arr;
	}

	
	private  Map<String,String> map;

	public void setMap(Map<String, String> map) {
		this.map = map;
	}
	@Override
	public String toString() {
		return "User [arr=" + Arrays.toString(arr) + ", map=" + map + "]";
	}
	
	

}
  • 如果是数组或者List集合,注入配置文件的方式是一样的
<bean id="collectionBean" class="com.itheima.demo5.CollectionBean">
	<property name="arrs">
		<list>
			<value>凤姐</value>
			<value>小三</value>
		</list>
	</property>
</bean>
  • 如果是Set集合,注入的配置文件方式如下:
<property name="sets">
	<set>
		<value>哈哈</value>
		<value>呵呵</value>
	</set>
</property>
  • 如果是Map集合,注入的配置方式如下:
<property name="map">
	<map>
		<entry key="老王2" value="38"/>
		<entry key="凤姐" value="38"/>
		<entry key="如花" value="29"/>
	</map>
</property>
  • 如果是properties属性文件的方式,注入的配置如下:
<property name="pro">
			<props>
				<prop key="uname">root</prop>
				<prop key="pass">123</prop>
			</props>
</property>
  • eg:DemoTest
	public void run3()
	{
		ApplicationContext ac= new ClassPathXmlApplicationContext("applicationContext.xml");
		User user=(User)ac.getBean("ColloectionMap");
		System.out.println(user);
	}

 

8.Spring框架的配置文件分开管理

  • 在src的目录下又多创建了一个配置文件,现在是两个核心的配置文件,那么加载这两个配置文件的方式有两种

        主配置文件中包含其他的配置文件(applicationContext2):    

    <import resource="applicationContext2.xml"/>
        


  DemoTest中工厂创建的时候直接加载多个配置文件:       

  ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
                        "applicationContext.xml","applicationContext2.xml");

 

9.Spring框架的IOC之注解方式的快速入门

注意:

 * (Component)组件注解,标记类
 * <bean id="userService" class="com.java.spring.UserServiceImpl">
 * 等价于 @Component(value="userService")
 * 有了注解全路径就可以省略了,
 *但是id不可以,否则类的名称就会默认以小写开头
 * 注解都有属性:eg;value
 * 是给注解起名字

9.1注解方式的过程:

     * 注解的方式
     * 开启了注解的扫描,扫描到对应的注解,这个类就会被创建实例对象
     * 拿到工厂
     *通过id值找到对象然后用它并且调用里面的方法     

9.2 注解方式的实现:

  • 步骤一:导入注解开发所有需要的jar包

 

  •  步骤二:创建对应的包结构,编写Java的类

* UserService            -- 接口
* UserServiceImpl        -- 具体的实现类

    

public interface UserService {
	public void save();
	public void save1();

}
package com.java.spring_ioc;

public class UserServiceImpl implements UserService {
      
	public void save() {
         System.out.println("我是service持久层 你好 :");
     
	}
	public void save1()
	{
		 System.out.println("我是service持久层 11你好 :");
		
	}		

}
  • 步骤三:在src的目录下,创建applicationContext.xml的配置文件

     注意:因为现在想使用注解的方式,那么引入的约束发生了变化

需要引入context的约束,具体的约束如下

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- bean definitions here -->
	
</beans>
  • 步骤四:在applicationContext.xml配置文件中加入开启组件扫描

<context:component-scan base-package="com.spring.demo1"/>

    * 注意:也可以采用如下配置
  

 <context:component-scan base-package="com.spring"/> 这样是扫描com.spring包下所有的内容

 

  • 步骤五:在UserServiceImpl的实现类上添加注解

 @Component(value="userService")


 相当于在XML的配置方式中 <bean id="userService" class="...">
  • 步骤六:编写测试代码

public class SpringDemo1 {
		@Test
		public void run1(){
			ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
			UserService us = (UserService) ac.getBean("userService");
			us.save();
		}
}

10.Spring框架中Bean管理的常用注解

 

10.1Spring中提供@Component的三个衍生注解:(功能目前来讲是一致的)

        * @Controller        -- 作用在WEB层
        * @Service            -- 作用在业务层
        * @Repository(仓库)        -- 作用在持久层

* 说明:这三个注解是为了让标注类本身的用途清晰,Spring在后续版本会对其增强

 

10.2注入的过程分析

       * 在userdao中做一个简单的注入 传统方式是自己new,现在交给容器去管理
       * 就在userdaoImpl中加 Component(value=userDao)可以,但是为更还就用 @Repository 
       * 现在就UserDaoImpl就交给IOC容器去管理了,名字为userDao
       * Dao会被扫描到,就去service中注入dao

       * 注入就得提供成员属性,private UserDao userDao;
       * 但不用提供set方法了,使用注解就不用提供set方法
       * 使用@Autowired +@Qualifier
       *@Autowired就会去容器中找,扎到UserDao就会自动注入

10.3注入的属性的类型

属性注入的注解(说明:使用注解注入的方式,可以不用提供set方法)

  •  如果是注入的普通类型,可以使用value注解

	@Value(value="波姐")
	private String name;
  • 如果注入的是对象类型,使用如下注解

@Autowired        
默认按类型进行自动装配
如果想按名称注入
@Qualifier    -- 强制使用名称注入

	 @Autowired//,,注入的是对象类型,使用注解@Autowired他是按类型自动装配
	 
	 @Qualifier(value="userDao") // 按名称注入	 	 	     
	private UserDao userDao;
  • @Resource    =@Autowired  +@Qualifier

 @Resource(name="userDao")
 private UserDao userDao;

		* 强调:Java提供的注解
		* 属性使用name属性

注意:假如在service层注入完后,service层就可以调用dao层的内容的

比如说:在service层就可调用dao层的save方法

eg:

public interface UserDao {
	public void saveCustomer();
}
import org.springframework.stereotype.Repository;

@Repository(value="userDao")
public class UserDaoImpl implements UserDao {

	@Override
	public void saveCustomer() {
		System.out.println("保存客户");
		
	}

}
public interface UserService {
	public void save();
	public void save1();

}
package com.java.spring_ioc;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
//import javax.annotation.Resource;
@Component(value="userService")
public class UserServiceImpl implements UserService {
      
	// 给name属性注入简琦的字符串,setName方法还可以省略不写
	@Value(value="简琦")
	private String name;

	/*
	 * public void setName(String name) { this.name = name; }
	 */
	
	  @Autowired//,,注入的是对象类型,使用注解@Autowired他是按类型自动装配
	  
	  @Qualifier(value="userDao") // 按名称注入	 	 	     

	//@Resource(name="userDao")
	private UserDao userDao;
	
	public void save() {
      System.out.println("我是service持久层 你好 :");
      userDao.saveCustomer();
	}
	public void save1()
	{
		 System.out.println("我是service持久层 11你好 :");
		
	}	
	

}
package com.java.spring_ioc;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class DemoTest {
	
	@Test  //传统的方式必须得自己new
	public void run1()
	{
		UserServiceImpl us =new UserServiceImpl();
		us.save1();
		System.out.println("执行完毕");
		
	}
	/**
	 * 注解的方式
	 * 开启了注解的扫描,扫描到对应的注解,这个类就会被创建实例对象
	 * 拿到工厂
	 *通过id值找到对象然后用它并且调用里面的方法
	 */
	
	  @Test public void run2() { // 获取工厂,加载配置文件 
		  ApplicationContext ac = new  ClassPathXmlApplicationContext("applicationContext.xml");
		  UserService us =  (UserService) ac.getBean("userService"); 
		  us.save();
	  
	  }

}

 

11.Bean的作用范围和生命周期的注解

 

    1. Bean的作用范围注解
        * 注解为@Scope(value="prototype"),作用在类上。值如下:
            * singleton        -- 单例,默认值
            * prototype        -- 多例
    
    2. Bean的生命周期的配置(了解)
        * 注解如下:
            * @PostConstruct    -- 相当于init-method
            * @PreDestroy        -- 相当于destroy-method

 

12.Spring框架整合JUnit单元测试

**不在需要ApplicationContext 每次都new一个ClasspathApplicationtext从配置文件中读取内容的话形式
**可以用注解的方式代替

具体步骤:


要求:必须先有JUnit的环境(即已经导入了JUnit4的开发环境)

  • 步骤一:在程序中引入:spring-test.jar

  • 步骤二:在具体的测试类上添加注解

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("classpath:applicationContext.xml")

public class SpringDemo1 {
	
	@Resource(name="userService")
	private UserService userService;
	
	@Test
	public void demo2(){
		userService.save();
	}
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值