SpringAOP 实例

SpringAOP详解+快速入门 本文介绍了 Spring AOP 的实现原理,并通过实例解析详细阐述了其实现过程。在使用 Spring AOP时,我们需要定义切面类,并为需要实现AOP的方法添加注解。 Spring 会自动将切面逻辑插入到这些方法中,从而实现AOP的功能。 阅读详情

一、介绍

这些天看了《Spring in Action》的第四章,讲解的是关于SpringAOP方面的,现在将自己的例子写出来。

二、AOP相关知识介绍

AOP可以做一些与业务逻辑不相关的操作,比如:日志、事务、安全等,使我们更加去关注自己的业务。

切面(Aspect) :要织入到业务上的一个类。切面是由切点和通知组成的

切点(pointcut):要执行的业务方法执行通知的一个标识。

通知(advice):切面要做的事情,比如日志记录什么的。

通知类型一般分为五种:

前置通知、后置通知、最终通知、环绕通知、异常通知

三、实例

其实我主要想写的是实例,以后能够找出来,项目是用maven构建的:

pom.xml如下: (要引入的jar)

<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.ry</groupId>
    <artifactId>CommonProject</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <groupId>com.ry</groupId>
  <artifactId>springSecurity</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
  <name>springSecurity Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <properties> <spring.version>4.2.0.RELEASE</spring.version></properties>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    
   	<dependency>  
         <groupId>org.springframework</groupId>  
         <artifactId>spring-beans</artifactId>  
         <version>${spring.version}</version>  
    </dependency>  
    <dependency>  
         <groupId>org.springframework</groupId>  
         <artifactId>spring-context</artifactId>  
         <version>${spring.version}</version>  
    </dependency>  
    <dependency>  
         <groupId>org.springframework</groupId>  
         <artifactId>spring-webmvc</artifactId>  
         <version>${spring.version}</version>  
    </dependency>  
    <dependency>  
       <groupId>org.springframework.security</groupId>  
       <artifactId>spring-security-web</artifactId>  
       <version>${spring.version}</version>  
    </dependency>  
    <dependency>  
        <groupId>org.springframework.security</groupId>  
        <artifactId>spring-security-config</artifactId>  
        <version>${spring.version}</version>  
    </dependency>  
    <dependency>  
        <groupId>jstl</groupId>  
        <artifactId>jstl</artifactId>  
        <version>1.2</version>  
    </dependency>  
    
    
    <dependency>
	    <groupId>javax.servlet</groupId>
	    <artifactId>javax.servlet-api</artifactId>
	    <version>3.0.1</version>
	    <scope>provided</scope>
	</dependency>
    
    
	    
  </dependencies>
  <build>
    <finalName>springSecurity</finalName>
  </build>
</project>

web.xml的配置文件:

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <!-- spring -->
  
  <servlet>
  	<servlet-name>springMVC</servlet-name>
  	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  	<init-param>
  		<param-name>contextConfigLocation</param-name>
  		<param-value>classpath:spring-*.xml</param-value>
  	</init-param>
  	<load-on-startup>1</load-on-startup>
  </servlet>
  
  <servlet-mapping>
  	<servlet-name>springMVC</servlet-name>
  	<url-pattern>/</url-pattern>
  </servlet-mapping>	
  

</web-app>

接下来,给出web.xml上对应的配置文件(spring-*.xml,这个文件要放在maven自动生成的resources目录下面,即:src/main/resources,我这里命名为spring-aop.xml):

spring-aop.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"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	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
	http://www.springframework.org/schema/context 
   	http://www.springframework.org/schema/context/spring-context.xsd
   	http://www.springframework.org/schema/mvc
	http://www.springframework.org/schema/mvc/spring-mvc.xsd
	">
	
	<!-- 开启springmvc注解模式 -->
	<mvc:annotation-driven />
	
	<mvc:default-servlet-handler />	
	
	
	<!-- 3.配置jsp 显示ViewResolver -->
	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/"></property>
		<property name="suffix" value=".jsp"></property>
	</bean>
	
	<!-- 扫描相关的bean -->
	<context:component-scan base-package="com.ry.controllers" />
		
	
	<bean id="advice" class="com.ry.aop.Advice" />
	<aop:config >
		<aop:aspect  ref="advice"  >
			<aop:before method="record" pointcut="execution(* com.ry.controllers.*.*(..))"/>	
		</aop:aspect>
	</aop:config>
	
</beans>	

这时,看到spring-aop.xml中定义了一个bean,这个类被作为一个切面,

创建package com.ry.aop 和com.ry.controllers,这两个package分别放Advice.class 和 TestController.class

Advice.class:

public class Advice {
	
	private final Logger logger = LoggerFactory.getLogger(Advice.class);
	
	public void record() {
		System.out.println("前置通知,执行目标方法之前");
		logger.info("前置通知,执行目标方法之前");
		
		
	}
}

TestController.class:

@Controller
@RequestMapping("test")
public class TestController {
	
	private final Logger logger = LoggerFactory.getLogger(TestController.class);
	
	@RequestMapping(value="t1")
	public String test(){
		logger.info("测试aop功能");
		return "index";
		
	}
	
}
再建一个日志文件logback.xml(与上面的spring-aop.xml放在同一个目录下)  :
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
	<!-- 定义log文件的home目录 -->
	<property name="LOG_HOME"  value="C:/Users/Administrator/Desktop/logs"></property>
	
	<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">  
        <encoder>  
            <!-- %.-1level 只显示信息级别的首字母,%-5level 左对齐显示信息级别全称 -->  
            
            <Pattern>[%date{yyyy-MM-dd HH:mm:ss}] [%-5level] --%mdc{client} %msg%n</Pattern>  
        </encoder>  
    </appender>  
    
    
    <appender name="TRACE_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">  
        <encoding>UTF-8</encoding>
        <file>${LOG_HOME}/trace.log</file>  
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <FileNamePattern>logs/trace.%d{yyyy-MM-dd}.log</FileNamePattern>  
        </rollingPolicy>  
        <layout>  
            <pattern>[%date{yyyy-MM-dd HH:mm:ss}] [%-5level] [%logger:%line] --%mdc{client} %msg%n</pattern>  
        </layout> 
       <!--  <filter class="ch.qos.logback.classic.filter.LevelFilter"> 
            <level>TRACE</level>  
            <onMatch>ACCEPT</onMatch>  
            <onMismatch>DENY</onMismatch>  
           </filter>  --> 
    </appender>
    
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">  
        <encoding>UTF-8</encoding>
        <file>${LOG_HOME}/info.log</file>  
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <FileNamePattern>logs/info.%d{yyyy-MM-dd}.log</FileNamePattern>  
        </rollingPolicy>  
        <layout>  
            <pattern>[%date{yyyy-MM-dd HH:mm:ss}] [%-5level] [%logger:%line] --%mdc{client} %msg%n</pattern>  
        </layout>
        <filter class="ch.qos.logback.classic.filter.LevelFilter"> 
            <level>INFO</level>  
            <onMatch>ACCEPT</onMatch>  
            <onMismatch>DENY</onMismatch>  
           </filter>     
    </appender>  
    
    
    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">  
        <encoding>UTF-8</encoding>
        <file>${LOG_HOME}/debug.log</file>  
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <FileNamePattern>logs/debug.%d{yyyy-MM-dd}.log</FileNamePattern>  
        </rollingPolicy>  
        <layout>  
            <pattern>[%date{yyyy-MM-dd HH:mm:ss}] [%-5level] [%logger:%line] --%mdc{client} %msg%n</pattern>  
        </layout> 
         <filter class="ch.qos.logback.classic.filter.LevelFilter"> 
            <level>DEBUG</level>  
            <onMatch>ACCEPT</onMatch>  
            <onMismatch>DENY</onMismatch>  
           </filter>   
    </appender>  
    
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">  
        <encoding>UTF-8</encoding>
        <file>${LOG_HOME}/warn.log</file>  
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <FileNamePattern>logs/warn.%d{yyyy-MM-dd}.log</FileNamePattern>  
        </rollingPolicy>  
        <layout>  
            <pattern>[%date{yyyy-MM-dd HH:mm:ss}] [%-5level] [%logger:%line] --%mdc{client} %msg%n</pattern>  
        </layout> 
         <filter class="ch.qos.logback.classic.filter.LevelFilter"> 
            <level>WARN</level>  
            <onMatch>ACCEPT</onMatch>  
            <onMismatch>DENY</onMismatch>  
           </filter>   
    </appender>  
    
     <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">  
        <encoding>UTF-8</encoding>
        <file>${LOG_HOME}/error.log</file>  
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">  
            <FileNamePattern>logs/error.%d{yyyy-MM-dd}.log</FileNamePattern>  
        </rollingPolicy>  
        <layout>  
            <pattern>[%date{yyyy-MM-dd HH:mm:ss}] [%-5level] [%logger:%line] --%mdc{client} %msg%n</pattern>  
        </layout> 
         <filter class="ch.qos.logback.classic.filter.LevelFilter"> 
            <level>ERROR</level>  
            <onMatch>ACCEPT</onMatch>  
            <onMismatch>DENY</onMismatch>  
           </filter>   
    </appender>  
    
   <!--  <logger name="com.mchange" level="INFO"/>  
    <logger name="org.springframework" level="WARN"/>  
    <logger name="java.sql.Connection" level="DEBUG"/>  
    <logger name="java.sql.ResultSet" level="INFO"/>  
    <logger name="com.boaotech.util" level="DEBUG"/>  -->
     
    <root level="TRACE">  
        <appender-ref ref="STDOUT"/>  
        <appender-ref ref="TRACE_FILE" />
           <appender-ref ref="INFO_FILE" />  
          <appender-ref ref="DEBUG_FILE" />  
         <appender-ref ref="WARN_FILE" />  
          <appender-ref ref="ERROR_FILE" />    
    </root>  
	
</configuration>

用tomcat运行项目:项目正常启动后

打开浏览器输入: http://localhost:8080/项目名/test/t1 ,点击输入后

控制台会输出相应的内容:


四、编写代码时遇到的问题:

控制台报错:

ClassNotFoundException :org.springframework.objenesis

这里报错,请将spring的版本换成 4.2.4-RELEASE


SpringAOP在项目中的简单应用 SpringAOP在项目中的简单应用   一、前言   项目背景 由于公司的机房到期,需要做应用迁移(包括数据库),割接到云平台。但是又不能进行一次性割接,需要分三个阶段:第一阶段割接2个地市,第二阶段再割接9个地市,第三阶段做全盘割接。在第一、第二阶段是要保证云平台与现网平台的应用能够正常并行运行。所以,要保证两边数据访问的正常,需要对某些功能进行改造。比如,某个子功能在并行阶段是不做... 阅读详情

相关推荐

小案例:利用图床自动化批量上传图片并获取图片链接

用python爬虫写了一个小脚本,用来自动上传图片到图床,然后返回链接,我们只需直接复制链接就可以。(需要安装Requests库) 因为不同图床需要提交的POST表单不一致,所以在这里我用ImgURL图床做示范,如果大家有需求,可自行修改代码。使用脚本的时候,我们只需把需要上传的图片和这个脚本放在同一个文件夹中,然后运行脚本,稍作等待,看到提示时就可以在脚本运行文件夹中发现一个名为“图片链接地址.txt”的文件,里面就是图片链接啦! 四、图片链接地址.txt(单张图片):...

采菊东篱下,Python满乾坤! 4409

【Spring Framework】Spring AOP 常用案例

通过这些常见的 Spring AOP 案例,我们可以看出 AOP 的强大和灵活性。Spring AOP 通过将横切关注点从业务逻辑中分离出来,实现了代码的模块化、解耦和可重用性,提升了应用程序的可维护性和扩展性。这些案例展示了如何利用 AOP 解决日志记录、事务管理、权限控制、性能监控、缓存管理、访问控制、数据验证和应用程序配置等常见问题。在实际应用中,可以根据需要灵活调整和扩展这些功能,为应用程序带来更高效的开发体验和更出色的性能表现。

u013675821的博客 2401

最强解析!CWRU轴承数据集Python实战:从数据加载到模型部署全流程

本文提供了一份完整的CWRU轴承数据集Python实战指南,涵盖从数据加载、预处理、特征工程到模型构建与训练的全流程。详细解析了如何利用1D-CNN、Transformer等深度学习模型进行轴承故障诊断,并介绍了模型评估、可解释性分析以及通过FastAPI部署模型的实用方法,为工业设备智能运维提供了一套可复用的解决方案。

time3的博客 365

Spring AOP 详细深入讲解+代码示例

Spring AOP(Aspect-Oriented Programming)是Spring框架提供的一种面向切面编程的技术。它通过将横切关注点(例如日志记录、事务管理、安全性检查等)从主业务逻辑代码中分离出来,以模块化的方式实现对这些关注点的管理和重用。在Spring AOP中,切面(Aspect)是一个模块化的关注点,它可以跨越多个对象,例如日志记录、事务管理等。切面通过定义切点(Pointcut)和增强(Advice)来介入目标对象的方法执行过程。

小电玩 2604

FFmpeg 部署与使用(含Docker部署)

ffmpeg 部署以及使用

weixin_38584583的博客 909

避坑指南:CoppeliaSim逆运动学仿真常见报错解决方案(附UR5+RG2爪完整Lua脚本)

本文针对CoppeliaSim机器人仿真中常见的逆运动学报错问题,提供了详细的避坑指南和解决方案。文章以UR5机械臂与RG2夹爪组合为例,深入剖析了模型装配、Dummy节点配置、Lua脚本编写等关键步骤中的常见错误,并附带了完整的、带错误处理的脚本代码,帮助用户快速定位并解决IK仿真失败问题,提升仿真效率。

weixin_29054399的博客 267

Spring AOP代码实现:实例演示与注解全解

1 理解AOP 1.1 什么是AOP AOP(Aspect Oriented Programming),面向切面思想,是Spring的三大核心思想之一(两外两个:IOC-控制反转、DI-依赖注入)。 那么AOP为何那么重要呢?在我们的程序中,经常存在一些系统性的需求,比如权限校验、日志记录、统计等,这些代码会散落穿插在各个业务逻辑中,非常冗余且不利于维护。例如下面这个示意图: 有多少业务操作,就要写多少重复的校验和日志记录代码,这显然是无法接受的。当然,用面向对象的思想,我们可以把这些重复的代码抽离出来,写

Marion的博客 1万+

M2DGR数据集在一些SLAM框架上的配置与运行:ORB-SLAM系列、VINS-Mono、LOAM系列、FAST-LIO系列、hdl_graph_slam

为了说明以上这些SLAM框架的测试与数据集适配,以M2DGR数据集为例进行各自的配置与运行,方便我以后适配自己的数据集,运行的SLAM框架包括:ORB-SLAM2、ORB-SLAM3、VINS-Mono、A-LOAM、LeGO-LOAM、LIO-SAM、LVI-SAM、FAST-LIO2、FAST-LIVO、Faster-LIO、hdl_graph_slam。实验基于Ubuntu20.04,其中ORB、VINS-Mono、和LOAM系列的安装参考我以前的博客,有详细的安装方法,其他的框架在后面会简单介绍一下

zardforever123的博客 1万+

Spring AOP 代码示例

SpringAOP 区分三个概念 类, 对象, 类对象 User u = new User(); User为一个类 u为一个User类的对象 User.class是User的类对象 AOP01 IUserService.java package com.qfedu.aop01; import java.util.List; public interface IUserService...

DavinDeng的博客 620

goahead(嵌入式Web服务器)之文件传输篇

goahead文件上传原理: 使用html form即表单提交文件上传请求,web服务器核心处理接收客户端Post过来的文件数据(注意post的是二进制数据),最后,web服务器把接收到文件数据以二进制格式写到服务器本端存储系统。 goahead文件上传步骤: 1、创建upload.html文件,内容如下: <html> <head> <meta charset="utf-8"/> <title>Upload</title> </head&g

weixin_40732273的博客 3495

[网络安全提高篇] 一二〇.恶意软件动态分析经典沙箱Cape批量提取动态API特征

这是作者网络安全自学教程系列,主要是关于安全工具和实践操作的在线笔记,特分享出来与博友们学习,希望您喜欢,一起进步。前文详细介绍动态分析沙箱Cape的安装过程,其是一个开源的自动恶意软件分析系统,通过自动运行和分析恶意软件,全面分析和提取恶意软件的关键特征。然而,当样本数量增加时,单个样本分析会降低效率。这篇文章将讲解如何实现Cape沙箱的批量分析,通过调用Python脚本文件来实施批量处理,并将分析结果存储在指定位置,最后补充submit.py的参数及Python调用方式。基础性文章,希望对您有帮助!

杨秀璋的专栏 4120

Spring AOP 代码案例

本文主要介绍了Spring AOP的通知的方法类型, 引入的AOP的依赖, 定义AOP, 还有AOP的工作流程

随便写点C++和JAVA的知识 396

无刷电机里的霍尔传感器,和 AS5600 编码器到底有什么区别?

摘要: 无刷电机中的霍尔传感器主要用于换相控制,提供6种状态反馈,无法实现精确角度测量。与AS5600磁编码器(分辨率4096)相比,霍尔仅能确保电机“转得对”,而编码器则用于高精度角度反馈。在机器人等需要位置闭环的场景中,两者需协同使用:霍尔负责基础换相,编码器提供精确角度控制。简单应用中可仅用霍尔,但高精度定位必须搭配编码器。

qq_45430571的博客 241

SpringAOP是啥,怎么用?

SpringAOP是啥,怎么用? 一、面试问题:什么是SpringAOP? SpringAOP的全称是(Aspect Oriented Programming)中文翻译过来是面向切面编程,个人理解:主要意思是我们的传统架构至上而下,后期想要从中间切入写代码添加功能,比如日志、权限、事务等,这时候我们就需要写使用代理模式写,而springaop就是专门把这一块写代码的地方给抽象了出来称为切面,从而解决的代码混乱的问题,它的底层实现也是基于代理模式(动态代理)完成的。 二、SpringAOP的应用场景有

Object_de_Father的博客 19万+

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

SpringAOP学习--SpringAOP简介及原理

前文对AOP做了介绍,实际项目中,一般不会直接上手手动实现aop,而是使用一些高级封装的aop实现,如SpringAOP。 Spring是一个广泛应用的框架,SpringAOP则是Spring提供的一个标准易用的aop框架,依托Spring的IOC容器,提供了极强的AOP扩展增强能力,对项目开发提供了极大地便利。 前文提到AOP的实现有AspectJ、JDK动态代理、CGLIB动态代理,SpringAOP不是一种新的AOP实现,其底层采用的是JDK/CGLIB动态代理。 JDK动态代理回顾 上一篇简单介绍了

u012098021的博客 6万+

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

SpringAOP使用

一、AOP介绍 AOP ,面向切面编程,在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面的编程。其实就是在代码运行,进行一定的包装,如在方法执行前、方法返回后、方法抛出异常后等地方进行一定的拦截处理或者叫增强处理 先讲一下AspectJ和Spring AOP关系,网上很多文章对AspectJ存在错误说法 AspectJ: AspectJ 来自于 Eclipse 基金会,...

LJJZJ的博客 586

Devexpress16.2.6破解工具

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

SpringAOP

spring aop

m0_58342797的博客 374

springAOP的实例

统⼀异常处理使⽤的是 @ControllerAdvice + @ExceptionHandler 来实现的,@ControllerAdvice 表示控制器通知类,@ExceptionHandler 是异常处理器,两个结合表示当出现异常的时候执⾏某个通知,也就是执⾏某个⽅法事件。

qq_45726327的博客 1710

springAOP

AOP是Aspect Oriented Programming(面向切面编程),切面是指某一特定问题,所以AOP也可以理解为面向特定方法编程。比如我们在用户登录时设置登录校验拦截器,就是对“登录校验”这一类问题的统一处理,所以拦截器是AOP的一种应用,而AOP是一种思想,拦截器就是AOP思想的一种实现。而Spring框架也实现了这种思想,提供了拦截器技术的相关接口。同样的,统一数据返回格式和统一异常处理,也是AOP思想的一种实现。

2202_75439262的博客 954

SpringAOP面向切面编程

介绍面向切面编程的思想(AOP),AOP的组成,SpringAOP的简单演示使用,SpringAOP基于动态代理的实现原理。

trong_ 的烂笔头 2544

springAOP到底是什么?

AOP和spring AOP 什么是AOP?面向切面编程。要想理解面向切面编程是什么,得先回答出下面4个问题。 1什么是面向切面编程技术? 2为什么要有面向切面编程技术? 3它和面向对象编程有什么关系? 4什么是spring AOP? 先来看第二个问题:为什么要有面向切面编程技术? 假如我们在开发自己的业务逻辑时,公司规定,所有业务逻辑都需要加上日志记录、权限验证,那么我们的代码就可能如下: cl...

qq_39229618的博客 301
上一篇: zTree与java后台结合
下一篇: Eclipse启动tomcat,项目没有在tomcat下显示的情况
ClumsyCoder
博客等级 码龄10年 2粉丝 20原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值