模拟Spring的AOP

基于Spring的AOP地铁乘坐服务模拟实验 一、实验目的和要求: 1.实验目的 1.掌握Spring框架的搭建过程; 2.掌握IoC、DI及其Bean的装配方式; 3.掌握AOP的相关概念及其编程思想实现; 4.掌握基于XML配置及注解方式的声明式AspectJ开发; 2.实验要求 1.完成使用Spring AOP模拟我们乘坐地铁服务中的安检(对应前置通知)、刷卡进站、乘坐及刷卡出站(对应可以是环绕通知)、运行过程中的异常(异常通知)、记录此次行程(最终通知)全过程; 2.记录本实验的过程,调试程序要记录调试过程中出现的问题及解决办法; 3.编写程序 阅读详情

模拟Spring的AOP(demo也包含了Ioc):

1.新建接口Advice

/**
 * 标识性接口,关键在于分离before、after横切关注点
 *
 * @Version 1.0
 * @Author XiaoGang
 * @Created Jan 9, 2017 10:21:01 PM
 * @Description
 *              <p>
 * @Modification
 *               <p>
 *               Date Author Version Description
 *               <p>
 *               Jan 9, 2017 XiaoGang 1.0 create file
 */
public interface Advice {

}
两个子接口:

/**
 * after 横切关注点,即在原方法调用【之后】被调用
 */
interface AfterAdvice extends Advice {

	public void after();
}

/**
 * before 横切关注点,即在原方法调用【之前】被调用
 */
interface BeforeAdvice extends Advice {

	public void before();
}

两个实现

public class LogAfterAdvice implements AfterAdvice {

	@Override
	public void after() {
		System.out.println("\n原业务方法被调用【之后】再打印日志...\n");
	}
}
/**
 * 用户自定义具体实现的before横切关注点
 */
public class LogBeforeAdvice implements BeforeAdvice {

	@Override
	public void before() {
		System.out.println("\n原业务方法被调用【之前】先打印日志...\n");
	}
}

2.创建接口ReportCreator

/**
 * /**
 * 报表生成的公共接口
 *
 * @Version 1.0
 * @Author XiaoGang
 * @Created Jan 9, 2017 10:17:41 PM
 * @Description
 *              <p>
 * @Modification
 *               <p>
 *               Date Author Version Description
 *               <p>
 *               Jan 9, 2017 XiaoGang 1.0 create file
 */
public interface ReportCreator {

	public void getHtmlReport(String path);

	public void getPdfReport(String path);
}
及其实现

/**
 * 用于根据【本地】文件路径生成报表
 */
public class LocalReportCreator {

	public LocalReportCreator() {
		// TODO Auto-generated constructor stub
	}

	public void getHtmlReport(String path) {
		System.out.println("根据【本地】文件生成【HTML】格式的报表 ...");
	}

	public void getPdfReport(String path) {
		System.out.println("根据【本地】文件生成【PDF】格式的报表 ...");
	}
}
/**
 * 用于根据【远程】文件路径生成报表
 */
public class RemoteReportCreator implements ReportCreator {

	@Override
	public void getHtmlReport(String path) {
		System.out.println("根据【远程】文件生成【HTML】格式的报表 ...");
	}

	@Override
	public void getPdfReport(String path) {
		System.out.println("根据【远程】文件生成【PDF】格式的报表 ...");
	}
}

3.创建一个工具类

/**
 * 工具类:处理配置文件中K-V对,即创建或注入bean
 */
public class BeanUtil {

	/**
	 * 利用反射进行依赖注入
	 * 
	 * @param bean
	 *            需要注入外部依赖的主体类实例
	 * @param fieldName
	 *            需要注入的字段名
	 * @param fieldRef
	 *            被注入的组件实例
	 * @throws Exception
	 */
	public static void setProperty(Object bean, String fieldName, Object fieldRef) throws Exception {

		// 获取主体类的完整名称
		final String className = getClassName(bean);

		// 获取主体类的所有 Method
		final Class beanClass = Class.forName(className);
		final Method[] methods = beanClass.getMethods();

		// 准备对应 setter()方法的完整名称
		final String setterName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1, fieldName.length());

		// 遍历找到对应 setter 方法,并调用 invoke()方法进行注入
		for (final Method m : methods) {
			if (m.getName().equals(setterName)) {
				m.invoke(bean, fieldRef);
				System.out.println("已调用 " + m.getName() + "() 向 " + className + " 注入 " + getClassName(fieldRef));
				return;
			}
		}
		System.out.println(">>注入失败: " + className + "类中不存在" + fieldName + "字段对应的setter()方法 ...");
	}

	/**
	 * 根据 Object 实例获取类的完整名称
	 */
	private static String getClassName(Object o) {
		if (o == null) {
			System.out.println("传入的 Object 实例为 null ...");
			return null;
		}
		final String fullName = o.toString();
		final String className = fullName.substring(0, fullName.indexOf("@"));
		return className;
	}
}

4.创建代理

/**
 * 代理提供者:实现invoke方法,构造具有横切关注点的动态代理对象
 */
public class ProxyHandler implements InvocationHandler {

	private Object target; // 被代理的目标对象

	private Advice beforeAdvice;// before 横切关注点

	private Advice afterAdvice; // after 横切关注点

	public ProxyHandler() {
		// 空构造方法
	}

	/**
	 * 3个setter方式的用于依赖注入
	 */
	public void setTarget(Object target) {
		this.target = target;
	}

	public void setBeforeAdvice(Advice beforeAdvice) {
		this.beforeAdvice = beforeAdvice;
	}

	public void setAfterAdvice(Advice afterAdvice) {
		this.afterAdvice = afterAdvice;
	}

	/**
	 * 实现invoke()方法,添加before、after关注点以实现AOP
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

		// 在被代理对象业务方法前后添加横切关注点方法
		aspect(beforeAdvice, "before");
		final Object result = method.invoke(target, args);
		aspect(afterAdvice, "after");

		return result;
	}

	/**
	 * 依据是否注入横切关注点来决定before、after的调用
	 */
	private void aspect(Advice advice, String aspectName) throws Exception {
		if (advice != null) {
			final Class c = advice.getClass();
			final Method[] methods = c.getMethods();
			for (final Method m : methods) {
				if (aspectName.equals(m.getName())) {
					// 以null参数调用已实现的before、after方法
					methods[0].invoke(advice, null);
				}
			}
		}
	}

	/**
	 * 静态工厂方法,用于获取已注入before、after的动态代理实例
	 */
	public Object getProxy(Object target) {
		final Class targetClass = target.getClass();
		/*
		 * loader: 目标类的类加载器 interfaces: 目标类已实现的接口 handler:
		 * 转发方法调用的调用处理类实例,这里是当前Handler
		 */
		final ClassLoader loader = targetClass.getClassLoader();
		final Class[] interfaces = targetClass.getInterfaces();

		// 创建并返回动态代理类实例
		return Proxy.newProxyInstance(loader, interfaces, this);
	}
}
5.创建代理工厂

/**
 * 工厂类:从外部读取配置信息创建并注入所需对象
 */
public class ProxyFactory {

	// 代理对象的提供者
	private ProxyHandler handler;

	// 被代理对象
	private Object target;

	// 所有组件类的集合
	private final Map<String, Object> beans;

	/**
	 * 读取外部配置文件初始化所有组件间的关系
	 */
	public ProxyFactory(String configFile) {
		beans = new HashMap<String, Object>();

		try {
			final Properties props = new Properties();
			props.load(new FileInputStream(configFile));

			// bean 声明及依赖注入的 key-value 对
			final Map<String, String> beanKV = new HashMap<String, String>();
			final Map<String, String> diKV = new HashMap<String, String>();

			for (final Map.Entry entry : props.entrySet()) {
				final String key = (String) entry.getKey();
				final String value = (String) entry.getValue();

				if (key.startsWith("Bean")) {
					beanKV.put(key, value);
				} else if (key.startsWith("DI")) {
					diKV.put(key, value);
				}
			}

			// 一定要先处理 bean 声明再进行依赖注入
			processKeyValue(beanKV);
			processKeyValue(diKV);

		} catch (final Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 处理 key-value
	 */
	private void processKeyValue(Map<String, String> map) throws Exception {
		for (final Map.Entry entry : map.entrySet()) {
			final String key = (String) entry.getKey();
			final String value = (String) entry.getValue();
			handleEntry(key, value);
		}
	}

	/**
	 * 利用工具类 BeanUtil 处理key-value对,即创建或注入bean
	 */
	private void handleEntry(String key, String value) throws Exception {
		final String[] keyParts = key.split("\\.");

		final String tag = keyParts[0];
		if ("Bean".equals(tag)) {
			// 组件定义:利用反射实例化该组件
			final Object bean = Class.forName(value).newInstance();
			System.out.println("利用反射创建对象:" + bean.getClass().getName());
			beans.put(keyParts[1], bean);

		} else if ("DI".equals(tag)) {
			// 依赖注入:获取需要bean的主体,以及被注入的实例
			final Object bean = beans.get(keyParts[1]);
			final Object fieldRef = beans.get(value);
			System.out.println("\n依赖注入目标:" + bean.getClass().getName() + ";被 注入对象:" + fieldRef.getClass().getName());
			BeanUtil.setProperty(bean, keyParts[2], fieldRef);
		}
	}

	/**
	 * 针对Factory已创建的Target获取代理对象
	 */
	public Object getProxy(String proxyName, String targetNanme) {
		final Object target = beans.get(targetNanme);
		if (target != null) {
			handler = (ProxyHandler) beans.get(proxyName);
			return handler.getProxy(target);
		}
		return null;
	}

}

6.创建一个配置文件config.properties

# define beans 
Bean.target=test.aop.report.RemoteReportCreator
Bean.targetProxy=test.aop.proxy.ProxyHandler
Bean.logBeforeAdvice=test.aop.advice.LogBeforeAdvice
Bean.logAfterAdvice=test.aop.advice.LogAfterAdvice
 
# define DI 
DI.targetProxy.target=target
DI.targetProxy.beforeAdvice=logBeforeAdvice
DI.targetProxy.afterAdvice=logAfterAdvice

7.创建测试类:

public class AOP_DI {

	public AOP_DI() {
		// TODO Auto-generated constructor stub
	}

	public static void main(String[] args) {
		// 初始化环境配置
		final ProxyFactory proxyFactory = new ProxyFactory("config.properties");
		// 获取被代理后的Target对象
		final ReportCreator reportCreator = (ReportCreator) proxyFactory.getProxy("targetProxy", "target");
		// 使用被代理后的target对象提供的服务
		reportCreator.getHtmlReport("http://code.google.com/file/...");
	}
}

测试结果:

利用反射创建对象:test.aop.proxy.ProxyHandler
利用反射创建对象:test.aop.advice.LogBeforeAdvice
利用反射创建对象:test.aop.advice.LogAfterAdvice
利用反射创建对象:test.aop.report.RemoteReportCreator

依赖注入目标:test.aop.proxy.ProxyHandler;被 注入对象:test.aop.advice.LogBeforeAdvice
已调用 setBeforeAdvice() 向 test.aop.proxy.ProxyHandler 注入 test.aop.advice.LogBeforeAdvice

依赖注入目标:test.aop.proxy.ProxyHandler;被 注入对象:test.aop.advice.LogAfterAdvice
已调用 setAfterAdvice() 向 test.aop.proxy.ProxyHandler 注入 test.aop.advice.LogAfterAdvice

依赖注入目标:test.aop.proxy.ProxyHandler;被 注入对象:test.aop.report.RemoteReportCreator
已调用 setTarget() 向 test.aop.proxy.ProxyHandler 注入 test.aop.report.RemoteReportCreator

原业务方法被调用【之前】先打印日志...

根据【远程】文件生成【HTML】格式的报表 ...

原业务方法被调用【之后】再打印日志...

一个简单的AOP就实现了,其核心就是动态代理。


转自 http://haolloyin.blog.51cto.com/1177454/476026/

Spring AOP模拟地铁乘坐服务全流程 本文还有配套的精品资源,点击获取 简介:本教程将探讨如何用Spring AOP技术模拟乘坐地铁的全过程,其中包括安检、进站、乘车、出站及异常处理等。通过AOP的面向切面编程范式,分离系统级关注点如日志、事务管理和安全性等,实现横切关注点的统一管理。教程中介绍了Spring AOP的核心概念和通知类型,包括前置通知、环绕通知、异常通知和最终通知,并通过代码示例展示了如何创建切... 阅读详情

相关推荐

模拟spring aop【一】基于jdk动态代理实现的aop

NULL 博文链接:https://johnyi.iteye.com/blog/385443

手动模拟实现Spring-AOP

Spring中AOP设计思路是这样的. 在BeaFactory.getBean()时,调用方法initBean(); 在该方法中判断当前Bean是否含有满足SpEL表达式的Method, 没有的话, 返回原始的Bean, 有的话, 会对当前Bean做动态代理, 当代理对象的方法被调用时,会发送通知到Aop拦截器,进而实现Aop的功能. 本篇文章思路接着上篇文章, (手动模拟实现Spr...

yangsnow_rain_wind的专栏 1337

Spring AOP简单模拟

模拟AOP源码 博文链接:https://senny.iteye.com/blog/466622

spring05——AspectJ开发

统治

地铁和人海 282

模拟实现spring IOC AOP的例子

模拟实现spring IOC AOP的例子,如果你是eclipse开发工具,解压直接导入就可以,别忘了,导入dom4j的jar包。

个人用java动态代理模拟实现spring aop

NULL 博文链接:https://zlx19900228.iteye.com/blog/843289

Spring-AOP实验

一.概述 AOP:(Aspect Oriented Programming)面向切面编程 OOP:(Object Oriented Programming)面向对象编程 面向切面编程:基于OOP基础之上的新的编程思想。指在程序运行期间,将某段代码动态的切入到指定方法的指定位置进行运行的这种编程方式。 二.AOP场景和JDK动态代理(AOP前奏) 怎么理解AOP,现在提出一个场景:计算器运...

努力找工作呀 2355

chapter05_aop地铁_用SpringAOP模拟乘坐地铁服务_

用Spring AOP模乘坐地铁服务中的安检(对应前置通知)、刷卡进站、乘坐及刷卡出站(对应可以是环绕通知)、运行过程中的异常(异常通知)、记录此次行程(最终通知)全过程

Spring中AOP的模拟实现

什么是AOP? 面向切面编程(AOP)完善spring的依赖注入(DI),面向切面编程在spring中主要表现为两个方面 1.面向切面编程提供声明式事务管理 2.spring支持用户自定义的切面 面向切面编程(aop)是对面向对象编程(oop)的补充, 面向对象编程将程序分解成各个层次的对象,面向切面编程将程序运行过程分解成各个切面。 AOP从程序运行角度考虑程序的结构,提

kiss_vicente的专栏 4137

FreeRTOS-Plus-CLI使用笔记

FreeRTOS-Plus-CLI使用笔记 一、简介 详细介绍可参考FreeRTOS-Plus-CLI官网地址入口 FreeRTOS+CLI(Command Line Interface, 命令行接口)提供了一种简单、小型、可扩展且RAM高效的方法,使FreeRTOS应用程序能够处理命令行输入。添加一条指令的步骤如下: 提供一个实现命令功能的函数 将命令映射到该功能函数 注册命令 运行命令解释器 命令行调试接口对于排查分析出现的问题提供了很好的接口,可以通过查看传感器信息判断传感器是否正常,可以查看内置

ApexYuan 6964

Intel Realsense windows安装与入门

realsense400系列介绍: https://www.intelrealsense.com/stereo-depth/?utm_source=intelcom_website&utm_medium=button&utm_campaign=day-to-day&utm_content=D400_learn-more_button realsense 435i介绍: ...

hanshuning的专栏 1万+

spring AOP 实现原理模拟实现

接着上篇spring IOC ,测试代码链接请到上篇文章找。 利用Java的反射与代理实现AOP 一.AOP概述       AOP(Aspect Oriented Programing),即面向切面编程,它主要用于日志记录、性能统计、安全控制、事务处理、异常处理等方面。它的主要意图就要将日志记录,性能统计,安全控制、事务处理、异常处理等等代码从业务逻辑代码中清楚地划分出来。通

丁辉-blog 2153

用PyTorch手把手搭建液态神经网络(LNN):从微分方程到无人机避障实战

本文详细介绍了如何使用PyTorch搭建液态神经网络(LNN),从微分方程基础到无人机避障实战应用。LNN通过动态时序建模和微分方程实现高效计算,特别适合多传感器数据融合场景。文章包含完整的代码实现、训练技巧及性能优化方案,帮助开发者快速掌握这一前沿技术。

uber9的博客 440

Java反射—模拟Spring的Aop

1.    大概流程   上篇文章已经结合Java反射解释了SpringAop的原理,这里我们简单模拟以下Spring的Aop实现。大体流程如下:   Ø  创建一个properties配置文件模拟Spring配置文件。   Ø  创建一个增强接口与一个实现类模拟Spring的Advice。   Ø  创建一个生成代理的工厂类,并在InvocationHandler类的invoke方法中织

大鹏 2468

Qlib数据获取避坑指南:从CSV导入到自定义数据源的完整解决方案

本文详细解析了Qlib数据获取的完整解决方案,从CSV导入到自定义数据源,涵盖了股票数据处理的关键技巧和常见陷阱。特别针对Qlib平台的数据格式要求和复权处理提供了实用指南,帮助量化投资者高效整合Wind等第三方数据源,确保数据质量与模型性能。

weixin_29047919的博客 304

PX4代码解析(1)

前言 做pixhawk飞控有一段时间了,但在学习过程中遇到许多困难,目前网上找不到比较完整的PX4学习笔记,我打算结合自己理解,写写自己对PX4源码的理解,不一定对,只是希望与各位大佬交流交流,同时梳理一下无人机知识。 目前打算分享以下几个内容:代码架构;通信协议;姿态解算算法,控制算法。先这样,后面想到再加。本章先来聊聊px4代码结构 一、代码整体结构 既然要聊px4代码结构,那就先把px4代码结构图放出来,因为px4源码仍然在不断更新迭代,因此老版本与新版本目录结构可能有些不同,我的代码解析参考版本为V

qq_36903625的博客 1万+

(Spring笔记)AOP切面编程——模拟实现AOP

AOP全称为Aspect Oriented Programming——面向切面编程,可通过运行期动态代理实现程序功能统一维护的一种技术。AOP是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。......

张松的博客 1268

西电计组实验二 运算器实验

算术逻辑运算实验 一.实验目的   1.了解简单运算器的数据传输通路。   2.验证运算功能发生器的组合功能。   3.掌握算术逻辑运算加、减、与的工作原理。   4.验证实验台运算的8位加、减、与、直通功能。   5.按给定数据,完成几种指定的算术和逻辑运算。 二.实验原理   算术逻辑单元ALU的数据通路如图2-1所示。其中运算器ALU181根据74LS181的功能用VHDL硬件描述语言编辑而成,构成8位字长的ALU。参加运算的两个8位数据分别为A[7…0]和B[7…0],运算模式由S[3…0]的16种

Polaris的博客 1万+

以注解方式模拟Spring的IoC,AOP

目录结构: @Component注解代码: package glut.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.anno

Leo's Blog 2437

2026最新贝壳二手房爬虫实战:突破极验5.0滑块验证码,完整房源数据采集方案

本文详细介绍了2026年贝壳找房爬虫技术方案,重点突破其极验5.0滑块验证码等反爬机制。文章首先解析了贝壳六大核心反爬模块,包括AI驱动的验证码、设备指纹绑定和TLS指纹识别等。针对最难破解的滑块验证码,提出了基于YOLOv11深度学习模型的缺口检测方案,准确率达99.5%,并结合人类行为轨迹模拟实现98%以上的成功率。最后设计了分布式爬虫架构,包含任务调度、代理池、验证码服务和数据清洗等模块,为大规模采集贝壳真实房源数据提供了完整解决方案。该方案在复杂反爬环境下仍保持高效稳定,具有重要的商业和研究价值。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 2054

【异常】Claude Code 第三方API 400报错(thinking type should be enabled or disabled)解决方案

摘要: Claude Code接入第三方API端点时出现400参数错误,主要因新版默认启用的Adaptive Thinking功能与旧版接口参数格式不兼容(需thinking: {type: "adaptive"},但第三方仅支持布尔值)。解决方案为修改本地settings.json配置文件,添加"CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING": "1"环境变量并重启客户端,即可恢复思考模式功能。Adaptive Th

奶爸的编程之路,也就一周冷个三天 1万+

java proxy InvocationHandler 模拟 spring aop

在学习spring的aop的时候,老师叫我们使用java的proxy和InvocationHandler来模拟spring的aop。 首先要了解什么是代理:所谓代理就是我想让小王去买包烟,但是我又不想直接通知小王,因为那样我感觉自己非常的掉价。所以我就叫小李去通知小王,让小王完成这件事。在这个过程中,我是一个主动方,小王是一个行为执行方,而小李就是一个代理。因为小李负责我和小王之间的关系,甚至小

wang735019的专栏 1378

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

spring 模拟之 aop

java探案 2017-05-16 13:01 书接上回,上一次我们介绍了spring的ioc,并对它进行了简单的模拟工作,这一次我们模拟一下aop,原理其实很简单,就是利用代理类。下面我们进行代理类的讲解 首先定义一个Handler实现InvocationHandler package com.dingjianlei.aop; import java.lang.reflect.Invoc

u011277123的博客 401

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

操作 spring 简单模拟-aop简单实现

书接上回,上一次我们介绍了spring的ioc,并对它进行了简单的模拟工作,这一次我们模拟一下aop,原理其实很简单,就是利用代理类。下面我们进行代理类的讲解 首先定义一个Handler实现InvocationHandler package com.dingjianlei.aop; import java.lang.reflect.InvocationHandler; im

工藤新一的博客 358

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

模拟spring aop【二】基于CGLIB实现的aop

基于CGLIB库模拟的简单AOP实现(前置通知部分)

john.yi 121
上一篇: 一个简单的Spring的Ioc的Demo
下一篇: 给Eclipse的工程导航视图添加自定义右键菜单
四滴火
博客等级 码龄15年 56粉丝 133原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值