diff --git a/discord4j/.gitignore b/discord4j/.gitignore
new file mode 100644
index 0000000000..b56f1dd0d0
--- /dev/null
+++ b/discord4j/.gitignore
@@ -0,0 +1,33 @@
+README.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/discord4j/pom.xml b/discord4j/pom.xml
new file mode 100644
index 0000000000..7687f63ad5
--- /dev/null
+++ b/discord4j/pom.xml
@@ -0,0 +1,63 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.3.5.RELEASE
+
+
+ com.baeldung
+ discord4j-bot
+ 0.0.1-SNAPSHOT
+ discord4j-bot
+ Demo Discord bot using Discord4J + Spring Boot
+
+
+ 1.8
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.junit.vintage
+ junit-vintage-engine
+
+
+
+
+
+ com.discord4j
+ discord4j-core
+ 3.1.1
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ 1.8
+
+
+
+
+
+
diff --git a/discord4j/src/main/java/com/baeldung/discordbot/BotConfiguration.java b/discord4j/src/main/java/com/baeldung/discordbot/BotConfiguration.java
new file mode 100644
index 0000000000..a60005e9b5
--- /dev/null
+++ b/discord4j/src/main/java/com/baeldung/discordbot/BotConfiguration.java
@@ -0,0 +1,48 @@
+package com.baeldung.discordbot;
+
+import com.baeldung.discordbot.events.EventListener;
+import discord4j.core.DiscordClientBuilder;
+import discord4j.core.GatewayDiscordClient;
+import discord4j.core.event.domain.Event;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.List;
+
+@Configuration
+public class BotConfiguration {
+
+ private static final Logger log = LoggerFactory.getLogger( BotConfiguration.class );
+
+ @Value("${token}")
+ private String token;
+
+ @Bean
+ public GatewayDiscordClient gatewayDiscordClient(List> eventListeners) {
+ GatewayDiscordClient client = null;
+
+ try {
+ client = DiscordClientBuilder.create(token)
+ .build()
+ .login()
+ .block();
+
+ for(EventListener listener : eventListeners) {
+ client.on(listener.getEventType())
+ .flatMap(listener::execute)
+ .onErrorResume(listener::handleError)
+ .subscribe();
+ }
+
+ client.onDisconnect().block();
+ }
+ catch ( Exception exception ) {
+ log.error( "Be sure to use a valid bot token!", exception );
+ }
+
+ return client;
+ }
+}
diff --git a/discord4j/src/main/java/com/baeldung/discordbot/DiscordBotApplication.java b/discord4j/src/main/java/com/baeldung/discordbot/DiscordBotApplication.java
new file mode 100644
index 0000000000..069a36635c
--- /dev/null
+++ b/discord4j/src/main/java/com/baeldung/discordbot/DiscordBotApplication.java
@@ -0,0 +1,12 @@
+package com.baeldung.discordbot;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class DiscordBotApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(DiscordBotApplication.class, args);
+ }
+}
diff --git a/discord4j/src/main/java/com/baeldung/discordbot/events/EventListener.java b/discord4j/src/main/java/com/baeldung/discordbot/events/EventListener.java
new file mode 100644
index 0000000000..ca4c79de0d
--- /dev/null
+++ b/discord4j/src/main/java/com/baeldung/discordbot/events/EventListener.java
@@ -0,0 +1,19 @@
+package com.baeldung.discordbot.events;
+
+import discord4j.core.event.domain.Event;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import reactor.core.publisher.Mono;
+
+public interface EventListener {
+
+ Logger LOG = LoggerFactory.getLogger(EventListener.class);
+
+ Class getEventType();
+ Mono execute(T event);
+
+ default Mono handleError(Throwable error) {
+ LOG.error("Unable to process " + getEventType().getSimpleName(), error);
+ return Mono.empty();
+ }
+}
diff --git a/discord4j/src/main/java/com/baeldung/discordbot/events/MessageCreateListener.java b/discord4j/src/main/java/com/baeldung/discordbot/events/MessageCreateListener.java
new file mode 100644
index 0000000000..f545489804
--- /dev/null
+++ b/discord4j/src/main/java/com/baeldung/discordbot/events/MessageCreateListener.java
@@ -0,0 +1,19 @@
+package com.baeldung.discordbot.events;
+
+import discord4j.core.event.domain.message.MessageCreateEvent;
+import org.springframework.stereotype.Service;
+import reactor.core.publisher.Mono;
+
+@Service
+public class MessageCreateListener extends MessageListener implements EventListener {
+
+ @Override
+ public Class getEventType() {
+ return MessageCreateEvent.class;
+ }
+
+ @Override
+ public Mono execute(MessageCreateEvent event) {
+ return processCommand(event.getMessage());
+ }
+}
diff --git a/discord4j/src/main/java/com/baeldung/discordbot/events/MessageListener.java b/discord4j/src/main/java/com/baeldung/discordbot/events/MessageListener.java
new file mode 100644
index 0000000000..e1f48468be
--- /dev/null
+++ b/discord4j/src/main/java/com/baeldung/discordbot/events/MessageListener.java
@@ -0,0 +1,19 @@
+package com.baeldung.discordbot.events;
+
+import discord4j.core.object.entity.Message;
+import reactor.core.publisher.Mono;
+
+public abstract class MessageListener {
+
+ public Mono 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();
+ }
+}
diff --git a/discord4j/src/main/java/com/baeldung/discordbot/events/MessageUpdateListener.java b/discord4j/src/main/java/com/baeldung/discordbot/events/MessageUpdateListener.java
new file mode 100644
index 0000000000..62802d4903
--- /dev/null
+++ b/discord4j/src/main/java/com/baeldung/discordbot/events/MessageUpdateListener.java
@@ -0,0 +1,22 @@
+package com.baeldung.discordbot.events;
+
+import discord4j.core.event.domain.message.MessageUpdateEvent;
+import org.springframework.stereotype.Service;
+import reactor.core.publisher.Mono;
+
+@Service
+public class MessageUpdateListener extends MessageListener implements EventListener {
+
+ @Override
+ public Class getEventType() {
+ return MessageUpdateEvent.class;
+ }
+
+ @Override
+ public Mono execute(MessageUpdateEvent event) {
+ return Mono.just(event)
+ .filter(MessageUpdateEvent::isContentChanged)
+ .flatMap(MessageUpdateEvent::getMessage)
+ .flatMap(super::processCommand);
+ }
+}
diff --git a/discord4j/src/main/resources/application.yml b/discord4j/src/main/resources/application.yml
new file mode 100644
index 0000000000..e2079e33b4
--- /dev/null
+++ b/discord4j/src/main/resources/application.yml
@@ -0,0 +1 @@
+token: 'our-token-here'
diff --git a/discord4j/src/test/java/com/baeldung/discordbot/DiscordBotLiveTest.java b/discord4j/src/test/java/com/baeldung/discordbot/DiscordBotLiveTest.java
new file mode 100644
index 0000000000..8d9a285748
--- /dev/null
+++ b/discord4j/src/test/java/com/baeldung/discordbot/DiscordBotLiveTest.java
@@ -0,0 +1,12 @@
+package com.baeldung.discordbot;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+public class DiscordBotLiveTest {
+
+ @Test
+ public void contextTest() {
+ }
+}
diff --git a/pom.xml b/pom.xml
index cba7e33b03..6c96d8d77e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -397,6 +397,7 @@
ddd
deeplearning4j
+ discord4j
disruptor
dozer
drools
@@ -909,6 +910,7 @@
ddd
deeplearning4j
+ discord4j
disruptor
dozer
drools