邂逅Spring,从入门到精通

专注于IT技术知识梳理,书写前沿技术文章!
更多技术在这里慢慢探索吧,请关注杰哥 公众号!

![在这里插入图片描述](https://img-blog.csdnimg.cn/2020111620380146.png#pic_center

  如文章对你有帮助,
   “ 评论”和 转发+关注(一键三连)是对我最大的支持!

一、Spring简介

  官网:http://www.springsource.org/spring-framework
  Spring 是另一个主流的 Java Web 开发框架,该框架是一个轻量级的应用框架,具有很高的凝聚力和吸引力。Spring 框架因其强大的功能以及卓越的性能而受到众多开发人员的喜爱。

  Spring 是分层的 Java SE/EE full-stack 轻量级开源框架,以 IoC(Inverse of Control,控制反转)和 AOP(Aspect Oriented Programming,面向切面编程)为内核,使用基本的 JavaBean 完成以前只可能由 EJB 完成的工作,取代了 EJB 臃肿和低效的开发模式。

  Spring 具有简单、可测试和松耦合等特点,不仅可以用于服务器端的开发,也可以应用于任何 Java 应用的开发中。Spring 框架的主要优点具体如下。
  1)方便解耦,简化开发
  Spring 就是一个大工厂,可以将所有对象的创建和依赖关系的维护交给 Spring 管理。
  2)方便集成各种优秀框架
  Spring 不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如 Struts2、Hibernate、MyBatis 等)的直接支持。
  3)降低 Java EE API 的使用难度
  Spring 对 Java EE 开发中非常难用的一些 API(JDBC、JavaMail、远程调用等)都提供了封装,使这些 API 应用的难度大大降低。
  4)方便程序的测试
  Spring 支持 JUnit4,可以通过注解方便地测试 Spring 程序。
  5)AOP 编程的支持
  Spring 提供面向切面编程,可以方便地实现对程序进行权限拦截和运行监控等功能。
  6)声明式事务的支持
  只需要通过配置就可以完成对事务的管理,而无须手动编程。

Spring模块:
在这里插入图片描述

二、Spring入门

1.环境搭建

  • Spring不依赖于容器的框架.没有tomcat也能运行,所以创建java项目即可。
  • Jar包介绍
    在这里插入图片描述
    2.IOC控制反转
    IoC 是指在程序开发中,实例的创建不再由调用者管理,而是由 Spring 容器创建。Spring 容器会负责控制程序之间的关系,而不是由程序代码直接控制,因此,控制权由程序代码转移到了 Spring 容器中,控制权发生了反转,这就是 Spring 的 IoC 思想。
    第一步:maven构建spring项目
    在这里插入图片描述
    在这里插入图片描述
    项目构建成功后,目录结构:
    在这里插入图片描述
    第二步:修改pom.xml文件
  <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>4.3.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>4.3.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.3.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-expression</artifactId>
            <version>4.3.6.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
    </dependencies>

第三步:在resources下添加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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    
</beans>

第四步:体验IOC
(1)创建UserDao

public class UserDao {
    public void save(){
        System.out.println("userDao say hello World!");
    }
}

(2)在applicationContext.xml中创建实例

<!-- 将指定类配置给 Spring, 让 Spring 创建其对象的实例  目的是解耦-->
    <bean id="userDao" class="com.beixi.dao.UserDao"  />

(3)测试TestIoc

public class TestIoc {
    public static void main(String[] args) {
        //1. 初始化 spring 容器,加载配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2. 通过容器获取 userDao 实例
        UserDao userDao = (UserDao)applicationContext.getBean("userDao");
        //3. 调用实例中的方法
        userDao.save();
    }
}

三、对象(Bean)创建方式

1.无参数构方式创建对象,默认创建方式.

  <bean id="peo" class="com.beixi.entity.User">
    </bean>

2.有参构造方式
 2.1 index: 从0开始的索引

<bean id="user" class="com.beixi.entity.User">
        <constructor-arg index="0"  value="001"></constructor-arg>
        <constructor-arg index="1"  value="贝西"></constructor-arg>
    </bean>

 2.2 name: 构造方法参数名称

<bean id="user" class="com.beixi.entity.User">
        <constructor-arg name="id" value="001"></constructor-arg>
        <constructor-arg name="name"  value="贝西"></constructor-arg>
    </bean>

 2.3 type: 构造方法参数类型,支持类型关键字(int)

<bean id="user" class="com.beixi.entity.User">
        <constructor-arg type="int" value="001"></constructor-arg>
        <constructor-arg type="java.lang.String" value="贝西"></constructor-arg>
    </bean>

四.Scope属性

  1. Scope是< bean> 的一个属性,控制如何实例化对象
    2.在Spring中每个对象默认都是单例的(有效范围:同一个< bean>标签)
    3.Scope属性可取值
    3.1 singleton: 默认值,单例的.使用ApplicationContext启动时实例化对象
     3.2 prototype:原型.每次调用时实例化.
<bean id="user" class="com.beixi.entity.User" scope="singleton">
        <constructor-arg type="int" value="001"></constructor-arg>
        <constructor-arg type="java.lang.String" value="贝西"></constructor-arg>
    </bean>
 public static void main(String[] args) {
        //1. 初始化 spring 容器,加载配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2. 通过容器获取 userDao 实例
        User user1 = (User)applicationContext.getBean("user");
        User user2 = (User)applicationContext.getBean("user");
        //3. 调用实例中的方法
        System.out.println(user1==user2);
    }

测试结果为true。 修改 scope=“prototype” 结果为false
 3.3 request:每次请求时实例化对象.
 3.4 session:每次产生session(HttpSession)时实例化
 3.5 application:产生application对象时实例化.一般都实例化一次.
 3.6 golbal session: 全局Golbal Session,web应用中一个新的全局HttpSessin对象.在spring-webmvc-portlet提供

五、DI依赖注入

1.DI的意义
 1.1 解除类与类之间高耦合性.
2.为什么称DI和IoC是同一个事情.
 2.1 Spring帮助创建对象的过程叫做IoC,创建对象时给对象中全局对象赋值叫做DI,所以认为IoC和DI是同一个事情.

六、依赖注入的几种方式

  1. 注入方式指的时给类中属性赋值
  2. 注入的几种方式
    2.1 构造注入.提供有参构造方法,通过的注入
    注意:上边已经介绍过了
<bean id="user" class="com.beixi.entity.User">
        <constructor-arg type="int" value="001"></constructor-arg>
        <constructor-arg type="java.lang.String" value="贝西"></constructor-arg>
    </bean>

 2.2 设值注入:执行属性的set方法.(实体类属性必须有set方法)
  2.2.1 结合< property>标签进行实现

 <bean id="user" class="com.beixi.entity.User">
        <property name="id" value="002"></property>
        <property name="name" value="贝西"></property>
    </bean>

如果注入的是类用ref属性指向类id值:

< property name=“classroom” ref=“classroom”>

七、设值注入时不同数据类型的注入方式

1.String或基本数据类型等

<bean id="classroom" class="com.beixi.pojo.Classroom">
    	<property name="id" value="1"></property>
</bean>

2.属性是对象类型

 <bean id="peo" class="com.beixi.pojo.People">
    	<property name="classroom" ref="classroom"></property>
    </bean> 

3.属性是数组时,和list可以相互替换

<property name="strs">
    		<array>
    			<value>1</value>
    			<value>2</value>
    			<value>3</value>
    			<value>4</value>
    		</array>
    	</property>

4.属性是List集合时,可以和array相互替换

<property name="list">
    		<list>
    			<value>1</value>
    			<value>2</value>
    			<value>3</value>
    			<value>4</value>
    		</list>
    	</property>

5.属性是Set集合时

<property name="set">
		<set>
			<value>2222</value>
			<value>3333</value>
			<value>444</value>
		</set>
	</property>

6.属性是Map集合时

       <property name="map">
    		<map>
    			<entry>
    				<key>
						<value>a</value>
    				</key>
    				<value>a的内容</value>
    			</entry>
    			<entry>
    				<key>
						<value>b</value>
    				</key>
    				<value>b的内容</value>
    			</entry>
    		</map>
    	</property>

7.属性是Properties类型时,用spring配置文件配置出.properties文件的效果.

      <property name="pro">
    		<props>
    			<prop key="key">value</prop>
    		</props>
    	</property>

八、类的实际注入

1.UserDao类

public class UserDao {
    public void save(){
        System.out.println("userDao say hello World!");
    }
}

2.UserService类

public class UserService {
    private UserDao userDao;
    public void save(){
        userDao.save();
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

3.applicationContext.xml

<bean id="userDao" class="com.beixi.dao.UserDao"  />
    <bean id="userService" class="com.beixi.service.UserService">
        <property name="userDao" ref="userDao"></property>
    </bean>

4.测试

  public static void main(String[] args) {
        //1. 初始化 spring 容器,加载配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2. 通过容器获取 userDao 实例
        UserService userService = (UserService)applicationContext.getBean("userService");
        //3. 调用实例中的方法
        userService.save();
    }

九、AOP的实现

Spring只支持XML方式而没有实现注解的方式(也叫AspectJ方式)的AOP,所以要使用@Aspect注解,只能引入AspectJ相关的 jar 包:

aopalliance-1.0.jar 和 aspectjweaver.jar
在这里插入图片描述
Spring的配置文件 applicationContext.xml 中引入context、aop对应的命名空间;

配置自动扫描的包,同时使切面类中相关方法中的注解生效,需自动地为匹配到的方法所在的类生成代理对象。

<?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:aop="http://www.springframework.org/schema/aop"
    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/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    <!-- 配置自动扫描的包 -->
    <context:component-scan base-package="com.qcc.beans.aop"></context:component-scan>
    <!-- 自动为切面方法中匹配的方法所在的类生成代理对象。 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

AOP中一些比较重要的概念

Joinpoint(连接点):程序执行时的某个特定的点,在Spring中就是某一个方法的执行 。

Pointcut(切点):说的通俗点,spring中AOP的切点就是指一些方法的集合,而这些方法是需要被增强、被代理的。一般都是按照一定的约定规则来表示的,如正则表达式等。切点是由一类连接点组成。

Advice(通知):还是说的通俗点,就是在指定切点上要干些什么。

Advisor(通知器):其实就是切点和通知的结合 。

注意:

1、环绕方法通知,环绕方法通知要注意必须给出调用之后的返回值,否则被代理的方法会停止调用并返回null,除非你真的打算这么做。

2、只有环绕通知才可以使用JoinPoint的子类ProceedingJoinPoint,各连接点类型可以调用代理的方法,并获取、改变返回值。

1、aop:pointcut如果位于aop:aspect元素中,则命名切点只能被当前aop:aspect内定义的元素访问到。为了能被整个aop:config元素中定义的所有增强访问,则必须在aop:config下定义切点。
2、如果在aop:config元素下直接定义aop:pointcut,必须保证aop:pointcut在aop:aspect之前定义。aop:config下还可以定义aop:advisor,三者在aop:config中的配置有先后顺序的要求:首先必须是aop:pointcut,然后是aop:advisor,最后是aop:aspect。而在aop:aspect中定义的aop:pointcut则没有先后顺序的要求,可以在任何位置定义。aop:pointcut:用来定义切入点,该切入点可以重用;aop:advisor:用来定义只有一个通知和一个切入点的切面;aop:aspect:用来定义切面,该切面可以包含多个切入点和通知,而且标签内部的通知和切入点定义是无序的;和advisor的区别就在此,advisor只包含一个通知和一个切入点。

3、在使用spring框架配置AOP的时候,不管是通过XML配置文件还是注解的方式都需要定义pointcut"切入点"。

例如定义切入点表达式 execution(* com.sample.service.impl….(…))

execution()是最常用的切点函数,其语法如下所示:
整个表达式可以分为五个部分:

(1)、execution(): 表达式主体。

(2)、第一个*号:表示返回类型,*号表示所有的类型。

(3)、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。

(4)、第二个*号:表示类名,*号表示所有的类。

(5)、*(…):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。

一、基于XML配置的Spring AOP

采用声明的方式实现(在XML文件中配置),大致步骤为:配置文件中配置pointcut, 在java中用编写实际的aspect 类, 针对对切入点进行相关的业务处理。

业务接口:

package com.spring.service;
public interface IUserManagerService {
    //查找用户
    public String findUser();
    //添加用户
    public void addUser();
}

业务实现:

package com.spring.service.impl;
import com.spring.service.IUserManagerService;
public class UserManagerServiceImpl implements IUserManagerService{
private String name;
    public void setName(String name){
        this.name=name;
    }
    public String getName(){
        return this.name;
    }
    public String findUser(){
        System.out.println("============执行业务方法findUser,查找的用户是:"+name+"=============");
        return name;
    }
    public void addUser(){
        System.out.println("============执行业务方法addUser=============");
        //throw new RuntimeException();
    }
}

切面类:

package com.spring.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
public class AopAspect {
    /**
     * 前置通知:目标方法调用之前执行的代码
      * @param jp
     */
    public void doBefore(JoinPoint jp){
        System.out.println("===========执行前置通知============");
    }
    /**
     * 后置返回通知:目标方法正常结束后执行的代码
      * 返回通知是可以访问到目标方法的返回值的
      * @param jp
     * @param result
     */
    public void doAfterReturning(JoinPoint jp,String result){
        System.out.println("===========执行后置通知============");
        System.out.println("返回值result==================="+result);
    }
    /**
     * 最终通知:目标方法调用之后执行的代码(无论目标方法是否出现异常均执行)
      * 因为方法可能会出现异常,所以不能返回方法的返回值
      * @param jp
     */
    public void doAfter(JoinPoint jp){
        System.out.println("===========执行最终通知============");
    }
    /**
     * 
     * 异常通知:目标方法抛出异常时执行的代码
     * 可以访问到异常对象
     * @param jp
     * @param ex
     */
    public void doAfterThrowing(JoinPoint jp,Exception ex){
        System.out.println("===========执行异常通知============");
    }

    /**
      * 环绕通知:目标方法调用前后执行的代码,可以在方法调用前后完成自定义的行为。
      * 包围一个连接点(join point)的通知。它会在切入点方法执行前执行同时方法结束也会执行对应的部分。
      * 主要是调用proceed()方法来执行切入点方法,来作为环绕通知前后方法的分水岭。
      * 
      * 环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法。
      * 而且环绕通知必须有返回值,返回值即为目标方法的返回值
      * @param pjp
      * @return
      * @throws Throwable
     */
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("======执行环绕通知开始=========");
         // 调用方法的参数
        Object[] args = pjp.getArgs();
        // 调用的方法名
        String method = pjp.getSignature().getName();
        // 获取目标对象
        Object target = pjp.getTarget();
        // 执行完方法的返回值
        // 调用proceed()方法,就会触发切入点方法执行
        Object result=pjp.proceed();
        System.out.println("输出,方法名:" + method + ";目标对象:" + target + ";返回值:" + result);
        System.out.println("======执行环绕通知结束=========");
        return result;
    }
}

Spring配置:

<?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:aop="http://www.springframework.org/schema/aop"
    xmlns:p="http://www.springframework.org/schema/p"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/tx 
    http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
    <!-- 声明一个业务类 -->
    <bean id="userManager" class="com.spring.service.impl.UserManagerServiceImpl">
        <property name="name" value="lixiaoxi"></property>
    </bean>  
    <!-- 声明通知类 -->
    <bean id="aspectBean" class="com.spring.aop.AopAspect" />
    <aop:config>
     <aop:aspect ref="aspectBean">
        <aop:pointcut id="pointcut" expression="execution(* com.spring.service.impl.UserManagerServiceImpl..*(..))"/>
        <aop:before method="doBefore" pointcut-ref="pointcut"/> 
        <aop:after-returning method="doAfterReturning" pointcut-ref="pointcut" returning="result"/>
        <aop:after method="doAfter" pointcut-ref="pointcut" /> 
        <aop:around method="doAround" pointcut-ref="pointcut"/> 
        <aop:after-throwing method="doAfterThrowing" pointcut-ref="pointcut" throwing="ex"/>
      </aop:aspect>
   </aop:config>
</beans>

测试类:

package com.spring.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.spring.service.IUserManagerService;
public class TestAop {
    public static void main(String[] args) throws Exception{
        ApplicationContext act =  new ClassPathXmlApplicationContext("applicationContext3.xml");
        IUserManagerService userManager = (IUserManagerService)act.getBean("userManager");
        userManager.findUser();
        System.out.println("\n");
        userManager.addUser();
    }
}

专注于IT技术知识梳理,书写前沿技术文章!
更多技术在这里慢慢探索吧,请关注杰哥 公众号!

![在这里插入图片描述](https://img-blog.csdnimg.cn/2020111620380146.png#pic_center

  如文章对你有帮助,
   “ 评论”和 转发+关注(一键三连)是对我最大的支持!

十.Spring整合MyBatis的步骤

1.导入Spring和MyBatis所有jar
2.先编写web.xml

<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee                       
	http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
	<!-- 告诉spring配置文件在哪里 -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:applicationContext.xml</param-value>
	</context-param>
	<!-- spring-web包中 -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
</web-app>

3.在src下新建applicationContext.xml(不需要编写mybatis.xml)

<beans xmlns="http://www.springframework.org/schema/beans"
    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" default-autowire="byName">
    <!-- 导入一个spring整合mybatis的包 -->
    <!-- spring-jdbc包下 -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    	<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    	<property name="url" value="jdbc:mysql://localhost:3306/mybatis"></property>
    	<property name="username" value="root"></property>
    	<property name="password" value="smallming"></property>
    </bean>
    <!-- 整合包中:创建sqlsessionFactory对象 -->
    <bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
    	<property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 配置由Spring帮助扫描包,由spring创建Mapper接口对象 ,名称为接口首字母变小写-->
    <!-- 在整合包中 -->
    <!-- 相当于mybatis.xml中mappers标签 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    	<property name="basePackage" value="com.bjsxt.mapper"></property>
    	<property name="sqlSessionFactoryBeanName" value="factory"></property>
    </bean>
    <!-- 在beans标签配置default-autowire -->
    <bean id="peopleService" class="com.bjsxt.service.impl.PeopleServiceImpl">
    </bean>
</beans>

4.创建mapper包,创建Mapper接口,如果非注解方式创建mapper.xml
5.创建service及实现类,在实现类中
 5.1 添加Mapper接口的对象,并提供get/set方法
 5.2 在接口中方法直接通过Mapper接口对象进行调用数据库访问代码
 5.3 把Service实现类配置applicatContext.xml中
  5.3.1 要对ServiceImple类中全局属性Mapper接口对象进行注入.

<bean id="peopleService" class="com.beixi.service.impl.PeopleServiceImpl">
</bean>
public List<People> show(People people) {
	return peopleMapper.selByPeople(people);
}

6.编写Servlet类
 6.1 Servlet中Service对象不能自己New否则出现空指针.
  6.1.1 Mapper接口对象null

private PeopleService peopleService ;
public void init(ServletConfig config) throws ServletException {
	super.init(config);
    //peopleServic不能自己new, 里面peopleMapper在spring中进行的依赖注入
	//结合web写的.如果单独测试ApplicationCOntext ac= new 	ClassPathXmlApplicationContext();
	WebApplicationContext wc = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
	peopleService = wc.getBean("peopleService",PeopleServiceImpl.class);
}
protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
	//通过service对象调用方法
	peopleService.show(null);
}
专注于IT技术知识梳理,书写前沿技术文章!
更多技术在这里慢慢探索吧,请关注杰哥 公众号!

![在这里插入图片描述](https://img-blog.csdnimg.cn/2020111620380146.png#pic_center

  如文章对你有帮助,
   “ 评论”和 转发+关注(一键三连)是对我最大的支持!
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贝西奇谈

你的鼓励将是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值