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

用户模块-SpringEvent观察者模式

1. 背景与需求

        在很多系统中,我们常常需要对用户的行为进行处理,比如发放奖励、处理通知等。在这个例子中,我们希望在两个场景下发放“改名卡”这个奖励:

  1. 用户注册时:当一个新用户注册成功时,我们希望立即发放改名卡作为奖励。

  2. 用户被点赞时:当其他用户点赞时,同样发放改名卡作为鼓励。

        为了实现这一功能,我们需要处理用户注册和点赞的业务逻辑,并在这些行为发生时自动触发相应的奖励发放。然而,直接将奖励发放逻辑写入注册和点赞的处理流程会导致代码变得越来越复杂,也会使得不同模块之间的耦合性增加。

问题

  • 当我们直接把发放改名卡的代码写在注册或者点赞处理的地方时,每次修改这部分代码时,都可能影响到注册和点赞的核心业务逻辑,这样不仅难以维护,还可能引入一些意外的错误。

  • 同时,我们希望能确保徽章的发放是可靠的,不能丢失。

解决方案: 为了解决这些问题,我们可以引入“事件驱动”的方式,通过事件(Event)来处理这类需求。Spring 提供了非常方便的事件机制,我们可以使用这个机制来“发布”一个事件(比如用户注册或点赞),然后通过“监听”这些事件来执行奖励发放的逻辑。

这种方式的好处是:

  • 解耦:注册和点赞逻辑不再关心徽章的发放,所有与奖励发放相关的逻辑都可以在独立的模块中完成。

  • 灵活性:如果以后需要修改奖励的发放规则,只需要修改事件监听的处理逻辑,而不必修改注册或点赞的核心业务代码。

  • 可靠性:事件机制可以确保即使在复杂的业务操作中,奖励的发放仍然可靠,避免出现遗漏。

2. 技术选择

        为了实现事件驱动的徽章发放功能,我们可以选择不同的技术方案。这里我们有两种常见的技术选择:

  1. RocketMQ

    • 什么是 RocketMQ?
      RocketMQ 是一个高性能的消息队列系统,主要用来处理大规模的异步消息。简单来说,它就像一个传递信息的中介,能够把消息可靠地传递到接收方。

    • 如何用它实现事件驱动?
      我们可以使用 RocketMQ 来发送用户注册或点赞事件,然后由其他系统(比如徽章发放服务)来消费这些消息,完成相应的处理。

    • 优点

      • 消息可靠:一旦消息发送出去,它一定会被消费到,不会丢失。

      • 高可用:适用于需要处理大量消息的场景。

    • 缺点

      • 与事务管理有点关系:如果消息是在事务中发送的,可能出现事务回滚时消息未能正确消费的问题,这就可能导致系统状态不一致。

  2. Spring 自带的事件机制(ApplicationEventPublisher)

    • 什么是 Spring 事件机制?
      Spring 提供了一个轻量级的事件机制,可以帮助我们在应用中定义和发布事件。它的基本概念是:当某个操作发生时,我们可以发布一个事件,系统中的其他部分可以监听到这个事件,并做相应的处理。

    • 如何用它实现事件驱动?
      我们可以使用 Spring 的 ApplicationEventPublisher 来发布用户注册或点赞事件,然后通过事件监听器(Listener)来处理发放改名卡的逻辑。

    • 优点

      • 与 Spring 自身高度集成,使用简单,不需要额外配置。

      • 可以灵活控制事件的处理方式:比如可以决定事件是在事务中执行,还是与事务独立执行。

      • 适合轻量级应用和不需要高并发的场景。

    • 缺点

      • 适用范围有限,主要适用于系统内部的事件通信,不能像 RocketMQ 一样处理跨系统的消息。

总结

  • 如果你的应用需要处理大量消息,特别是跨系统的消息传递,RocketMQ 是一个可靠的选择。

  • 如果你更关注轻量级的事件驱动架构,并且不需要复杂的分布式消息处理,Spring 自带的事件机制 会是一个更简单、易于实现的方案。

        在本例中,我们选择了 Spring 事件机制,因为用户注册和徽章发放的操作本身是属于同一个系统内部的,且不需要高并发的消息处理,Spring 事件就能够满足我们的需求,同时提供了灵活的事务控制。

3. SpringEvent 实现方案

        现在,我们已经了解了事件驱动的好处和技术选择,接下来我们看看如何用 Spring 的事件机制来实现这个功能。

3.1 定义事件

在 Spring 中,事件是通过继承 ApplicationEvent 类来定义的。事件类通常包含两个部分:

  1. 事件的发布者:指明谁发布了这个事件(例如:注册模块)。

  2. 事件的数据:传递给监听者的数据(例如:注册的用户信息)。

        我们需要创建一个自定义事件类,来表示用户注册事件。在这个事件类中,我们将包含用户的信息。

import org.springframework.context.ApplicationEvent;public class UserRegistrationEvent extends ApplicationEvent {private String username;public UserRegistrationEvent(Object source, String username) {super(source);  // 调用父类的构造方法,传递事件发布者this.username = username;}public String getUsername() {return username;}
}

        这里的 UserRegistrationEvent 类继承了 ApplicationEvent,并通过构造方法传递了事件发布者和注册用户的用户名。

3.2 发布事件

        事件类定义好后,我们就可以在需要的地方发布事件了。在我们的案例中,当用户注册时,我们会通过 ApplicationEventPublisher 来发布 UserRegistrationEvent 事件。

        通常,事件的发布是通过 Spring 容器来完成的,所以我们可以注入 ApplicationEventPublisher 来发送事件。

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.beans.factory.annotation.Autowired;public class UserService {@Autowiredprivate ApplicationEventPublisher eventPublisher;public void registerUser(String username) {// 1. 用户注册的业务逻辑System.out.println(username + " 注册成功!");// 2. 发布用户注册事件UserRegistrationEvent event = new UserRegistrationEvent(this, username);eventPublisher.publishEvent(event);}
}

        在上面的代码中,registerUser 方法模拟了用户注册的过程。当用户注册成功后,我们就通过 eventPublisher.publishEvent 发布了一个 UserRegistrationEvent 事件。

3.3 事件监听器

        事件发布后,我们还需要定义事件监听器(Listener),来监听这些事件并执行具体的操作(比如发放改名卡)。

        Spring 提供了 ApplicationListener 接口来实现事件监听。我们可以创建一个 UserRegistrationListener 类,来处理用户注册事件,并在事件发生时发放改名卡。

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;@Component
public class UserRegistrationListener implements ApplicationListener<UserRegistrationEvent> {@Overridepublic void onApplicationEvent(UserRegistrationEvent event) {// 获取事件中的用户名String username = event.getUsername();// 发放改名卡的逻辑System.out.println("给用户 " + username + " 发放改名卡!");}
}

        在这个类中,UserRegistrationListener 实现了 ApplicationListener 接口,并重写了 onApplicationEvent 方法来处理 UserRegistrationEvent 事件。当事件触发时,这个方法会被调用,进而执行发放改名卡的操作。

3.4 事务控制

Spring 事件有一个很大的优点,就是我们可以自由控制事件的发布是否与事务一起执行。比如在用户注册的场景中,用户注册操作和发放改名卡的操作不一定要在同一个事务中执行。我们可以选择将事件发布放在事务外部,避免一旦注册失败,改名卡发放也被回滚。

这种灵活性使得我们可以更好地控制系统的业务逻辑。

3.5 总结

通过以上步骤,我们就完成了 Spring 事件驱动的用户注册和改名卡发放功能。总结一下,主要步骤有:

  1. 定义事件:通过创建自定义的事件类 UserRegistrationEvent 来表示用户注册行为。

  2. 发布事件:在用户注册时,通过 ApplicationEventPublisher 发布事件。

  3. 监听事件:通过实现 ApplicationListener 接口,创建事件监听器来处理事件,执行改名卡的发放操作。

  4. 事务控制:控制事件是否与事务一起回滚,确保逻辑的解耦。

        这种方式不仅使得代码结构更加清晰,也提高了系统的可维护性和扩展性。

4. RocketMQ 与 Spring 事件的对比

        在选择技术方案时,我们主要考虑 RocketMQ 和 Spring 自带的事件机制。虽然这两者都能实现事件驱动,但它们在一些关键特性上有所不同。接下来,我们将对它们进行详细的对比,帮助大家理解如何选择最适合自己应用的方案。

4.1 消息传递的范围

  • RocketMQ
    RocketMQ 是一个分布式消息队列,它的设计目的是跨系统、跨服务地传递消息。简单来说,如果你的应用需要将消息传递到不同的系统或者服务中,RocketMQ 非常合适。例如,当用户在一个系统注册后,需要通知到其他独立的服务(比如通知服务、奖励服务等),RocketMQ 就能很好地处理这些跨服务的消息传递。

  • Spring 事件
    Spring 事件机制主要用于同一个应用(同一个 Spring 容器)内部的事件传递。当事件发布后,系统内部的其他模块可以通过监听器来响应事件。因此,Spring 事件适用于应用内部的事件驱动。例如,用户注册时发放改名卡的操作,可以在同一个 Spring 容器内通过事件机制处理。

总结

  • RocketMQ 更适合分布式系统,跨服务传递消息。

  • Spring 事件 更适合单一应用内部的事件驱动。

4.2 消息的可靠性

  • RocketMQ
    RocketMQ 作为一个消息队列系统,设计上就是为了确保消息的可靠传递。在发送消息时,它保证即使出现网络故障、系统崩溃等情况,消息也能被正确传递。消息队列会持久化存储消息,直到消息被消费成功,这确保了消息不会丢失。

  • Spring 事件
    Spring 事件机制是基于应用上下文的事件传播,它不涉及消息的持久化和可靠性。也就是说,当你发布一个 Spring 事件时,如果事件监听器没有执行或者执行失败,并不会像 RocketMQ 那样自动保证消息的可靠性。因此,Spring 事件适合那些不要求事件消息“保证送达”的场景。

总结

  • RocketMQ 提供高可靠性的消息传递,确保消息不会丢失。

  • Spring 事件 不保证消息的持久化,适合内部事件驱动,不需要保证每次消息都成功送达。

4.3 事务处理

  • RocketMQ
    RocketMQ 支持与事务的结合,它可以在消息发送时与事务绑定,确保在事务成功提交时消息也被发送出去。如果事务回滚,RocketMQ 会保证消息也不会被发送出去。这个功能适合需要强一致性的场景,比如金融交易系统。

  • Spring 事件
    Spring 事件提供了更灵活的事务控制。你可以选择事件是否和事务一起提交。也就是说,当你发布一个 Spring 事件时,Spring 事件可以选择在事务提交后执行,也可以在事务外部执行。如果某个操作失败导致事务回滚,Spring 事件机制允许你决定是否也回滚事件的执行。这让它更加适合一些不那么严格要求事务一致性的场景。

总结

  • RocketMQ 可以与事务结合,确保消息和事务的一致性,适用于强一致性要求的场景。

  • Spring 事件 允许灵活地控制事件是否与事务一起执行,适合不强制要求一致性的应用。

4.4 系统架构复杂度

  • RocketMQ
    由于 RocketMQ 是一个独立的消息队列系统,它需要单独的部署和运维工作。你需要确保消息队列的高可用性、可靠性以及性能,这增加了系统的复杂度。

  • Spring 事件
    Spring 事件机制是 Spring 框架自带的功能,完全在应用内部工作,不需要额外的基础设施支持。因此,使用 Spring 事件时,不需要担心额外的部署和运维工作,架构较为简单。

总结

  • RocketMQ 增加了系统的架构复杂度,需要考虑消息队列的部署、维护等。

  • Spring 事件 更加简单,适合内部使用,不需要额外的基础设施。

4.5 性能

  • RocketMQ
    作为分布式消息系统,RocketMQ 支持高吞吐量和高并发,能够处理大量的消息。它适用于需要处理海量数据的场景,比如大规模的分布式系统或实时数据流处理。

  • Spring 事件
    Spring 事件机制虽然简单高效,但它适用于单个应用内部的事件传播,不涉及大规模的消息处理。对于高并发场景,Spring 事件的性能可能不如 RocketMQ。

总结

  • RocketMQ 适合大规模、高并发的消息传递。

  • Spring 事件 适用于轻量级应用,不需要大规模的消息处理。

总结对比

特性RocketMQSpring 事件
应用场景分布式系统,跨服务消息传递单一应用内部的事件驱动
可靠性提供高可靠性,确保消息不会丢失不保证消息的持久化和可靠性
事务处理支持与事务结合,确保消息与事务一致性支持灵活的事务控制,可以选择与事务一起执行
架构复杂度增加系统架构复杂度,需要独立部署和维护简单易用,不需要额外的基础设施
性能支持高吞吐量和高并发,适合海量数据处理适用于轻量级事件驱动,性能相对较低

        通过上面的对比,我们可以看到,RocketMQ 适合复杂的大规模系统,特别是需要跨服务、跨系统的消息传递,而 Spring 事件 更适合简单的、单一应用内的事件驱动,且实现起来更为轻量和简单。

5. 实现步骤

        在这一部分,我们将详细介绍如何使用 Spring 事件机制 来实现用户注册时发放改名卡的功能。整个过程分为几个简单的步骤,帮助你一步一步完成实现。

5.1 创建事件类

        首先,我们需要定义一个事件类,用来表示用户注册时触发的事件。这个事件类会包含一些必要的信息,比如用户名。

  • 创建 UserRegistrationEvent,继承自 ApplicationEvent

  • 在类中定义一个 username 字段,用于保存注册的用户信息。

import org.springframework.context.ApplicationEvent;public class UserRegistrationEvent extends ApplicationEvent {private String username;public UserRegistrationEvent(Object source, String username) {super(source);  // 调用父类构造器this.username = username;}public String getUsername() {return username;}
}

这样,我们就创建好了一个事件类,它会在用户注册时触发。

5.2 发布事件

        接下来,当用户注册时,我们需要发布这个事件。发布事件的方式是通过 Spring 的 ApplicationEventPublisher 来完成的。

  • 在注册用户的服务类中注入 ApplicationEventPublisher

  • 在用户注册成功后,创建 UserRegistrationEvent 事件,并通过 eventPublisher.publishEvent() 来发布事件。

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.beans.factory.annotation.Autowired;public class UserService {@Autowiredprivate ApplicationEventPublisher eventPublisher;public void registerUser(String username) {// 用户注册的业务逻辑System.out.println(username + " 注册成功!");// 发布注册事件UserRegistrationEvent event = new UserRegistrationEvent(this, username);eventPublisher.publishEvent(event);}
}

在上面的代码中,当用户注册成功后,我们就发布了一个 UserRegistrationEvent 事件。

5.3 创建事件监听器

        发布事件后,我们还需要创建一个监听器来处理这个事件。当事件被触发时,监听器会执行相应的操作,例如发放改名卡。

  • 创建一个实现了 ApplicationListener 接口的类。

  • 在类中实现 onApplicationEvent() 方法,接收事件,并执行相应的操作。

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;@Component
public class UserRegistrationListener implements ApplicationListener<UserRegistrationEvent> {@Overridepublic void onApplicationEvent(UserRegistrationEvent event) {// 获取事件中的用户名String username = event.getUsername();// 发放改名卡的逻辑System.out.println("给用户 " + username + " 发放改名卡!");}
}

在这个 UserRegistrationListener 类中,当 UserRegistrationEvent 事件发生时,onApplicationEvent() 方法就会被调用,从而执行发放改名卡的操作。

5.4 事件与事务控制

        Spring 事件的一个重要特点是,你可以灵活地控制事件是否和事务一起执行。在我们这个场景中,发放改名卡并不是用户注册的关键操作,所以我们不需要将事件的处理放在事务中,避免事务回滚时影响事件的执行。

通过 Spring 事件,我们可以将事件的执行放在事务外部,这样即使用户注册的事务回滚了,改名卡的发放也不会受到影响。

5.5 测试与验证

完成了事件类、发布和监听的代码后,我们需要验证它们是否正确工作。

  1. 测试用户注册:当调用 registerUser() 方法时,应该能正确发布 UserRegistrationEvent 事件。

  2. 验证改名卡发放:当事件触发后,UserRegistrationListener 中的 onApplicationEvent() 方法应该被调用,控制台会输出发放改名卡的消息。

public class UserServiceTest {@Autowiredprivate UserService userService;@Testpublic void testUserRegistration() {userService.registerUser("john_doe");  // 注册用户,触发事件// 验证改名卡发放逻辑(可以通过断言或者日志输出验证)}
}

这样,通过测试,我们可以确认事件的发布与处理过程都没有问题。

总结

整个实现过程包括了以下几个步骤:

  1. 创建事件类:定义一个事件类 UserRegistrationEvent 来表示用户注册事件。

  2. 发布事件:在用户注册后,使用 ApplicationEventPublisher 发布事件。

  3. 创建事件监听器:实现 ApplicationListener 接口,编写监听器来处理事件,发放改名卡。

  4. 事务控制:确保事件的处理不受事务回滚的影响,选择是否将事件与事务一起执行。

  5. 测试验证:通过测试确保事件发布和监听的过程正确无误。

        这样,我们就完成了基于 Spring 事件的用户注册和改名卡发放功能。

6. 优势与总结

        在这一部分,我们来总结一下使用 Spring 事件机制 来实现用户注册时发放改名卡的功能的优势,同时回顾整个实现过程。

6.1 优势

使用 Spring 事件机制 解决问题,有以下几个明显的优势:

  1. 解耦合
    Spring 事件机制能够帮助我们将事件的发布者和事件的处理者解耦。也就是说,发布注册事件的代码和处理改名卡发放的代码可以分开管理,互不依赖。这样做的好处是,未来如果我们需要更改改名卡发放的逻辑时,只需要修改监听器中的代码,而不需要改变用户注册的逻辑。

  2. 灵活的事务控制
    使用 Spring 事件时,我们可以自由选择事件的处理是否和事务一起执行。在这个例子中,发放改名卡的操作不影响用户注册的核心流程,因此我们选择将事件处理放在事务外部。这样,用户注册的事务失败时,不会影响改名卡的发放,保证了系统的稳定性。

  3. 高扩展性
    如果未来需要添加更多的事件处理逻辑,例如当用户注册后发放优惠券、发送欢迎邮件等,只需要再添加相应的事件监听器即可,而无需修改原有的用户注册逻辑。这让我们的系统变得非常容易扩展。

  4. 简化了业务流程
    通过使用事件机制,我们将复杂的业务流程拆解成了多个简单的事件处理逻辑。每个事件监听器负责处理一个特定的业务,代码更简洁、清晰,便于维护和修改。

6.2 总结

        我们使用 Spring 事件机制实现了一个非常实用的功能——用户注册时发放改名卡。在整个实现过程中,我们完成了以下步骤:

  • 创建了一个表示用户注册的事件类;

  • 使用 ApplicationEventPublisher 发布事件;

  • 实现了事件监听器来处理发放改名卡的逻辑;

  • 通过 Spring 事件机制,我们解耦了用户注册和改名卡发放的代码,同时也灵活控制了事务的执行。

        与传统的业务流程处理方式相比,Spring 事件机制提供了一种更简洁、灵活和可扩展的解决方案。它不仅能够让我们的代码更加清晰易维护,还能避免未来系统功能扩展时的繁琐修改。

        总的来说,Spring 事件机制 在实际开发中有着广泛的应用场景,尤其适合用于需要解耦且有多个监听者的业务逻辑。通过事件机制,我们可以大大提高代码的可读性、可维护性以及系统的灵活性。

相关文章:

用户模块-SpringEvent观察者模式

1. 背景与需求 在很多系统中&#xff0c;我们常常需要对用户的行为进行处理&#xff0c;比如发放奖励、处理通知等。在这个例子中&#xff0c;我们希望在两个场景下发放“改名卡”这个奖励&#xff1a; 用户注册时&#xff1a;当一个新用户注册成功时&#xff0c;我们希望立即发…...

三目云台转动性能稳定性

三目云台是一种具备三个摄像头或观测窗口的云台设备&#xff0c;其转动性能对于实现全方位、多角度的监控或观测至关重要。以下是对三目云台转动的详细分析&#xff1a; 一、转动原理 云台本身是一种摄像机稳定器&#xff0c;通过内置的电机和控制系统实现转动。三目云台则在…...

Python基础语法3

目录 1、函数 1.1、语法格式 1.2、函数返回值 1.3、变量作用域 1.4、执行过程 1.5、链式调用 1.6、嵌套调用 1.7、函数递归 1.8、参数默认值 1.9、关键字参数 2、列表 2.1、创建列表 2.2、下标访问 2.3、切片操作 2.4、遍历列表元素 2.5、新增元素 2.6、查找元…...

45、子类需要重写父类的构造函数嘛,子类自己的构造函数呢?

45、子类需要重写父类的构造函数嘛&#xff0c;子类自己的构造函数呢&#xff1f; 一、子类是否需要重写父类的构造函数&#xff1f; 1. 不需要重写的场景 基类有无参构造函数 若父类&#xff08;基类&#xff09;显式或隐式定义了无参构造函数&#xff0c;子类无需重写构造函…...

C语言 ——— 分支循环语句

目录 分支循环语句 单分支 多分支 switch 分支语句 牛刀小试 判断一个数是否是奇数 输出 1-100之间 的奇数 计算 n 的阶乘 计算 1! 2! 3! ... n! 在一个有序数组中查找具体的某一个数字 打印 100-200 之间的素数 求两个整数的最大公约数 getchar函数 和 putc…...

解耦旧系统的利器:Java 中的适配器模式(Adapter Pattern)实战解析

在现代软件开发中&#xff0c;我们经常需要与旧系统、第三方库或不一致接口打交道。这时候&#xff0c;如果能优雅地整合这些不兼容组件&#xff0c;又不破坏原有结构&#xff0c;就需要一位“翻译官” —— 适配器模式。本文将通过 Java 实例&#xff0c;详细讲解适配器模式的…...

C++学习之游戏服务器开发十五QT登录器实现

目录 1.界面搭建 2.登录客户端步骤分析 3.拼接登录请求实现 4.发送http请求 5.服务器登录请求处理 6.客户端处理服务器回复数据 7.注册页面启动 8.qt启动游戏程序 1.界面搭建 2.登录客户端步骤分析 3.拼接登录请求实现 CGI 程序处理流程 程序员自己写程序处理各种业务 …...

搭建Stable Diffusion图像生成系统实现通过网址访问(Ngrok+Flask实现项目系统公网测试,轻量易部署)

目录 前言 背景与需求 &#x1f3af; 需求分析 核心功能 网络优化 方案确认 1. 安装 Flask 和 Ngrok 2. 构建 Flask 应用 3. 使用 Ngrok 实现内网穿透 4. 测试图像生成接口 技术栈 实现流程 优化目标 实现细节 1. 迁移到Flask 2. 持久化提示词 3. 图像下载功能 …...

第五章:5.3 ESP32物联网应用:阿里云IoT平台与腾讯云IoT平台的数据上传与远程控制

一、阿里云IoT平台接入​​ 1. 准备工作 ​​注册阿里云账号​​ 访问阿里云官网&#xff0c;注册并完成实名认证。​​创建产品和设备​​ 进入​​物联网平台控制台​​ → ​​公共实例​​ → ​​创建产品​​&#xff08;例如产品名称“ESP32_Sensor”&#xff0c;节点…...

【AI News | 20250423】每日AI进展

AI Repos 1、suna Suna是一款完全开源的AI助手&#xff0c;旨在通过自然对话帮助用户轻松完成现实世界的任务。它作为您的数字伙伴&#xff0c;提供研究、数据分析和日常问题解决等功能&#xff0c;并结合强大的能力与直观的界面&#xff0c;理解您的需求并交付成果。Suna的工…...

3.1 Agent定义与分类:自主Agent、协作Agent与混合Agent的特点

随着人工智能技术的快速发展&#xff0c;智能代理&#xff08;Agent&#xff09;作为一种能够感知环境、自主决策并采取行动的计算实体&#xff0c;已成为人工智能领域的重要研究对象和应用工具。特别是在大模型&#xff08;Large Models&#xff09;的赋能下&#xff0c;Agent…...

stack和queue的学习

stack的介绍 stack的文档介绍 stack是一种容器适配器&#xff0c;专门用在具有后进先出操作的上下文环境中&#xff0c;其删除只能从容器的一端进行元素的插入与提取操作。stack是作为容器适配器被实现的&#xff0c;容器适配器即是对特定类封装作为其底层的容器&#xff0c;…...

leetcode-位运算

位运算 371. 两整数之和 题目 给你两个整数 a 和 b &#xff0c;不使用 运算符 和 - &#xff0c;计算并返回两整数之和。 示例 1&#xff1a; 输入&#xff1a; a 1, b 2 输出&#xff1a; 3 示例 2&#xff1a; 输入&#xff1a; a 2, b 3 输出&#xff1a; 5 提示&am…...

《浔川AI翻译v6.1.0问题已修复公告》

《浔川AI翻译v6.1.0问题已修复公告》 尊敬的浔川AI翻译用户&#xff1a; 感谢您对浔川AI翻译的支持与反馈&#xff01;我们已针对 **v6.1.0** 版本中用户反馈的多个问题进行了全面修复&#xff0c;并优化了系统稳定性。以下是本次修复的主要内容&#xff1a; 已修复问题 ✅…...

Unity 创建、读取、改写Excel表格数据

1.导入EPPlus.dll、Excel.dll、Mysql.Data.dll、System.Data.dll&#xff1b;&#xff08;我这里用的是&#xff1a;Unity2017.3.0&#xff09; 2.代码如下&#xff1a; using System.Data; using System.IO; using UnityEngine; using OfficeOpenXml; using UnityEditor; us…...

【阿里云大模型高级工程师ACP习题集】2.3 优化提示词改善答疑机器人回答质量

练习题: 【单选题】在使用大模型进行意图识别时,通过设计特定提示词引导模型生成符合预期回答的方法,其本质是( )。 A. 修改模型本身参数 B. 依靠构造输入激发模型内部已有知识 C. 对模型进行微调 D. 改变模型的训练数据 【多选题】以下哪些属于提示词框架中的要素( )。…...

富文本编辑器实现

&#x1f3a8; 富文本编辑器实现原理全解析 &#x1f4dd; 基本实现路径图 #mermaid-svg-MO1B8a6kAOmD8B6Y {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-MO1B8a6kAOmD8B6Y .error-icon{fill:#552222;}#mermaid-s…...

海量粒子特效解决方案:VEG

Unity 官方除了一个 GPU 粒子特效的解决方案&#xff1a;Visual Effect Graph&#xff0c;即 VEG&#xff0c;能支持百万级粒子特效的播放。在性能要求高的使用场景中&#xff0c;这个解决方案就能完美解决原本 Particle System 性能低下的问题。关于 VEG 的基本使用方法参考官…...

Java高频面试之并发编程-06

hello啊&#xff0c;各位观众姥爷们&#xff01;&#xff01;&#xff01;本baby今天来报道了&#xff01;哈哈哈哈哈嗝&#x1f436; 面试官&#xff1a;线程上下文切换是什么&#xff1f; 线程上下文切换&#xff08;Thread Context Switching&#xff09;是操作系统中 CPU…...

Windows 同步技术-一次性初始化

组件通常设计为在首次调用时执行初始化任务&#xff0c;而不是加载它们时。 一次性初始化函数可确保此初始化仅发生一次&#xff0c;即使多个线程可能尝试初始化也是如此。 Windows Server 2003 和 Windows XP&#xff1a; 应用程序必须使用 互锁函数 或其他同步机制提供自己的…...

Transformer起源-Attention Is All You Need

这篇笔记主要讲解Attention Is All You Need论文。《Attention Is All You Need》由 Ashish Vaswani 等人撰写&#xff0c;于 2017 年发表在 NIPS&#xff08;Neural Information Processing Systems&#xff09;会议上。它提出了一种全新的神经网络架构——Transformer&#x…...

被裁20240927 --- 视觉目标跟踪算法

永远都像初次见你那样使我心荡漾 参考文献目前主流的视觉目标跟踪算法一、传统跟踪算法1. 卡尔曼滤波&#xff08;Kalman Filter&#xff09;2. 相关滤波&#xff08;Correlation Filter&#xff0c;如KCF、MOSSE&#xff09;3. 均值漂移&#xff08;MeanShift/CamShift&#x…...

每日学习Java之一万个为什么(JUC)

文章目录 Git复习synchronized介绍基本概念特点 使用模板1. 同步方法格式特点 2. 同步代码块格式特点 常见面试题1. synchronized的实现原理&#xff1f;2. synchronized与ReentrantLock的区别&#xff1f;3. synchronized的缺点&#xff1f;4. 死锁的四个必要条件&#xff1f;…...

代码分享:python实现svg图片转换为png和gif

import cairosvg import imageio from PIL import Image import io import osdef svg_to_png(svg_path, png_path):try:cairosvg.svg2png(urlsvg_path, write_topng_path)print(f"成功将 {svg_path} 转换为 {png_path}")except Exception as e:print(f"转换为 P…...

前端热门面试题day1

内容回答较粗糙&#xff0c;如有疑问请自行搜索资料 什么是vue中的slot&#xff1f;它有什么作用 Vue中的Slot&#xff08;插槽&#xff09;就像给组件预先留的“内容停车位”&#xff0c;让父组件能把自定义内容“塞”到子组件的指定位置。它的主要作用是&#xff1a; 灵活定…...

DCAN,ECAN和MCAN的区别

DCAN、ECAN和MCAN的主要区别在于它们各自的管理范围和功能。‌ ‌DCAN&#xff08;动力CAN系统&#xff09;‌&#xff1a;DCAN主要负责协调电机控制单元&#xff08;MCU&#xff09;、电池管理系统&#xff08;BMS&#xff09;、直流电压变换器&#xff08;DC/DC&#xff09;和…...

基于Python爬虫的豆瓣电影信息爬取(可以根据选择电影编号得到需要的电影信息)

# 豆瓣电影信息爬虫(展示效果如下图所示:) 这是一个功能强大的豆瓣电影信息爬虫程序,可以获取豆瓣电影 Top 250 的详细信息。 ## 功能特点 - 自动爬取豆瓣电影 Top 250 的所有电影信息 - 支持分页获取,每页 25 部电影,共 10 页 - 获取每部电影的详细信息,包括: - 标题…...

Linux系统学习----概述与目录结构

linux 是一个开源、免费的操作系统&#xff0c;其稳定性、安全性、处理多并发已经得到业界的认可&#xff0c;目前很多企业级的项目 (c/c/php/python/java/go)都会部署到 Linux/unix 系统上。 一、虚拟机系统操作 1.网络连接的三种方式&#xff08;桥接模式、nat模式、主机模…...

软考资料分享

分享一些软考资料 16系统分析师-基础知识精讲夸克网盘分享1701系统分析师夸克网盘分享1804系统架构设计师夸克网盘分享19软考系统架构设计师2024年11月夸克网盘分享2006信息系统项目管理师夸克网盘分享21软考高级信息系统项目夸克网盘分享22系统分析师视频教程真题资料夸克网盘…...

什么是 GLTF/GLB? 3D 内容创建的基本数据格式说明,怎么下载GLB/GLTF格式模型

GLTF 概述 GLTF 是一种 3D 模型格式&#xff0c;广泛用于在 Web 上共享和显示 3D 内容。 它经过优化&#xff0c;可在 WebGL 中轻松加载&#xff0c;使用 WebGL 可以快速高效地渲染 3D 模型。 GLTF 是 Khronos Group 开发的开放标准之一&#xff0c;以 JSON 或二进制格式表示…...

湖南大学-操作系统实验四

HUNAN UNIVERSITY 操作系统实验报告 一、实验题目 实验四 中断、异常和陷阱指令是操作系统的基石&#xff0c;现代操作系统就是由中断驱动的。本实验和实验五的目的在于深刻理解中断的原理和机制&#xff0c;掌握CPU访问中断控制器的方法&#xff0c;掌握Arm体系结构的中断机…...

3.第三章:数据治理的战略价值

文章目录 3.1 数据治理与企业战略3.1.1 数据驱动的决策体系3.1.2 数据资产的价值挖掘3.1.3 风险防控与合规管理 3.2 数据治理的业务价值3.2.1 提升客户体验3.2.2 优化运营效率3.2.3 加速产品创新 3.3 数据治理的技术价值3.3.1 提升数据质量3.3.2 优化数据架构3.3.3 增强系统集成…...

[KVM] KVM挂起状态恢复失败与KVM存储池迁移

背景&#xff1a;发现KVM host上的几台虚拟机挂起了(paused)&#xff0c;但是并没有执行virsh suspend <vm_hostname>&#xff0c;且使用virsh resume <vm_hostname> 无法恢复。原因是这个几个虚拟机归属的存储池所在的磁盘满了。所以想把虚拟机迁移到磁盘空间富余…...

图文结合 - 光伏系统产品设计PRD文档 -(慧哥)慧知开源充电桩平台

光伏系统产品设计PRD文档 ‌版本号‌&#xff1a;1.0 ‌修订日期‌&#xff1a;2023年10月 ‌作者‌&#xff1a; 一、文档概述 1.1 背景与目标 ‌行业背景‌&#xff1a;全球光伏装机量年增长20%&#xff0c;数字化运维需求迫切‌用户痛点‌&#xff1a;现有系统存在数据延…...

linux-相关命令

一、Linux 详细介绍 1. 什么是 Linux&#xff1f; Linux 是一个开源的类 Unix 操作系统&#xff0c;其核心是 Linux 内核。它最早由 Linus Torvalds 在 1991 年发布&#xff0c;后来逐渐发展成各种发行版&#xff08;如 Ubuntu、CentOS、Debian、Arch 等&#xff09;。 2. L…...

Hive中Map和Reduce阶段的分工

在Hive查询执行过程中,Map和Reduce阶段有明确的分工,但实际情况要复杂一些。 基本分工原则 ​​Map阶段​​: 主要职责是读取输入数据并进行初步处理输出键值对形式的数据​​Reduce阶段​​: 接收Map阶段输出的键值对对相同键的值进行聚合/计算输出最终结果实际执行中的复…...

前端笔记-Vue router

学习目标 Vue Router路由管理1、路由配置2、嵌套路由3、路由守卫与权限控制 一、路由配置&#xff08;给网站做地图&#xff09; npm i vue-router ​作用​&#xff1a;告诉浏览器什么地址该显示什么页面 ​核心代码​&#xff1a; // 创建路由并暴露出去// 第一步&#x…...

MySQL的日志--Redo Log【学习笔记】

MySQL的日志--Redo Log 知识来源&#xff1a; 《MySQL是怎样运行的》--- 小孩子4919 MySQL的事务四大特性之一就是持久性&#xff08;Durability&#xff09;。但是底层是如何实现的呢&#xff1f;这就需要我们的Redo Log&#xff08;重做日志&#xff09;闪亮登场了。它记录着…...

《系统分析师-第三阶段—总结(五)》

背景 采用三遍读书法进行阅读&#xff0c;此阶段是第三遍。 过程 第9章 总结 在这个过程中&#xff0c;对导图的规范越来越清楚&#xff0c;开始结构化&#xff0c;找关系&#xff0c;找联系。...

【LangChain4j】AI 第二弹:项目中接入 LangChain4j

普通接入方式 参考文档&#xff1a; Get Started https://docs.langchain4j.dev/get-started 1.添加依赖 <!-- 基于open-ai的langchain4j接口&#xff1a;ChatGPT、deepseek都是open-ai标准下的大模型 --> <dependency><groupId>dev.langchain4j</grou…...

测试基础笔记第十天

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、查询语句1.基本查询2.条件查询3.模糊查询4.范围查询5.判断空 二、其他复杂查询1.排序2.聚合函数3.分组4.分页查询 一、查询语句 1.基本查询 – 需求1: 准备商…...

代理模式:控制对象访问的中间层设计

代理模式&#xff1a;控制对象访问的中间层设计 一、模式核心&#xff1a;通过代理对象控制对目标对象的访问 在软件开发中&#xff0c;有时需要为对象添加一个 “代理” 来控制对它的访问&#xff0c;例如&#xff1a; 远程代理&#xff1a;访问远程对象时&#xff08;如 R…...

Python类和对象二(十一)

构造函数&#xff1a; 重写&#xff1a; 通过类名访问类里面的方法的做法&#xff0c;称为调用未绑定的父类方法&#xff0c;他有时候会产生钻石继承问题&#xff1a; 发现A重复初始化了两次&#xff0c;类c同事继承类B1和B2&#xff0c;类B1和B2又是继承类A的&#xff0c;当c…...

大模型在代码安全检测中的应用

大模型在代码安全检测领域的应用近年来取得显著进展&#xff0c;尤其在代码审查&#xff08;Code Review, CR&#xff09;场景中展现出高效性与准确性。以下是其核心优势、技术路径、挑战及实践案例的总结&#xff1a; 一、技术优势与核心能力 语义理解与上下文分析 大模型通过…...

Python实现图片浏览器

Python实现图片浏览器 支持浏览多种常见图片格式&#xff1a;JPG, JPEG, PNG, GIF, BMP, TIFF, WEBP 通过"打开文件夹"按钮选择任何包含图片的文件夹 灵活的排序选项&#xff1a; 按时间排序&#xff08;新→旧或旧→新&#xff09; 按文件名排序&#xff08;A→…...

网页设计规范:从布局到交互的全方位指南

网页设计规范看似繁杂&#xff0c;但其实都是为了给用户提供更好的体验。只有遵循这些规范&#xff0c;才能设计出既美观又实用的网页&#xff0c;让用户在浏览网页时感到舒适、愉悦。 一、用户体验至上 用户体验&#xff08;UX&#xff09;是网页设计的核心原则之一。设计师…...

哪些心电图表现无缘事业编体检呢?

根据《公务员录用体检通用标准》心血管系统条款及事业单位体检实施细则&#xff0c;心电图不合格主要涉及以下类型及处置方案&#xff1a; 一、心律失常类 早搏&#xff1a;包括房性早搏、室性早搏和交界性早搏。如果每分钟早搏次数较多&#xff08;如超过5次&#xff09;&…...

Java基础系列-HashMap源码解析1-BST树

文章目录 序二叉搜索树&#xff08;BST&#xff09;引入查找5插入9极端情况删除删除叶节点 10删除节点只有左子树或只有右子树删除节点既有左子树又有右子树为什么这么代替&#xff1f; 序 提到HashMap&#xff0c;就不得不提红黑树&#xff08;HashMap1.8之后&#xff09;&am…...

生物计算安全攻防战:从DNA存储破译到碳基芯片防御体系重构

随着碳基生物芯片突破冯诺依曼架构限制&#xff0c;DNA数据存储密度达到1EB/克量级&#xff0c;合成生物学与信息技术的融合正引发新一轮安全革命。本文深入解析碳基芯片逆向工程路径&#xff0c;揭示酶驱动DNA数据解码的技术突破&#xff0c;预警合成生物回路潜在的数据泄露风…...

【金仓数据库征文】从Oracle到KingbaseES的语法兼容与迁移

随着“信创”战略的深入推进&#xff0c;国产数据库逐渐成为IT系统的重要组成部分。KingbaseES&#xff08;金仓数据库&#xff09;凭借其良好的Oracle兼容性和日益完善的生态&#xff0c;成为金融、政务等核心行业国产化替代的重要选项。本文将从语法兼容性分析出发&#xff0…...