Java后台集成融云即时通讯IM

Java后台集成融云即时通讯IM

由于公司需求,需要使用融云开发一个客服和用户的单聊模式的聊天功能,看了一天的文档才摸清楚接入流程,这里记录一下用Java后台系统集成融云即时通讯IM的流程,以防以后用到忘记了。

不管是Web、Android、iOS、小程序,哪个端需要做出聊天功能,如果是一套完成的即时通讯项目,都需要后台服务端的支持,我的项目就是Java搭建的后台,直接上流程吧!!
很多同学私信我要源码,其实按照文章的步骤集成完成可以成功,如果需要源码的直接去下载吧demo_rongyun.rar
一:在融云注册一个账号,创建IM的应用,这是前提,只有创建了应用才有App Key、App Secret。
1.访问
https://developer.rongcloud.cn/signup

在这里插入图片描述
使用手机号注册账户。
2. 填写企业名称和邮箱地址。在这里插入图片描述
3. 进行邮箱验证。在这里插入图片描述
4. 在开发者后台点击 服务管理在这里插入图片描述
5. 选择对应环境的 AppKey在这里插入图片描述

二:有了appKey,appSecret之后,可以撸代码了。此步骤是搭建后台,提供获取token接口给各前端。
1.后台我的框架就是一个springboot项目,请自行创建项目,pom.xml里面引入融云的依赖包

<dependency>
	    <groupId>cn.rongcloud.im</groupId>
	    <artifactId>server-sdk-java</artifactId>
	    <version>3.1.6</version>
</dependency>

2.创建一个UserService类,主要作用是获取token,

生成用户在融云的唯一身份标识 Token,客户端在使用融云通讯能力前必须获取 Token,融云 SDK
每次连接服务器时,都需要向融云服务器提供 Token,以便验证身份。

意思就是各端通过SDK调用各种方法功能的时候,都需要token,才能调成功,所以我们后台需要写一个获取token的接口,供各端使用!(至于为什么各端不自己去获取token,这个问题,自己可以百度咨询,安全问题哈所以放在后台获取),

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import io.rong.RongCloud;
import io.rong.methods.user.User;
import io.rong.models.Result;
import io.rong.models.response.TokenResult;
import io.rong.models.response.UserResult;
import io.rong.models.user.UserModel;

@Service
public class UserService {

	private static final Logger logger = LoggerFactory.getLogger(UserService.class);
	
    private static String appKey = "你刚才注册的appKey";
   
    private static String appSecret = "你刚才注册的appSecret";
    
    /**
     * 自定义api地址
     */
    @SuppressWarnings("unused")
	private static String api = "http://api-cn.ronghub.com";

    /**
     * API 文档: http://www.rongcloud.cn/docs/server_sdk_api/user/user.html#register
         *  注册用户,生成用户在融云的唯一身份标识 Token
     * @param 	userModel id、name、portrait三个参数必传
     * @return  Result
     */
    public TokenResult getToken(UserModel userModel) throws Exception {
    	RongCloud rongCloud;
    	if(null == rongCloudIMProperties) {
    		rongCloud = RongCloud.getInstance(appKey, appSecret);
    	}else {
    		rongCloud = RongCloud.getInstance(rongCloudIMProperties.getAppKey(), rongCloudIMProperties.getAppSecret());
    	}
    	// 自定义 api 地址方式
    	// RongCloud rongCloud = RongCloud.getInstance(appKey, appSecret,api);
    	// 使用 百度 HTTPDNS 获取最快的 IP 地址进行连接
    	// BaiduHttpDNSUtil.setHostTypeIp("account_id", "secret", rongCloud.getApiHostType());
    	
    	// 设置连接超时时间
    	// rongCloud.getApiHostType().setConnectTimeout(10000);
    	// 设置读取超时时间
    	// rongCloud.getApiHostType().setReadTimeout(10000);
    	// 获取备用域名List
    	// List<HostType> hosttypes = rongCloud.getApiHostListBackUp();
    	// 设置连接、读取超时时间
    	// for (HostType hosttype : hosttypes) {
    	//     hosttype.setConnectTimeout(10000);
    	//     hosttype.setReadTimeout(10000);
    	// }
    	User user = rongCloud.user;
    	TokenResult result = user.register(userModel);
    	logger.info("getToken:  " + result.toString());
    	return result;
    }
  
}
/**
 * 融云IM配置映射类
 */
@Component
@ConfigurationProperties(prefix = "rongcloud.im")
public class RongCloudIMProperties {

	private String appKey;
	 
	private String appSecret;
	 
	 
	public String getAppKey() {
		return appKey;
	}

	public void setAppKey(String appKey) {
		this.appKey = appKey;
	}

	public String getAppSecret() {
		return appSecret;
	}

	public void setAppSecret(String appSecret) {
		this.appSecret = appSecret;
	}

	@Override
    public String toString() {
	    return "RongCloudIMProperties{" +
	        "appKey:'" + appKey + '\'' +
	        ", appSecret:" + appSecret +
	        '}';
    } 
}

application.yml配置

rongcloud:
 im:
  appKey: ***********
  appSecret: *********

3.创建一个UserController类,供各端接口调用

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.rong.models.response.TokenResult;
import io.rong.models.user.UserModel;

@RestController
@RequestMapping("/v1/api/user")
public class UserController extends BaseController {
    
	private static final Logger logger = LoggerFactory.getLogger(UserController.class);
	
	@Autowired
	private UserService userService;
	
	/**
	 * 根据userId,userName获取token
	 * @param userId
	 * @param userName
	 * @return
	 */
    @GetMapping("/getToken")
    public String getToken(String userId,String userName) {
    	logger.info("enter into getToken function......");
    	logger.info("======userId:{}=======userName:{}", userId, userName);
    	if(StringUtils.isEmpty(userId) || StringUtils.isEmpty(userName)) {
    		return responseJson("99","userId、userName请求参数都不能为空",null);
    	}
    	UserModel userModel = new UserModel();
    	userModel.setId(userId);
    	userModel.setName(userName);
    	userModel.setPortrait("http://www.rongcloud.cn/images/logo.png");
    	TokenResult result;
		try {
			result = userService.getToken(userModel);
		} catch (Exception e) {
			logger.error("获取 Token 失败 ", e);
			return responseJson("999","获取 Token 失败",null);
		}
    	return responseJson("00","请求成功",result);
    }
    
	public String responseJson(String code,String msg,Object obj){
    	Map<String, Object> res = new HashMap<>();
		res.put("code", code);
		res.put("msg", msg);
		if (obj == null) {
			obj = new Object();
		}
		res.put("data", obj);
		String ret = JSONObject.toJSONString(res,SerializerFeature.WriteMapNullValue,SerializerFeature.DisableCircularReferenceDetect,SerializerFeature.PrettyFormat,SerializerFeature.SortField);
		logger.info("RESPONSE:" + ret);
		return ret;
	}
}

三: 前端开发,其实融云提供了各个端的demo代码,我这边主要是记录接入流程,简便为主,哈哈,用的H5+JQuery手工做了一个demo。
由于不是专业前端,所以demo没有样式可言,只是功能。我这边做了2个页面,模拟了一个客服聊天页面,一个用户聊天页面。

客服端页面:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="format-detection" content="telephone=no"/>
    <meta name="apple-mobile-web-app-capable" content="yes"/>
    <title>客服坐席端</title>
    <script src="https://apps.bdimg.com/libs/jquery/1.11.3/jquery.min.js"></script>
    <script src="http://cdn.ronghub.com/RongIMLib-3.0.5-dev.js"></script>
    <script type="text/javascript">
        var connectflag = false;

        $(document).ready(function(){
			
			var im = RongIMLib.init({
                appkey: '你刚才注册的appKey'
            });

            var conversationList = []; // 当前已存在的会话列表
            im.watch({
                conversation: function(event){
                    var updatedConversationList = event.updatedConversationList; // 更新的会话列表
                    console.log('更新会话汇总:', updatedConversationList);
                    console.log('最新会话列表:', im.Conversation.merge({
                        conversationList,
                        updatedConversationList
                    }));
                },
                message: function(event){
                    var message = event.message;
                    console.log('收到新消息:', message);
                    $('#jsmsg').val(message.content.content);
                },
                status: function(event){
                    var status = event.status;
                    console.log('连接状态码:', status);
                }
            });

            /* 开发者后台获取或 Server API */
            var user = {
                token: ''
            };
            
            $.ajax({
                url: "http://localhost:8080/v1/api/user/getToken",
                data:{"userId":'kyy_kf_1',"userName":'客服坐席1号'},
                type: "GET",
                error:function (data) {
                    console.log(data);
                },
                success:function (data) {
                    console.log(data);
                    var code = data.code;
                    if('00' == code){
                        user.token = data.data.token;
                    }
                }
            });

            im.connect(user).then(function(user) {
                console.log('链接成功, 链接用户 id 为: ', user.id);
                connectflag = true;
            }).catch(function(error) {
                console.log('链接失败: ', error.code, error.msg);
            });

            $('#send').click(function() {
                if(connectflag){
                    var conversation = im.Conversation.get({
                        targetId: 'kyy_yh_1',// 用户的suerID
                        type: RongIMLib.CONVERSATION_TYPE.PRIVATE
                    });
                    conversation.send({
                        messageType: RongIMLib.MESSAGE_TYPE.TEXT, // 'RC:TxtMsg'
                        content: {
                            content: $('#fsmsg').val() // 文本内容
                        }
                    }).then(function(message){
                        console.log('发送文字消息成功', message);
                    });
                }
            });
        });
        
        
    </script>
  </head>
  <body>
      <h2>客服坐席聊天</h2>
      输入聊天消息:<input id="fsmsg" type="text" />
      <input id="send" type="button" value="发送"/>
      <br/>
      接收到的消息:<input id="jsmsg" type="text" />
  </body>
</html>

用户端页面:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="format-detection" content="telephone=no"/>
    <meta name="apple-mobile-web-app-capable" content="yes"/>
    <title>用户端</title>
    <script src="https://apps.bdimg.com/libs/jquery/1.11.3/jquery.min.js"></script>
    <script src="http://cdn.ronghub.com/RongIMLib-3.0.5-dev.js"></script>
    <script type="text/javascript">
        var connectflag = false;
        
        $(document).ready(function(){
            var im = RongIMLib.init({
                appkey: '你刚才注册的appKey'
            });

            var conversationList = []; // 当前已存在的会话列表
            im.watch({
                conversation: function(event){
                    var updatedConversationList = event.updatedConversationList; // 更新的会话列表
                    console.log('更新会话汇总:', updatedConversationList);
                    console.log('最新会话列表:', im.Conversation.merge({
                        conversationList,
                        updatedConversationList
                    }));
                },
                message: function(event){
                    var message = event.message;
                    console.log('收到新消息:', message);
                    $('#jsmsg').val(message.content.content);
                },
                status: function(event){
                    var status = event.status;
                    console.log('连接状态码:', status);
                }
            });

            /* 开发者后台获取或 Server API */
            var user = {
                token: ''
            };

            $.ajax({
                url: "http://localhost:8080/v1/api/user/getToken",
                data:{"userId":'kyy_yh_1',"userName":'用户1号'},
                type: "GET",
                error:function (data) {
                    console.log(data);
                },
                success:function (data) {
                    console.log(data);
                    var code = data.code;
                    if('00' == code){
                        user.token = data.data.token;
                    }
                }
            });

            im.connect(user).then(function(user) {
                console.log('链接成功, 链接用户 id 为: ', user.id);
                connectflag = true;
            }).catch(function(error) {
                console.log('链接失败: ', error.code, error.msg);
            });


            $('#send').click(function() {
                if(connectflag){
                    var conversation = im.Conversation.get({
                        targetId: 'kyy_kf_1',// 客服坐席的userID
                        type: RongIMLib.CONVERSATION_TYPE.PRIVATE
                    });
                    conversation.send({
                        messageType: RongIMLib.MESSAGE_TYPE.TEXT, // 'RC:TxtMsg'
                        content: {
                            content: $('#fsmsg').val() // 文本内容
                        }
                    }).then(function(message){
                        console.log('发送文字消息成功', message);
                    });
                }
            });
        }); 
        
    </script>
  </head>
  <body>
    <h2>用户端聊天</h2>
    输入聊天消息:<input id="fsmsg" type="text" />
    <input id="send" type="button" value="发送"/>
    <br/>
    接收到的消息:<input id="jsmsg" type="text" />
  </body>
</html>

四:页面开发好后,可以收发消息了,这些消息的数据,按理来说应该入库。
1.此时就需要再融云的控制台配置消息回调了。
在这里插入图片描述
我这里只配置了一个文本消息的回调,一切都是为了实现集成流程,真实项目里肯定是根据业务场景个性化配置。
2.后台创建IMCallBackApiController类,添加回调接口

import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.json.JSONObject;

@Controller
@RequestMapping("/v1/api/im")
public class IMCallBackApiController {
    private static final Logger logger = LoggerFactory.getLogger(IMCallBackApiController.class);
       
   /**
     * 接收即时通讯IM消息回调
     * @param request
     * @param appKey		应用 App Key
     * @param fromUserId	发送用户 Id。
     * @param targetId		目标会话 Id,根据会话类型可能为单聊 Id、群聊 Id、聊天室 Id。
     * @param msgType		消息类型,文本消息 RC:TxtMsg 、 图片消息 RC:ImgMsg 其他消息类型请参见消息类型说明文档。
     * @param content		发送消息内容
     * @param channelType	会话类型,二人会话是 PERSON 、讨论组会话是 PERSONS 、群组会话是 GROUP 、聊天室会话是 TEMPGROUP 。
     * @param msgTimeStamp	服务端收到客户端发送消息时的服务器时间(1970年到现在的毫秒数)。
     * @param messageId		消息唯一标识。
     * @return JSONObject	{ "pass": 1 }   1 表示正常下发此条消息,0 表示拒绝不下发此条消息。
     */
    @PostMapping("/callBackEvent")
    @ResponseBody
    public JSONObject callBackEvent(HttpServletRequest request,String appKey,String fromUserId,String targetId,
    		String msgType,String content,String channelType,String msgTimeStamp,String messageId) {
    	logger.info("callBackEvent function startTime:{}", System.currentTimeMillis());
    	logger.info("----------收到IM 给到的回调消息appKey={},  fromUserId={},targetId={},msgType={},content={},channelType={},msgTimeStamp={},messageId={}-----------", 
    			appKey, fromUserId, targetId, msgType, content, channelType, msgTimeStamp, messageId);
    	JSONObject ret = new JSONObject() {
    		{put("pass", 1);}
    	};
        try {
        	HandleCallBackMsg handleCallBackMsg = HandleCallBackMsg
        			.builder()
        			.appKey(appKey)
        			.fromUserId(fromUserId)
        			.targetId(targetId)
        			.msgType(msgType)
        			.content(content)
        			.channelType(channelType)
        			.msgTimeStamp(msgTimeStamp)
        			.messageId(messageId)
        			.build();
            //TO-DO handleCallBackMsg 实体类里就是回调的所有数据,此时就是根据自己的项目 串行或者异步把消息入库或者别的业务逻辑
          
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            ret.put("pass", 0);
        }
        logger.info("callBackEvent function endTime:{}", System.currentTimeMillis());
        return ret;
    }
 
}

3.HandleCallBackMsg实体类

import lombok.Builder;
import lombok.Data;
import lombok.experimental.Tolerate;

@Data
@Builder
public class HandleCallBackMsg {

    /*
     * 应用 App Key
     */
	private String appKey;
	
	/*
	 * 发送用户 Id。
	 */
	private String fromUserId;
	
	/*
	 * 目标会话 Id,根据会话类型可能为单聊 Id、群聊 Id、聊天室 Id。
	 */
	private String targetId;
	
	/*
	 * 消息类型,文本消息 RC:TxtMsg 、 图片消息 RC:ImgMsg 其他消息类型请参见消息类型说明文档。
	 */
	private String msgType;
	
	/*
	 * 发送消息内容
	 */
	private String content;
	
	/*
	 * 会话类型,二人会话是 PERSON 、讨论组会话是 PERSONS 、群组会话是 GROUP 、聊天室会话是 TEMPGROUP 。
	 */
	private String channelType;
	
	/*
	 * 服务端收到客户端发送消息时的服务器时间(1970年到现在的毫秒数)。
	 */
	private String msgTimeStamp;
	
	/*
	 * 消息唯一标识。
	 */
	private String messageId;
	
	@Tolerate
    public HandleCallBackMsg() {
		
	}
}

总结:
以上就完成了最基础的Web+后台集成融云IM单聊收发消息的功能,聊天的消息是各端直接调用SDK和融云交互,然后融云又通过异步的消息回调把消息推送给我们的后台系统,这样就实现了即时通讯的解耦,体现了用第三方插件完成实时通讯的业务需求。
看下效果吧
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 7
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

打成jar包

纯手工撸码打字不易喜欢就打赏吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值