Spring AOP技术
1.AOP基本介绍
传统的面向对象方法是 对象.方法()然后被调用
面向切面编程是什么呢?
首先满足 @1 类的这个方法是通过动态代理实现的比如有个A.say()方法。
然后有一个切面类B,这个类也有许多方法比如study(),但是不同的是,这个类中的方法study(),可以插入到A.say()的方法前后进行。 当A.say()被调用的时候,切面类B的study()方法就会被自动调用。
这就和传统的直接调用B.study()方法不同,切面类的方法是直接插入到另外一个动态代理类的方法的前后的。

AOP的核心概念
面向切面编程(AOP)是一种编程范式,它允许开发者将横切关注点(如日志记录、事务管理、安全性等)与业务逻辑分离,从而提高代码的模块化和可维护性。在Java中,AOP通常通过使用框架如Spring来实现。
介绍AOP的关键术语
切面(Aspect):切面是封装横切关注点的模块。它包含了一组通知(Advice)和切入点(Pointcut)。
连接点(Joinpoint):在程序执行过程中的特定点,如方法的调用或执行,异常的抛出等。
切点(Pointcut):切点是定义在哪些连接点上应用通知的规则。
通知(Advice):通知是在切点上执行的代码,它定义了在连接点上执行的逻辑,如前置、后置、环绕等。
解释AOP的几种通知类型
前置(Before):在方法执行前执行的通知。
后置(After):在方法执行后执行的通知,无论方法是否成功执行。
环绕(Around):在方法调用前后都可以执行的通知,可以控制方法的调用过程。
异常(Throws):在方法抛出异常后执行的通知。
最终(AfterReturning):在方法正常返回后执行的通知。
2.AOP的快速入门
在xml配置下:
<context:annotation-config/><context:component-scan base-package="aspectj"/><!--启用基于注解方式的AOP功能--><aop:aspectj-autoproxy proxy-target-class="true"/>
【Spring进阶系列丨第十篇】基于注解的面向切面编程(AOP)详解_spring 切面 注解-CSDN博客
3.AOP的切入表达式
语法细节
注意第一个*是包含了任意的权限修饰符和返回值。

方法说明

注意细节
4.JoinPoint连接点
// 获取目标方法名
joinPoint.getSignature().getName();
// 获取目标方法所属类的简单类名
joinPoint.getSignature().getDeclaringType().getSimpleName();// 获取目标方法所属类的类名
joinPoint.getSignature().getDeclaringTypeName();// 获取目标方法声明类型(public、private、protected)
joinPoint.getSignature().getModifiers();// 获取传入目标方法的参数,返回一个数组
Object[] args = joinPoint.getArgs();// 获取被代理的对象
joinPoint.getTarget();// 获取代理对象自己
joinPoint.getThis();
在如下代码中要将beforeMethod()方法切入到aspectj包下的SmartDog类的getSum()下
@Before(value = "execution(public float aspectj.SmartDog.getSum(float, float))")
public void beforeMethod(JoinPoint joinPoint){
joinPoint.getSignature().getName(); // 获取目标方法名
joinPoint.getSignature().getDeclaringType().getSimpleName(); // 获取目标方法所属类的简单类名
joinPoint.getSignature().getDeclaringTypeName(); // 获取目标方法所属类的类名
joinPoint.getSignature().getModifiers(); // 获取目标方法声明类型(public、private、protected)
Object[] args = joinPoint.getArgs(); // 获取传入目标方法的参数,返回一个数组
joinPoint.getTarget(); // 获取被代理的对象
joinPoint.getThis(); // 获取代理对象自己
}
5.返回,异常,环绕通知返回结果
//返回通知@AfterReturning(value = "execution(public float aspectj.SmartDog.getSum(float, float))", returning = "res")public void showSuccessEndLog(JoinPoint joinPoint, Object res) {Signature signature = joinPoint.getSignature();System.out.println("SmartAnimalAspect-切面类showSuccessEndLog()-方法执行正常结束-日志-方法名-" + signature.getName() + " 返回的结果是=" + res);}//异常通知@AfterThrowing(value = "execution(public float aspectj.SmartDog.getSum(float, float))", throwing = "throwable")public void showExceptionLog(JoinPoint joinPoint, Throwable throwable) {Signature signature = joinPoint.getSignature();System.out.println("SmartAnimalAspect-切面类showExceptionLog()-方法执行异常-日志-方法名-" + signature.getName() + " 异常信息=" + throwable);}
6.切入点表达式重用
在这些切入方法里面,如果是作用于同一个方法,就会让切入表达式感到重复和冗余,于是为了统一管理切入点表达式,可以使用切入点表达式重用技术
package aspectj;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;/*** @version 1.0* 这是一个切面类*/
@Aspect
@Component("smartAnimalAspect")
public class SmartAnimalAspect {// 切入表达式重用技术@Pointcut(value = "execution(public float aspectj.SmartDog.getSum(float, float))")public void mypointcut(){}//给SmartDog配置前置,返回,异常,最终通知//解读//1.@Before表示我们目标对象执行前要执行的哪个方法//2.value = "execution(public float aspectj.SmartDog.getSum(float, float))"// 是指定切入到哪个类的哪个方法 形式是:访问修饰符 返回类型 全类名.方法名(形参列表) execution是执行的意思// JoinPoint joinPoint 在底层执行的时候,由Aspectj切面框架,会给该切入方法传入jointPoint对象// 通过该对象可以获得相关的信息。//前置通知@Before(value = "mypointcut()")public void showBeginLog(JoinPoint joinPoint) {//通过连接点对象joinPoint 可以获取方法签名Signature signature = joinPoint.getSignature();System.out.println("SmartAnimalAspect-切面类showBeginLog()[使用的myPointCut()]-方法执行前-日志-方法名-" + signature.getName() + "-参数 "+ Arrays.asList(joinPoint.getArgs()));}//返回通知@AfterReturning(value = "mypointcut()",returning = "res")public void showSuccessEndLog(JoinPoint joinPoint, Object res) {Signature signature = joinPoint.getSignature();System.out.println("SmartAnimalAspect-切面类showSuccessEndLog()-方法执行正常结束-日志-方法名-" + signature.getName() + " 返回的结果是=" + res);}//异常通知@AfterThrowing(value = "mypointcut()",throwing = "throwable")public void showExceptionLog(JoinPoint joinPoint, Throwable throwable) {Signature signature = joinPoint.getSignature();System.out.println("SmartAnimalAspect-切面类showExceptionLog()-方法执行异常-日志-方法名-" + signature.getName() + " 异常信息=" + throwable);}//最终通知@After(value = "mypointcut()")public void showFinallyEndLog(JoinPoint joinPoint) {Signature signature = joinPoint.getSignature();System.out.println("SmartAnimalAspect-切面类showFinallyEndLog()-方法最终执行完毕-日志-方法名-" + signature.getName());}}
7.切面优先级问题
举例
切面类1(优先执行)
package aspectj;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.Arrays;/*** @version 1.0* 这是一个切面类*/
@Order(value = 1)
@Aspect
@Component("smartAnimalAspect")
public class SmartAnimalAspect {// 切入表达式重用技术@Pointcut(value = "execution(public float aspectj.SmartDog.getSum(float, float))")public void mypointcut(){}//前置通知
// @Before(value = "execution(public float aspectj.SmartDog.getSum(float, float))")@Before(value = "mypointcut()")public void showBeginLog(JoinPoint joinPoint) {//通过连接点对象joinPoint 可以获取方法签名Signature signature = joinPoint.getSignature();System.out.println("1前置通知" + signature.getName() + "-参数 "+ Arrays.asList(joinPoint.getArgs()));}//返回通知
// @AfterReturning(value = "execution(public float aspectj.SmartDog.getSum(float, float))", returning = "res")@AfterReturning(value = "mypointcut()",returning = "res")public void showSuccessEndLog(JoinPoint joinPoint, Object res) {Signature signature = joinPoint.getSignature();System.out.println("1返回通知" + signature.getName() + " 返回的结果是=" + res);}//异常通知
// @AfterThrowing(value = "execution(public float aspectj.SmartDog.getSum(float, float))", throwing = "throwable")@AfterThrowing(value = "mypointcut()",throwing = "throwable")public void showExceptionLog(JoinPoint joinPoint, Throwable throwable) {Signature signature = joinPoint.getSignature();System.out.println("1异常通知" + signature.getName() + " 异常信息=" + throwable);}//最终通知
// @After(value = "execution(public float aspectj.SmartDog.getSum(float, float))")@After(value = "mypointcut()")public void showFinallyEndLog(JoinPoint joinPoint) {Signature signature = joinPoint.getSignature();System.out.println("1最终通知" + signature.getName());}}
切面类2(没有切面类1的优先级高)
package aspectj;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;import java.util.Arrays;/*** @version 1.0* 这是一个切面类*/
@Order(value = 2)
@Aspect
@Component("smartAnimalAspect2")
public class SmartAnimalAspect2 {// 切入表达式重用技术@Pointcut(value = "execution(public float aspectj.SmartDog.getSum(float, float))")public void mypointcut(){}//前置通知
// @Before(value = "execution(public float aspectj.SmartDog.getSum(float, float))")@Before(value = "mypointcut()")public void showBeginLog(JoinPoint joinPoint) {//通过连接点对象joinPoint 可以获取方法签名Signature signature = joinPoint.getSignature();System.out.println("2前置通知");}//返回通知
// @AfterReturning(value = "execution(public float aspectj.SmartDog.getSum(float, float))", returning = "res")@AfterReturning(value = "mypointcut()",returning = "res")public void showSuccessEndLog(JoinPoint joinPoint, Object res) {Signature signature = joinPoint.getSignature();System.out.println( "2返回通知 返回的结果是=" + res);}//异常通知
// @AfterThrowing(value = "execution(public float aspectj.SmartDog.getSum(float, float))", throwing = "throwable")@AfterThrowing(value = "mypointcut()",throwing = "throwable")public void showExceptionLog(JoinPoint joinPoint, Throwable throwable) {Signature signature = joinPoint.getSignature();System.out.println("2异常通知" + throwable);}//最终通知
// @After(value = "execution(public float aspectj.SmartDog.getSum(float, float))")@After(value = "mypointcut()")public void showFinallyEndLog(JoinPoint joinPoint) {Signature signature = joinPoint.getSignature();System.out.println("2最终通知" + signature.getName());}}
结果:

注意
不能理解成:优先级高的每个消息通知都先执行,这个和方法调用机制(和 Filter 过滤器链式调用类似)
8.基于XML的AOP
定义SmartAnimalable接口
package xml;/*** @author ygd*/
public interface SmartAnimalable {float getSum(float i, float j);float getSub(float i, float j);
}
定义SmartDog类
package xml;/*** @author ygd*/
public class SmartDog implements SmartAnimalable {@Overridepublic float getSum(float i, float j) {float result = i + j;System.out.println("getSum() 方法内部打印 result= " + result);return result;}@Overridepublic float getSub(float i, float j) {float result = i - j;System.out.println("getSub() 方法内部打印 result= " + result);return result;}
}
定义SmartAnimalAspect切面类
package xml;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;import java.util.Arrays;/*** @version 1.0* 这是一个基于XML的切面类*/public class SmartAnimalAspect {public void showBeginLog(JoinPoint joinPoint) {//通过连接点对象joinPoint 可以获取方法签名Signature signature = joinPoint.getSignature();System.out.println("1前置通知" + signature.getName() + "-参数 "+ Arrays.asList(joinPoint.getArgs()));}public void showSuccessEndLog(JoinPoint joinPoint, Object res) {Signature signature = joinPoint.getSignature();System.out.println("1返回通知" + signature.getName() + " 返回的结果是=" + res);}public void showExceptionLog(JoinPoint joinPoint, Throwable throwable) {Signature signature = joinPoint.getSignature();System.out.println("1异常通知" + signature.getName() + " 异常信息=" + throwable);}public void showFinallyEndLog(JoinPoint joinPoint) {Signature signature = joinPoint.getSignature();System.out.println("1最终通知" + signature.getName());}}
定义beans01.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"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/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"><!--配置一个切面类对象-bean--><bean class="xml.SmartAnimalAspect" id="smartAnimalAspect"/>
<!--配置SmartDog对象-bean--><bean class="xml.SmartDog" id="dog"/>
<!--配置切面类,一定要引入xmlns:aop命名空间--><aop:config>
<!-- 注意顺序,先配置切入点,在配置切面对象-->
<!--配置切入点--><aop:pointcut id="mypointcut" expression="execution(public float xml.SmartDog.getSum(float, float))"/>
<!--这里指定切面对象--><aop:aspect ref="smartAnimalAspect" order="10">
<!--配置前置通知--><aop:before method="showBeginLog" pointcut-ref="mypointcut"/>
<!--配置返回通知--><aop:after-returning method="showSuccessEndLog" pointcut-ref="mypointcut" returning="res"/>
<!--配置异常通知--><aop:after-throwing method="showExceptionLog" pointcut-ref="mypointcut" throwing="throwable"/>
<!--配置最终通知--><aop:after method="showFinallyEndLog" pointcut-ref="mypointcut"/></aop:aspect></aop:config></beans>
注意点:要 先配置切面点,在配置切面类
xml的语法,跟上面所写的基于注解的aop道理都是一样的。
9.Spring的AOP机制是基于Spring框架中的基于JDK的动态代理和基于CGLib的动态代理
动态代理 基于jdk的Proxy(面向接口) 与spring的CGlib(面向父类)-CSDN博客
相关文章:
Spring AOP技术
1.AOP基本介绍 AOP 的全称 (aspect oriented programming) ,面向切面编程。 1.和传统的面向对象不同。 面向切面编程是根据自我的需求,将切面类的方法切入到其他的类的方法中。(这么说抽象吧!来张图来解释。) 如图 传…...
数字IC实践项目(10)—基于System Verilog的DDR4 Model/Tb 及基础Verification IP的设计与验证(付费项目)
数字IC实践项目(10)—基于System Verilog的DDR4 Model/Tb 及基础Verification IP的设计与验证(付费项目) 前言项目框图1)DDR4 Verification IP2)DDR4 JEDEC Model & Tb 项目文件1)DDR4 Veri…...
MATLAB保存多帧图形为视频格式
基本思路 在Matlab中,要将drawnow绘制的多帧数据保存为视频格式,首先需要创建一个视频写入对象。这个对象用于将每一帧图像数据按照视频格式的要求进行组合和编码。然后,在每次drawnow更新绘图后,将当前的图形窗口内容捕获为一帧图…...
redis7.x源码分析:(3) dict字典
dict字典采用经典hash表数据结构实现,由键值对组成,类似于C中的unordered_map。两者在代码实现层面存在一些差异,比如gnustl的unordered_map分配的桶数组个数是(质数n),而dict分配的桶数组个数是࿰…...
连续九届EI稳定|江苏科技大学主办
【九届EI检索稳定|江苏科技大学主办 | IEEE出版 】 🎈【截稿倒计时】!!! ✨徐秘书:gsra_huang ✨往届均已检索,已上线IEEE官网 🎊第九届清洁能源与发电技术国际学术会议(CEPGT 2…...
HarmonyOS NEXT应用开发实战 ( 应用的签名、打包上架,各种证书详解)
前言 没经历过的童鞋,首次对HarmonyOS的应用签名打包上架可能感觉繁琐。需要各种秘钥证书生成和申请,混在一起也分不清。其实搞清楚后也就那会事,各个文件都有它存在的作用。 HarmonyOS通过数字证书与Profile文件等签名信息来保证鸿蒙应用/…...
【CICD】CICD 持续集成与持续交付在测试中的应用
一、什么是CICD? CI/CD 是指持续集成(Continuous Integration)和持续部署(Continuous Deployment)或持续交付(Continuous Delivery) 1.1 持续集成(Continuous Integration…...
Dolby TrueHD和Dolby Digital Plus (E-AC-3)编码介绍
文章目录 1. Dolby TrueHD特点总结 2. Dolby Digital Plus (E-AC-3)特点总结 Dolby TrueHD 与 Dolby Digital Plus (E-AC-3) 的对比 Dolby TrueHD和Dolby Digital Plus (E-AC-3) 是两种高级的杜比音频编码格式,常用于蓝光影碟、流媒体、影院等高品质音频传输场景。它…...
数字频率计的设计-- 基于 HDL 方法
目录 数字频率计的设计 1.计数、锁存与显示译码电路设计 2.主控电路设计 3.分频电路设计 4.顶层电路设计 伪随机序列发生器 的设计 数字频率计的设计 基于HDL设计数字系统时,可以根据需要应用Verilog HDL描述所需要的功能电路,既有利于节约资源&am…...
[程序员] 没有产生core文件的原因
最近和同事一块看一个core文件没有产生的问题,总结了一些在CSDN的专栏里。分析的过程,参考使用了ftrace的功能,感觉非常实用。 如果有需要可以参考。大体上就这么几种情况:信号的特殊处理,coredump相关的配置没有设置正确,文件系统访问权限问题,setuid相关的不匹配问题。…...
【数字图像处理+MATLAB】基于 Sobel 算子计算图像梯度并进行边缘增强:使用 imgradientxy 函数
引言 在图像处理中,边缘通常是图像中像素强度变化最大的地方,这种变化可以通过计算图像的梯度来量化。梯度是一个向量,它的方向指向像素强度增加最快的方向,它的大小(或者说幅度)表示像素强度增加的速度。…...
P10901 [蓝桥杯 2024 省 C] 封闭图形个数
铁子们好呀,今天博主给大家更新一道编程题!!! 题目链接如下: P10901 [蓝桥杯 2024 省 C] 封闭图形个数 好,接下来,我将从三个方面讲解这道例题。分别是 题目解析算法原理代码实现 文章目录 1.题…...
ubuntu-desktop-24.04上手指南(更新阿里源、安装ssh、安装chrome、设置固定IP、安装搜狗输入法)
ubuntu-desktop-24.04上手指南(更新阿里源、安装ssh、安装chrome、设置固定IP、安装搜狗输入法) 一、更新并安装基础软件 #切换root用户 sudo su -#更新 apt update #升级 apt upgrade#install vim apt install vim#install net-tools apt install net-tools二、安装ssh并设置…...
手机直连卫星NTN通信初步研究
目录 1、手机直连卫星之序幕 2、卫星NTN及其网络架构 2.1 NTN 2.2 NTN网络架构 3、NTN的3GPP标准化进程 3.1 NTN需要适应的特性 3.2 NTN频段 3.3 NTN的3GPP标准化进程概况 3.4 NTN的3GPP标准化进程的详情 3.4.1 NR-NTN 3.4.1.1 NTN 的无线相关 SI/WI 3.4.1.2…...
蓝桥杯c++算法学习【2】之搜索与查找(九宫格、穿越雷区、迷宫与陷阱、扫地机器人:::非常典型的必刷例题!!!)
别忘了请点个赞收藏关注支持一下博主喵!!! 关注博主,更多蓝桥杯nice题目静待更新:) 搜索与查找 一、九宫格 【问题描述】 小明最近在教邻居家的小朋友小学奥数,而最近正好讲述到了三阶幻方这个部分,三 …...
Android加载pdf
依赖 implementation com.squareup.okhttp3:okhttp:4.9.1 implementation com.github.barteksc:android-pdf-viewer:3.2.0-beta.1在project.build中添加该源 maven { url "https://repository.liferay.com/nexus/content/repositories/public/" }XML <LinearLa…...
IOT物联网低代码可视化大屏解决方案汇总
目录 参考来源云服务商阿里云物联网平台产品主页产品文档 开源项目DGIOT | 轻量级工业物联网开源平台项目特点项目地址开源许可 IoTGateway | 基于.NET6的跨平台工业物联网网关项目特点项目地址开源许可 IoTSharp | 基于.Net Core开源的物联网基础平台项目特点项目地址开源许可…...
Python的面向对象day7
1、什么是面向对象 面向对象称为OO,他通过将数据和功能封装在一个被称为‘对象’的实体中,来组织和管理代码。面向对象变成(OOP)具有四个特性,封装、继承、多态、抽象 优点:模块化、安全性高、代码重用性…...
计算机网络(11)和流量控制补充
这一篇对数据链路层中的和流量控制进行详细学习 流量控制(Flow Control)是计算机网络中确保数据流平稳传输的技术,旨在防止数据发送方发送过多数据,导致接收方的缓冲区溢出,进而造成数据丢失或传输失败。流量控制通常…...
Rust 所有权机制
Rust 所有权机制 本文示例代码地址 所有权是Rust中最独特的特性,它让Rust无需GC就可以保证内存安全。 什么是所有权? 所有权(ownership)是 Rust 用于如何管理内存的一组规则。所有程序都必须管理其运行时使用计算机内存的方式…...
【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...
Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...
三维GIS开发cesium智慧地铁教程(5)Cesium相机控制
一、环境搭建 <script src"../cesium1.99/Build/Cesium/Cesium.js"></script> <link rel"stylesheet" href"../cesium1.99/Build/Cesium/Widgets/widgets.css"> 关键配置点: 路径验证:确保相对路径.…...
visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力
引言: 在人工智能快速发展的浪潮中,快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型(LLM)。该模型代表着该领域的重大突破,通过独特方式融合思考与非思考…...
深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
Git常用命令完全指南:从入门到精通
Git常用命令完全指南:从入门到精通 一、基础配置命令 1. 用户信息配置 # 设置全局用户名 git config --global user.name "你的名字"# 设置全局邮箱 git config --global user.email "你的邮箱example.com"# 查看所有配置 git config --list…...
