一、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();
}
}