spring框架三种类型项目实现--基础maven类型、纯注解开发型、aop结合注解开发型


本次介绍只基于后端,非web,转换成web就添加web层基于servlet进行前后端交互就可以了
这种虽然说是spring框架,但是都是基于maven进行开发,所以创建项目是创建一个maven项目,然后添加spring依赖进行基于spring框架进行开发

1.基础maven类型

基础maven类型,与maven框架开发差不多,只不过加入了spring依赖,其中内部逻辑是不变的,但是不同的是在spring中,xml配置文件连接service和dao层方式是不一样的,除此之外一模一样.
基础版架构:
在这里插入图片描述

1.开发准备–pom.xml添加spring依赖

maven项目开发第一步,添加依赖和插件,因为我们不是web项目,不需要添加tomcat插件,不过web和非web项目开发是一致的,没什么差别
pom.xml中需要添加的依赖

<dependencies>
        <!--mybatis包-->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis</artifactId>
                <version>3.5.3</version>
            </dependency>
        <!--连接mysql-->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.1.47</version>
            </dependency>
        <!--spring依赖包-->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.1.9.RELEASE</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>5.1.9.RELEASE</version>
            </dependency>
        <!--线程池包-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.1.16</version>
            </dependency>
        <!--mybatis-spring整合包(主要配置)-->
            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis-spring</artifactId>
                <version>1.3.0</version>
            </dependency>
    </dependencies>

2.创建properties文件

依赖环境添加好之后,我们就可以进行项目开发了,因为要进行数据库的操作,所以我们先创建一个数据库连接配置----里面的数据库名和用户密码设置自己的
创建一个jdbc.properties文件

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_db
jdbc.username=root
jdbc.password=root

还是三层架构开发

因为没有前后端的交互,所以web层就没了,只有后端的dao层和service层

3.domain层创建实体类javabean

看看数据库里面有什么,哇,原来是这
三列,分别为id(int),name(string),money(double)–之后的案例也是用这个数据库
在这里插入图片描述
所以在domain层中创建一个实体类Account
因为只是简单介绍,里面直接添加tostring输出数据

public class Account implements Serializable {

    private Integer id;
    private String name;
    private Double money;

    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 Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}

4.dao层操作

创建了实体类,我们就可以创建dao层进行数据库操作了,在这里你想对数据库做什么就做什么
创建一个接口AccountDao,在里面我们进行对数据库的增删改查操作

public interface AccountDao {

    void save(Account account);

    void delete(Integer id);

    void update(Account account);

    List<Account> findAll();

    Account findById(Integer id);
}

这样一个简单的dao就搞定了,既然dao添加了相应方法,我们就得在对应的资源文件中进行数据库语句的添加

5.resources中对应dao配置文件添加

dao在哪我在哪,dao有啥我有啥
在resources对应dao层也搞一个对应AccountDao接口的AccountDao.xml文件,其实并不需要这样那样的,不过为了后续业务扩展更新,做成这样对应相应修改很直观简便,做项目架构很重要.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dou.dao.AccountDao">

    <!--配置根据id查询-->
    <select id="findById" resultType="account" parameterType="int">
        select * from spring where id = #{id}
    </select>

    <!--配置查询所有-->
    <select id="findAll" resultType="account">
        select * from spring
    </select>

    <!--配置保存-->
    <insert id="save" parameterType="account">
        insert into spring(name,money)values(#{name},#{money})
    </insert>

    <!--配置删除-->
    <delete id="delete" parameterType="int">
        delete from spring where id = #{id}
    </delete>

    <!--配置根据名称查询-->
    <select id="findByName" resultType="account" parameterType="string">
        select * from spring where name = #{name}
    </select>
    <!--配置更新-->
    <update id="update" parameterType="account">
        update spring set name=#{name},money=#{money} where id=#{id}
    </update>
</mapper>

6.业务层service开发

dao层搞好了,对应数据库连接也搞好了,接着就是业务层实现了,业务层怎么搞呢,
先做业务接口创建对应方法, 然后进行Impl业务逻辑实现
创建AccountService接口:

public interface AccountService {

    void save(Account account);

    void delete(Integer id);

    void update(Account account);

    List<Account> findAll();

    Account findById(Integer id);
}

然后在业务层中创建包Impl,这个主要是区分一下方法和实现,在Impl下创建AccountServiceImpl实现类,继承AccountService接口
因为没交互,所以…极其简单

public class AccountServiceImpl implements AccountService {

    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public void save(Account account) {
    accountDao.save(account);
    }

    public void update(Account account){
     accountDao.update(account);
    }

    public void delete(Integer id) {
    accountDao.delete(id);
    }

    public Account findById(Integer id) {
      return  accountDao.findById(id);
    }

    public List<Account> findAll() {
       return  accountDao.findAll();
    }
}

7.spring环境配置文件

数据库也连接了,实现类也实现了,然后把spring的环境配置好就可以进行应用了
在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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
">

    <!--加载配置文件 *号是是个properties文件我就加载-->
    <context:property-placeholder location="classpath:*.properties"/>

    <!--数据库信息-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!--配置service作为spring的bean,注入dao-->
    <bean id="accountService" class="com.dou.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"/>
    </bean>

    <!--spring整合mybatis后控制创建连接的对象-->
    <bean  class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据库连接-->
        <property name="dataSource" ref="dataSource"/>
        <!--domain起别名-->
        <property name="typeAliasesPackage" value="com.dou.domain"/>
    </bean>

    <!--//扫描org.mybatis.spring.sample.mapper下的所有接口(各种增删改查等),然后创建各自接口的动态代理类。-->
    <bean  class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.dou.dao"/>
    </bean>

</beans>

里面是什么东西呢,就是以前maven项目中mapper映射文件里面的内容,可以对比一下,一毛一样(对比代码)

**maven----**
    <!--定义property的配置-->
    <properties resource="jdbc.properties"></properties>
**spring----**
<!--加载配置文件-->
    <context:property-placeholder location="classpath:*.properties"/>
    
**maven----**
    <!--配置别名:别名配置是给实体类用的,不能用在dao上-->
    <typeAliases>
        <!--指定实体类所在的包,此时包下所有类都会注册别名,别名就是类名称-->
        <package name="com.itheima.domain"></package>
    </typeAliases>
**spring----**
<!--domain起别名-->
        <property name="typeAliasesPackage" value="com.dou.domain"/>
        
**maven----**
    <!--配置默认环境-->
    <environments default="mysql">
        <!--配置mysql的环境-->
        <environment id="mysql">
            <!--配置事务的类型-->
            <transactionManager type="JDBC"></transactionManager>
            <!--配置数据源信息-->
            <dataSource type="POOLED" >
                <!--配置连接数据库的四个基本信息-->
                <property name="driver" value="${jdbc.driver}"></property>
                <property name="url" value="${jdbc.url}"></property>
                <property name="username" value="${jdbc.username}"></property>
                <property name="password" value="${jdbc.password}"></property>
            </dataSource>
        </environment>
    </environments>
**spring----**
<!--数据库信息-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>


**maven----**
    <!--配置映射配置文件的位置-->
    <mappers>
        <!--指定实体映射配置文件所在的包,指定的是dao接口所在的包-->
        <package name="com.itheima.dao"></package>
    </mappers>
 **spring----**
 <!--//扫描org.mybatis.spring.sample.mapper下的所有接口(各种增删改查等),然后创建各自接口的动态代理类。-->
    <bean  class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.dou.dao"/>
    </bean>

8.运行一下子

配置结束,随便写个main实现一下就行
在java下创建一个App类去连接配置文件,调用其中的方法,看看是不是实现了

public class App {
    public static void main(String[] args) {
        //连接配置文件
        ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取对应Dao接口bean,类型需要强转为服务层接口类
        AccountService accountService= (AccountService) ctx.getBean("accountService");
        
        
//方法实现:
        //查看
        List<Account> all1 = accountService.findAll();
        System.out.println(all1);

        //保存
        Account account = new Account(2,"张飞",33.3);
        accountService.save(account);

        //单个查看
        Account ac1 = accountService.findById(2);
        System.out.println(ac1);

        //修改4,名字变成寒蝉
        account.setName("寒蝉");
        accountService.update(account);

        //单个查看
        Account ac2 = accountService.findById(2);
        System.out.println(ac2);

        //删除
        accountService.delete(2);

        //查看
        List<Account> all2 = accountService.findAll();
        System.out.println(all2);
    }
}

2.纯注解开发型

在这里插入图片描述

注释使我们人能看懂的
注解就是计算机能看懂的语言,用了注解计算机会自动判断识别并进行操作,简化代码

1.pom.xml添加依赖

这个是跟基础类型的依赖相同的,没有特殊添加,因为第一个把maven整合spring依赖加进去了,基础版是不需要的,主要是用于添加一些注解的

2.配置文件转换为配置类

配置文件全部以注解形式体现,注解就是为了消除配置文件,把resources中的文件全部消除

比如AccountDao.xml中的文件,是连接dao和数据库的窗口:

<!--配置根据id查询-->
    <select id="findById" resultType="account" parameterType="int">
        select * from spring where id = #{id}
    </select>

    <!--配置查询所有-->
    <select id="findAll" resultType="account">
        select * from spring
    </select>

    <!--配置保存-->
    <insert id="save" parameterType="account">
        insert into spring(id,name,money)values(#{id},#{name},#{money})
    </insert>

    <!--配置删除-->
    <delete id="delete" parameterType="int">
        delete from spring where id = #{id}
    </delete>

    <!--配置根据名称查询-->
    <select id="findByName" resultType="account" parameterType="string">
        select * from spring where name = #{name}
    </select>
    <!--配置更新-->
    <update id="update" parameterType="account">
        update spring set name=#{name},money=#{money} where id=#{id}
    </update>

这些语句不用再创建类,直接用以前maven项目经验,在AccountDao接口中直接注解在接口方法上(没有什么好坏的说法,都一个熊样)

public interface AccountDao {

    @Insert("insert into spring (id,name,monry) values(#{id},#{name},#{monry})")
    void save(Account account);

    @Delete("delete from spring where id = #{id}")
    void delete(Integer id);

    @Update("update spring set name=#{name},money=#{money} where id=#{id}")
    void update(Account account);

    @Select("select * from spring")
    List<Account> findAll();

    @Select("select * from spring where id=#{id}")
    Account findById(Integer id);
}

然后是jdbc.properties文件了,里面是连接的数据库信息:

 jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_db
jdbc.username=root
jdbc.password=root

这个文件比较特殊,所以就另外创建配置类添加信息
比如创建一个包config专门存放java配置类
然后在config包下创建一个JDBCConfig类,存放连接数据库的信息

public class JDBCConfig {
    //value设置对应属性的值(或对方法)进行传参
    @Value("com.mysql.jdbc.Driver")
    private  String driver;
    @Value("jdbc:mysql://localhost:3306/spring_db")
    private  String url;
    @Value("root")
    private  String username;
    @Value("root")
    private  String password;

//设置该方法的返回值作为spring管理的bean,作用:连接数据库
    @Bean("dataSource")
    public DataSource DataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(username);
        ds.setPassword(password);
        return ds;
    }
}

然后就是重点了,applicationContext.xml文件就不需要了,直接转换:


 <!--加载配置文件-->           --不需要这个文件了,转换成配置类了,会直接在主配置类中加载
    <context:property-placeholder location="classpath:*.properties"/>

    <!--数据库信息-->           --这个就转换到JDBCConfig类中                   
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>

    </bean>                   --                  
    <!--配置service作为spring的bean,注入dao-->        
    <!--现在@Service("accountService")@Autowired private AccountDao accountDao就可以实现引入类型注入,set方法也就不需要了;-->
    <bean id="accountService" class="com.dou.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"/>
    </bean>

    <!--spring整合mybatis后控制创建连接的对象-->  --数据库连接也已经放进JDBCConfig配置类中去了
    <bean  class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--数据库连接-->
        <property name="dataSource" ref="dataSource"/>
        <!--domain起别名-->   --放进了MyBatisConfig
        <property name="typeAliasesPackage" value="com.dou.domain"/>
    </bean>

    <!--//扫描org.mybatis.spring.sample.mapper下的所有接口(各种增删改查等),然后创建各自接口的动态代理类。-->                     
--也放进了MyBatisConfig
    <bean  class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.dou.dao"/>
    </bean>
</beans>

转换成注解的话先在config包下创建一个核心配置类,例如SpringConfig,使用注解时要先在核心配置类添加@Configuration,设置项目开发为纯注解格式,设置当前类为spring核心配置加载类,其他次要第三方类直接集合形式导入,第三方类就例如JDBCCofig类,还有创建一个例如MyBatisConfig类,里面存放applicationContext中特殊形式的的信息,比如起别名和扫描dao下所有接口的信息,单独存放在一个配置类中,不破坏已有架构文件的结构

MyBatisConfig类:
重点之一,里面方法上注解为Bean,就是在运行时会被扫描器所扫描到的方法

public class MyBatisConfig {

  //消灭Xml文件(方法注解)--后续扫描
    @Bean
    public SqlSessionFactoryBean getSqlSessionFactory(@Autowired DataSource dataSource){
        SqlSessionFactoryBean ssfb=new SqlSessionFactoryBean();
        ssfb.setTypeAliasesPackage("com.dou.domain");
        ssfb.setDataSource(dataSource);
        return  ssfb;
    }
    @Bean
    public MapperScannerConfigurer getMapperScannerConfigurer(){
        MapperScannerConfigurer msc=new MapperScannerConfigurer();
        msc.setBasePackage("com.dou.dao");
        return  msc;
    }
}

然后就是SpringConfig配置类(特别重要):
这里设置为主配置类,因为写的东西特别少,所以里面并没有什么东西,在后续的开发中,如果需要什么配置可以直接填充,很方便.

//设置纯注解格式--设置当前类为spring核心配置加载类,其他次要第三方类直接集合形式导入
@Configuration
//bean扫描注解,扫描路径看仔细,是最上层路径*(替代context扫描)
@ComponentScan("com.dou")

//加载properties文件,就是咱们常用的jdbc配置文件
//这个东西可以引入,或者直接建一个config配置类导入,下面就是用的直接导入import
/*@PropertySource("classpath:jdbc.properties")*/


@Import({JDBCConfig.class,MyBatisConfig.class})
public class SpringConfig {
}

三层架构包

跟基础型开发差不多,多理解就感觉一毛一样,直接贴代码了

3.dao层

AccountDao

public interface AccountDao {

    @Insert("insert into spring (id,name,money) values(#{id},#{name},#{money})")
    void save(Account account);

    @Delete("delete from spring where id = #{id}")
    void delete(Integer id);

    @Update("update spring set name=#{name},money=#{money} where id=#{id}")
    void update(Account account);

    @Select("select * from spring")
    List<Account> findAll();

    @Select("select * from spring where id=#{id}")
    Account findById(Integer id);
}

4.service层

包括service接口和service实现类,一毛一样

AccountService接口

public interface AccountService {

    void save(Account account);

    void delete(Integer id);

    void update(Account account);

    List<Account> findAll();

    Account findById(Integer id);

}

Impl包下的业务实现类AccountServiceImpl

//component同样适用 设置该类为spring管理的bean
@Service("accountService")
public class AccountServiceImpl implements AccountService {

    //设置对应属性的对象(或对方法)进行引用类型注入,以前用set注入,现在不需要了(参数)
    @Autowired
    private AccountDao accountDao;

    public void save(Account account) {
    accountDao.save(account);
    }

    public void update(Account account){
     accountDao.update(account);
    }

    public void delete(Integer id) {
    accountDao.delete(id);
    }

    public Account findById(Integer id) {
      return  accountDao.findById(id);
    }

    public List<Account> findAll() {
       return  accountDao.findAll();
    }
}

5.还是实现一下

实现类中原本是用ClassPathXmlApplicationContext加载xml配置文件,现在注解形式不需要xml文件,直接加载主要配置类文件SpringConfig,使用AnnotationConfigApplicationContext加载

 public static void main(String[] args) {
        //xml配置加载ClassPathXmlApplicationContext
       /* ApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
        AccountService accountService= (AccountService) ctx.getBean("accountService");
        Account ac = accountService.findById(1);
        System.out.println(ac);*/

       //配置文件类SpringConfig加载*(纯注解格式文件加载,跟加载xml配置文件不一样,为AnnotationConfigApplicationContext)
       ApplicationContext ctx=new AnnotationConfigApplicationContext(SpringConfig.class);
        AccountService accountService= (AccountService) ctx.getBean("accountService");

        //剩下的这是功能实现
        //方法实现:
        //查看
        List<Account> all1 = accountService.findAll();
        System.out.println(all1);

        //保存
        Account account = new Account(2,"张飞",33.3);
        accountService.save(account);

        //单个查看
        Account ac1 = accountService.findById(2);
        System.out.println(ac1);

        //修改4,名字变成寒蝉
        account.setName("寒蝉");
        accountService.update(account);

        //单个查看
        Account ac2 = accountService.findById(2);
        System.out.println(ac2);

        //删除
        accountService.delete(2);

        //查看
        List<Account> all2 = accountService.findAll();
        System.out.println(all2);
    }
}

注解结束!!感谢我自己,谢谢谢谢,又浪费了时间,谢谢你

Aop开发

Aop开发好处很明显,解耦,减少内存使用,每段代码只需要把特有功能添加上去就可以了,公共功能可以设置before、after使用,也可以添加异常输出等等…也可以设置around,按源代码顺序去实现,

1.依赖添加

只需要在pom.xml中添加一个Aop依赖就行了

<!--导入Aop坐标-->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>

2.改写注解项目实现AOP

改写时候不需要修改任何注解时的代码,只需要添加共性功能就行,代码太少不需要抽取什么东西
重点:在主要配置类SpringConfig中添加一个注解@EnableAspectJAutoProxy,设置开启AOP注解驱动的支持

@Configuration
@ComponentScan("com.dou")
/*@PropertySource("classpath:jdbc.properties")*/
@Import({JDBCConfig.class,MyBatisConfig.class})

//设置当前类开启AOP注解驱动的支持,加载AOP注解--重点
@EnableAspectJAutoProxy
public class SpringConfig {
}

3.添加AOP类

创建一个AOP的包,在里面添加aop方法
在AOP包下创建一个类RunTimeMonitorAdvice

//主--设置该类为spring管理的bean
@Component
//设置当前类为切面类
@Aspect
public class RunTimeMonitorAdvice {

    //切入点,监控业务层接口,Service结尾方法
    @Pointcut("execution(* com.dou.service.*Service.*(..))")
    public void pt(){}

    //所有注解必须加pt()方法,不然默认无切入
    //业务模块代码执行之前执行
    @Before("pt()")
    public void  before(){
        System.out.println("有业务我就开始");
    }

    //该注解标注的方法在业务模块代码执行之后执行
    //@AfterThrowing这个差不多的是报错执行,不写了
    @AfterReturning("pt()")
    public  void afterreturning(){
        System.out.println("这个业务代码执行完了");
    }

    //在所有的Advice执行完成后执行,类似finally
    @After("pt()")
    public void after(){
        System.out.println("这个执行完了");
    }

    //环绕通知,用于调用业务模块的代码,--重点,切入是一个一个方法切入,不是一次全部方法切入
    // 无论是调用前逻辑还是调用后逻辑,都可以在该方法中编写,
    // 甚至其可以根据一定的条件而阻断业务模块的调用;
    @Around("pt()")
    public Object runtimeAround(ProceedingJoinPoint pjp) throws Throwable {
        //获取执行签名信息
        Signature signature = pjp.getSignature();
        //通过签名获取执行类型(接口名)
        String className = signature.getDeclaringTypeName();
        //通过签名获取执行操作名称(方法名)
        String methodName = signature.getName();

        //这行代码是重点,调用业务层方法进行执行,没有它就没有新世界
        Object ret = pjp.proceed(pjp.getArgs());
        System.out.println(ret);

        //执行时长累计值
        long sum = 0L;
            //获取操作前系统时间beginTime
            long startTime = System.currentTimeMillis();
            /*//原始操作调用--傻帽操作,谁写的
            pjp.proceed(pjp.getArgs());*/
            //获取操作后系统时间endTime
            long endTime = System.currentTimeMillis();
            sum += endTime-startTime;

        //打印信息
        System.out.println(className+":"+methodName+"执行时间run:"+sum+"ms");
        return ret;
    }
}

@before和@after他们是内部执行
App的main方法输出是在最最后的,不要搞混了

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值