当前位置: 首页 > news >正文

猿创征文|Spring系列框架之面向切面编程AOP

⭐️前面的话⭐️

本篇文章将介绍一种特别重要的思想,AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。

AOP把软件系统分为两个部分:核心关注点横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。

📒博客主页:未见花闻的博客主页
🎉欢迎关注🔎点赞👍收藏⭐️留言📝
📌本文由未见花闻原创,CSDN首发!
📆首发时间:🌴2022年9月6日🌴
📆修改时间:🌴2023年4月11日🌴
✉️坚持和努力一定能换来诗与远方!
💭推荐书籍:📚《Spring实战》,📚《SpringBoot实战》
💬参考在线编程网站:🌐牛客网🌐力扣
博主的码云gitee,平常博主写的程序代码都在里面。
博主的github,平常博主写的程序代码都在里面。
🍭作者水平很有限,如果发现错误,一定要及时告知作者哦!感谢感谢!


📌导航小助手📌

  • 1.面向切面编程AOP
    • 1.1什么是AOP?
    • 1.2AOP的作用
    • 1.3AOP的核心概念
  • 2.Spring AOP
    • 2.1Spring AOP的使用
    • 2.2AspectJ表达式基本语法
    • 2.3抛出异常后通知与环绕通知
    • 2.4Spring AOP的实现原理


封面区


1.面向切面编程AOP

1.1什么是AOP?

AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。OOP引入封装、继承、多态等概念来建立一种对象层次结构,用于模拟公共行为的一个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的无关的代码被称为横切(cross cutting),在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

AOP技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。

使用"横切"技术,AOP把软件系统分为两个部分:核心关注点横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的多处,而各处基本相似,比如权限认证、日志、事物。AOP的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。

1.2AOP的作用

想象一个场景,我们在做后台系统时,除了登录和注册等几个功能不需要做用户登录验证之外,其他几乎所有页面都需要先验证用户登录的状态,那这个时候我们要怎么处理呢?

如果不使用AOP,我们就需要在每一个Controller层都写一遍验证用户是否已经登录的程序,如果你实现的功能有很多,并且这些功能都需要进行登录验证,那你就需要编写大量重复的代码,非常的麻烦,尽管你可以将登录验证实现的逻辑封装在一个方法中,但是你要在很多地方调用这个方法,还是很麻烦。

如果使用AOP,在进入核心的业务代码之前会做统一的一个拦截,去验证用户是否登录,这样就很方便,仅需做一个拦截工作,再将验证代码一执行即可。

除了登录验证功能之外,还有很多功能也可以使用AOP,比如:

  • 统一日志记录与持久化。
  • 统一方法执行时间统计。
  • 统一数据返回格式。
  • 统一处理程序中的异常。
  • 统一事务的开启与提交。

也就是说使用 AOP 可以扩充多个对象的某个能力,所以 AOP 可以说是 OOP (Object Oriented Programming,面向对象编程)的补充和完善。

1.3AOP的核心概念

1、横切关注点

想要对哪些方法或类进行拦截,拦截后怎么处理,这些关注点称之为横切关注点。

2、切面(aspect)

类是对物体特征的抽象,切面就是对横切关注点的抽象,你可以认为切面相当于横切关注点。

3、连接点(joinpoint)

被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器。

4、切入点(pointcut)

提供一组规则,根据规则匹配合法的连接点,满足规则的连接点可以理解为切点,然后可以为切点提供具体的处理(通知)。

5、通知(advice)

所谓通知指的就是指拦截到连接点之后要执行的代码,或者说在切点出所需要执行的代码是什么。

通知包含前置通知,后置通知,返回之后通知,抛异常后通知与环绕通知五类。

在Spring切面类中,可以在方法上使用以下注解,会设置方法为通知方法,在满足条件后会调用对应满足条件的方法:

  • 前置通知使用@Before∶通知方法会在目标方法调用之前执行。
  • 后置通知使用@After∶通知方法会在目标方法返回或者抛出异常后调用。
  • 返回之后通知使用@AfterReturning∶ 通知方法会在目标方法返回后调用。
  • 抛异常后通知使用@AfterThrowing∶ 通知方法会在目标方法抛出异常后调用。
  • 环绕通知使用@Around∶通知包裹了被通知的方法,在被通知的方法通知之前和调用之后执行自定义的行为。

1

6、目标对象

代理的目标对象。

7、织入(weaving)

织入(weaving)即代理的生成时机,
织入是把切面应用到目标对象并创建新的代理对象的过程,切面在指定的连接点被织入到目标对象中。
在目标对象的生命周期里有多个点可以进行织入∶

  • 编译期∶切面在目标类编译时被织入。这种方式需要特殊的编译器。AspectJ的织入编译器就是以这种方式织入切面的。
  • 类加载器∶切面在目标类加载到JVM时被织入。这种方式需要特殊的类加载器(ClassLoader),它可以在目标类被引入应用之前增强该目标类的字节码。AspectJ5的加载时织入(load-time weaving.LTW)就支持以这种方式织入切面。
  • 运行期∶切面在应用运行的某一时刻被织入。一般情况下,在织入切面时,AOP容器会为目标对象动态创建一个代理对象。SpringAOP就是以这种方式织入切面的。

8、引入(introduction)

在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段。

2.Spring AOP

面向切面编程是一种思想,Spring AOP是AOP的一种实现。

2.1Spring AOP的使用

SpringAOP使用的主要步骤为:
第一步,在SpringBoot项目中添加AOP相关的依赖。
第二步,定义切面。
第三步,定义切点。
第四步,实现通知。

第一步,在SpringBoot项目中添加AOP相关的依赖,就是在Maven的配置文件中添加aop的依赖。
由于使用Edit Starters插件访问官方的源是找不到有关SpringBoot的AOP依赖,这是因为在idea中,上面只列举了一些常用的依赖,不是所有依赖都在上面,如果找不到我们就去Maven中央仓库中去寻找。

搜索一下,找到这个依赖,然后进去复制依赖信息拷贝到Maven的配置文件中就行。
2

		<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-aop --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>

第二步,定义切面,在spring boot项目中其实就是加上@Aspect和@Component注解的一个类,这个类就表示一个切面。

//设置切面,这个类就是一个切面
@Aspect
@Component
public class UserAspect {...
}

第三步,在切面里面定义切点,在Spring中其实本质上就是一个方法,具体说是使用 @Pointcut注解修饰的一个方法,该方法不需要配置任何信息。

    //定义切点,设置拦截规则@Pointcut("execution(* com.example.demo.controller.UserController.* (..))")public void pointcut() {}

其中@Pointcut注解中的参数是一个AspectJ表达式,它的作用就是设置哪些返回值类型哪些类的哪些方法需要拦截可以指定到参数列表。
4

第四步,实现通知,本质上就是实现一个方法,只不过在方法上加上不同通知类型的注解即可,如前置通知加上@Before注解,注解的参数为切点方法名。

    //前置通知@Before("pointcut()")public void doBefore() {System.out.println("执行Before通知");}

同理,后置通知也是如此,就是将注解改为@After:

    //后置通知@After("pointcut()")public void doAfter() {System.out.println("执行After通知");}

以及目标方法返回后通知@AfterReturning:

    //返回之后通知@AfterReturning("pointcut()")public void doAfterRunning() {System.out.println("执行AfterRunning通知");}

我们来验证一下上述设置切面拦截代码的正确性,我们写一个在拦截范围的类以及方法:
5
启动程序,我们访问页面http://127.0.0.1:8080/user/hello,看看控制台的输出:
6
通过运行结果我们也能够看出上面三种通知方式执行的时机以及先后顺序。

2.2AspectJ表达式基本语法

*∶匹配任意字符,只匹配一个元素(包,类,或方法,方法参数)
..∶匹配任意字符,可以匹配多个元素,在表示类时,必须和*联合使用,匹配参数列表时表示匹配所有类型的参数列表。
+ ∶ 表示按照类型匹配指定类及其所有子类,必须跟在类名后面,如com.Car+,表示拦截Cat类以及继承Cat类的所有子类。

切点表达式由切点函数组成,其中execution()是最常用的切点函数,用来匹配方法,语法为∶

execution(<权限修饰符><返回类型><..方法(参数)><异常>)

其中权限修饰符与异常项一般省略,返回类型方法以及参数不可省略,其他项可以省略。

权限修饰符:

  • 填写权限修饰符,就只会匹配相应修饰符修饰的方法。
  • 省略,权限不作为限制,所有权限修饰符的方法都会匹配。

返回类型,必须参数,不可省略:

  • 填写具体返回类型,就匹配相应返回类型的方法。
  • *表示匹配所有返回值类型的方法。

包,类,一般情况下要有,但是可以省略:

  • 填写包和类,就只匹配你所规定的包或类。
  • *表示匹配某目录下所有的包或者类。
  • +作用在类上,匹配该类以及继承该类的所有子类。

方法,表示需要匹配方法的名字,参数表示需要匹配参数列表的类型,不可省略:

  • 指定方法名和参数列表,就只匹配你所限定的方法。
  • *可以作用在方法匹配字段上,表示匹配某类中所有的方法。
  • ..可以作用在参数列表上,对参数列表类型不做限制。

异常,可以匹配抛出指定异常的方法,该参数一般省略。

下面来看几个例子,我们来了解一下AspectJ表达式:

execution(* com.cad.demo.User.*(..))∶匹配User类里的所有方法。
execution(* com.cad.demo.User+.*(..))∶匹配User类及其子类中的所有方法。
execution(* com.cad.*.*(..))∶匹配com.cad包下的所有类的所有方法。
execution(* com.cad..*.*(..))∶匹配 com.cad 包下、子孙包下所有类的所有方法。
execution(* addUser(String,int))∶ 匹配 addUser 方法,且第一个参数类型是 String,第二个参数类型是int。

2.3抛出异常后通知与环绕通知

前面我们已经介绍了前置通知,后者通知以及返回后通知的演示,下面我们继续介绍剩下两种通知,在上面已经实现代码基础上,我们继续添加通知来进行演示。

抛出异常后通知,其实和前面三种通知的用法可以说一模一样,只不过只有当程序出现异常的时候才会执行该通知,写法如下,就是在切面类中实现一个方法,使用@AfterThrowing注解修饰即可:

    //抛异常后通知@AfterThrowing("pointcut()")public void doAfterThrowing() {System.out.println("抛出异常后,执行AfterThrowing通知");}

然后我们再在目标方法中构造一个异常,异常随便写一个异常就行,如算术异常:
8

我们访问页面http://127.0.0.1:8080/user/world来看一看控制台输出:
9
由于出现了异常,方法被强制终止了,没有返回,所以没有返回后通知。

最后还剩下一个环绕通知,环绕通知你可以理解为将前置通知和后置通知一体化了,环绕通知最常见的用法之一就是计算目标方法执行的时间是多少,使用其他通知无法做到,如果使用前置加后置通知进行对目标方法的计时,在单线程下没有问题,但是在多线程下有问题,当一个线程正在计时时,另外一个线程调用了前置通知,此时计时开始的时间就被刷新了,那自然计算得到的目标方法执行时间也就不准确了,而环绕通知使一体化的,不存在类似这种线程安全的问题。

环绕通知相比于其他的三种通知的使用方法较为复杂,首先实现环绕通知的方法必须含有ProceedingJoinPoint类的参数和使用 @Around注解修饰,表示连接点的执行进度,方法体里面第一步是执行环绕方法的前置通知,然后通过该类对象获取目标方法执行进度并调用,再执行环绕通知的后置通知,最后并返回该目标方法进度。

    @Around("pointcut()")public Object doAround(ProceedingJoinPoint joinPoint) {Object res = null;System.out.println("执行环绕通知前置通知");try {//根据连接点进度获取目标方法,并执行目标方法res = joinPoint.proceed();} catch (Throwable e) {e.printStackTrace();}System.out.println("环绕通知后置通知");return res;}

我们访问页面http://127.0.0.1:8080/user/hello来看一看控制台输出:
10

我们可以基于环绕通知实现对目标方法的计时功能:
实现思路很简单,就是在执行目标方法之前开始计时,执行完目标方法之后结束计时,差值就是方法运行的时间。

计时的方式可以使用时间戳或者spring中的StopWatch类,后者更准确一点,其实都差不多。

我们可以通过传入的joinPoint对象获取目标方法的方法名以及具体所在类和包,joinPoint.getSignature().toString()就能生成目标方法的全部有关名字的信息,我们可以加上一个方法的信息来表示哪一个方法执行的时间。

    @Around("pointcut()")public Object doTime(ProceedingJoinPoint joinPoint) {Object result = null;//System.out.println("环绕通知前置通知");String methodName = "";long start = 0;long end = 0;StopWatch stopWatch = new StopWatch();try {//执行拦截方法start = System.currentTimeMillis();stopWatch.start();methodName = joinPoint.getSignature().toString();result = joinPoint.proceed();} catch (Throwable throwable) {throwable.printStackTrace();} finally {end = System.currentTimeMillis();stopWatch.stop();}//System.out.println("环绕通知后置通知");System.out.println(methodName + "执行了" + (end - start) + "ms");System.out.println(methodName + "执行了" + (stopWatch.getTotalTimeMillis()) + "ms");return result;}

运行结果:
11

2.4Spring AOP的实现原理

Spring AOP是构建在动态代理基础上,因此 Spring对AOP的支持局限于方法级别的拦截。

Spring AOP支持JDKProxy 和CGLIBProxy方式实现动态代理。默认情况下,对于非final修饰的类,SpringAOP会基于CGLIBProxy生成代理类,CGLIBProxy生成代理类的原理就是继承目标类,被关键字final修饰的类,由于不能被继承,所以会基于DKProxy生成代理类。
13
SpringAOP的本质就是生成一个目标对象的代理类,当前端传来请求时,不会将请求直接交给目标对象,而是首先代理类进行处理,如果满足一定的条件,才会将请求交给目标对象。

如果处理请求前需要登录验证,那么代理类会去验证用户账户是否登录,如果用户登录了才会将请求交给目标对象并执行核心业务代码,否则代理类之间返回响应让用户先登录。


参考 & 资料

Spring3:AOP

觉得文章写得不错的老铁们,点赞评论关注走一波!谢谢啦!

1-99

相关文章:

猿创征文|Spring系列框架之面向切面编程AOP

⭐️前面的话⭐️ 本篇文章将介绍一种特别重要的思想&#xff0c;AOP&#xff08;Aspect Oriented Programming&#xff09;&#xff0c;即面向切面编程&#xff0c;可以说是OOP&#xff08;Object Oriented Programming&#xff0c;面向对象编程&#xff09;的补充和完善。 …...

IoT架构设计

当前有一个支持5000万用户并发访问的网站&#xff0c;每个用户都有一个IOT设备&#xff0c;用户可以查看设备状态&#xff0c;接受设备通知 1.架构设计 针对不同的业务量模型&#xff0c;可以采用不同的架构设计&#xff0c;如下&#xff1a; 低业务量模型 针对低业务量模型…...

EasyRecovery16电脑硬盘数据恢复软件功能讲解

硬盘是很常见的存储数据的设备&#xff0c;硬盘中很多重要的数据一旦丢失会很麻烦&#xff0c;不过现在有硬盘数据恢复软件可以自行在家恢复数据。今天的文章就带大家来看看硬盘恢复数据的软件EasyRecovery。 EasyRecovery 是一款专业的数据恢复软件&#xff0c;支持恢复不同存…...

信道通信基础 - 传输介质(双绞线、光纤)

文章目录 1 概述2 传输介质2.1 双绞线2.2 光纤 3 扩展3.1 网工软考真题 1 概述 2 传输介质 2.1 双绞线 双绞线&#xff1a;8 根铜导线每 2 根扭在一起&#xff08;百兆用 4 根&#xff0c;千兆必须用 8 根&#xff09;分类 2.2 光纤 光纤&#xff1a;利用光在 玻璃或塑料纤…...

黑马Redis原理篇

黑马Redis原理篇 1、数据结构1.1、动态字符串SDS1.2、IntSet1.3、Dict1.4、ZipList1.5、QuickList1.6、SkipList1.7、RedisObject1.8、五种数据结构1. String&#xff08;小EMBSTR,大RAW (SDS),少量整数INT&#xff09;2. List&#xff08;Redis3.2之后使用QuickList实现&#…...

Sql Server增加字段、修改字段、修改类型、修改默认值

1、修改字段名&#xff1a; alter table 表名 rename column A to B 2、修改字段类型&#xff1a; alter table 表名 alter column 字段名 type not null 3、修改字段默认值   alter table 表名 add default (0) for 字段名 with values 如果字段有默认值&#xff0c;则需要…...

计算机网络第一章(谢希仁第8版学习)

作者&#xff1a;爱塔居 专栏&#xff1a;计算机网络 作者简介&#xff1a;大三学生&#xff0c;希望和大家一起加油 文章目录 目录 文章目录 一、网络、互连网、互联网&#xff08;因特网&#xff09;的概念 二、因特网的组成 三、交换方式 3.1 电路交换 3.2 分组交换 3.3 电路…...

Java反射机制

文章目录 Java反射机制一、反射的用处二、获取字节码文件对象的三种方式1.Class.forName形式2.class属性获取形式3.Student对象获取形式 三、获取构造方法四、获取成员变量五、获取成员方法六、反射的好处&#xff08;面试题&#xff09;七、反射的实例1.泛型擦除2.修改字符串的…...

New:dbForge Edge 2023 4in1 Enterprise Edition Crack

dbForge Edge 2023 4in1 Enterprise Edition 赋予自己开发和管理 SQL Server、MySQL、Oracle 和 PostgreSQL 数据库的广泛能力 dbForge Edge&#xff1a;您的终极多数据库解决方案 让我们来看看。您需要处理多个数据库管理系统。同时&#xff0c;您希望能够灵活有效地处理范围广…...

基于高效率IP路由查找的内容

访问【WRITE-BUG数字空间】_[内附完整源码和文档] 实现最基本的前缀树查找,调研并实现某种IP前缀查找方案,- 基于forwarding-table.txt数据集(Network, Prefix Length, Port) - 本实验只考虑静态数据集&#xff0c;不考虑表的添加或更新- 以前缀树查找结果为基准&#xff0c;检…...

【VLAN如何划分?6个方法帮你解决!好用又简单!】

如何选择交换机&#xff1f;如何根据项目确定网络结构&#xff1f;交换机做为大家工作中最常用的设备之一&#xff0c;关于它的选择&#xff0c;不得不知。 在做项目时都有这样的疑问&#xff0c;因为参数决定了项目预算&#xff0c;常用的园区组网技术也是多种多样。 我们来…...

网络通信概述 -了解网络编程,什么是ip和端口,url

网络&#xff1a;网络就是一种辅助双方或者多方能够连接到一起的工具。 左&#xff1a;单机游戏&#xff08;无网络&#xff09; 右&#xff1a;网络游戏 网络编程&#xff1a;网络编程就是&#xff0c;让在不同的电脑上的软件能够进行数据传递&#xff0c;即进程之间的通信。…...

【Windows线程开发】Windows线程同步技术

我们在上一章节中讲解了关于Windows的线程基础&#xff0c;相信大家已经对线程有了基本的概念。这一章节中&#xff0c;我们来讲讲线程同步技术&#xff0c;包括加锁技术&#xff08;原子锁和互斥体&#xff09;和事件&#xff0c;信号量。 文章目录 一.原子锁二.互斥体三.事件…...

【数据结构与算法】- 期末考试

课程链接: 清华大学驭风计划 代码仓库&#xff1a;Victor94-king/MachineLearning: MachineLearning basic introduction (github.com) 驭风计划是由清华大学老师教授的&#xff0c;其分为四门课&#xff0c;包括: 机器学习(张敏教授) &#xff0c; 深度学习(胡晓林教授), 计算…...

股票?看我用python采集数据制作成交量图表

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 开发环境 & 第三方模块: 解释器版本: python 3.8 代码编辑器: pycharm 2021.2 requests: pip install requests 爬虫 pyecharts: pip install pyecharts 数据分析 pandas: pip install pandas 数据分析 基本流…...

C++中的多态,以及多态的实现、以及实现多态的两个特例。

一、 多态是什么&#xff1f; 通俗点说&#xff0c;就是多种形态。具体点就是不同对象完成某种事情&#xff0c;会产生不一样的状态。 举个例子&#xff1a;就好比&#xff1a;买票的时候&#xff0c;普通人、学生、军人等等&#xff0c;他们买票有不同的结果&#xff0c;普通人…...

ESP32-C2系列开发板简介

C2是一个芯片采用4毫米x 4毫米封装&#xff0c;与272 kB内存。它运行框架&#xff0c;例如ESP-Jumpstart和ESP造雨者&#xff0c;同时它也运行ESP-IDF。ESP-IDF是Espressif面向嵌入式物联网设备的开源实时操作系统&#xff0c;受到了全球用户的信赖。它由支持Espressif以及所有…...

AI在狂飙,ChatGPT-4可直接在iPhone上使用啦

今天凌晨&#xff0c;OpenAI 正式在 App Store 推出了 ChatGPT 的 iOS app&#xff0c;瞬间冲上苹果商店免费榜第二名&#xff0c;效率榜第一名。 于是兴致勃勃的去下载体验了一番。整体不错&#xff0c;以后手机使用官方的 ChatGPT 更方便啦&#xff01;而且使用 GPT4 不再麻…...

【计算机操作系统学习资源汇总】

引言 做优秀资源的搬运工&#xff01;阅读经典&#xff0c;传承经典&#xff01; 每个人的水平和理解不同&#xff0c;因此总结的水平也不同&#xff0c;推荐阅读一手资源&#xff0c;有时间尽量啃书。 发现好的资源会持续更新… 看书的一点小建议 1. 《深入理解计算机系统》…...

吴恩达 x OpenAI Prompt Engineering教程中文笔记

Datawhale干货 作者&#xff1a;刘俊君&#xff0c;Datawhale成员 完整课程&#xff1a;《吴恩达ChatGPT最新课程》 &#x1f433;Reasons & Importance Important for research, discoveries, and advancement 对研究、发现和进步很重要 Accelerate the scientific resea…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

【决胜公务员考试】求职OMG——见面课测验1

2025最新版&#xff01;&#xff01;&#xff01;6.8截至答题&#xff0c;大家注意呀&#xff01; 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:&#xff08; B &#xff09; A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

关于 WASM:1. WASM 基础原理

一、WASM 简介 1.1 WebAssembly 是什么&#xff1f; WebAssembly&#xff08;WASM&#xff09; 是一种能在现代浏览器中高效运行的二进制指令格式&#xff0c;它不是传统的编程语言&#xff0c;而是一种 低级字节码格式&#xff0c;可由高级语言&#xff08;如 C、C、Rust&am…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

SQL Server 触发器调用存储过程实现发送 HTTP 请求

文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...

热烈祝贺埃文科技正式加入可信数据空间发展联盟

2025年4月29日&#xff0c;在福州举办的第八届数字中国建设峰会“可信数据空间分论坛”上&#xff0c;可信数据空间发展联盟正式宣告成立。国家数据局党组书记、局长刘烈宏出席并致辞&#xff0c;强调该联盟是推进全国一体化数据市场建设的关键抓手。 郑州埃文科技有限公司&am…...

针对药品仓库的效期管理问题,如何利用WMS系统“破局”

案例&#xff1a; 某医药分销企业&#xff0c;主要经营各类药品的批发与零售。由于药品的特殊性&#xff0c;效期管理至关重要&#xff0c;但该企业一直面临效期问题的困扰。在未使用WMS系统之前&#xff0c;其药品入库、存储、出库等环节的效期管理主要依赖人工记录与检查。库…...

车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...

python读取SQLite表个并生成pdf文件

代码用于创建含50列的SQLite数据库并插入500行随机浮点数据&#xff0c;随后读取数据&#xff0c;通过ReportLab生成横向PDF表格&#xff0c;包含格式化&#xff08;两位小数&#xff09;及表头、网格线等美观样式。 # 导入所需库 import sqlite3 # 用于操作…...