Springboot简单集成安装MQTT与Kafka

1. 依赖/配置

依赖

<!-- MQTT -->
<dependency>
    <groupId>org.eclipse.paho</groupId>
    <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
    <version>1.2.5</version>
</dependency>
<!--kafka-->
<dependency>
    <groupId>org.springframework.kafka</groupId>
    <artifactId>spring-kafka</artifactId>
</dependency>

配置

spring:
  main:
    allow-circular-references: true #允许循环依赖,如果有这个情况的话
  kafka:
    bootstrap-servers: localhost:9092  #kafka地址

# ----MQTT
customer:
  mqtt:
    broker: tcp://localhost:1883
      clientId: nays_service #发布客户端ID
      userName: admin 
      password: public

2. 订阅/发布

2.1 Kafka

消息生产者

package com.jdck.msg.kafka;

import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.ExecutionException;

/**
 * 创建消息生产者
 *
 * @author gongjp
 * @since 2024/8/21 13:42
 */
@Component
@Slf4j
public class KafkaProducer {

    @Resource
    private KafkaTemplate<String, Object> kafkaTemplate;

    public static final String TOPIC_TEST = "kafka-test";

    public static final String TOPIC_GROUP = "test-consumer-group";

    public void send(Object obj) throws ExecutionException, InterruptedException {
        // 发送消息
        kafkaTemplate.send(TOPIC_TEST, obj);
        log.info("【Kafka】--[{}]<发送>消息{}",TOPIC_TEST ,obj);
    }
}

消息消费者

package com.jdck.msg.kafka;

import lombok.extern.slf4j.Slf4j;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;

/**
 * 创建消息消费者
 *
 * @author gongjp
 * @since 2024/8/21 13:44
 */
@Component
@Slf4j
public class KafkaConsumer {

    @KafkaListener(topics = KafkaProducer.TOPIC_TEST, groupId = KafkaProducer.TOPIC_GROUP)
    public void topicTest(String message) {
        log.info("【Kafka】--[{}]<接收>消息{}", KafkaProducer.TOPIC_TEST, message);
    }

}

2.2 MQTT

配置类(构建客户端)

package com.jdck.msg.mqtt;

import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * MQTT配置类
 *
 * @author gongjp
 * @since 2024/8/21 14:38
 */
@Configuration
public class MqttConfig {
    // 使用@Value注解从配置文件读取MQTT服务器的URL
    @Value("${customer.mqtt.url:tcp://localhost:1883}")
    private String url;

    // 客户端ID,通常每个客户端应该有一个唯一的ID
    @Value("${customer.mqtt.clientId:SpringBootMqttClient}")
    private String clientId;

    // 用户名和密码(可选)
    @Value("${customer.mqtt.username:}")
    private String username;

    @Value("${customer.mqtt.password:}")
    private String password;

    // 创建一个MqttClient的Bean,这样它就可以被Spring容器管理
    @Bean
    public MqttClient mqttClient() throws Exception {
        // 创建MqttClient实例
        MqttClient client = new MqttClient(url, clientId);
        // 设置连接选项
        MqttConnectOptions connOpts = new MqttConnectOptions();
        connOpts.setCleanSession(true); // 清理会话

        // 如果提供了用户名和密码,则设置它们
        if (username != null && password != null) {
            connOpts.setUserName(username);
            connOpts.setPassword(password.toCharArray());
        }

        // 连接到MQTT服务器
        client.connect(connOpts);
        return client;
    }

}

发布

package com.jdck.msg.mqtt;

import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 消息发布
 *
 * @author gongjp
 * @since 2024/8/21 14:40
 */
// 标记这是一个服务类
@Service
@Slf4j
public class MqttPublisher {

    // 自动注入MqttClient的Bean
    @Autowired
    private MqttClient mqttClient;

    // 定义一个方法来发送MQTT消息
    public void publish(String topic, String payload) throws Exception {
        // 创建一个MqttMessage实例,设置消息内容
        MqttMessage message = new MqttMessage(payload.getBytes());
        // 发送消息到指定的主题
        mqttClient.publish(topic, message);
        log.info("【MQTT】--[{}]<发送>消息:{}",topic,message);
    }
}

接收消息

package com.jdck.msg.mqtt;

import com.jdck.msg.kafka.KafkaProducer;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.*;
import org.springframework.stereotype.Component;

/**
 * XXX
 *
 * @author gongjp
 * @since 2024/8/21 14:57
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class MqttSubscriber implements MqttCallback {

    private final MqttClient mqttClient;
    private final KafkaProducer kafkaProducer;

    /**
     * 应用启动时订阅MQTT主题
     *
     * @throws MqttException 如果订阅过程中发生异常
     */
    @PostConstruct
    public void start() throws MqttException {
        mqttClient.setCallback(this);
        mqttClient.subscribe("mqtt/receive");
    }

    /**
     * 应用关闭时断开MQTT连接(可选)
     *
     * @throws MqttException 如果断开连接过程中发生异常
     */
    @PreDestroy
    public void stop() throws MqttException {
        mqttClient.disconnect();
    }


    /**
     * 连接丢失时的处理逻辑
     * @param throwable
     */
    @Override
    public void connectionLost(Throwable throwable) {

    }

    /**
     * 处理接收到的消息
     * @param topic topic
     * @param mqttMessage 消息
     * @throws Exception
     */
    @Override
    public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
        log.info("【MQTT】--[{}]<接收>消息:{}",topic,mqttMessage);
        //接收到消息再发送到kafka
        kafkaProducer.send(mqttMessage.toString());
    }

    @Override
    public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {

    }
}

3. 测试

3.1 Controller

package com.jdck.msg.controller;

import com.jdck.msg.kafka.KafkaProducer;
import com.jdck.msg.mqtt.MqttPublisher;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * 测试服务类
 *
 * @author gongjp
 * @since 2024/8/21 10:03
 */
@RestController
@Slf4j
@RequiredArgsConstructor
public class SendController {

    private final MqttPublisher mqttPublisher;
    private final KafkaProducer kafkaProducer; // 注意使用自己创建的,看清楚!

    /**
     * 发送mqtt信息
     * @param topic 要发到哪一个主题
     * @param msg 发送的消息
     * @return
     */
    @RequestMapping("/send/mqtt")
    public String sendMessageByMqtt(String topic,String msg){
        try {
            mqttPublisher.publish(topic,msg);
            return "发送成功";
        } catch (Exception e) {
            log.error("发送失败",e);
            return "发送失败";
        }
    }

    /**
     * 发送Kafka消息
     * 
     * @param msg
     * @return
     */
    @RequestMapping("/send/kafka")
    public String sendMessageByKafka(String msg){
        try {
            kafkaProducer.send(msg);
            return "发送成功";
        } catch (Exception e) {
            log.error("发送失败",e);
            return "发送失败";
        }
    }
}

3.2 MQTTX

使用mqtt建立连接然后发送信息到指定的topic

4. 参考/安装教程

4.1. MQTT

  1. springboot集成mqtt

springboot集成mqtt

4.2 Kafka

  1. kafka安装
kafka 安装、配置、启动、测试说明:
1. 安装:直接官网下载安装包,解压到指定位置即可(kafka 依赖的 Zookeeper 在文件中已包含)
下载地址:https://kafka.apache.org/downloads
示例版本:kafka_2.13-2.8.0.tgz
下载后可本地解压安装,解压位置自选,如 D:\Java 下
解压命令:tar -zxvf kafka_2.13-2.8.0.tgz
PS:可在 idea 命令行窗口或 git 提供的命令窗口中进行命令操作
使用 git 提供的命令窗口:空白文件夹中右键——》Git Bash Here 即可打开
2. 添加地址配置
在 D:\Java\kafka_2.13-2.8.0\config\server.properties 中搜索添加以下两行配置:
listeners=PLAINTEXT://localhost:9092
advertised.listeners=PLAINTEXT://localhost:9092
说明:以上配置默认是注释掉的,可搜索找到,根据需求进行自定义地址配置
  1. Kafka的使用(Windows中)

Kafka使用

### PurchaseServlet的设计与实现 以下是基于需求编写的 `PurchaseServlet` 类,该类实现了通过 `HttpSession` 管理购物车状态、将生成的 Session ID 存储到 Cookie 中,并最终重定向至 `CartServlet` 页面。 #### 代码实现 ```java import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @WebServlet("/purchase") public class PurchaseServlet extends HttpServlet { private static final long serialVersionUID = 1L; @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 获取当前会话或创建新会话 HttpSession session = request.getSession(true); // 初始化购物车对象(如果尚未存在) if (session.getAttribute("cart") == null) { Cart cart = new Cart(); // 假设已定义了一个名为 Cart 的购物车类 session.setAttribute("cart", cart); } // 将 Session ID 添加到 Cookie 并设置过期时间 String sessionId = session.getId(); Cookie cookie = new Cookie("JSESSIONID", sessionId); cookie.setPath("/"); cookie.setMaxAge(60 * 30); // 设置 Cookie 过期时间为 30 分钟 response.addCookie(cookie); // 重定向到 CartServlet 页面 response.sendRedirect(request.getContextPath() + "/cart"); } } ``` --- ### 功能解析 1. **获取或创建会话** 使用 `request.getSession(true)` 方法确保每次请求都会返回一个有效的会话实例。如果不存在现有会话,则自动创建一个新的会话[^1]。 2. **初始化购物车对象** 如果会话中未绑定购物车对象,则创建新的 `Cart` 对象并将其存储在会话中。此操作确保每个用户的购物车状态独立维护[^4]。 3. **存储 Session ID 到 Cookie** 创建一个名为 `JSESSIONID` 的 Cookie 来保存会话标识符,并设置其路径为根路径 (`/`) 最大存活时间为 30 分钟。这样客户端可以在后续请求中携带该 Cookie 自动恢复会话状态[^2]。 4. **重定向至目标页面** 调用 `response.sendRedirect()` 方法将用户重定向到指定的目标地址 `/cart`,即 `CartServlet` 处理程序所在位置[^5]。 --- ### 注意事项 - 需要提前定义好 `Cart` 类及其方法,以便支持实际业务逻辑。 - 若项目运行过程中遇到 XML 文件配置错误或其他问题,可根据提示调整 Tomcat 或 IDE 的环境设置。 - 在生产环境中应考虑安全性措施,例如加密敏感数据或将重要信息存储于服务器端而非客户端 Cookie 中。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值