springboot项目通过EMQX整合MQTT

1 篇文章 0 订阅

记录一次项目需求中要求使用emqx平台并通过mqtt协议的任务,首先必须安装搭建emqx,官网根据需求安装即可。

本文参考转载于- java连接MQTT服务器(Springboot整合MQTT)_mqtt java-CSDN博客

1、首先springboot项目中引入有关mqtt的 pom文件依赖

        <dependency>
            <groupId>org.springframework.integration</groupId>
            <artifactId>spring-integration-mqtt</artifactId>
        </dependency>

2、application.properties中配置

## MQTT##
mqtt.host=tcp://xxx.xx.xx.xx:1883
mqtt.clientId=xxxx
mqtt.username=xxxxxxxx
mqtt.password=xxxxxxxx

3、mqtt工具类



/**
 * MQTT工具类操作
 *
 */
@Slf4j
@Component
public class MQTTConnect {

  @Value("${mqtt.host}")
  private String HOST;

  @Value("${mqtt.clientId}")
  private String clientId;


  private MqttClient mqttClient;

  /**
   * 客户端connect连接mqtt服务器
   *
   * @param username 用户名
   * @param password 密码
   * @param mqttCallback 回调函数
   **/
  public void setMqttClient(String username, String password, MqttCallback mqttCallback)
      throws MqttException {
    MqttConnectOptions options = mqttConnectOptions(username, password);
        /*if (mqttCallback == null) {
            mqttClient.setCallback(new Callback());
        } else {
        }*/
    mqttClient.setCallback(mqttCallback);
    mqttClient.connect(options);
  }

  /**
   * MQTT连接参数设置
   */
  private MqttConnectOptions mqttConnectOptions(String userName, String passWord)
      throws MqttException {
    mqttClient = new MqttClient(HOST, clientId + SnowflakeIdWorker.generateId().toString(), new MemoryPersistence());
    MqttConnectOptions options = new MqttConnectOptions();
    options.setUserName(userName);
    options.setPassword(passWord.toCharArray());
    options.setConnectionTimeout(10);///默认:30
    options.setAutomaticReconnect(true);//默认:false
    options.setCleanSession(true);//默认:true
    //options.setKeepAliveInterval(20);//默认:60
    return options;
  }

  /**
   * 关闭MQTT连接
   */
  public void close() throws MqttException {
    mqttClient.close();
    mqttClient.disconnect();
  }

  /**
   * 向某个主题发布消息 默认qos:1
   */
  public void pub(String topic, byte[] msg) throws MqttException {
    MqttMessage mqttMessage = new MqttMessage();
    mqttMessage.setQos(2);
    mqttMessage.setPayload(msg);
    MqttTopic mqttTopic = mqttClient.getTopic(topic);
    MqttDeliveryToken token = mqttTopic.publish(mqttMessage);
    token.waitForCompletion();
  }

  /**
   * 向某个主题发布消息
   *
   * @param topic: 发布的主题
   * @param msg: 发布的消息
   * @param qos: 消息质量    Qos:0、1、2
   */
  public void pub(String topic, byte[] msg, int qos) throws MqttException {
    MqttMessage mqttMessage = new MqttMessage();
    mqttMessage.setQos(qos);
    mqttMessage.setPayload(msg);
    MqttTopic mqttTopic = mqttClient.getTopic(topic);
    MqttDeliveryToken token = mqttTopic.publish(mqttMessage);
    token.waitForCompletion();
  }

  /**
   * 订阅某一个主题 ,此方法默认的的Qos等级为:1
   *
   * @param topic 主题
   */
  public void sub(String topic) throws MqttException {
    mqttClient.subscribe(topic);
  }

  /**
   * 订阅某一个主题,可携带Qos
   *
   * @param topic 所要订阅的主题
   * @param qos 消息质量:0、1、2
   */
  public void sub(String topic, int qos) throws MqttException {
    mqttClient.subscribe(topic, qos);
  }

}

其中

mqttClient = new MqttClient(HOST, clientId + SnowflakeIdWorker.generateId().toString(), new MemoryPersistence());中使用雪花算法原因是每次生成不一样的clientId,我就是在这里踩了坑,如果使用固定的一个clientId的话,其他地方就不能在使用这个clientId,否则设备会一直断线重连....

4、mqtt回调函数


/**
 * MQTT回调函数
 *
 */
@Slf4j
@Component
public class InitCallback implements MqttCallback {


     @Autowired
     private xxxService xxxService;

  /**
   * MQTT 断开连接会执行此方法
   */
  @Override
  public void connectionLost(Throwable cause) {
//    log.error(cause.getMessage(), cause);
    log.info(cause.getMessage());
  }

  /**
   * publish发布成功后会执行到这里
   */
  @Override
  public void deliveryComplete(IMqttDeliveryToken token) {
    log.info("publish已成功发布完毕");
  }




  /**
   * subscribe订阅后得到的消息会执行到这里
   */
  @Override
  public void messageArrived(String topic, MqttMessage message) {
    log.info("[{}] : {}", topic, new String(message.getPayload()));
    xxxService.subscribeMessage(topic,message);
  }


}

5、mqtt监听器



/**
 * 项目启动 监听主题
 *
 */
@Slf4j
@Component
public class MQTTListener implements ApplicationListener<ContextRefreshedEvent> {

  @Value("${mqtt.username}")
  private String username;
  @Value("${mqtt.password}")
  private String password;
  private final MQTTConnect server;
  private final InitCallback initCallback;

  @Autowired
  public MQTTListener(MQTTConnect server, InitCallback initCallback) {
    this.server = server;
    this.initCallback = initCallback;
  }

  @Override
  public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
    try {
      server.setMqttClient(username, password, initCallback);
      server.sub("/xxx/+");     //此处定义监听主题
      log.info("我是订阅者");
    } catch (MqttException e) {
      log.error(e.getMessage(), e);
    }
  }
}


6、业务类

@Service
public class xxxServiceImpl implements xxxService {

    @Autowired
    private MQTTConnect server;


@Override
    public MessageBody test(Dto dto) {

        String token = "xxxxxxx";
        String instruction = token+GetCRC_MODBUS(token)+"88";   //此处生成的instructon为设备厂商指定的发布命令,组成部分为 发出命令 + 命令的CRC值 + 固定值88,此处为样例可按照具体需求更改
       
        byte[] testBytes = hex2Byte(instruction);

        server.pub("/xxx/xxxx",testBytes ,1);

     }

}

7、java计算 crc16校验

/*
    * 计算CRC16值
    * */
    public static String GetCRC_MODBUS(String str) {
        byte[] bytes = toBytes(str);
        int CRC = 0x0000ffff;
        int POLYNOMIAL = 0x0000a001;
        int i, j;
        for (i = 0; i < bytes.length; i++) {
            CRC ^= ((int) bytes[i] & 0x000000ff);
            for (j = 0; j < 8; j++) {
                if ((CRC & 0x00000001) != 0) {
                    CRC >>= 1;
                    CRC ^= POLYNOMIAL;
                } else {
                    CRC >>= 1;
                }
            }
        }
         String crc = Integer.toHexString(CRC).toLowerCase();
        if(crc.length() < 4){
            crc = "0" + crc;
        }
        return crc.substring(2)+crc.substring(0,2);
    }

8、将16进制字符转换成byte[]数组方法

 public static byte[] hex2Byte(String string) {
        if (string == null || string.length() < 1) {
            return null;
        }
        // 因为一个byte生成两个字符,长度对应1:2,所以byte[]数组长度是字符串长度一半
        byte[] bytes = new byte[string.length() / 2];
        // 遍历byte[]数组,遍历次数是字符串长度一半
        for (int i = 0; i < string.length() / 2; i++) {
            // 截取没两个字符的前一个,将其转为int数值
            int high = Integer.parseInt(string.substring(i * 2, i * 2 + 1), 16);
            // 截取没两个字符的后一个,将其转为int数值
            int low = Integer.parseInt(string.substring(i * 2 + 1, i * 2 + 2), 16);
            // 高位字符对应的int值*16+低位的int值,强转成byte数值即可
            // 如dd,高位13*16+低位13=221(强转成byte二进制11011101,对应十进制-35)
            bytes[i] = (byte) (high * 16 + low);
        }
        return bytes;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值