AOP 与 Spring中AOP使用(下)

AOP通知类型

前置通知

在目标方法执行之前进行操作

UserDao.java

public class UserDao {
    public void add(){
        System.out.println("添加用户");
    }
}

切面类 MyAspect.java

public class MyAspect {
    public void check(){
        System.out.println("权限校验");
    }
}

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:aop="http://www.springframework.org/schema/aop"
       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.xsd">

    <bean id="userDao" class="com.xzh.spring.demo4.UserDao"/>
    <bean id="myAspect" class="com.xzh.spring.demo4.MyAspect"/>
    <!--配置AOP-->
    <aop:config>
        <!--切点:给那个方法做增强-->
        <aop:pointcut id="point1" expression="execution(* com.xzh.spring.demo4.UserDao.add(..))"/>
        <!--配置切面:增强的功能是什么-->
        <aop:aspect ref="myAspect">
            <!--前置通知-->
            <aop:before method="check" pointcut-ref="point1"/>
        </aop:aspect>
    </aop:config>
</beans>

AOP测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
    @Resource(name = "userDao")
    private UserDao userDao;
    @Test
    public void test() {
        this.userDao.add();
    }
}

后置通知

在目标方法执行之后 进行操作

UserDao.java

public class UserDao {
    public void add(){
        System.out.println("添加用户");
    }

    public void update(){
        System.out.println("更新用户");
    }
}

切面类 MyAspect.java

public class MyAspect {
    public void check(){
        System.out.println("权限校验");
    }

    public void log(){
        System.out.println("日志记录");
    }
}

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:aop="http://www.springframework.org/schema/aop"
       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.xsd">

    <bean id="userDao" class="com.xzh.spring.demo4.UserDao"/>
    <bean id="myAspect" class="com.xzh.spring.demo4.MyAspect"/>
    <!--配置AOP-->
    <aop:config>
        <!--切点:给那个方法做增强-->
        <aop:pointcut id="point1" expression="execution(* com.xzh.spring.demo4.UserDao.add(..))"/>
        <aop:pointcut id="point2" expression="execution(* com.xzh.spring.demo4.UserDao.update(..))"/>
        <!--配置切面:增强的功能是什么-->
        <aop:aspect ref="myAspect">
            <!--前置通知-->
            <aop:before method="check" pointcut-ref="point1"/>
            <!--后置通知-->
            <aop:after-returning method="log" pointcut-ref="point2"/>
        </aop:aspect>
    </aop:config>
</beans>

AOP测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
    @Resource(name = "userDao")
    private UserDao userDao;
    @Test
    public void test() {
        this.userDao.update();
    }
}
后置通知获取切入点的返回值

UserDao.java

public class UserDao {
    public void add(){
        System.out.println("添加用户");
    }

    public String update(){
        System.out.println("更新用户");
        return "更新成功!";
    }
}

切面类 MyAspect.java

public class MyAspect {
    public void check(){
        System.out.println("权限校验");
    }

    public void log(Object res){
        System.out.println("日志记录:" + res);
    }
}

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:aop="http://www.springframework.org/schema/aop"
       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.xsd">

    <bean id="userDao" class="com.xzh.spring.demo4.UserDao"/>
    <bean id="myAspect" class="com.xzh.spring.demo4.MyAspect"/>
    <!--配置AOP-->
    <aop:config>
        <!--切点:给那个方法做增强-->
        <aop:pointcut id="point1" expression="execution(* com.xzh.spring.demo4.UserDao.add(..))"/>
        <aop:pointcut id="point2" expression="execution(* com.xzh.spring.demo4.UserDao.update(..))"/>
        <!--配置切面:增强的功能是什么-->
        <aop:aspect ref="myAspect">
            <!--前置通知-->
            <aop:before method="check" pointcut-ref="point1"/>
            <!--后置通知-->
            <aop:after-returning method="log" pointcut-ref="point2" returning="res"/>
        </aop:aspect>
    </aop:config>
</beans>

AOP测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
    @Resource(name = "userDao")
    private UserDao userDao;
    @Test
    public void test() {
        this.userDao.update();
    }
}

环绕通知

在目标方法执行之前 和之后进行操作

UserDao.java

public class UserDao {
    public void add(){
        System.out.println("添加用户");
    }

    public String update(){
        System.out.println("更新用户");
        return "更新成功!";
    }

    public void delete(){
        System.out.println("删除用户");
    }
}

切面类 MyAspect.java

public class MyAspect {
    public void check(){
        System.out.println("权限校验");
    }

    public void log(Object res){
        System.out.println("日志记录:" + res);
    }

    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("开启事务");
        Object proceed = joinPoint.proceed();
        System.out.println("提交事务");
        return proceed;
    }
}

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:aop="http://www.springframework.org/schema/aop"
       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.xsd">

    <bean id="userDao" class="com.xzh.spring.demo4.UserDao"/>
    <bean id="myAspect" class="com.xzh.spring.demo4.MyAspect"/>
    <!--配置AOP-->
    <aop:config>
        <!--切点:给那个方法做增强-->
        <aop:pointcut id="point1" expression="execution(* com.xzh.spring.demo4.UserDao.add(..))"/>
        <aop:pointcut id="point2" expression="execution(* com.xzh.spring.demo4.UserDao.update(..))"/>
        <aop:pointcut id="point3" expression="execution(* com.xzh.spring.demo4.UserDao.delete(..))"/>
        <!--配置切面:增强的功能是什么-->
        <aop:aspect ref="myAspect">
            <!--前置通知-->
            <aop:before method="check" pointcut-ref="point1"/>
            <!--后置通知-->
            <aop:after-returning method="log" pointcut-ref="point2" returning="res"/>
            <!--环绕通知-->
            <aop:around method="around" pointcut-ref="point3"/>
        </aop:aspect>
    </aop:config>
</beans>

AOP测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
    @Resource(name = "userDao")
    private UserDao userDao;
    @Test
    public void test() {
        this.userDao.delete();
    }
}

异常抛出通知

在程序出现异常时进行操作

UserDao.java

public class UserDao {
    public void add(){
        System.out.println("添加用户");
    }

    public String update(){
        System.out.println("更新用户");
        return "更新成功!";
    }

    public void delete(){
        System.out.println("删除用户");
    }

    public void find(){
        System.out.println("查找用户");
        int i = 1 / 0;
    }
}

切面类 MyAspect.java

public class MyAspect {
    public void check(){
        System.out.println("权限校验");
    }

    public void log(Object res){
        System.out.println("日志记录:" + res);
    }

    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("开启事务");
        Object proceed = joinPoint.proceed();
        System.out.println("提交事务");
        return proceed;
    }

    public void exceptionMethod(){
        System.out.println("有异常");
    }
}

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:aop="http://www.springframework.org/schema/aop"
       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.xsd">

    <bean id="userDao" class="com.xzh.spring.demo4.UserDao"/>
    <bean id="myAspect" class="com.xzh.spring.demo4.MyAspect"/>
    <!--配置AOP-->
    <aop:config>
        <!--切点:给那个方法做增强-->
        <aop:pointcut id="point1" expression="execution(* com.xzh.spring.demo4.UserDao.add(..))"/>
        <aop:pointcut id="point2" expression="execution(* com.xzh.spring.demo4.UserDao.update(..))"/>
        <aop:pointcut id="point3" expression="execution(* com.xzh.spring.demo4.UserDao.delete(..))"/>
        <aop:pointcut id="point4" expression="execution(* com.xzh.spring.demo4.UserDao.find(..))"/>
        <!--配置切面:增强的功能是什么-->
        <aop:aspect ref="myAspect">
            <!--前置通知-->
            <aop:before method="check" pointcut-ref="point1"/>
            <!--后置通知-->
            <aop:after-returning method="log" pointcut-ref="point2" returning="res"/>
            <!--环绕通知-->
            <aop:around method="around" pointcut-ref="point3"/>
            <!--异常抛出通知-->
            <aop:after-throwing method="exceptionMethod" pointcut-ref="point4"/>
        </aop:aspect>
    </aop:config>
</beans>

AOP测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
    @Resource(name = "userDao")
    private UserDao userDao;
    @Test
    public void test() {
        this.userDao.find();
    }
}
异常抛出通知获取异常信息

UserDao.java

public class UserDao {
    public void add(){
        System.out.println("添加用户");
    }

    public String update(){
        System.out.println("更新用户");
        return "更新成功!";
    }

    public void delete(){
        System.out.println("删除用户");
    }

    public void find(){
        System.out.println("查找用户");
        int i = 1 / 0;
    }
}

切面类 MyAspect.java

public class MyAspect {
    public void check(){
        System.out.println("权限校验");
    }

    public void log(Object res){
        System.out.println("日志记录:" + res);
    }

    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("开启事务");
        Object proceed = joinPoint.proceed();
        System.out.println("提交事务");
        return proceed;
    }

    public void exceptionMethod(Throwable ex){
        System.out.println("有异常:" + ex.getMessage());
    }
}

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:aop="http://www.springframework.org/schema/aop"
       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.xsd">

    <bean id="userDao" class="com.xzh.spring.demo4.UserDao"/>
    <bean id="myAspect" class="com.xzh.spring.demo4.MyAspect"/>
    <!--配置AOP-->
    <aop:config>
        <!--切点:给那个方法做增强-->
        <aop:pointcut id="point1" expression="execution(* com.xzh.spring.demo4.UserDao.add(..))"/>
        <aop:pointcut id="point2" expression="execution(* com.xzh.spring.demo4.UserDao.update(..))"/>
        <aop:pointcut id="point3" expression="execution(* com.xzh.spring.demo4.UserDao.delete(..))"/>
        <aop:pointcut id="point4" expression="execution(* com.xzh.spring.demo4.UserDao.find(..))"/>
        <!--配置切面:增强的功能是什么-->
        <aop:aspect ref="myAspect">
            <!--前置通知-->
            <aop:before method="check" pointcut-ref="point1"/>
            <!--后置通知-->
            <aop:after-returning method="log" pointcut-ref="point2" returning="res"/>
            <!--环绕通知-->
            <aop:around method="around" pointcut-ref="point3"/>
            <!--异常抛出通知-->
            <aop:after-throwing method="exceptionMethod" pointcut-ref="point4" throwing="ex"/>
        </aop:aspect>
    </aop:config>
</beans>

AOP测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
    @Resource(name = "userDao")
    private UserDao userDao;
    @Test
    public void test() {
        this.userDao.find();
    }
}

最终通知

无论代码是否有异常,都会执行

UserDao.java

public class UserDao {
    public void add(){
        System.out.println("添加用户");
    }

    public String update(){
        System.out.println("更新用户");
        return "更新成功!";
    }

    public void delete(){
        System.out.println("删除用户");
    }

    public void find(){
        System.out.println("查找用户");
        int i = 1 / 0;
    }
}

切面类 MyAspect.java

public class MyAspect {
    public void check(){
        System.out.println("权限校验");
    }

    public void log(Object res){
        System.out.println("日志记录:" + res);
    }

    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("开启事务");
        Object proceed = joinPoint.proceed();
        System.out.println("提交事务");
        return proceed;
    }

    public void exceptionMethod(Throwable ex){
        System.out.println("有异常:" + ex.getMessage());
    }

    public void after(){
        System.out.println("最终通知");
    }
}

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:aop="http://www.springframework.org/schema/aop"
       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.xsd">

    <bean id="userDao" class="com.xzh.spring.demo4.UserDao"/>
    <bean id="myAspect" class="com.xzh.spring.demo4.MyAspect"/>
    <!--配置AOP-->
    <aop:config>
        <!--切点:给那个方法做增强-->
        <aop:pointcut id="point1" expression="execution(* com.xzh.spring.demo4.UserDao.add(..))"/>
        <aop:pointcut id="point2" expression="execution(* com.xzh.spring.demo4.UserDao.update(..))"/>
        <aop:pointcut id="point3" expression="execution(* com.xzh.spring.demo4.UserDao.delete(..))"/>
        <aop:pointcut id="point4" expression="execution(* com.xzh.spring.demo4.UserDao.find(..))"/>
        <!--配置切面:增强的功能是什么-->
        <aop:aspect ref="myAspect">
            <!--前置通知-->
            <aop:before method="check" pointcut-ref="point1"/>
            <!--后置通知-->
            <aop:after-returning method="log" pointcut-ref="point2" returning="res"/>
            <!--环绕通知-->
            <aop:around method="around" pointcut-ref="point3"/>
            <!--异常抛出通知-->
            <aop:after-throwing method="exceptionMethod" pointcut-ref="point4" throwing="ex"/>
            <!--最终通知-->
            <aop:after method="after" pointcut-ref="point4"/>
        </aop:aspect>
    </aop:config>
</beans>

AOP测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
    @Resource(name = "userDao")
    private UserDao userDao;
    @Test
    public void test() {
        this.userDao.find();
    }
}

AOP切入点表达式

  • 基于execution函数完成

execution语法:

【访问修饰符】 方法返回值 包名.类名.方法名(参数)
public com.myxq.demo2.GoodsDaoImpl.save(..)     // 参数为任意参数

* com.myxq.demo2.GoodsDaoImpl.save(..)       // * 为任意类型

* com.myxq.demo2.GoodsDaoImpl+.save(..)      // + 当前类和子类

* com.myxq..*.*(..)                   // com.myxq包以及子包下面所有类的所有方法

AOP注解方式ApsectJ开发

GoodsDao 接口:

public interface GoodsDao {
    public void save();
    public String update();
    public void delete();
    public void find();
}

GoodsDao 实现类 GoodsDaoImpl:

public class GoodsDaoImpl implements GoodsDao {
    @Override
    public void save() {
        System.out.println("保存操作");
    }

    @Override
    public String update() {
        System.out.println("更新操作");
        return "更新完成";
    }

    @Override
    public void delete() {
        System.out.println("删除操作");
    }

    @Override
    public void find() {
        System.out.println("查询操作");
        int i = 1 / 0;
    }
}

1. 引入Jar包

1472533-20190512153230259-549434903.png

2. 引入配置文件

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:aop="http://www.springframework.org/schema/aop"
       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.xsd">

</beans>

3. 编写切面类配置

public class GoodsDaoAspect {
    public void log(){
        System.out.println("前置增强");
    }
}

将切面类交给 spring 管理,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:aop="http://www.springframework.org/schema/aop"
       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.xsd">

    <bean id="goodsDao" class="com.xzh.spring.demo5.GoodsDaoImpl"/>
    <bean id="goodsAspect" class="com.xzh.spring.demo5.GoodsDaoAspect"/>

</beans>

4. 使用注解的AOP对象目标类进行增强

在配置文件 applicationContext.xml 中开启以注解形式进行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"
       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.xsd">
    <!--AOP配置开启注解-->
    <aop:aspectj-autoproxy/>

    <bean id="goodsDao" class="com.xzh.spring.demo5.GoodsDaoImpl"/>
    <bean id="goodsAspect" class="com.xzh.spring.demo5.GoodsDaoAspect"/>

</beans>
在切面类上添加注解
@Aspect
public class GoodsDaoAspect {
    @Before(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.save(..))")
    public void before(){
        System.out.println("前置增强");
    }
}
测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class GoodsTest {
    @Resource(name = "goodsDao")
    private GoodsDao goodsDao;
    @Test
    public void test(){
        this.goodsDao.save();
    }
}

5. 注解AOP通知类型

@Before 前置通知

切面类:

@Aspect
public class GoodsDaoAspect {
    @Before(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.save(..))")
    public void before(){
        System.out.println("前置增强");
    }
}
@AfterReturning 后置通知

(1)没有返回值

切面类:

@Aspect
public class GoodsDaoAspect {
    @AfterReturning(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.update(..))")
    public void afterReturning(){
        System.out.println("后置通知");
    }
}

(2)有返回值

切面类:

@Aspect
public class GoodsDaoAspect {
    @AfterReturning(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.update(..))", returning = "res")
    public void afterReturning(Object res){
        System.out.println("后置通知" + res);
    }
}

1472533-20190512153240090-929795259.png

@Around 环绕通知

切面类:

@Aspect
public class GoodsDaoAspect {
    @Around(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.delete(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("开启事务");
        Object proceed = joinPoint.proceed();
        System.out.println("提交事务");
        return proceed;
    }
}
@AfterThrowing 异常抛出通知

(1)没有获取异常信息

切面类:

@Aspect
public class GoodsDaoAspect {
    @AfterThrowing(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.find(..))")
    public void afterThrowing(){
        System.out.println("异常通知");
    }
}

(2)获取异常信息

切面类:

@Aspect
public class GoodsDaoAspect {
    @AfterThrowing(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.find(..))", throwing = "ex")
    public void afterThrowing(Throwable ex){
        System.out.println("异常通知" + ex.getMessage());
    }
}
@After 最终通知

无论代码是否有异常,都会执行

切面类:

@Aspect
public class GoodsDaoAspect {
    @After(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.find(..))")
    public void after(){
        System.out.println("最终通知");
    }
}

6. 定义多个切入点

一个通知同时定义到多个方法当中

@Aspect
public class GoodsDaoAspect {
    @Before(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.save(..)) || execution(* com.xzh.spring.demo5.GoodsDaoImpl.delete(..))")
    public void before (){
        System.out.println("前置通知");
    }
}

7. AOP的注解切入点的配置

可以在切面当中定义好切入点,在通知当中直接使用定义好的切入点表达式

@Aspect
public class GoodsDaoAspect {
    @Before(value = "GoodsDaoAspect.pointSave() || GoodsDaoAspect.pointDelete()")
    public void before (){
        System.out.println("前置通知");
    }

    @Pointcut(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.save(..))")
    private void pointSave(){}  // 写一个空方法,相等于给切点起别名

    @Pointcut(value = "execution(* com.xzh.spring.demo5.GoodsDaoImpl.delete(..))")
    private void pointDelete(){}
}

8. 当使用接口时与不使用接口内部代理区别

(1)使用接口 JDK动态代理

1472533-20190512155826782-396600856.png

(2)不使用接口 CGLIB代理

1472533-20190512155830614-1409246284.png

转载于:https://www.cnblogs.com/xzh0717/p/10850929.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值