Backend Development 15 min read

How to Build Real‑Time Chat with RabbitMQ MQTT and Zero Backend Code

This guide explains how to use RabbitMQ's MQTT plugin and MQTT.js to implement instant messaging, covering MQTT protocol basics, enabling RabbitMQ MQTT and Web‑MQTT, using MQTTBox for testing, creating a pure HTML/JavaScript chat client, and integrating MQTT into a SpringBoot application for backend notifications.

macrozheng
macrozheng
macrozheng
How to Build Real‑Time Chat with RabbitMQ MQTT and Zero Backend Code

MQTT Protocol

MQTT (Message Queuing Telemetry Transport) is a lightweight publish/subscribe communication protocol built on TCP/IP, offering real‑time reliable messaging with minimal code and bandwidth.

MQTT Related Concepts

Publisher: the sender of messages.

Subscriber: the receiver of messages.

Broker: the intermediary that routes messages between publishers and subscribers.

Topic: the routing key for messages; subscribers receive messages published to the topics they subscribe to.

Payload: the content of a message.

QoS (Quality of Service):

QoS 0 (At most once): may lose or duplicate messages.

QoS 1 (At least once): ensures delivery but may duplicate.

QoS 2 (Exactly once): guarantees a single delivery.

Enable MQTT in RabbitMQ

RabbitMQ requires installation and then enabling the MQTT plugin.

Install and start RabbitMQ.

Enable the MQTT plugin with the command:

<code>rabbitmq-plugins enable rabbitmq_mqtt</code>

After enabling, the MQTT service runs on port

1883

.

MQTT Client

Use MQTTBox to test MQTT instant‑messaging functionality.

Download and install MQTTBox.

Click

Create MQTT Client

to create a client.

Configure the client with broker address, username, password, and QoS.

Add a subscriber for topic

testTopicA

and publish messages to it.

The subscriber receives messages in real time.

Frontend Direct Instant Messaging

Using HTML + JavaScript and RabbitMQ Web‑MQTT, you can implement a simple chat without any backend code.

Enable RabbitMQ Web‑MQTT support:

<code>rabbitmq-plugins enable rabbitmq_web_mqtt</code>

Web‑MQTT runs on port

15675

.

Use the

MQTT.js

library (https://github.com/mqttjs/MQTT.js) to communicate with the broker.

HTML page example (code block) shows UI elements, connection to

ws://localhost:15675/ws

, subscription, message publishing, and display.

<code>&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;title&gt;Title&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div&gt;
    &lt;label&gt;目标Topic:&lt;input id="targetTopicInput" type="text"&gt;&lt;/label&gt;&lt;br&gt;
    &lt;label&gt;发送消息:&lt;input id="messageInput" type="text"&gt;&lt;/label&gt;&lt;br&gt;
    &lt;button onclick="sendMessage()"&gt;发送&lt;/button&gt;
    &lt;button onclick="clearMessage()"&gt;清空&lt;/button&gt;
    &lt;div id="messageDiv"&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;script src="https://unpkg.com/mqtt/dist/mqtt.min.js"&gt;&lt;/script&gt;
&lt;script&gt;
    // RabbitMQ web‑mqtt connection address
    const url = 'ws://localhost:15675/ws';
    // Get topic from URL query string
    const topic = getQueryString("topic");
    // Connect to the broker
    let client = mqtt.connect(url);
    client.on('connect', function () {
        client.subscribe(topic, function (err) {
            if (!err) {
                showMessage("订阅topic:" + topic + "成功!");
            }
        });
    });
    // Receive messages
    client.on('message', function (topic, message) {
        showMessage("收到消息:" + message.toString());
    });
    // Send message
    function sendMessage() {
        let targetTopic = document.getElementById("targetTopicInput").value;
        let message = document.getElementById("messageInput").value;
        client.publish(targetTopic, message);
        showMessage("发送消息给" + targetTopic + "的消息:" + message);
    }
    // Get query string parameter
    function getQueryString(name) {
        let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
        let r = window.location.search.substr(1).match(reg);
        if (r != null) {
            return decodeURIComponent(r[2]);
        }
        return null;
    }
    // Display message in the list
    function showMessage(message) {
        let messageDiv = document.getElementById("messageDiv");
        let messageEle = document.createElement("div");
        messageEle.innerText = message;
        messageDiv.appendChild(messageEle);
    }
    // Clear message list
    function clearMessage() {
        let messageDiv = document.getElementById("messageDiv");
        messageDiv.innerHTML = "";
    }
&lt;/script&gt;
&lt;/html&gt;</code>

Testing with Two Pages

Open two pages with topics

testTopicA

(http://localhost:8088/page/index?topic=testTopicA) and

testTopicB

(http://localhost:8088/page/index?topic=testTopicB).

Send messages between them and observe real‑time updates.

Using MQTT in SpringBoot

When backend notification is required, integrate MQTT into a SpringBoot application.

Add the

spring-integration-mqtt

dependency in

pom.xml

:

<code>&lt;dependency&gt;
    &lt;groupId&gt;org.springframework.integration&lt;/groupId&gt;
    &lt;artifactId&gt;spring-integration-mqtt&lt;/artifactId&gt;
&lt;/dependency&gt;</code>

Configure MQTT settings in

application.yml

(url, username, password, defaultTopic).

<code>rabbitmq:
  mqtt:
    url: tcp://localhost:1883
    username: guest
    password: guest
    defaultTopic: testTopic</code>

Create a Java configuration class

MqttConfig

to bind these properties.

<code>@Data
@EqualsAndHashCode(callSuper = false)
@Component
@ConfigurationProperties(prefix = "rabbitmq.mqtt")
public class MqttConfig {
    private String username;
    private String password;
    private String defaultTopic;
    private String url;
}</code>

Configure inbound message handling with a

@ServiceActivator

that logs received payloads.

<code>@Configuration
public class MqttInboundConfig {
    @Autowired
    private MqttConfig mqttConfig;

    @Bean
    public MessageChannel mqttInputChannel() {
        return new DirectChannel();
    }

    @Bean
    public MessageProducer inbound() {
        MqttPahoMessageDrivenChannelAdapter adapter =
            new MqttPahoMessageDrivenChannelAdapter(mqttConfig.getUrl(), "subscriberClient",
                mqttConfig.getDefaultTopic());
        adapter.setCompletionTimeout(5000);
        adapter.setConverter(new DefaultPahoMessageConverter());
        adapter.setQos(1);
        adapter.setOutputChannel(mqttInputChannel());
        return adapter;
    }

    @Bean
    @ServiceActivator(inputChannel = "mqttInputChannel")
    public MessageHandler handler() {
        return message -> log.info("handleMessage : {}", message.getPayload());
    }
}
</code>

Configure outbound publishing with a gateway and a

@ServiceActivator

that sends messages to the default topic.

<code>@Configuration
public class MqttOutboundConfig {
    @Autowired
    private MqttConfig mqttConfig;

    @Bean
    public MqttPahoClientFactory mqttClientFactory() {
        DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
        MqttConnectOptions options = new MqttConnectOptions();
        options.setServerURIs(new String[]{ mqttConfig.getUrl() });
        options.setUserName(mqttConfig.getUsername());
        options.setPassword(mqttConfig.getPassword().toCharArray());
        factory.setConnectionOptions(options);
        return factory;
    }

    @Bean
    @ServiceActivator(inputChannel = "mqttOutboundChannel")
    public MessageHandler mqttOutbound() {
        MqttPahoMessageHandler handler = new MqttPahoMessageHandler("publisherClient", mqttClientFactory());
        handler.setAsync(true);
        handler.setDefaultTopic(mqttConfig.getDefaultTopic());
        return handler;
    }

    @Bean
    public MessageChannel mqttOutboundChannel() {
        return new DirectChannel();
    }
}
</code>

Define an MQTT gateway interface for sending messages.

<code>@Component
@MessagingGateway(defaultRequestChannel = "mqttOutboundChannel")
public interface MqttGateway {
    void sendToMqtt(String payload);
    void sendToMqtt(String payload, @Header(MqttHeaders.TOPIC) String topic);
    void sendToMqtt(@Header(MqttHeaders.TOPIC) String topic, @Header(MqttHeaders.QOS) int qos, String payload);
}
</code>

Create a REST controller exposing endpoints to send messages to the default topic or a specified topic.

<code>@RestController
@RequestMapping("/mqtt")
public class MqttController {
    @Autowired
    private MqttGateway mqttGateway;

    @PostMapping("/sendToDefaultTopic")
    public CommonResult sendToDefaultTopic(String payload) {
        mqttGateway.sendToMqtt(payload);
        return CommonResult.success(null);
    }

    @PostMapping("/sendToTopic")
    public CommonResult sendToTopic(String payload, String topic) {
        mqttGateway.sendToMqtt(payload, topic);
        return CommonResult.success(null);
    }
}
</code>

Calling the API sends messages; logs show successful receipt:

<code>2020-09-17 14:29:01.689  INFO 11192 --- [ubscriberClient] c.m.mall.tiny.config.MqttInboundConfig   : handleMessage : 来自网页上的消息
2020-09-17 14:29:06.101  INFO 11192 --- [ubscriberClient] c.m.mall.tiny.config.MqttInboundConfig   : handleMessage : 来自网页上的消息
2020-09-17 14:29:07.384  INFO 11192 --- [ubscriberClient] c.m.mall.tiny.config.MqttInboundConfig   : handleMessage : 来自网页上的消息
</code>

Conclusion

Message middleware is increasingly popular; it provides reliable asynchronous communication and can also serve instant‑messaging needs. If no special business requirements exist, clients or front‑ends can directly use MQTT to achieve real‑time chat. When backend integration is required, SpringBoot offers a straightforward way to incorporate MQTT, making message middleware a solid choice for instant communication.

WebSocketRabbitMQSpringBootInstant MessagingMQTT
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.