最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

SpringBoot集成開(kāi)源IM框架MobileIMSDK,實(shí)現(xiàn)即時(shí)通訊IM聊天功能

2022-05-05 15:38 作者:nickkckckck  | 我要投稿


一、前言

MobileIMSDK 是什么?

MobileIMSDK??是一套專(zhuān)門(mén)為移動(dòng)端開(kāi)發(fā)的開(kāi)源IM即時(shí)通訊框架,超輕量級(jí)、高度提煉,一套API優(yōu)雅支持UDP 、TCP 、WebSocket 三種協(xié)議,支持iOS、Android、H5、標(biāo)準(zhǔn)Java平臺(tái),服務(wù)端基于Netty編寫(xiě)。

工程地址是:

  • 1)Gitee碼云地址:https://www.oschina.net/p/mobileimsdk

  • 2)Github托管地址:https://github.com/JackJiang2011/MobileIMSDK?

本文將實(shí)現(xiàn):

  • 1)基于springboot 集成 MobileIMSDK;

  • 2)開(kāi)發(fā)IM服務(wù)端;

  • 3)開(kāi)發(fā)客戶端;

  • 4)實(shí)現(xiàn)Java客戶端與客戶端之間的通信。

* 補(bǔ)充說(shuō)明:本文所示Demo源碼,請(qǐng)從文末“本文小結(jié)”的最后鏈接中下載!

二、SpringBoot 集成 MobileIMSDK 準(zhǔn)備

2.1 MobileIMSDK下載

MobileIMSDK下載地址:

  • 1)國(guó)外地址:MobileIMSDK的Github地址(最新版打包下載)

  • 2)國(guó)內(nèi)地址:MobileIMSDK的碼云gitee地址(訪問(wèn)速度快!,最新版打包下載)

需要用到的lib包:

  • 1)服務(wù)端所需jar包:?sdk_binary/Server/

  • 2)客服端所需jar包:?sdk_binary/Client_TCP/java/

如下圖所示:

2.2 pom.xml中引入相關(guān)依賴(lài)

由于這里是maven項(xiàng)目,其中一部分jar包可通過(guò)maven倉(cāng)庫(kù)直接引入,而其余的則通過(guò)外部jar包引入方式使用即可~

如下4個(gè)需作為外部jar包在pom.xml中引入 :

?

<!-- [url=https://mvnrepository.com/artifact/com.google.code.gson/gson]https://mvnrepository.com/artifact/com.google.code.gson/gson[/url] -->

<dependency>

????<groupId>com.google.code.gson</groupId>

????<artifactId>gson</artifactId>

????<version>2.8.5</version>

</dependency>

?

<!-- MobileIMSDK所需jar包依賴(lài)[注:這里是在本地lib中引入,maven中央倉(cāng)庫(kù)中暫無(wú)此jar包],要與<includeSystemScope>true</includeSystemScope>配合使用-->

<dependency>

????<groupId>com.zhengqing</groupId>

????<artifactId>MobileIMSDK4j</artifactId>

????<scope>system</scope>

????<systemPath>${project.basedir}/src/main/resources/lib/MobileIMSDK4j.jar</systemPath>

</dependency>

<dependency>

????<groupId>com.zhengqing</groupId>

????<artifactId>MobileIMSDKServerX_meta</artifactId>

????<scope>system</scope>

????<systemPath>${project.basedir}/src/main/resources/lib/MobileIMSDKServerX_meta.jar</systemPath>

</dependency>

<dependency>

????<groupId>com.zhengqing</groupId>

????<artifactId>swing-worker-1.2(1.6-)</artifactId>

????<scope>system</scope>

????<systemPath>${project.basedir}/src/main/resources/lib/swing-worker-1.2(1.6-).jar</systemPath>

</dependency>

<dependency>

????<groupId>com.zhengqing</groupId>

????<artifactId>MobileIMSDKServerX_netty</artifactId>

????<scope>system</scope>

????<systemPath>${project.basedir}/src/main/resources/lib/MobileIMSDKServerX_netty.jar</systemPath>

</dependency>

<plugins>

????<!-- maven打包插件 -> 將整個(gè)工程打成一個(gè) fatjar -->

????<plugin>

????????<groupId>org.springframework.boot</groupId>

????????<artifactId>spring-boot-maven-plugin</artifactId>

????????<!-- 作用:項(xiàng)目打成jar,同時(shí)把本地jar包也引入進(jìn)去 -->

????????<configuration>

????????????<includeSystemScope>true</includeSystemScope>

????????</configuration>

????</plugin>

</plugins>

三、開(kāi)發(fā)服務(wù)端

?

3.1 與客服端的所有數(shù)據(jù)交互事件(實(shí)現(xiàn)ServerEventListener類(lèi))

public class ServerEventListenerImpl implements ServerEventListener {

????private static Logger logger = LoggerFactory.getLogger(ServerEventListenerImpl.class);

?

????/**

?????* 用戶身份驗(yàn)證回調(diào)方法定義.

?????* <p>

?????* 服務(wù)端的應(yīng)用層可在本方法中實(shí)現(xiàn)用戶登陸驗(yàn)證。

?????* <br>

?????* 注意:本回調(diào)在一種特殊情況下——即用戶實(shí)際未退出登陸但再次發(fā)起來(lái)登陸包時(shí),本回調(diào)是不會(huì)被調(diào)用的!

?????* <p>

?????* 根據(jù)MobileIMSDK的算法實(shí)現(xiàn),本方法中用戶驗(yàn)證通過(guò)(即方法返回值=0時(shí))后

?????* ,將立即調(diào)用回調(diào)方法 {@link #onUserLoginAction_CallBack(int, String, IoSession)}。

?????* 否則會(huì)將驗(yàn)證結(jié)果(本方法返回值錯(cuò)誤碼通過(guò)客戶端的 ChatBaseEvent.onLoginMessage(int dwUserId, int dwErrorCode)

?????* 方法進(jìn)行回調(diào))通知客戶端)。

?????*

?????* @param userId? 傳遞過(guò)來(lái)的準(zhǔn)一id,保證唯一就可以通信,可能是登陸用戶名、也可能是任意不重復(fù)的id等,具體意義由業(yè)務(wù)層決定

?????* @param token?? 用于身份鑒別和合法性檢查的token,它可能是登陸密碼,也可能是通過(guò)前置單點(diǎn)登陸接口拿到的token等,具體意義由業(yè)務(wù)層決定

?????* @param extra?? 額外信息字符串。本字段目前為保留字段,供上層應(yīng)用自行放置需要的內(nèi)容

?????* @param session 此客戶端連接對(duì)應(yīng)的 netty “會(huì)話”

?????* @return 0 表示登陸驗(yàn)證通過(guò),否則可以返回用戶自已定義的錯(cuò)誤碼,錯(cuò)誤碼值應(yīng)為:>=1025的整數(shù)

?????*/

????@Override

????public int onVerifyUserCallBack(String userId, String token, String extra, Channel session) {

????????logger.debug("【DEBUG_回調(diào)通知】正在調(diào)用回調(diào)方法:OnVerifyUserCallBack...(extra="+ extra + ")");

????????return 0;

????}

?

????/**

?????* 用戶登錄驗(yàn)證成功后的回調(diào)方法定義(可理解為上線通知回調(diào)).

?????* <p>

?????* 服務(wù)端的應(yīng)用層通??稍诒痉椒ㄖ袑?shí)現(xiàn)用戶上線通知等。

?????* <br>

?????* 注意:本回調(diào)在一種特殊情況下——即用戶實(shí)際未退出登陸但再次發(fā)起來(lái)登陸包時(shí),回調(diào)也是一定會(huì)被調(diào)用。

?????*

?????* @param userId? 傳遞過(guò)來(lái)的準(zhǔn)一id,保證唯一就可以通信,可能是登陸用戶名、也可能是任意不重復(fù)的id等,具體意義由業(yè)務(wù)層決定

?????* @param extra?? 額外信息字符串。本字段目前為保留字段,供上層應(yīng)用自行放置需要的內(nèi)容。為了豐富應(yīng)用層處理的手段,在本回調(diào)中也把此字段傳進(jìn)來(lái)了

?????* @param session 此客戶端連接對(duì)應(yīng)的 netty “會(huì)話”

?????*/

????@Override

????public void onUserLoginAction_CallBack(String userId, String extra, Channel session) {

????????logger.debug("【IM_回調(diào)通知OnUserLoginAction_CallBack】用戶:"+ userId + " 上線了!");

????}

?

????/**

?????* 用戶退出登錄回調(diào)方法定義(可理解為下線通知回調(diào))。

?????* <p>

?????* 服務(wù)端的應(yīng)用層通常可在本方法中實(shí)現(xiàn)用戶下線通知等。

?????*

?????* @param userId? 下線的用戶user_id

?????* @param obj

?????* @param session 此客戶端連接對(duì)應(yīng)的 netty “會(huì)話”

?????*/

????@Override

????public void onUserLogoutAction_CallBack(String userId, Object obj, Channel session) {

????????logger.debug("【DEBUG_回調(diào)通知OnUserLogoutAction_CallBack】用戶:"+ userId + " 離線了!");

????}

?

????/**

?????* 通用數(shù)據(jù)回調(diào)方法定義(客戶端發(fā)給服務(wù)端的(即接收user_id="0")).

?????* <p>

?????* MobileIMSDK在收到客戶端向user_id=0(即接收目標(biāo)是服務(wù)器)的情況下通過(guò)

?????* 本方法的回調(diào)通知上層。上層通??稍诒痉椒ㄖ袑?shí)現(xiàn)如:添加好友請(qǐng)求等業(yè)務(wù)實(shí)現(xiàn)。

?????*

?????* <p style="background:#fbf5ee;border-radius:4px;">

?????* <b><font color="#ff0000">【版本兼容性說(shuō)明】</font></b>本方法用于替代v3.x中的以下方法:<br>

?????* <code>public boolean onTransBuffer_CallBack(String userId, String from_user_id

?????* , String dataContent, String fingerPrint, int typeu, Channel session);

?????* </code>

?????*

?????* @param userId?????? 接收方的user_id(本方法接收的是發(fā)給服務(wù)端的消息,所以此參數(shù)的值肯定==0)

?????* @param from_user_id 發(fā)送方的user_id

?????* @param dataContent? 數(shù)據(jù)內(nèi)容(文本形式)

?????* @param session????? 此客戶端連接對(duì)應(yīng)的 netty “會(huì)話”

?????* @return true表示本方法已成功處理完成,否則表示未處理成功。此返回值目前框架中并沒(méi)有特殊意義,僅作保留吧

?????* @since 4.0

?????*/

????@Override

????public boolean onTransBuffer_C2S_CallBack(Protocal p, Channel session) {

????????// 接收者uid

????????String userId = p.getTo();

????????// 發(fā)送者uid

????????String from_user_id = p.getFrom();

????????// 消息或指令內(nèi)容

????????String dataContent = p.getDataContent();

????????// 消息或指令指紋碼(即唯一ID)

????????String fingerPrint = p.getFp();

????????// 【重要】用戶定義的消息或指令協(xié)議類(lèi)型(開(kāi)發(fā)者可據(jù)此類(lèi)型來(lái)區(qū)分具體的消息或指令)

????????inttypeu = p.getTypeu();

?

????????logger.debug("【DEBUG_回調(diào)通知】[typeu="+ typeu + "]收到了客戶端"+ from_user_id + "發(fā)給服務(wù)端的消息:str="+ dataContent);

????????returntrue;

????}

?

????/**

?????* 通道數(shù)據(jù)回調(diào)函數(shù)定義(客戶端發(fā)給客戶端的(即接收方user_id不為“0”的情況)).

?????* <p>

?????* <b>注意:</b>本方法當(dāng)且僅當(dāng)在數(shù)據(jù)被服務(wù)端成功在線發(fā)送出去后被回調(diào)調(diào)用.

?????* <p>

?????* 上層通??稍诒痉椒ㄖ袑?shí)現(xiàn)用戶聊天信息的收集,以便后期監(jiān)控分析用戶的行為等^_^。

?????* <p>

?????* 提示:如果開(kāi)啟消息QoS保證,因重傳機(jī)制,本回調(diào)中的消息理論上有重復(fù)的可能,請(qǐng)以參數(shù) #fingerPrint

?????* 作為消息的唯一標(biāo)識(shí)ID進(jìn)行去重處理。

?????*

?????* <p style="background:#fbf5ee;border-radius:4px;">

?????* <b><font color="#ff0000">【版本兼容性說(shuō)明】</font></b>本方法用于替代v3.x中的以下方法:<br>

?????* <code>public void onTransBuffer_C2C_CallBack(String userId, String from_user_id

?????* , String dataContent, String fingerPrint, int typeu);

?????*

?????* @param userId?????? 接收方的user_id(本方法接收的是客戶端發(fā)給客戶端的,所以此參數(shù)的值肯定>0)

?????* @param from_user_id 發(fā)送方的user_id

?????* @param dataContent

?????* @since 4.0

?????*/

????@Override

????public void onTransBuffer_C2C_CallBack(Protocal p) {

????????// 接收者uid

????????String userId = p.getTo();

????????// 發(fā)送者uid

????????String from_user_id = p.getFrom();

????????// 消息或指令內(nèi)容

????????String dataContent = p.getDataContent();

????????// 消息或指令指紋碼(即唯一ID)

????????String fingerPrint = p.getFp();

????????// 【重要】用戶定義的消息或指令協(xié)議類(lèi)型(開(kāi)發(fā)者可據(jù)此類(lèi)型來(lái)區(qū)分具體的消息或指令)

????????inttypeu = p.getTypeu();

?

????????logger.debug("【DEBUG_回調(diào)通知】[typeu="+ typeu + "]收到了客戶端"+ from_user_id + "發(fā)給客戶端"+ userId + "的消息:str="+ dataContent);

????}

?

????/**

?????* 通用數(shù)據(jù)實(shí)時(shí)發(fā)送失敗后的回調(diào)函數(shù)定義(客戶端發(fā)給客戶端的(即接收方user_id不為“0”的情況)).

?????* <p>

?????* 注意:本方法當(dāng)且僅當(dāng)在數(shù)據(jù)被服務(wù)端<u>在線發(fā)送</u>失敗后被回調(diào)調(diào)用.

?????* <p>

?????* <b>此方法存的意義何在?</b><br>

?????* 發(fā)生此種情況的場(chǎng)景可能是:對(duì)方確實(shí)不在線(那么此方法里就可以作為離線消息處理了)、

?????* 或者在發(fā)送時(shí)判斷對(duì)方是在線的但服務(wù)端在發(fā)送時(shí)卻沒(méi)有成功(這種情況就可能是通信錯(cuò)誤

?????* 或?qū)Ψ椒钦Mǔ龅形吹竭_(dá)會(huì)話超時(shí)時(shí)限)。<br><u>應(yīng)用層在此方法里實(shí)現(xiàn)離線消息的處理即可!</u>

?????*

?????* <p style="background:#fbf5ee;border-radius:4px;">

?????* <b><font color="#ff0000">【版本兼容性說(shuō)明】</font></b>本方法用于替代v3.x中的以下方法:<br>

?????* <code>public boolean onTransBuffer_C2C_RealTimeSendFaild_CallBack(String userId

?????* , String from_user_id, String dataContent, String fingerPrint, int typeu);

?????* </code>

?????*

?????* @param userId?????? 接收方的user_id(本方法接收的是客戶端發(fā)給客戶端的,所以此參數(shù)的值肯定>0),此id在本方法中不一定保證有意義

?????* @param from_user_id 發(fā)送方的user_id

?????* @param dataContent? 消息內(nèi)容

?????* @param fingerPrint? 該消息對(duì)應(yīng)的指紋(如果該消息有QoS保證機(jī)制的話),用于在QoS重要機(jī)制下服務(wù)端離線存儲(chǔ)時(shí)防止重復(fù)存儲(chǔ)哦

?????* @return true表示應(yīng)用層已經(jīng)處理了離線消息(如果該消息有QoS機(jī)制,則服務(wù)端將代為發(fā)送一條偽應(yīng)答包

?????* (偽應(yīng)答僅意味著不是接收方的實(shí)時(shí)應(yīng)答,而只是存儲(chǔ)到離線DB中,但在發(fā)送方看來(lái)也算是被對(duì)方收到,只是延

?????* 遲收到而已(離線消息嘛))),否則表示應(yīng)用層沒(méi)有處理(如果此消息有QoS機(jī)制,則發(fā)送方在QoS重傳機(jī)制超時(shí)

?????* 后報(bào)出消息發(fā)送失敗的提示)

?????* @see #onTransBuffer_C2C_CallBack(Protocal)

?????* @since 4.0

?????*/

????@Override

????public boolean onTransBuffer_C2C_RealTimeSendFaild_CallBack(Protocal p) {

????????// 接收者uid

????????String userId = p.getTo();

????????// 發(fā)送者uid

????????String from_user_id = p.getFrom();

????????// 消息或指令內(nèi)容

????????String dataContent = p.getDataContent();

????????// 消息或指令指紋碼(即唯一ID)

????????String fingerPrint = p.getFp();

????????// 【重要】用戶定義的消息或指令協(xié)議類(lèi)型(開(kāi)發(fā)者可據(jù)此類(lèi)型來(lái)區(qū)分具體的消息或指令)

????????inttypeu = p.getTypeu();

?

????????logger.debug("【DEBUG_回調(diào)通知】[typeu="+ typeu + "]客戶端"+ from_user_id + "發(fā)給客戶端"+ userId + "的消息:str="+ dataContent

????????????????+ ",因?qū)崟r(shí)發(fā)送沒(méi)有成功,需要上層應(yīng)用作離線處理哦,否則此消息將被丟棄.");

????????returnfalse;

????}

}

3.2 服務(wù)端主動(dòng)發(fā)起消息的QoS回調(diào)通知(實(shí)現(xiàn)MessageQoSEventListenerS2C類(lèi))

public class MessageQoSEventS2CListnerImpl implements MessageQoSEventListenerS2C {

????private static Logger logger = LoggerFactory.getLogger(MessageQoSEventS2CListnerImpl.class);

?

????@Override

????public void messagesLost(ArrayList<Protocal> lostMessages) {

????????logger.debug("【DEBUG_QoS_S2C事件】收到系統(tǒng)的未實(shí)時(shí)送達(dá)事件通知,當(dāng)前共有"

????????????????+ lostMessages.size() + "個(gè)包QoS保證機(jī)制結(jié)束,判定為【無(wú)法實(shí)時(shí)送達(dá)】!");

????}

?

????@Override

????public void messagesBeReceived(String theFingerPrint) {

????????if(theFingerPrint != null) {

????????????logger.debug("【DEBUG_QoS_S2C事件】收到對(duì)方已收到消息事件的通知,fp="+ theFingerPrint);

????????}

????}

}

3.3 服務(wù)端配置

public class ServerLauncherImpl extends ServerLauncher {

????// 靜態(tài)類(lèi)方法:進(jìn)行一些全局配置設(shè)置

????static{

????????// 設(shè)置MobileIMSDK服務(wù)端的網(wǎng)絡(luò)監(jiān)聽(tīng)端口

????????ServerLauncherImpl.PORT = 7901;

?

????????// 開(kāi)/關(guān)Demog日志的輸出

????????QoS4SendDaemonS2C.getInstance().setDebugable(true);

????????QoS4ReciveDaemonC2S.getInstance().setDebugable(true);

????????ServerLauncher.debug = true;

?

????????// TODO 與客戶端協(xié)商一致的心跳敏感模式設(shè)置

//????? ServerToolKits.setSenseMode(SenseMode.MODE_10S);

?

????????// 關(guān)閉與Web端的消息互通橋接器(其實(shí)SDK中默認(rèn)就是false)

????????ServerLauncher.bridgeEnabled = false;

????????// TODO 跨服橋接器MQ的URI(本參數(shù)只在ServerLauncher.bridgeEnabled為true時(shí)有意義)

//???? BridgeProcessor.IMMQ_URI = "amqp://js:19844713@192.168.31.190";

????}

?

????// 實(shí)例構(gòu)造方法

????public ServerLauncherImpl() throws IOException {

????????super();

????}

?

????/**

?????* 初始化消息處理事件監(jiān)聽(tīng)者.

?????*/

????@Override

????protected void initListeners() {

????????// ** 設(shè)置各種回調(diào)事件處理實(shí)現(xiàn)類(lèi)

????????this.setServerEventListener(newServerEventListenerImpl());

????????this.setServerMessageQoSEventListener(newMessageQoSEventS2CListnerImpl());

????}

}

3.4 服務(wù)端啟動(dòng)類(lèi)

溫馨小提示:這里由于小編將服務(wù)端和客戶端集成在同一個(gè)項(xiàng)目中,因此如下配置:

  • SpringBoot的CommandLineRunner接口主要用于實(shí)現(xiàn)在服務(wù)初始化后,去執(zhí)行一段代碼塊邏輯(run方法),這段初始化代碼在整個(gè)應(yīng)用生命周期內(nèi)只會(huì)執(zhí)行一次!

  • @Order(value = 1) :按照一定的順序去執(zhí)行,value值越小越先執(zhí)行

@Slf4j

@Component

@Order(value = 1)

public class ChatServerRunner implements CommandLineRunner {

????@Override

????public void run(String... strings) throws Exception {

????????log.info("================= ↓↓↓↓↓↓ 啟動(dòng)MobileIMSDK服務(wù)端 ↓↓↓↓↓↓ =================");

????????// 實(shí)例化后記得startup哦,單獨(dú)startup()的目的是讓調(diào)用者可以延遲決定何時(shí)真正啟動(dòng)IM服務(wù)

????????final ServerLauncherImpl sli = new ServerLauncherImpl();

????????// 啟動(dòng)MobileIMSDK服務(wù)端的Demo

????????sli.startup();

?

????????// 加一個(gè)鉤子,確保在JVM退出時(shí)釋放netty的資源

????????Runtime.getRuntime().addShutdownHook(newThread(sli::shutdown));

????}

}

如果服務(wù)端與客戶端不在同一個(gè)項(xiàng)目 ,服務(wù)端可直接通過(guò)如下方式啟動(dòng)即可~

?

四、開(kāi)發(fā)客戶端

?

4.1 客戶端與IM服務(wù)端連接事件

@Slf4j

public class ChatBaseEventImpl implements ChatBaseEvent {

?

????@Override

????public void onLoginMessage(int dwErrorCode) {

????????if(dwErrorCode == 0) {

????????????log.debug("IM服務(wù)器登錄/連接成功!");

????????} else{

????????????log.error("IM服務(wù)器登錄/連接失敗,錯(cuò)誤代碼:"+ dwErrorCode);

????????}

????}

?

????@Override

????public void onLinkCloseMessage(int dwErrorCode) {

????????log.error("與IM服務(wù)器的網(wǎng)絡(luò)連接出錯(cuò)關(guān)閉了,error:"+ dwErrorCode);

????}

}

4.2 接收消息事件

@Slf4j

public class ChatTransDataEventImpl implements ChatTransDataEvent {

?

????@Override

????public void onTransBuffer(String fingerPrintOfProtocal, String userid, String dataContent, inttypeu) {

????????log.debug("[typeu="+ typeu + "]收到來(lái)自用戶"+ userid + "的消息:"+ dataContent);

????}

?

????@Override

????public void onErrorResponse(int errorCode, String errorMsg) {

????????log.debug("收到服務(wù)端錯(cuò)誤消息,errorCode="+ errorCode + ", errorMsg="+ errorMsg);

????}

}

4.3 消息是否送達(dá)事件

@Slf4j

public class MessageQoSEventImpl implements MessageQoSEvent {

?

????@Override// 對(duì)方未成功接收消息的回調(diào)事件 lostMessages:存放消息內(nèi)容

????public void messagesLost(ArrayList<Protocal> lostMessages) {

????????log.debug("收到系統(tǒng)的未實(shí)時(shí)送達(dá)事件通知,當(dāng)前共有"+ lostMessages.size() + "個(gè)包QoS保證機(jī)制結(jié)束,判定為【無(wú)法實(shí)時(shí)送達(dá)】!");

????}

?

????@Override// 對(duì)方成功接收到消息的回調(diào)事件

????public void messagesBeReceived(String theFingerPrint) {

????????if(theFingerPrint != null) {

????????????log.debug("收到對(duì)方已收到消息事件的通知,fp="+ theFingerPrint);

????????}

????}

}

4.4 MobileIMSDK初始化配置

public class IMClientManager {

????private static IMClientManager instance = null;

?

????/**

?????* MobileIMSDK是否已被初始化. true表示已初化完成,否則未初始化.

?????*/

????privatebooleaninit = false;

?

????public static IMClientManager getInstance() {

????????if(instance == null) {

????????????instance = new IMClientManager();

????????}

????????return instance;

????}

?

????private IMClientManager() {

????????initMobileIMSDK();

????}

?

????public void initMobileIMSDK() {

????????if(!init) {

????????????// 設(shè)置服務(wù)器ip和服務(wù)器端口

????????????ConfigEntity.serverIP = "127.0.0.1";

????????????ConfigEntity.serverPort = 8901;

?

????????????// MobileIMSDK核心IM框架的敏感度模式設(shè)置

//?????????? ConfigEntity.setSenseMode(SenseMode.MODE_10S);

?

????????????// 開(kāi)啟/關(guān)閉DEBUG信息輸出

????????????ClientCoreSDK.DEBUG = false;

?

????????????// 設(shè)置事件回調(diào)

????????????ClientCoreSDK.getInstance().setChatBaseEvent(newChatBaseEventImpl());

????????????ClientCoreSDK.getInstance().setChatTransDataEvent(newChatTransDataEventImpl());

????????????ClientCoreSDK.getInstance().setMessageQoSEvent(newMessageQoSEventImpl());

?

????????????init = true;

????????}

????}

}

4.5 連接IM服務(wù)端,發(fā)送消息

服務(wù)類(lèi):

public interface IChatService {

?

????/**

?????* 登錄連接IM服務(wù)器請(qǐng)求

?????*

?????* @param username: 用戶名

?????* @param password: 密碼

?????* @return: void

?????*/

????void loginConnect(String username, String password);

?

????/**

?????* 發(fā)送消息

?????*

?????* @param friendId: 接收消息者id

?????* @param msg:????? 消息內(nèi)容

?????* @return: void

?????*/

????void sendMsg(String friendId, String msg);

}

服務(wù)實(shí)現(xiàn)類(lèi):

@Slf4j

@Service

@Transactional(rollbackFor = Exception.class)

public class ChatServiceImpl implements IChatService {

????@Override

????public void loginConnect(String username, String password) {

????????// 確保MobileIMSDK被初始化哦(整個(gè)app生生命周期中只需調(diào)用一次哦)

????????// 提示:在不退出app的情況下退出登陸后再重新登陸時(shí),請(qǐng)確保調(diào)用本方法一次,不然會(huì)報(bào)code=203錯(cuò)誤哦!

????????IMClientManager.getInstance().initMobileIMSDK();

?

????????// * 異步提交登陸名和密碼

????????new LocalUDPDataSender.SendLoginDataAsync(username, password) {

????????????/**

?????????????* 登陸信息發(fā)送完成后將調(diào)用本方法(注意:此處僅是登陸信息發(fā)送完成,真正的登陸結(jié)果要在異步回調(diào)中處理哦)。

?????????????* @param code 數(shù)據(jù)發(fā)送返回碼,0 表示數(shù)據(jù)成功發(fā)出,否則是錯(cuò)誤碼

?????????????*/

????????????protected void fireAfterSendLogin(int code) {

????????????????if(code == 0) {

????????????????????log.debug("數(shù)據(jù)發(fā)送成功!");

????????????????} else{

????????????????????log.error("數(shù)據(jù)發(fā)送失敗。錯(cuò)誤碼是:"+ code);

????????????????}

????????????}

????????}.execute();

????}

?

????@Override

????public void sendMsg(String friendId, String msg) {

????????// 發(fā)送消息(異步提升體驗(yàn),你也可直接調(diào)用LocalUDPDataSender.send(..)方法發(fā)送)

????????new LocalUDPDataSender.SendCommonDataAsync(msg, friendId) {

????????????@Override

????????????protected void onPostExecute(Integer code) {

????????????????if(code == 0) {

????????????????????log.debug("數(shù)據(jù)已成功發(fā)出!");

????????????????} else{

????????????????????log.error("數(shù)據(jù)發(fā)送失敗。錯(cuò)誤碼是:"+ code + "!");

????????????????}

????????????}

????????}.execute();

????}

}

五、編寫(xiě)Controller進(jìn)行測(cè)試

@RestController

@RequestMapping("/api")

@Api(tags = "聊天測(cè)試-接口")

public class ChatController {

????@Autowired

????private IChatService chatService;

?

????@PostMapping(value = "/loginConnect", produces = Constants.CONTENT_TYPE)

????@ApiOperation(value = "登陸請(qǐng)求", httpMethod = "POST", response = ApiResult.class)

????public ApiResult loginConnect(@RequestParamString username, @RequestParamString password) {

????????chatService.loginConnect(username, password);

????????return ApiResult.ok();

????}

?

????@PostMapping(value = "/sendMsg", produces = Constants.CONTENT_TYPE)

????@ApiOperation(value = "發(fā)送消息", httpMethod = "POST", response = ApiResult.class)

????public ApiResult sendMsg(@RequestParam String friendId, @RequestParam String msg) {

????????chatService.sendMsg(friendId, msg);

????????return ApiResult.ok();

????}

}

啟動(dòng)項(xiàng)目,訪問(wèn):http://127.0.0.1:8080/swagger-ui.html

?

1) loginConnect接口:

任意輸入一個(gè)賬號(hào)密碼登錄連接IM服務(wù)端:

控制臺(tái)日志如下:

?

2)sendMsg接口:

給指定用戶發(fā)送消息:這里由于只有一個(gè)客戶端,上一步登錄了一個(gè)admin賬號(hào),因此小編給admin賬號(hào)(也就是自己) 發(fā)送消息

控制臺(tái)日志如下:

六、本文小結(jié)

關(guān)于集成可參考MobileIMSDK給出的文檔一步一步實(shí)現(xiàn)。

該開(kāi)源工程對(duì)應(yīng)的官方文檔比較齊全,需要哪個(gè)端,就去看對(duì)應(yīng)端的手冊(cè)就好了。

1)Demo安裝和使用

  • 客戶端Demo安裝和使用幫助(Android)?[1]

  • 客戶端Demo安裝和使用幫助(iOS)?[2]

  • 客戶端Demo安裝和使用幫助(Java)?[3]

  • 客戶端Demo演示和說(shuō)明(H5)?[4]

  • 服務(wù)端Demo安裝和使用幫助?[5]?new

2)開(kāi)發(fā)者指南

  • 客戶端開(kāi)發(fā)指南(Android)

  • 客戶端開(kāi)發(fā)指南(iOS)

  • 客戶端開(kāi)發(fā)指南(Java)

  • 客戶端開(kāi)發(fā)指南(H5)

  • 服務(wù)端開(kāi)發(fā)指南

3)API文檔

  • 客戶端SDK API文檔(Android):TCP版、UDP版

  • 客戶端SDK API文檔(iOS):TCP版、UDP版

  • 客戶端SDK API文檔(Java):TCP版、UDP版

  • 客戶端SDK API文檔(H5):點(diǎn)此進(jìn)入

  • 服務(wù)端SDK API文檔

另外:作者給出了通過(guò)Java GUI編程實(shí)現(xiàn)的一個(gè)小demo,我們可以先將其運(yùn)行起來(lái),先體驗(yàn)一下功能,代碼量也不是太多,我們可以通過(guò)debug方式查看執(zhí)行流程。

清楚執(zhí)行流程之后我們就可以將demo中的代碼移植到我們自己的項(xiàng)目中加以修改運(yùn)用于自己的業(yè)務(wù)中,切勿拿起就跑,否則一旦運(yùn)氣不好,將浪費(fèi)更多的時(shí)間去集成,這樣很不好!

?

最后:案例demo中相關(guān)代碼注釋都有,這里就簡(jiǎn)單說(shuō)下整個(gè)流程吧:

  • 1)首先啟動(dòng)IM服務(wù)端

  • 2)用戶在客戶端登錄一個(gè)用戶與服務(wù)端建立連接保持通信( 客戶端ChatServiceImpl中l(wèi)oginConnect方法為登錄連接服務(wù)端事件;服務(wù)端ServerEventListenerImpl中onUserLoginVerify方法為服務(wù)端接收的上線通知事件);

  • 3)客戶端通過(guò) ChatServiceImpl中sendMsg方法發(fā)送一條消息,如果對(duì)方在線能接收消息則走服務(wù)端ServerEventListenerImpl中onTransferMessage4C2C方法,否則走onTransferMessage_RealTimeSendFaild方法;如果對(duì)方成功接收到消息,客戶端將走M(jìn)essageQoSEventImpl中messagesBeReceived事件,否則走messagesLost事件;

  • 4)客戶端通過(guò)ChatMessageEvent中onRecieveMessage回調(diào)事件接收消息。

附:本文案例demo源碼下載:

  • 1)主地址:https://gitee.com/zhengqingya/java-workspace

  • 2)備地址:https://gitee.com/instant_messaging_network/java-workspace

附錄:更多IM聊天新手實(shí)踐代碼

  1. 《跟著源碼學(xué)IM(一):手把手教你用Netty實(shí)現(xiàn)心跳機(jī)制、斷線重連機(jī)制》

  2. 《跟著源碼學(xué)IM(二):自已開(kāi)發(fā)IM很難?手把手教你擼一個(gè)Andriod版IM》

  3. 《跟著源碼學(xué)IM(三):基于Netty,從零開(kāi)發(fā)一個(gè)IM服務(wù)端》

  4. 《跟著源碼學(xué)IM(四):拿起鍵盤(pán)就是干,教你徒手開(kāi)發(fā)一套分布式IM系統(tǒng)》

  5. 《跟著源碼學(xué)IM(五):正確理解IM長(zhǎng)連接、心跳及重連機(jī)制,并動(dòng)手實(shí)現(xiàn)》

  6. 《跟著源碼學(xué)IM(六):手把手教你用Go快速搭建高性能、可擴(kuò)展的IM系統(tǒng)》

  7. 《跟著源碼學(xué)IM(七):手把手教你用WebSocket打造Web端IM聊天》

  8. 《跟著源碼學(xué)IM(八):萬(wàn)字長(zhǎng)文,手把手教你用Netty打造IM聊天》

  9. 《跟著源碼學(xué)IM(九):基于Netty實(shí)現(xiàn)一套分布式IM系統(tǒng)》

  10. 《跟著源碼學(xué)IM(十):基于Netty,搭建高性能IM集群(含技術(shù)思路+源碼)》


SpringBoot集成開(kāi)源IM框架MobileIMSDK,實(shí)現(xiàn)即時(shí)通訊IM聊天功能的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
阳高县| 贵德县| 策勒县| 定西市| 南安市| 斗六市| 蓝田县| 乌拉特前旗| 宁晋县| 大足县| 景东| 北海市| 浏阳市| 新宾| 滨海县| 舟山市| 宝丰县| 乐亭县| 伊春市| 陵水| 胶州市| 湟中县| 娄烦县| 香港 | 达尔| 深州市| 岳普湖县| 托里县| 唐河县| 上犹县| 宜昌市| 娄烦县| 石景山区| 巫溪县| 察隅县| 东城区| 合水县| 海城市| 衢州市| 万山特区| 东平县|