1.概述
Discord4J是一个开源Java库,主要可用于快速访问Discord Bot API 。它与Project Reactor高度集成,以提供完全无阻塞的反应式API。
在本教程中,我们将使用Discord4J创建一个能够响应预定义命令的简单Discord机器人。我们将在Spring Boot的基础上构建该bot,以演示在Spring Boot启用的许多其他功能上扩展我们的bot是多么容易。
完成后,该机器人将能够侦听名为“!todo”的命令,并将打印出静态定义的待办事项列表。
2.创建一个Discord的应用程序
为了使我们的机器人能够接收来自Discord的更新并在通道中发布响应,我们需要在Discord开发人员门户中创建一个Discord应用程序并将其设置为机器人。这是一个简单的过程。由于Discord允许在一个开发人员账户下创建多个应用程序或漫游器,因此可以使用不同的设置多次尝试。
以下是创建新应用程序的步骤:
- 登录到Discord开发人员门户
- 在“应用程序”选项卡中,单击“新应用程序”
- 输入我们的机器人的名称,然后点击“创建”
- 上载应用程序图标和说明,然后单击“保存更改”
现在已经存在一个应用程序,我们只需要向它添加漫游器功能即可。这将生成Discord4J所需的机器人令牌。
以下是将应用程序转换为机器人程序的步骤:
- 在“应用程序”选项卡中,选择我们的应用程序(如果尚未选择)。
- 在Bot标签中,点击“添加Bot”,然后确认我们要这样做。
既然我们的应用程序已经成为真正的机器人,请复制令牌,以便可以将其添加到我们的应用程序属性中。注意不要公开共享此令牌,因为其他人将能够在模仿我们的机器人的同时执行恶意代码。
现在我们准备编写一些代码!
3.创建一个Spring Boot应用
构建新的Spring Boot应用程序后,我们需要确保包括Discord4J核心依赖项:
<dependency>
<groupId>com.discord4j</groupId>
<artifactId>discord4j-core</artifactId>
<version>3.1.1</version>
</dependency>
Discord4J的工作方式是使用我们之前创建的机器人令牌GatewayDiscordClient
这个客户端对象允许我们注册事件侦听器并配置许多东西,但至少必须至少调用login()
方法。这会将我们的漫游器显示为在线。
首先,让我们将bot令牌添加到application.yml
文件中:
token: 'our-token-here'
接下来,让我们将其注入@Configuration
类,在其中可以实例化GatewayDiscordClient
:
@Configuration
public class BotConfiguration {
@Value("${token}")
private String token;
@Bean
public GatewayDiscordClient gatewayDiscordClient() {
return DiscordClientBuilder.create(token)
.build()
.login()
.block();
}
}
在这一点上,我们的机器人将被视为在线,但目前还没有任何作用。让我们添加一些功能。
4.添加事件监听器
聊天机器人的最常见功能是命令。这是在CLI中看到的一种抽象,其中用户键入一些文本以触发某些功能。我们可以在Discord机器人中通过侦听用户发送的新消息并在适当的时候以智能回复来实现此目的。
我们可以听很多类型的事件。但是,注册所有侦听器的方法都是相同的,因此让我们首先为所有事件侦听器创建一个接口:
import discord4j.core.event.domain.Event;
public interface EventListener<T extends Event> {
Logger LOG = LoggerFactory.getLogger(EventListener.class);
Class<T> getEventType();
Mono<Void> execute(T event);
default Mono<Void> handleError(Throwable error) {
LOG.error("Unable to process " + getEventType().getSimpleName(), error);
return Mono.empty();
}
}
现在,我们可以根据需要为所有discord4j.core.event.domain.Event
扩展实现此接口。
在实现第一个事件侦听器之前,让我们修改客户端@Bean
配置以获取EventListener列表,以便它可以注册在Spring ApplicationContext
EventListener
:
@Bean
public <T extends Event> GatewayDiscordClient gatewayDiscordClient(List<EventListener<T>> eventListeners) {
GatewayDiscordClient client = DiscordClientBuilder.create(token)
.build()
.login()
.block();
for(EventListener<T> listener : eventListeners) {
client.on(listener.getEventType())
.flatMap(listener::execute)
.onErrorResume(listener::handleError)
.subscribe();
}
return client;
}
现在,注册事件侦听器所需要做的就是实现我们的接口,并使用@Component
的构造型注释对其进行注释。现在,注册将自动为我们进行!
我们可以选择分别显式地注册每个事件。但是,通常最好采用模块化的方法,以实现更好的代码可伸缩性。
现在我们的事件侦听器设置已完成,但该漫游器仍未执行任何操作,因此让我们添加一些事件以进行侦听。
4.1 命令处理
要接收用户的命令,我们可以侦听两种不同的事件类型: MessageCreateEvent
用于新消息,而MessageUpdateEvent
用于更新消息。我们可能只想听新消息,但是作为学习的机会,让我们假设我们要为我们的机器人同时支持两种事件。这将提供一层额外的健壮性,我们的用户可能会喜欢。
这两个事件对像都包含有关每个事件的所有相关信息。特别是,我们对消息的内容,消息的作者以及发布到的渠道感兴趣。幸运的是,所有这些数据点都存在于这两种事件类型都提供Message
收到Message
,我们可以检查作者以确保它不是机器人,我们可以检查消息内容以确保它与我们的命令匹配,并且可以使用消息的通道发送响应。
因为我们可以通过它们的Message
对象完全处理两个事件,所以让我们将所有下游逻辑放在一个公共位置,以便两个事件侦听器都可以使用它:
import discord4j.core.object.entity.Message;
public abstract class MessageListener {
public Mono<Void> processCommand(Message eventMessage) {
return Mono.just(eventMessage)
.filter(message -> message.getAuthor().map(user -> !user.isBot()).orElse(false))
.filter(message -> message.getContent().equalsIgnoreCase("!todo"))
.flatMap(Message::getChannel)
.flatMap(channel -> channel.createMessage("Things to do today:\n - write a bot\n - eat lunch\n - play a game"))
.then();
}
}
这里有很多事情要做,但这是命令和响应的最基本形式。这种方法使用了反应式功能设计,但是可以使用block()
以更传统的命令式方式编写此功能。
跨多个bot命令扩展,调用不同的服务或数据存储库,甚至使用Discord角色作为对某些命令的授权,都是良好的bot命令体系结构的常见部分。由于我们的监听器是Spring管理的@Service
,因此我们可以轻松地注入其他Spring管理的bean来完成这些任务。但是,在本文中我们不会解决任何问题。
4.2 EventListener<MessageCreateEvent>
要接收来自用户的新消息,我们必须收听MessageCreateEvent
。由于命令处理逻辑已经存在于MessageListener
,我们可以对其进行扩展以继承该功能。另外,我们需要实现EventListener
接口以符合我们的注册设计:
@Service
public class MessageCreateListener extends MessageListener implements EventListener<MessageCreateEvent> {
@Override
public Class<MessageCreateEvent> getEventType() {
return MessageCreateEvent.class;
}
@Override
public Mono<Void> execute(MessageCreateEvent event) {
return processCommand(event.getMessage());
}
}
通过继承,消息将传递到我们的processCommand()
方法,在该方法中发生所有验证和响应。
此时,我们的机器人将接收并响应“!todo”命令。但是,如果用户更正了他们键入错误的命令,则该漫游器将不会响应。让我们用另一个事件侦听器来支持此用例。
4.3 EventListener<MessageUpdateEvent>
用户编辑消息时,将发送MessageUpdateEvent
我们可以侦听此事件以识别命令,就像侦听MessageCreateEvent
。
就我们的目的而言,我们仅在消息内容已更改的情况下关心此事件。我们可以忽略此事件的其他实例。幸运的是,我们可以使用isContentChanged()
方法来过滤掉此类实例:
@Service
public class MessageUpdateListener extends MessageListener implements EventListener<MessageUpdateEvent> {
@Override
public Class<MessageUpdateEvent> getEventType() {
return MessageUpdateEvent.class;
}
@Override
public Mono<Void> execute(MessageUpdateEvent event) {
return Mono.just(event)
.filter(MessageUpdateEvent::isContentChanged)
.flatMap(MessageUpdateEvent::getMessage)
.flatMap(super::processCommand);
}
}
在这种情况下,由于getMessage()
返回Mono<Message>
而不是原始Message
,因此我们需要使用flatMap()
将其发送到我们的超类。
5.测试Discord机器人
现在我们有了一个运行正常的Discord机器人,我们可以将其邀请到Discord服务器并对其进行测试。
要创建邀请链接,我们必须指定漫游器正常运行所需的权限。流行的第三方“不和谐权限计算器”通常用于生成具有所需权限的邀请链接。尽管不建议将其用于生产,但我们可以仅出于测试目的选择“管理员”,而不必担心其他权限。只需提供我们的机器人的客户端ID(可在Discord Developer Portal中找到),然后使用生成的链接邀请我们的机器人到服务器即可。
如果我们不向该机器人授予管理员权限,则可能需要调整通道权限,以便该机器人可以在通道中进行读写。
现在,机器人会响应消息“!todo”,并且在编辑消息时说“!todo”:
6.概述
本教程描述了使用Discord4J库和Spring Boot创建Discord bot的所有必要步骤。最后,它描述了如何为机器人设置基本的可伸缩命令和响应结构。
对于完整且有效的机器人,请在GitHub上查看源代码。需要有效的机器人令牌才能运行它。
0 评论