MQTT 订阅、下发指令、重启、关闭

一、mqtt配置类

@Entity
@Table(name = "tb_mqtt_config")
@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
public class MqttConfig extends UuIdEntity<String> {

   //ip
    @Column(name = "ip") 
    private String mqttIp; 
    //端口
    @Column(name = "port") 
    private String mattPort; 
    //账户
    @Column(name = "account") 
    private String userName; 
    //密码
    @Column(name = "password") 
    private String passwd;  
    //客户端id
    @Column(name = "client_id") 
    private String clientId; 
    //网关id
    @Column(name = "gateway_id") 
    private String gatewayId;
    //版本号
    @Column(name = "version_number") 
    private String versionId; 
    //修改时间
    @Column(name = "update_time") 
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @Temporal(TemporalType.TIMESTAMP)
    private Date updateTime;       
    

}

二、建立公共的监听类

 

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.IMqttMessageListener;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttMessage;

/**
 *
 * @author Administrator
 */
@Slf4j
public class MyTopicListener implements IMqttMessageListener {

    MqttClient client;
    private String topic;
    private int qos;

    public MyTopicListener(String topic, int qos, MqttClient client) {
        this.topic = topic;
        this.qos = qos;
        this.client = client;
    }

    @Override
    public void messageArrived(String string, MqttMessage mm) throws Exception {
        log.info("topic 监听:");
        log.info(string);
        log.info(new String(mm.getPayload()));
    }

    public String getTopic() {
        return topic;
    }

    public int getQos() {
        return qos;
    }

    public boolean isNum(String value, int minLenth, int maxLength) {
        boolean flag = false;

        String pattern = "^(\\d{" + minLenth + "," + maxLength + "})$";
        if (minLenth == maxLength) {
            pattern = "^(\\d{" + minLenth + "})$";
        }
        Pattern p = Pattern.compile(pattern);
        Matcher m = p.matcher(value);
        flag = m.matches();
        return flag;

    }

}

 三、业务逻辑层类  实现数据存储text文本,并存入数据库文件路径

@Slf4j
@Service
public class DataSendService {  
    @Value("${app.auth.trajectoryPath}")
    private String trajectoryPath;       
    
    @Resource
    TrajectoryRepository trajectoryDao;
    @Resource
    RecipientsRecordsRepository recipientsRecordsDao;
    
    //定位数据存储文本文件
    public  void positionSending(JSONObject data) {
        
        String path = trajectoryPath; //文件存储位置
        String dateUrl =DateUtil.format(new Date(),"YYMMDD");  
        String eId=data.getString("eId"); 
        String trajectory=path + "/" + dateUrl+"/" +eId+".txt";
        try {
            //如果文件夹不存在则创建    
            File folder = new File(path + "/" + dateUrl);
            if (!folder.exists() && !folder.isDirectory()) {
                folder.mkdir();
            }  
            //如果文件不存在则创建    
            File file = new File(trajectory);
            if(!file.exists()){  
                file.createNewFile();//创建失败会抛出异常throw new IOException("Invalid file path");
            }  
            //重组数据 
            JSONArray jsonList= JSON.parseArray( data.getString("data"));
            StringBuffer stringBuffer = new StringBuffer();
            for(int i=0;i<jsonList.size();i++){
                JSONObject map = new JSONObject(); 
                JSONObject job = jsonList.getJSONObject(i);
                map.put("eId", eId);
                map.put("altitude", job.getString("altitude"));
                map.put("soc", job.getString("soc"));
                map.put("eventTime", job.getString("eventTime"));
                map.put("lon", job.getString("lon"));
                map.put("lat", job.getString("lat"));
                map.put("speed", job.getString("speed"));
                stringBuffer.append(map.toJSONString());
                stringBuffer.append("\n");
            }
            //数据写入文本 
            try(BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file,true)))){  
                bw.write(stringBuffer.toString()); 
                bw.close();
            } catch (Exception e) {
                e.printStackTrace();
            } 
            positionSave(trajectory,eId);
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
    //定位数据存出数据库
    public  void positionSave(String trajectory,String eId) { 
            //是否存入数据库 
                Trajectory t=trajectoryDao.findByTrajectoryUrl(trajectory);
                if(t==null){//没有记录
                //查询相关设备的最新领用记录
                RecipientsRecords recipientsRecord=recipientsRecordsDao.findTop1ByEquipmentIdOrderByRecipientsTimeDesc(eId);
                        Trajectory ele=new Trajectory();
                    if(recipientsRecord!=null){
                        ele.setRecipientsRecordsId(recipientsRecord.getId());
                        ele.setRecipientsName(recipientsRecord.getRecipientsName());
                        ele.setOrganizationId(recipientsRecord.getOrganizationId());
                        ele.setEquipmentName(recipientsRecord.getEquipmentName());
                    }
                        ele.setEquipmentId(eId);
                        ele.setTrajectoryUrl(trajectory);
                        ele.setCreateTime(new Date());
                        trajectoryDao.save(ele);
                } 
    } 
    
}

四、建立数据上送监听,调用  业务逻辑层类 

import com.alibaba.fastjson.JSONObject; 
import com.jinpower.eims.bds.service.DataSendService;
import com.jinpower.framework.common.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttMessage;

/**
 *
 *
 * 定位数据上送
 * 
 */
@Slf4j 
public class DateSend extends
        MyTopicListener {
    

    private String responseTopic;//响应topic  
    public DateSend(String topic, String responseTopic, int qos, MqttClient client) {
        super(topic, qos, client);
        this.responseTopic = responseTopic;
    }

    @Override
    public void messageArrived(String string, MqttMessage mm) {
        JSONObject data;
        int mid = -1;
        try {
            log.info(this.getTopic() + ">>" + new String(mm.getPayload(), "UTF-8"));
            //解析数据 
            data = JSONObject.parseObject(new String(mm.getPayload(), "UTF-8"));
            if (data == null || data.isEmpty()) {
                throw new RuntimeException("参数不能为空");
            }
            mid = data.getIntValue("mid");   
            //定位数据上送
            SpringUtil.getBean(DataSendService.class).positionSending(data);   
        } catch (Exception ex) {
            JSONObject err = new JSONObject();
            err.put("statusCode", -1);
            err.put("mid", mid);
            err.put("statusDesc", "error packet");
            try {
                client.publish(responseTopic, err.toJSONString().getBytes("UTF-8"), 1, false);
            } catch (Exception e) {

            }
            log.error(ex.getMessage(), ex);
        }

    }
    


}

五、建立mqtt实例(读取mqtt配置,订阅数据上送实例)

@Slf4j
public class MqttInstance {

    static final String GATEWAYID = "{gatewayId}";
    static final String VERSIONID = "{versionId}"; 
    
    //定位数据上送/jinpower/{gatewayId}/{versionId}/data
    static final String TOPIC_RESET_DATE_REQUSET = "/jinpower/" + GATEWAYID+ "/" + VERSIONID  + "/data"; 
    //短报文消息上送/jinpower/{gatewayId}/{versionId}/msg
    static final String TOPIC_RESET_MSG_REQUSET = "/jinpower/" + GATEWAYID+ "/" + VERSIONID  + "/msg"; 
    //设备运行状态上送/jinpower/{gatewayId}/{versionId}/dev/status
    static final String TOPIC_RESET_STATUS_REQUSET = "/jinpower/" + GATEWAYID+ "/" + VERSIONID  + "/dev/status"; 
 
    private MqttClient client;
    private MqttMessage message;
    private MqttCallback callback = null;
    private boolean cleanSession;
    //mqtt 配置信息类(自定义)
    private MqttConfig config;
    //订阅topic 列表
    private String[] topicFilters = {}; 
    private List<MyTopicListener> topicListener;
    private static MqttInstance instance; 
    private MqttConfigRepository mqttConfigDao;

    //重连线程
    Thread reConnectThread = null;

    private MqttInstance() {
        this.cleanSession = true;
        this.topicListener = Lists.newArrayList();
    }

    public static synchronized MqttInstance getInstance() {
        if (instance == null) {
            instance = new MqttInstance();
        }
        return instance;
    }

    private MqttConfig getMqttConfigFromDb() {
        if (mqttConfigDao == null) {
            log.info("mqttConfigDao is null");
            return null;
        }
        Specification<MqttConfig> specification = (root, query, builder) -> query.where(builder.isNotNull(root.get("id"))).getRestriction();
        Optional<Object> t = mqttConfigDao.findOne(specification);
        return (!t.isPresent()) ? null : (MqttConfig) t.get();
    }

    /**
     *
     * @param isRefresh 是否刷新配置
     * @return
     */
    public MqttConfig getConfig(boolean isRefresh) {
        if (config == null || isRefresh) {
            config = getMqttConfigFromDb();
        }

        return config;
    }

    public void restart() throws MqttException {
        //注销
        this.destroy();
        log.info("---------注销client---------");
        this.getConfig(true);
        initClient();
        //订阅topic
        subscribe();

    }

    private synchronized MqttClient initClient() {
        try {
            if (getConfig(false) == null) {
                return null;
            }
            String clientId = getConfig(false).getClientId();
            String serverURI = "tcp://" + getConfig(false).getMqttIp() + ":" + getConfig(false).getMattPort();
            client = new MqttClient(serverURI, clientId, new MemoryPersistence());
            MqttConnectOptions options = new MqttConnectOptions();
            options.setCleanSession(cleanSession);
            options.setAutomaticReconnect(true);
            options.setUserName(getConfig(false).getUserName());
            options.setPassword(getConfig(false).getPasswd().toCharArray());
            options.setConnectionTimeout(10);
            options.setKeepAliveInterval(60);

            if (callback == null) {
                client.setCallback(new MqttCallback() {

                    @Override
                    public void connectionLost(Throwable arg0) {
                        log.info("");
                        // TODO 自动生成的方法存根
                        log.info(clientId + " connectionLost " + arg0);
                    }

                    @Override
                    public void deliveryComplete(IMqttDeliveryToken arg0
                    ) {
                        log.info("");
                        // TODO 自动生成的方法存根
                        log.info(clientId + " deliveryComplete " + arg0);
                    }

                    @Override
                    public void messageArrived(String arg0, MqttMessage arg1) throws Exception {
                        log.info("");
                        // TODO 自动生成的方法存根
                        log.info(clientId + " messageArrived: " + arg0 + "," + arg1.toString());
                    }
                }
                );
            } else {
                client.setCallback(callback);
            }

            client.connect(options);

        } catch (MqttException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
            log.error(e.getMessage(), e);
            client = null;
        } finally {
            return client;
        }
    }

    /**
     * 订阅消息
     */
    private void subscribe() throws MqttException {
        if (!isClientValid()) {
            log.error("mqtt client 没有初始化");
            return;
        }
        log.info("开始构建订阅topic");
        topicListener.clear();
        //注册设备 

        String resetDateTopic = TOPIC_RESET_DATE_REQUSET.replace(GATEWAYID, getConfig(false).getGatewayId()).replace(VERSIONID, getConfig(false).getVersionId());
        String resetMsgTopic = TOPIC_RESET_MSG_REQUSET.replace(GATEWAYID, getConfig(false).getGatewayId()).replace(VERSIONID, getConfig(false).getVersionId());
        String reseStatusTopic = TOPIC_RESET_STATUS_REQUSET.replace(GATEWAYID, getConfig(false).getGatewayId()).replace(VERSIONID, getConfig(false).getVersionId());
        topicListener.add(new DateSend(resetDateTopic, "", 1, client));
        topicListener.add(new MsgSend(resetMsgTopic, "", 1, client));
        topicListener.add(new StatuaSend(reseStatusTopic, "", 1, client));
        if (topicListener == null || topicListener.size() == 0) {
            return;
        }
        topicFilters = new String[topicListener.size()];
        int[] qosList = new int[topicListener.size()];
        IMqttMessageListener[] listenerList = new IMqttMessageListener[topicListener.size()];
        int i = 0;
        log.info("订阅topic");
        for (MyTopicListener t : topicListener) {
            log.info(t.getTopic());
            topicFilters[i] = t.getTopic();
            listenerList[i] = t;
            qosList[i] = t.getQos();
            i++;
        }
        client.subscribe(topicFilters, qosList, listenerList);

    }

    public boolean isClientValid() {

        return client != null && client.isConnected();
    }

    /**
     * 发布消息
     *
     * @param topic
     * @param msg
     */
    public void sendMessage(String topic, String msg) {
        try {
            if (!isClientValid()) {
                log.error("mqtt client 没有初始化");
                return;
            }
            message = new MqttMessage();
            message.setQos(1);
            message.setRetained(false);
            message.setPayload(msg.getBytes());
            MqttTopic mqttTopic = client.getTopic(topic);
            MqttDeliveryToken token = mqttTopic.publish(message);//发布主题
            token.waitForCompletion();

        } catch (MqttPersistenceException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
            log.error(e.getMessage(), e);
        } catch (MqttException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
            log.error(e.getMessage(), e);
        }
    }

 
    public void send(final String topic, final JSONObject data) {
        try {
            if (!isClientValid()) {
                log.error("mqtt client 没有初始化");
                return;
            }
            String _topic = topic.replace(GATEWAYID, getConfig(false).getGatewayId());
            message = new MqttMessage();
            message.setQos(1);
            message.setRetained(false);
            message.setPayload(data.toJSONString().getBytes());
            MqttTopic mqttTopic = client.getTopic(_topic);
            MqttDeliveryToken token = mqttTopic.publish(message);//发布主题
            log.info(_topic + ">>>>" + data);
            token.waitForCompletion();

        } catch (MqttPersistenceException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
            log.error(e.getMessage(), e);
        } catch (MqttException e) {
            // TODO 自动生成的 catch 块
            e.printStackTrace();
            log.error(e.getMessage(), e);
        }
    }

    public void setMqttConfigDao(MqttConfigRepository mqttConfigDao) {
        this.mqttConfigDao = mqttConfigDao;
    }

    /**
     * *
     * 注销
     */
    public void destroy() {
        if (client == null) {
            return;
        }

        try {
            if (topicFilters != null && topicFilters.length > 0) {
                client.unsubscribe(topicFilters);
            }

            client.disconnect();
            client.setCallback(null);
            client = null;
            topicListener.clear();
            topicFilters = null;
        } catch (MqttException ex) {
            log.error(ex.getLocalizedMessage(), ex);
        }
    }

    /**
     * *
     * 连接状态
     */
     public boolean connStatus() {
        log.info("---------client链接状态---------"); 

        return isClientValid();
    }   
    
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值