Recently in a SaaS enterprise using MQTT to develop the IM messaging push service, the development of some problems recorded, the project is still in business, the complete messaging service includes 4 modules---Protocol protocol, signaling signal, rules rule, state status, This topic is mainly the protocol part of the agreement.
The main technology involves MONGODB,WEBSERVICE,HTTPCLIENT,MQTT, etc.
Protocol is divided into four module classes to achieve, of course, this is for later extensibility is better
First look at our main class, primarily a framework of the MQTT basic approach
public class Mqttprotocol {private static Logger Logger = Logger.getlogger (Mqttprotocol.class); public static final String HOST = "tcp://xx.xx.xx.xx:1883"; private static final String CLIENTID = "yyyy"; Private Mqttclient client; Private mqttconnectoptions options = new Mqttconnectoptions (); Private String userName = "admin"; Private String PassWord = "public"; public Mqttmessage message; Private Pushcallback callback; /** * For initializing mqttclient client, setting callback function, connecting MQTT server * @throws mqttexception */Public Mqttprotocol () throws Mqtt Exception {//memorypersistence Sets the Save form for CLIENTID, which defaults to saving the client with memory = new Mqttclient (HOST, CLIENTID, New Memorypersistence ()); callback = new Pushcallback (); Client.setcallback (callback); options = new Mqttconnectoptions (); Options.setcleansession (FALSE); Options.setkeepaliveinterval (60); Connect (); }/** * Connect an MQTT messaging server,At the same time, the disconnection function is set up, mainly for high availability, our program will not terminate at the time the network server crashes */private void Connect () {SimpleDateFormat sdf= New SimpleDateFormat (CONSTANT.DATE_FORMAT_MDYHMS); System.out.println (Sdf.format (System.currenttimemillis ())); Boolean tryconnecting = true; while (tryconnecting) {try {client.connect (options); } catch (Exception E1) {System.out.println ("Connection Attempt failed with '" +e1.getcause () + "'. Retrying. "); if (client.isconnected ()) {System.out.println ("Connected."); Tryconnecting = false; } else {pause (); }}} private void Pause () {try {thread.sleep (1000); } catch (Interruptedexception e) {//Error handling goes here ...} }/** * * @param topic * @param QoS * @throws MqttpersistenceexcEption * @throws mqttexception * Subscription Related topics */public void Subscribe (String topic, int QoS) throws Mqttpersistenceexception, Mqttexception {client.subscribe (topic, QoS); }/** * * @throws mqttpersistenceexception * @throws mqttexception * Disconnect Server * * public void Disconnect () throws Mqttpersistenceexception, mqttexception {client.disconnect (); }/** * * @author Binshi * Implements Mqttcallback interface, mainly for processing after receiving messages */Private class PUSHCA Llback implements Mqttcallback {/** * after disconnection the system will automatically call this function, while in this function to re-connect operation */public void connection Lost (Throwable cause) {//The connection is lost, usually in the face of the re-connected System.out.println ("disconnection, can be re-connected"); Connect (); try {subscribe (constant.topic_mqtt_protocol, 2),} catch (Mqttpersistenceexception e) {//TODO auto-generated catch Blocke.printstacktrace ();} catch (mqttexception e) {//TODO auto-generated catch Blocke.printstacktrace ();} After the/** * message is successfully delivered, the system automatically calls this function to indicate that the message was successfully sent to topic */@Override public void Deliverycomplete (Imqttdeliveryt Oken arg0) {//TODO auto-generated Method Stub System.out.println ("Deliverycomplete---------" + arg0.iscomplete ()); /** * Connect MONGO database, return mongocollection * @param collectionname * @return * */public void me for specific collection Ssagearrived (String topic, Mqttmessage message) throws Exception {System.out.println (topic); SimpleDateFormat sdf= New SimpleDateFormat (CONSTANT.DATE_FORMAT_MDYHMS); System.out.println (Sdf.format (System.currenttimemillis ())); SYSTEM.OUT.PRINTLN ("Receive Message Subject:" + topic); SYSTEM.OUT.PRINTLN ("Receive Message QoS:" + Message.getqos ()); SYSTEM.OUT.PRINTLN ("Receive Message content:" + new String (Message.getpayload ())); 1 Extract Event signaling message string Messagejudge=new string (Message.getpayload ()); SYSTEM.OUT.PRINTLN ("Ignore all robot messages and offline offline messages"); Jsonobject jo=new jsonobject (); try {jo=jsonobject.fromobject (Messagejudge);} catch (Exception e) {e.printstacktrace ();} String from=jo.getstring ("from"); System.out.println ("Get from" +from); System.out.println ("Determines whether the message contains offline, if it contains a offline, is 1 not processed"); String offline=null;if (Messagejudge.contains ("Offline")) {offline=jo.getstring ("Offline");} if ((offline==null) && (!from.contains ("Robot")) {System.out.println ("Handling non-system messages and non-offline messages"); String type=jo.getstring ("type"); System.out.println ("Get Type" +type), if (Type.equals ("Shakehand")) {System.out.println ("process shakehand message"); String admin= "Doyounkowwhy", if (Jo.tostring (). Contains ("admin")) {admin=jo.getstring ("admin");} System.out.println ("Get admin if 1 is defined as customer service, otherwise the normal user admin is" +admin "), if (Admin.equals (" 1 ")) {System.out.println (" Process Customer service handshake message " ); SYSTEM.OUT.PRINTLN ("Send Handshake success message"); Mqtttopic retopic=client.gettopic (topic); Msgoperation.sendsysmsgtoclient (From, "0", "1005", "Handshake succeeded", null,retopic); SYSTEM.OUT.PRINTLN ("Send a message to the client that is not received offline"); String convid=jo.getstring ("Convid"); String database= "Dolina"; String collection= "messAges "; Mongodbdao.getmongodbdaoinstance (). Sendofflinemsgtoclient (from, convid,retopic,database,collection);} ELSE{SYSTEM.OUT.PRINTLN ("Handling handshake messages for ordinary users"); String appid=jo.getstring ("AppID"); String pageid=jo.getstring ("PageID"); String convid=jo.getstring ("Convid"); Mqtttopic retopic=client.gettopic (topic); Msgoperation.sendshakehandinfo (From,convid,appid,pageid,retopic);}} else if (type.equals ("text") | | Type.equals ("image")) {System.out.println ("Processing pictures and text messages"); String tmpindex=jo.getstring ("Tmpindex"); String convid=jo.getstring ("Convid"); Mqtttopic retopic=client.gettopic (topic); Msgoperation.gettextmsg (Tmpindex, from, Convid, retopic); System.out.println ("Save picture Text message"); String database= "Dolina"; String collection= "Messages"; Mongodbdao.getmongodbdaoinstance (). savetextmsg (Database,collection,jo);} else if (type.equals ("ack")) {System.out.println ("Process ack message"); String tmpindex=jo.getstring ("Tmpindex"); String convid=jo.getstring ("Convid"); String database= "Dolina"; String collection= "Messages"; Mongodbdao.getmongodbdaoinstanCE (). Getack (Tmpindex,convid,from,database,collection);}} }}/** * * @param args * @throws mqttexception * The entire project starts here, generating an executable jar package, which is the main class. */public static void main (string[] args) throws Mqttexception {Mqttprotocol signal = new MQTTPR Otocol (); Signal.message = new Mqttmessage (); /** Server.message.setQos (2); Server.message.setRetained (FALSE); Server.message.setPayload ("Send Message to Client 124". GetBytes ()); Server.subscribe ("/engyne/1/7/169573fcbc96a816281192222", 2); */Signal.subscribe (Constant.topic_mqtt_protocol, 2); System.out.println (signal.message.isRetained () + "------ratained status"); }}
The next step is to make our remote connection module, primarily by invoking the remote interface via a given URL
public class Remoteoperation{private static Logger Logger = Logger.getlogger (mqttprotocol.class); public static Jsonobject remotecall (String url) throws HttpException, ioexception{httpclient HttpClient = new HttpClient ( ); GetMethod method =null; Method=new getmethod (URL); int retcode = Httpclient.executemethod (method); if (retcode! = HTTPSTATUS.SC_OK) {//Send unsuccessful logger.info ("Remote Call error"); return null; } else { String BODY = method.getresponsebodyasstring (); Logger.info (body+ "remote invocation of PHP Success"); Jsonobject jsonobject=new Jsonobject (); try {jsonobject=jsonobject.fromobject (body);} catch (Exception e) { E.printstacktrace ();} if (Method! = null) { method.releaseconnection (); } return jsonobject; }}}
The following is a package of related operations for the MONGO database, designed as a singleton mode, equivalent to using the same client to open the connection each time, similar to the concept of connection pooling, of course, the business logic part can be replaced
public class Mongodbdao{private static Logger Logger = Logger.getlogger (Mongodbdao.class); instances of/** * mongoclient represent database connections Pool, is thread-safe, can be multi-threaded sharing, the client in the multi-threaded conditions only to maintain an instance can * Mongo is non-thread-safe, the MongoDB API has been proposed to replace the Mongo * */Private Mongo Client mongoclient = null; /** * * Private Constructor * Shibin * */Private Mongodbdao () {if (mongoclient = = null) {Stri ng url = constant.mongo_mqtt_url; String user = Constant.mongo_mqtt_user; String password = Constant.mongo_mqtt_password; String database = Constant.mongo_mqtt_database; int port = 27017; ServerAddress serveraddress = new serveraddress (URL, port); list<serveraddress> serveraddresses = new arraylist<serveraddress> (); Serveraddresses.add (serveraddress); Mongocredential credential = mongocredential.createcredential (user, database, Password.tochararray ()); List<mongocredential> credentials = new ArraylisT<mongocredential> (); Credentials.add (credential); Mongoclient = new Mongoclient (serveraddresses, credentials); System.out.println (mongoclient); SYSTEM.OUT.PRINTLN ("Initialize client completion"); }}/******** Singleton mode declaration, a hungry man generation, ensure thread safety ********************///class initialization, self-instantiation, a hungry man singleton mode private St atic final Mongodbdao Mongodbdao = new Mongodbdao (); /** * Method Name: Getmongodbdaoimplinstance * shibin * Description: Static factory Method for single Example * @return * */Publ IC static Mongodbdao getmongodbdaoinstance () {return mongodbdao; public void Sendofflinemsgtoclient (string from, String Convid,mqtttopic retopic,string database,string collection) Throws Mqttpersistenceexception, Mqttexception{system.out.println ("Get a Message connection"); Mongodatabase mongodatabase = mongoclient.getdatabase (database); Mongocollection mongocollection = Mongodatabase.getcollection (collection); System.out.println ("Get convid correspondingMSG list "); Basicdbobject query = new Basicdbobject (); Query.put ("_id", Convid); finditerable<document> iterable=null;iterable = mongocollection.find (query), if (Iterable.first ()!=null) { System.out.println (Iterable.first ()); String res= Iterable.first (). ToJson (); Jsonobject jo=new Jsonobject (); try {jo=jsonobject.fromobject (res);} catch (Exception e) {e.printstacktrace ();} Jsonarray Jsonarray=jo.getjsonarray ("msg"); for (int i=0;i<jsonarray.length (); i++) {String read= Jsonarray.getjsonobject (i). getString ("read"); System.out.println ("Obtain msg corresponding to the section" +i+ "record of the Read Information" +read); System.out.println ("To determine if read contains the from information, if it is not included and the message is not his own, send her the message"); if (!read.contains (from) &&! Jsonarray.getjsonobject (i). GetString ("from"). Equals (from) {System.out.println ("Get the prototype of this message, then add offline=1 and send a message"); Jsonobject Msg=jsonarray.getjsonobject (i); Msg.put ("Offline", "1"), Retopic.publish (Msg.tostring (). GetBytes (), 0, FALSE);} ELSE{SYSTEM.OUT.PRINTLN ("No offline message for" +from);}}} public void savetextmsg (String databasE,string collection,jsonobject Jo) {mongodatabase mongodatabase = mongoclient.getdatabase (database); Mongocollection mongocollection = Mongodatabase.getcollection (collection); Basicdbobject query = new Basicdbobject (); String convid=jo.getstring ("Convid"); Query.put ("_id", Convid); Finditerable iterable; iterable = mongocollection.find (query); System.out.println ("Value before updating message" +iterable.first ()); Bson filter = Filters.eq ("_id", Convid);D ocument content = new Document (); String type=jo.getstring ("type"), if (Type.equals ("text")) {string Contentmsg=jo.getjsonobject ("content"). getString ("content"); Content.put ("Content", contentmsg);} Else{string url=jo.getjsonobject ("content"). GetString ("url"); Content.put ("url", URL);} String admin=jo.getjsonobject ("Extra"). GetString ("admin"); String headimgurl=jo.getjsonobject ("Extra"). GetString ("Headimgurl"); String nickname=jo.getjsonobject ("Extra"). GetString ("nickname"); String from=jo.getstring ("from"); String tmpindex=jo.getstring ("Tmpindex");D ocument extra = new document (), Extra.put (" nickname ", nickname);D ocument doc = new document ();d oc.put (" from ", from); Arraylist<string> read=new arraylist<string> ();d oc.put ("read", read);D ocument tdoc = new Document (); Tdoc.put ("msg", Doc); UpdateOptions updateoptions=new UpdateOptions (); Updateoptions.upsert (true); Mongocollection.updateone (filter, new Document ("$addToSet", Tdoc), updateOptions); iterable = mongocollection.find (query); System.out.println ("Value after update message" +iterable.first ());} public void Getack (String tmpindex,string convid,string from,string database,string collection) {System.out.println (" Update the Read field in message after receiving an ACK message "); Mongodatabase mongodatabase = mongoclient.getdatabase (database); Mongocollection mongocollection = Mongodatabase.getcollection (collection); Basicdbobject query = new Basicdbobject (); Query.put ("_id", Convid); Query.put ("Msg.tmpindex", Tmpindex); Basicdbobject Query1 = new Basicdbobject (); Query1.put ("_id", Convid); FindiTerable iterable; Finditerable Iterable2; iterable = Mongocollection.find (query1); iterable2 = mongocollection.find (query); SYSTEM.OUT.PRINTLN ("Update the value before the message satisfies the ID filter criteria" +iterable.first ()); SYSTEM.OUT.PRINTLN ("Update the value before the message satisfies the ID and Tmpindex filter Criteria" +iterable2.first ()); if (Iterable2.first ()!=null) {Document doc = new Document (); Doc.put ("Msg.$.read", from); UpdateOptions updateoptions=new UpdateOptions (); Updateoptions.upsert (TRUE); Mongocollection.updateone (query, New Document ("$addToSet", Doc), updateOptions); } iterable = Mongocollection.find (Query1); System.out.println ("Value after update messages" +iterable.first ());}}
The rest of the business logic is not much to say, mainly about MQTT high-availability disconnects and MONGO-related operations
Java back-End IM messaging push service development--protocol