由于业务需求,需要在系统中集成环信,所以去看了下官方文档,写篇博客分享一下。

在开始之前,我们需要了解一下什么是REST

REST(Representational State Transfer)是一种轻量级的 Web Service 架构风格,可以翻译成“表述性状态转移”,实现和操作明显比 SOAP 和 XML-RPC 更为简洁,可以完全通过 HTTP 协议实现,还可以利用缓存 Cache 来提高响应速度,性能、效率和易用性上都优于 SOAP 协议。

REST 架构遵循了 CRUD 原则,CRUD原则对于资源只需要四种行为:Create(创建)、Read(读取)、Update(更新)和Delete(删除)就可以完成对其操作和处理。这四个操作是一种原子操作,对资源的操作包括获取、创建、修改和删除资源的操作正好对应HTTP 协议提供的 GET、POST、PUT 和 DELETE 方法,因此 REST 把 HTTP 对一个 URL 资源的操作限制在POST、GET、PUT 和 DELETE 这四个之内。这种针对网络应用的设计和开发方式,可以降低开发的复杂性,提高系统的可伸缩性。

我看到一篇关于RESTful的很不错的文章:RESTful API 设计指南,有兴趣的可以看下,讲的很好。

环信 REST 平台

环信 REST 平台提供的是一个多租户用户体系,资源以集合(Collection)的形式来描述,这里所说的 Collection 包括 DataBase、企业(orgs)、应用(apps)、IM用户(users)、群组(chatgroups)、消息(chatmessages)、文件(chatfiles)等等,之间的包含关系是:

DB = {org1, org2, …}
org = {app1, app2, …}
app = {users, messages, chatfiles, chatmessages, chatgroups, …}
users = {user1, user2, …}
messages = {message1, message2, …}
chatfiles = {chatfile1, chatfile2, …}
chatmessages = {chatmessage1, chatmessage2, …}
chatgroups = {group1, group2, …}

多租户是指软件架构支持一个实例服务多个用户(Customer),每一个用户被称之为租户(Tenant),软件给予租户可以对系统进行部分定制的能力,如用户界面颜色或业务规则,但是他们不能定制修改软件的代码。详情可查看官方文档:服务端集成。

在环信服务体系中,不同org之间的用户数据相互隔离,同一个 org 下不同 APP 之间的用户数据相互隔离。

REST server

环信的服务器端接口都是通过REST服务方式提供的,REST API基于最简单的HTTP协议,在各个编程语言中都提供了良好的支持。

REST client

REST client 就是调用 REST API 的程序端,调用方式有多种:Linux curl、浏览器、编程语言 HTTP 请求访问实现等。

调用 REST API,本质就是发送 HTTP 请求,只不过大家常用的可能是 HTTP GET 和 HTTP POST 请求,但是在 REST 里面还经常用到 HTTP PUT 和 HTTP DELETE。在 REST 中,把这四种操作称之为动词,可以(但不是特别准确)想象成增删改查。

而动词所操作的对象,在 REST 中,被称之为“资源”,也就是 URL,而这些也都是标准的 HTTP 协议的内容。实际上,当我们在浏览器中打开一个网站的时候,例如,打开环信官网,浏览器实际上发送给网站服务器的,就是一个 HTTP GET 的请求。

需要注意的是,环信的 REST API 都是基于 JSON 的,所以在构造 HTTP 请求的时候,需要在 HTTP HEADER 中指明:

Header_name Header_value Description
Accept application/json 服务器端返回给客户端的数据类型
Content-Type application/json 客户端发送到服务器端的数据类型

JAVA

在 Java 中,REST client 实现方式有多种,比如 JBOss RestEasy、Sun Jersey、Dropwizard、Apache HTTPClient。
本文用的是Spring的RestTemplate。有一篇不错的博客:Spring RestTemplate中几种常见的请求方式,可以去看看。

在集成之前,我们得在环信上注册并创建一个账号。

注册开发者账号

第 1 步:进入环信官网,选择“注册 > 注册即时通讯云”,进入环信管理后台的注册页面。

第 2 步:在注册页面中,填写详细资料,并点击“注册”按钮。

注册成功后,我们会向您填写的邮箱中发送验证信息,请前往邮箱进行账号激活。

创建应用

账号激活成功后,回到控制台登录页面登录到开发者后台。

第 1 步:在我的应用中,点击创建应用按钮,如下图:

第 2 步:填写创建应用的名称(内容只限于数字、大小写字母),如下图:

(应用名称会存在于你生成的 AppKey 中,如:测试 Demo 中 AppKey 为 easemob-demo#chatdemo,则 chatdemo 为填写的应用名称。注册授权根据需要自行选择,AppKey的长度限制为1k字节以内。)

第 3 步:填写好应用名称后,点确定。创建成功,系统会为你生成 AppKey 以及相关配置信息,如下图:


之后,将此 AppKey 配置到 Android、iOS、Web IM 上即可。

名词 解释
org_name 企业的唯一标识,开发者在环信开发者管理后台注册账号时填写的企业 ID
app_name 同一“企业”下“APP”唯一标识,开发者在环信开发者管理后台创建应用时填写的“应用名称”
org_admin 开发者在环信开发者管理后台注册时填写的“用户名”,企业管理员拥有对该企业账号下所有资源的操作权限
AppKey 一个 APP 的唯一标识,规则是 ${org_name} # ${app_name}

这些在官方文档上都是有的,可点击查看:注册并创建应用

编写代码

接下来就开始用户集成了,详细的就不说了,可点击查看用户体系集成。

主要把写好的工具类分享一下。在对应的场景,只需调用对应的方法即可。


import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.io.FileUtils;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.*;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;/***  环信工具类*/
public class HXUtil {private static RestTemplate restTemplate = new RestTemplate();// 企业的唯一标识,开发者在环信开发者管理后台注册账号时填写的企业 IDprivate static final String ORG_NAME = "1122161011178276";// App的client_idprivate static final String CLIENT_ID = "YXA6Irz_oI-GEead-FFvbfaMbQ";// App的client_secretprivate static final String CLIENT_SECRET = "YXA6VsR5JypETS3iPFvNNxYklmho0Vw";// 同一“企业”下“APP”唯一标识,开发者在环信开发者管理后台创建应用时填写的“应用名称”private static final String APP_NAME = "testapp";// 链接前缀private static final String URL_PREFIX = "http://a1.easemob.com/" + ORG_NAME + "/" + APP_NAME + "/";// 缓存的tokenprivate static Token token;// token的失效时间private static long expiresTime;public enum HXMessageType {txt,// 文本img,// 图片loc,// 位置audio,// 音频video,// 视频file// 文件}/*** 获取Token* 注意:关于有效时间,我在网上找过,说的是7天,但是返回的是5184000,*          但是官网上说是以秒为单位,这么算下来就是60天了,*            觉得不太对,就先将有效时间设为了7天* @return token*/public static Token getToken() {// 判断Token是否已经过期,如果过期需要重新获取if (token == null || expiresTime < new Date().getTime()) {try {JSONObject body = new JSONObject();body.put("grant_type", "client_credentials");body.put("client_id", CLIENT_ID );body.put("client_secret", CLIENT_SECRET );HttpEntity httpEntity = new HttpEntity(body.toString(), null);ResponseEntity<Token> tokenResponseEntity = restTemplate.postForEntity(URL_PREFIX + "token", httpEntity, Token.class);token =  tokenResponseEntity.getBody();// 设置7天后过期Calendar c = Calendar.getInstance();c.add(Calendar.DATE, 7);expiresTime = c.getTime().getTime();} catch (RestClientException e) {e.printStackTrace();}}return token;}/*** 添加用户** @param username 用户名(唯一非空)* @param password 密码* @return 是否成功*/public static boolean addUser(String username, String password) {try {JSONArray body = new JSONArray();JSONObject jsonObject = new JSONObject();jsonObject.put("username", username);jsonObject.put("password", password);body.add(jsonObject);HttpEntity httpEntity = new HttpEntity(body.toString(), null);ResponseEntity responseEntity = restTemplate.postForEntity(URL_PREFIX + "users", httpEntity, null);return responseEntity.getStatusCodeValue() == 200;} catch (RestClientException e) {e.printStackTrace();return false;}}/*** 修改用户密码** @param username    用户名* @param newpassword 新密码* @return 是否成功*/public static boolean updatePassword(String username, String newpassword) {try {JSONObject body = new JSONObject();body.put("newpassword", newpassword);HttpHeaders headers = new HttpHeaders();headers.add("Authorization", "Bearer " + getToken().getAccess_token());HttpEntity httpEntity = new HttpEntity(body.toString(), headers);ResponseEntity responseEntity = restTemplate.postForEntity(URL_PREFIX + "users/{username}/password", httpEntity, null, username);System.out.println(responseEntity.getStatusCodeValue());return responseEntity.getStatusCodeValue() == 200;} catch (RestClientException e) {e.printStackTrace();return false;}}/*** 删除用户** @param username 用户名*/public static boolean deleteUser(String username) {try {HttpEntity httpEntity = new HttpEntity(null, getHttpHeaders(MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON));ResponseEntity<HXUser> responseEntity = restTemplate.exchange(URL_PREFIX + "users/{username}", HttpMethod.DELETE, httpEntity, HXUser.class, username);System.out.println(responseEntity.getStatusCodeValue());return responseEntity.getStatusCodeValue() == 200;} catch (RestClientException e) {e.printStackTrace();return false;}}/*** 添加好友** @param ownerUsername 用户名* @param friendName    好友用户名* @return 是否成功*/public static boolean addFriend(String ownerUsername, String friendName) {try {HttpEntity httpEntity = new HttpEntity(null, getHttpHeaders(MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON));ResponseEntity responseEntity = restTemplate.postForEntity(URL_PREFIX + "users/{owner_username}/contacts/users/{friend_username}", httpEntity, HXUser.class, ownerUsername, friendName);System.out.println(responseEntity.getStatusCodeValue());return responseEntity.getStatusCodeValue() == 200;} catch (RestClientException e) {e.printStackTrace();return false;}}/*** 删除好友** @param ownerUsername 用户名* @param friendName    好友用户名* @return 是否成功*/public static boolean deleteFriend(String ownerUsername, String friendName) {try {HttpEntity httpEntity = new HttpEntity(null, getHttpHeaders(MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON));ResponseEntity responseEntity = restTemplate.exchange(URL_PREFIX + "users/{owner_username}/contacts/users/{friend_username}", HttpMethod.DELETE, httpEntity, HXUser.class, ownerUsername, friendName);System.out.println(responseEntity.getStatusCodeValue());return responseEntity.getStatusCodeValue() == 200;} catch (RestClientException e) {e.printStackTrace();return false;}}/*** 发送消息** @param sendUser   发送用户* @param targetUser 接收用户* @param msg        发送消息* @return 是否成功*/public static boolean sendToUser(String sendUser, String targetUser, String msg) {try {JSONObject body = new JSONObject();body.put("target_type", "users");JSONArray targetUserjson = new JSONArray();targetUserjson.add(targetUser);body.put("target", targetUserjson);JSONObject msgJson = new JSONObject();msgJson.put("type", HXMessageType.txt.name());msgJson.put("msg", msg);body.put("msg", msgJson);body.put("from", sendUser);HttpEntity httpEntity = new HttpEntity(body, getHttpHeaders(MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON));ResponseEntity responseEntity = restTemplate.postForEntity(URL_PREFIX + "messages", httpEntity, null);System.out.println(responseEntity.getStatusCodeValue());return responseEntity.getStatusCodeValue() == 200;} catch (RestClientException e) {e.printStackTrace();return false;}}/*** 获取HttpHeaders** @param contentType 客户端发送类型* @param accept      响应类型* @return HttpHeaders*/private static HttpHeaders getHttpHeaders(MediaType contentType, MediaType... accept) {HttpHeaders headers = new HttpHeaders();headers.add("Authorization", "Bearer " + getToken().getAccess_token());headers.setContentType(contentType != null ? contentType : MediaType.APPLICATION_JSON);headers.setAccept(Arrays.asList((accept != null && accept.length > 0) ? accept : new MediaType[]{MediaType.APPLICATION_JSON}));return headers;}}

这里用到了两个实体类:HXUser、Token

HXUser:


public class HXUser {private String uuid; // 用户的UUID,标识字段private String type; // 类型,“user”用户类型private Long created;private Long modified;private String username; // 用户名,也就是环信 ID,(唯一,非空)private String nickName; // 昵称private boolean activated; // 用户是否已激活,“true”已激活,“false“封禁,封禁需要通过解禁接口进行解禁,才能正常登录public String getUuid() {return uuid;}public void setUuid(String uuid) {this.uuid = uuid;}
}

Token:


public class Token {private String access_token; // 有效的token字符串private String expires_in;   // token 有效时间,以秒为单位,在有效期内不需要重复获取private String application;  // 当前 App 的 UUID 值// getter and setter
}

本来还是想把上传文件和发送图片等写上的,后来由于需求,决定把聊天这部分交由前端直接访问环信了,所以写完发送消息就没再写了。

其实聊天这部分本人也是推荐由前端来写的。即时通信讲究的就是一个即时性,如果由后端来的话,就不能保证这个即时性了,因为如果前端走后端,后端再走环信,需要两步,而前端直接走环信,则只需要一步,就算网络等外界因素的存在,也不会太慢。而且前端也可以对消息进行一个缓存,从而降低网络访问,而且现在的IM应用也基本上都是这么来的。

以上仅供参考,如有不妥的地方请留下您的见解,谢谢。

Java服务端集成环信IM相关推荐

  1. Java服务端集成环信im即时通讯

    Java服务端集成环信im即时通讯 先去GitHub上下载官方给的示例 说明一下环信给的demo 解压下载的包 导入项目之后加几个jar包 注意事项 修改OrgInfo和TokenUtil类 跟据IM ...

  2. 集成环信即时通讯(IM)及使用——服务端

    文章目录 目的 流程 使用 注册账号和创建应用 调用环信接口 建议 如何自己搭建一个im服务器 目的 本篇讲述服务端如何集成环信SDK,实现IM系统. 流程 注册账号 创建应用 调用环信接口 使用 注 ...

  3. Java集成环信即时通讯(SpringBoot)

    Java集成环信即时通讯(SpringBoot) 前言:链接: 环信官网友情链接. 官网注册一个社区版账号,社区版限制注册100个用户. 企业版资费如下 还有硬性要求,账号余额9000以上 准备完成得 ...

  4. 【快速搞定】教你如何快速集成环信(android端EaseUI),跳过我踩过的坑

    [快速搞定]教你如何快速集成环信(android端EaseUI),跳过我踩过的坑 一.前言 最近,公司准备集成一个即时通讯的功能,于是我找到了环信,于是我就这样被坑了,于是就有了本文来教大家如何跳出我 ...

  5. java服务端部署到k8s集群

    首先java服务端部署到k8s中是通过git提交,那要准备好各种配置 1.先创建一个空的git文件 2.java服务端的jar包放到文件中 3.提交的文件必须包含java环境(这个环境就是引入自己打包 ...

  6. 环信是否支持html,VUE项目集成环信WebIM即时通信以及所遇到的问题

    功能背景: 以前和朋友一块儿作了一个wbe项目集成环信的即时通讯的功能,作的时候感叹web端文档太少,并且npm包有一些坑,记录下来写了这篇博客,以后不断有人加我微信问我,怎么集成.如今我再来重写一下 ...

  7. 环信即时通讯SDK集成——如何使用Swift快速集成环信IM iOS SDK并实现单聊

    本文介绍如何使用swift快速集成环信即时通讯 IM iOS SDK 实现单聊. 前提条件 • Xcode (推荐最新版本). • 安装 iOS 10.0 或更高版本的 iOS 模拟器或 Apple ...

  8. 聊一聊 Java 服务端中的乱象

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 来源:阿里巴巴中间件 查尔斯·狄更斯在<双城记>中写道 ...

  9. 那些年,我们见过的 Java 服务端乱象

    点击上方"方志朋",选择"设为星标" 做积极的人,而不是积极废人 Photo by The Book Tutor @Youtube 文 | 陈昌毅 导读 查尔斯 ...

最新文章

  1. FFmpeg中RTSP客户端拉流测试代码
  2. android 视频图片,Android - 视频提取图片方法
  3. 第七章 ReentrantLock总结
  4. html页面创建二维数组,二维数组到HTML表?
  5. 二 Array 数组常用操作方法
  6. Delphi自定义过程获取本机ip,名字,用户名
  7. 括号生成Python解法
  8. 【Android 修炼手册】Gradle 篇 -- Android Gradle Plugin 主要流程分析
  9. c ++递归算法数的计数_C ++程序使用数组中的递归查找数字的最后一次出现
  10. C++ 对引用的理解5
  11. 计算机网络项目化实训教程,计算机网络项目实训教程
  12. HTMl文件的阶层架构 访问父元素和子元素
  13. HDU2027 统计元音【入门】
  14. 点分十进制ip地址转为十进制数字地址-python3实现
  15. 为什么蓝鸽的听力下载完还是听不了_听力训练方法干货-说说我与雅思听力的那些事情...
  16. 问题:宇视摄像机如何对接第三方录像机
  17. 80386 保护模式
  18. Android OpenGL ES(七)----理解纹理与纹理过滤
  19. python操作word文档
  20. redis入门(三)

热门文章

  1. 一个想法(续三):一份IT技术联盟创业计划书,开启众筹创业征程
  2. 如何用u盘制作成linux系统的安装盘
  3. 第四战:“合纵”与“连横”(“战国纵横家书”辨别修订版)诸子百家走四方的美好时代
  4. Java程序设计基础【1】
  5. 数据库api如何获取实时股票数据?
  6. 隐私保护的数据挖掘综述
  7. 线性代数-思维导图(5)
  8. 微信小程序(视图与逻辑)
  9. 国内知名的信息与通讯调查研究咨询公司情况
  10. Oracle数据库常见的增删改查操作语句大全