栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot(22) 集成MobileIMSDK实现即时通讯

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot(22) 集成MobileIMSDK实现即时通讯

一、前言 MobileIMSDK是什么?

一个专为移动端开发的开源原创即时通讯框架,超轻量级、高度提炼,完全基于UDP协议,支持iOS、Android、标准Java平台,服务端基于Mina和Netty编写。MobileIMSDK还可与姊妹工程 MobileIMSDK-Web无缝互通,从而实现Web网页端聊天或推送等。

本文将实现
  1. 基于springboot2.1.8.RELEASE 集成 MobileIMSDK
  2. 开发IM服务端
  3. 开发客户端
  4. 实现Java客户端与客户端之间的通信
二、SpringBoot 集成 MobileIMSDK 准备 1、MobileIMSDK下载:https://gitee.com/jackjiang/MobileIMSDK
  1. 服务端所需jar包: dist/server-xxx
  2. 客服端所需jar包: dist/client/java
2、pom.xml中引入相关依赖

由于这里是maven项目,其中一部分jar包可通过maven仓库直接引入,而其余的则通过外部jar包引入方式使用即可~

如下4个需作为外部jar包在pom.xml中引入



    com.google.code.gson
    gson
    2.8.5




    com.zhengqing
    MobileIMSDK4j
    system
    ${project.basedir}/src/main/resources/lib/MobileIMSDK4j.jar


    com.zhengqing
    MobileIMSDKServerX_meta
    system
    ${project.basedir}/src/main/resources/lib/MobileIMSDKServerX_meta.jar


    com.zhengqing
    swing-worker-1.2(1.6-)
    system
    ${project.basedir}/src/main/resources/lib/swing-worker-1.2(1.6-).jar


    com.zhengqing
    MobileIMSDKServerX_netty
    system
    ${project.basedir}/src/main/resources/lib/MobileIMSDKServerX_netty.jar


    
    
 org.springframework.boot
 spring-boot-maven-plugin
 
 
     true
 
    

三、开发服务端

1、与客服端的所有数据交互事件(实现ServerEventListener类)
public class ServerEventListenerImpl implements ServerEventListener {
    private static Logger logger = LoggerFactory.getLogger(ServerEventListenerImpl.class);

    
    @Override
    public int onVerifyUserCallBack(String userId, String token, String extra, Channel session) {
 logger.debug("【DEBUG_回调通知】正在调用回调方法:OnVerifyUserCallBack...(extra=" + extra + ")");
 return 0;
    }

    
    @Override
    public void onUserLoginAction_CallBack(String userId, String extra, Channel session) {
 logger.debug("【IM_回调通知OnUserLoginAction_CallBack】用户:" + userId + " 上线了!");
    }

    
    @Override
    public void onUserLogoutAction_CallBack(String userId, Object obj, Channel session) {
 logger.debug("【DEBUG_回调通知OnUserLogoutAction_CallBack】用户:" + userId + " 离线了!");
    }

    
    @Override
    public boolean onTransBuffer_C2S_CallBack(Protocal p, Channel session) {
 // 接收者uid
 String userId = p.getTo();
 // 发送者uid
 String from_user_id = p.getFrom();
 // 消息或指令内容
 String dataContent = p.getDataContent();
 // 消息或指令指纹码(即唯一ID)
 String fingerPrint = p.getFp();
 // 【重要】用户定义的消息或指令协议类型(开发者可据此类型来区分具体的消息或指令)
 int typeu = p.getTypeu();

 logger.debug("【DEBUG_回调通知】[typeu=" + typeu + "]收到了客户端" + from_user_id + "发给服务端的消息:str=" + dataContent);
 return true;
    }

    
    @Override
    public void onTransBuffer_C2C_CallBack(Protocal p) {
 // 接收者uid
 String userId = p.getTo();
 // 发送者uid
 String from_user_id = p.getFrom();
 // 消息或指令内容
 String dataContent = p.getDataContent();
 // 消息或指令指纹码(即唯一ID)
 String fingerPrint = p.getFp();
 // 【重要】用户定义的消息或指令协议类型(开发者可据此类型来区分具体的消息或指令)
 int typeu = p.getTypeu();

 logger.debug("【DEBUG_回调通知】[typeu=" + typeu + "]收到了客户端" + from_user_id + "发给客户端" + userId + "的消息:str=" + dataContent);
    }

    
    @Override
    public boolean onTransBuffer_C2C_RealTimeSendFaild_CallBack(Protocal p) {
 // 接收者uid
 String userId = p.getTo();
 // 发送者uid
 String from_user_id = p.getFrom();
 // 消息或指令内容
 String dataContent = p.getDataContent();
 // 消息或指令指纹码(即唯一ID)
 String fingerPrint = p.getFp();
 // 【重要】用户定义的消息或指令协议类型(开发者可据此类型来区分具体的消息或指令)
 int typeu = p.getTypeu();

 logger.debug("【DEBUG_回调通知】[typeu=" + typeu + "]客户端" + from_user_id + "发给客户端" + userId + "的消息:str=" + dataContent
  + ",因实时发送没有成功,需要上层应用作离线处理哦,否则此消息将被丢弃.");
 return false;
    }
}
2、服务端主动发起消息的QoS回调通知(实现MessageQoSEventListenerS2C类)
public class MessageQoSEventS2CListnerImpl implements MessageQoSEventListenerS2C {
    private static Logger logger = LoggerFactory.getLogger(MessageQoSEventS2CListnerImpl.class);

    @Override
    public void messagesLost(ArrayList lostMessages) {
 logger.debug("【DEBUG_QoS_S2C事件】收到系统的未实时送达事件通知,当前共有"
  + lostMessages.size() + "个包QoS保证机制结束,判定为【无法实时送达】!");
    }

    @Override
    public void messagesBeReceived(String theFingerPrint) {
 if (theFingerPrint != null) {
     logger.debug("【DEBUG_QoS_S2C事件】收到对方已收到消息事件的通知,fp=" + theFingerPrint);
 }
    }
}
3、服务端配置
public class ServerLauncherImpl extends ServerLauncher {
    // 静态类方法:进行一些全局配置设置
    static {
 // 设置AppKey(此key目前为保留字段,请忽略之)
 ServerLauncher.appKey = "5418023dfd98c579b6001741";

 // 设置MobileIMSDK服务端的网络监听端口
 ServerLauncherImpl.PORT = 7901;

 // 开/关Demog日志的输出
 QoS4SendDaemonS2C.getInstance().setDebugable(true);
 QoS4ReciveDaemonC2S.getInstance().setDebugable(true);
 ServerLauncher.debug = true;

 // TODO 与客户端协商一致的心跳敏感模式设置
//		ServerToolKits.setSenseMode(SenseMode.MODE_10S);

 // 关闭与Web端的消息互通桥接器(其实SDK中默认就是false)
 ServerLauncher.bridgeEnabled = false;
 // TODO 跨服桥接器MQ的URI(本参数只在ServerLauncher.bridgeEnabled为true时有意义)
//		BridgeProcessor.IMMQ_URI = "amqp://js:19844713@192.168.31.190";
    }

    // 实例构造方法
    public ServerLauncherImpl() throws IOException {
 super();
    }

    
    @Override
    protected void initListeners() {
 // ** 设置各种回调事件处理实现类
 this.setServerEventListener(new ServerEventListenerImpl());
 this.setServerMessageQoSEventListener(new MessageQoSEventS2CListnerImpl());
    }
    
}
4、服务端启动类

温馨小提示:这里由于小编将服务端和客户端集成在同一个项目中,因此如下配置

  1. SpringBoot的CommandLineRunner接口主要用于实现在服务初始化后,去执行一段代码块逻辑(run方法),这段初始化代码在整个应用生命周期内只会执行一次!
  2. @Order(value = 1) :按照一定的顺序去执行,value值越小越先执行
@Slf4j
@Component
@Order(value = 1)
public class ChatServerRunner implements CommandLineRunner {

    @Override
    public void run(String... strings) throws Exception {
 log.info("================= ↓↓↓↓↓↓ 启动MobileIMSDK服务端 ↓↓↓↓↓↓ =================");
 // 实例化后记得startup哦,单独startup()的目的是让调用者可以延迟决定何时真正启动IM服务
 final ServerLauncherImpl sli = new ServerLauncherImpl();
 // 启动MobileIMSDK服务端的Demo
 sli.startup();

 // 加一个钩子,确保在JVM退出时释放netty的资源
 Runtime.getRuntime().addShutdownHook(new Thread(sli::shutdown));
    }

}

如果服务端与客户端不在同一个项目 ,服务端可直接通过如下方式启动即可~

四、开发客户端

1、客户端与IM服务端连接事件
@Slf4j
public class ChatbaseEventImpl implements ChatbaseEvent {

    @Override
    public void onLoginMessage(int dwErrorCode) {
 if (dwErrorCode == 0) {
     log.debug("IM服务器登录/连接成功!");
 } else {
     log.error("IM服务器登录/连接失败,错误代码:" + dwErrorCode);
 }
    }

    @Override
    public void onlinkCloseMessage(int dwErrorCode) {
 log.error("与IM服务器的网络连接出错关闭了,error:" + dwErrorCode);
    }

}
2、接收消息事件
@Slf4j
public class ChatTransDataEventImpl implements ChatTransDataEvent {

    @Override
    public void onTransBuffer(String fingerPrintOfProtocal, String userid, String dataContent, int typeu) {
 log.debug("[typeu=" + typeu + "]收到来自用户" + userid + "的消息:" + dataContent);
    }

    @Override
    public void onErrorResponse(int errorCode, String errorMsg) {
 log.debug("收到服务端错误消息,errorCode=" + errorCode + ", errorMsg=" + errorMsg);
    }

}
3、消息是否送达事件
@Slf4j
public class MessageQoSEventImpl implements MessageQoSEvent {

    @Override // 对方未成功接收消息的回调事件 lostMessages:存放消息内容
    public void messagesLost(ArrayList lostMessages) {
 log.debug("收到系统的未实时送达事件通知,当前共有" + lostMessages.size() + "个包QoS保证机制结束,判定为【无法实时送达】!");
    }

    @Override // 对方成功接收到消息的回调事件
    public void messagesBeReceived(String theFingerPrint) {
 if (theFingerPrint != null) {
     log.debug("收到对方已收到消息事件的通知,fp=" + theFingerPrint);
 }
    }

}
4、MobileIMSDK初始化配置
public class IMClientManager {
    private static IMClientManager instance = null;

    
    private boolean init = false;

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

    private IMClientManager() {
 initMobileIMSDK();
    }

    public void initMobileIMSDK() {
 if (!init) {
     // 设置AppKey
     ConfigEntity.appKey = "5418023dfd98c579b6001741";

     // 设置服务器ip和服务器端口
     ConfigEntity.serverIP = "127.0.0.1";
     ConfigEntity.serverUDPPort = 7901;

     // MobileIMSDK核心IM框架的敏感度模式设置
//			ConfigEntity.setSenseMode(SenseMode.MODE_10S);

     // 开启/关闭DEBUG信息输出
     ClientCoreSDK.DEBUG = false;

     // 设置事件回调
     ClientCoreSDK.getInstance().setChatbaseEvent(new ChatbaseEventImpl());
     ClientCoreSDK.getInstance().setChatTransDataEvent(new ChatTransDataEventImpl());
     ClientCoreSDK.getInstance().setMessageQoSEvent(new MessageQoSEventImpl());

     init = true;
 }
    }

}
6、连接IM服务端,发送消息

服务类

public interface IChatService {

    
    void loginConnect(String username, String password);

    
    void sendMsg(String friendId, String msg);

}

服务实现类

@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class ChatServiceImpl implements IChatService {

    @Override
    public void loginConnect(String username, String password) {
 // 确保MobileIMSDK被初始化哦(整个APP生生命周期中只需调用一次哦)
 // 提示:在不退出APP的情况下退出登陆后再重新登陆时,请确保调用本方法一次,不然会报code=203错误哦!
 IMClientManager.getInstance().initMobileIMSDK();

 // * 异步提交登陆名和密码
 new LocalUDPDataSender.SendLoginDataAsync(username, password) {
     
     protected void fireAfterSendLogin(int code) {
  if (code == 0) {
      log.debug("数据发送成功!");
  } else {
      log.error("数据发送失败。错误码是:" + code);
  }
     }
 }.execute();
    }

    @Override
    public void sendMsg(String friendId, String msg) {
 // 发送消息(异步提升体验,你也可直接调用LocalUDPDataSender.send(..)方法发送)
 new LocalUDPDataSender.SendCommonDataAsync(msg, friendId) {
     @Override
     protected void onPostExecute(Integer code) {
  if (code == 0) {
      log.debug("数据已成功发出!");
  } else {
      log.error("数据发送失败。错误码是:" + code + "!");
  }
     }
 }.execute();
    }

}
五、编写Controller进行测试
@RestController
@RequestMapping("/api")
@Api(tags = "聊天测试-接口")
public class ChatController {

    @Autowired
    private IChatService chatService;

    @PostMapping(value = "/loginConnect", produces = Constants.CONTENT_TYPE)
    @ApiOperation(value = "登陆请求", httpMethod = "POST", response = ApiResult.class)
    public ApiResult loginConnect(@RequestParam String username, @RequestParam String password) {
 chatService.loginConnect(username, password);
 return ApiResult.ok();
    }

    @PostMapping(value = "/sendMsg", produces = Constants.CONTENT_TYPE)
    @ApiOperation(value = "发送消息", httpMethod = "POST", response = ApiResult.class)
    public ApiResult sendMsg(@RequestParam String friendId, @RequestParam String msg) {
 chatService.sendMsg(friendId, msg);
 return ApiResult.ok();
    }

}

启动项目,访问:http://127.0.0.1:8080/swagger-ui.html

1、 loginConnect接口:任意输入一个账号密码登录连接IM服务端


控制台日志如下:

2、 sendMsg接口:给指定用户发送消息,这里由于只有一个客户端,上一步登录了一个admin账号,因此小编给admin账号(也就是自己) 发送消息


控制台日志如下:

六、总结

关于集成可参考MobileIMSDK给出的文档一步一步实现,其中给出了通过Java GUI编程实现的一个小demo,我们可以先将其运行起来,先体验一下功能,代码量也不是太多,我们可以通过debug方式查看执行流程,清楚执行流程之后我们就可以将demo中的代码移植到我们自己的项目中加以修改运用于自己的业务中,切勿拿起就跑,否则一旦运气不好,将浪费更多的时间去集成,这样很不好!

案例demo中相关代码注释都有,这里就简单说下整个流程吧:

  1. 首先启动IM服务端
  2. 用户在客户端登录一个用户与服务端建立连接保持通信( 客户端ChatServiceImpl中loginConnect方法为登录连接服务端事件;服务端ServerEventListenerImpl中onUserLoginAction_CallBack方法为服务端接收的上线通知事件)
  3. 客户端通过 ChatServiceImpl中sendMsg方法发送一条消息,如果对方在线能接收消息则走服务端ServerEventListenerImpl中onTransBuffer_C2C_CallBack方法,否则走onTransBuffer_C2C_RealTimeSendFaild_CallBack方法;如果对方成功接收到消息,客户端将走MessageQoSEventImpl中messagesBeReceived事件,否则走messagesLost事件
  4. 客户端通过ChatTransDataEventImpl中onTransBuffer回调事件接收消息
本文案例demo源码

https://gitee.com/zhengqingya/java-workspace

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号