0%

即时通讯IM

背景

最近在做一款直播app,涉及到了IM通讯,实现直播群组聊天,IM注册、登录,改换头像、昵称等。用的是腾讯IM。

Api调用

准备工作

服务端需记录腾讯IM控制台里的sdk app id及应用的密钥

代码

Constant.java

1
2
3
4
5
6
public class Constant {
//IM通讯sdkappid 密钥
public static final Integer SDK_APPID = ######;
public static final String KEY = "#######################################3";
public static final String IDENTIFIER = "admin";
}

TimService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
@Service("timService")
public class TimService {
private static final Logger log = LoggerFactory.getLogger(TimService.class);
public static final String HOST = "https://console.tim.qq.com";

@Autowired
private RestTemplate restTemplate;

@SysLog("单账号导入")
public ProcessResult accountImport(String Identifier) {
String userSig = getUserSig();
String url = formatUrl("im_open_login_svc", "account_import", userSig);
Map jsonObj = Collections.singletonMap("Identifier",Identifier);
HttpEntity<String> formEntity = new HttpEntity<String>(JsonUtil.toJSON(jsonObj));
Map<String, String> result = restTemplate.postForObject(url, formEntity, Map.class);
if ("OK".equalsIgnoreCase(result.get("ActionStatus"))) {
return new ProcessResult(ProcessResult.SUCCESS,"single account import success");
}
return new ProcessResult(ProcessResult.ERROR,"single account import failure");
}

@SysLog("创建群组")
public String createGroup(GoVideo goVideo) {
String userSig = getUserSig();
String url = formatUrl("group_open_http_svc", "create_group", userSig);
Map<String, Object> jsonObj = new HashMap<>();
//jsonObj.put("Owner_Account",username);群主的userId 待后期扩展
jsonObj.put("Type","AVChatRoom");//音视频聊天室
jsonObj.put("Name","Group-"+goVideo.getId());
jsonObj.put("GroupId","live-"+goVideo.getId());
HttpEntity<String> formEntity = new HttpEntity<String>(JsonUtil.toJSON(jsonObj));
Map<String, String> result = restTemplate.postForObject(url, formEntity, Map.class);
return result.get("ActionStatus");
}

@SysLog("APP自定义脏字")
@PostMapping(value = "/addDirtyWOrd")
public ProcessResult addDirtyWord(@RequestBody String jsonString) {
Map jsonObj = JsonUtil.fromJSON(jsonString, Map.class);
String userSig = getUserSig();
String url = formatUrl("openim_dirty_words", "add", userSig);
HttpEntity<String> formEntity = new HttpEntity<String>(JsonUtil.toJSON(jsonObj));
Map<String, String> rowData = restTemplate.postForObject(url, formEntity, Map.class);
String actionStatus = rowData.get("ActionStatus");
if("OK".equalsIgnoreCase(actionStatus)) {
return new ProcessResult(ProcessResult.SUCCESS,"add dirty word success");
}
return new ProcessResult(ProcessResult.ERROR,"add dirty word failure :: " + JsonUtil.toJSON(rowData));
}

@SysLog("解散群组")
@PostMapping(value = "/destroyGroup")
public String destroyGroup(GoVideo goVideo) {
Map<String,Object> jsonObj = new HashMap();
jsonObj.put("GroupId",goVideo.getGroupId());
String userSig = getUserSig();
String url = formatUrl("group_open_http_svc", "destroy_group", userSig);
HttpEntity<String> formEntity = new HttpEntity<String>(JsonUtil.toJSON(jsonObj));
Map<String, String> rowData = restTemplate.postForObject(url, formEntity, Map.class);
log.info("===========解散群组================== {}", goVideo.getGroupId());
return rowData.get("ActionStatus");
}

/**
* im注册
* @param nickName
* @param faceUrl
* @return
*/
public String registe(String uuid,String nickName,String faceUrl){
String userSig = getUserSig();
String url = formatUrl("im_open_login_svc","account_import",userSig);
Map<String,Object> jsonObj = new HashMap();
jsonObj.put("Identifier",uuid);
jsonObj.put("Nick",nickName);
jsonObj.put("FaceUrl",faceUrl);
Map<String, String> result = restTemplate.postForObject(url, jsonObj, Map.class);
return result.get("ActionStatus");
}

/**
* im修改头像
* @param
* @return
*/
public String updateImFaceUrl(User user) {
String userSig = getUserSig();
String url = formatUrl("profile", "portrait_set", userSig);
ArrayList<Object> profileItem = new ArrayList<>();
HashMap<String, Object> jsonObj = new HashMap<>();
jsonObj.put("Tag", "Tag_Profile_IM_Image");
jsonObj.put("Value", user.getAvatar());
profileItem.add(jsonObj);
MapBuild<String, String> obj = new MapBuild<String, String>().put("From_Account",user.getUuid()).put("ProfileItem", profileItem);
Map<String, String> result = restTemplate.postForObject(url, obj.build(), Map.class);
return result.get("ActionStatus");
}

/**
* im修改昵称
* @param uuid
* @param nickName
* @return
*/
public String updateImNick(String uuid,String nickName) {
String userSig = getUserSig();
String url = formatUrl("profile", "portrait_set", userSig);
ArrayList<Object> profileItem = new ArrayList<>();
HashMap<String, Object> jsonObj = new HashMap<>();
jsonObj.put("Tag", "Tag_Profile_IM_Nick");
jsonObj.put("Value", nickName);
profileItem.add(jsonObj);
MapBuild<String, String> obj = new MapBuild<String, String>().put("From_Account", uuid).put("ProfileItem", profileItem);
Map<String, String> result = restTemplate.postForObject(url, obj.build(), Map.class);
return result.get("ActionStatus");
}

/**
*
* @param uuid
* @return
*/
public String getProfilePortrait(String uuid){
String userSig = getUserSig();
String url = formatUrl("profile","portrait_get",userSig);
MapBuild<String, String[]> obj = new MapBuild<String, String[]>().put("To_Account",new String[] {uuid})
.put("TagList",new String[] {"Tag_Profile_IM_Nick","Tag_Profile_IM_Image"});
Map<String, String> result = restTemplate.postForObject(url, obj.build(), Map.class);
return result.get("ActionStatus");
}


private String formatUrl(String serviceName, String cmdName, String usersig) {
double rd = Math.random() * 999_999_999;
String url = String.format("%s/v4/%s/%s?usersig=%s&identifier=%s&sdkappid=%s&random=%d&contenttype=json", HOST, serviceName, cmdName, usersig, Constant.IDENTIFIER, Constant.SDK_APPID,
(int) rd);
return url;
}

@SysLog("获取userSig")
public String getUserSig() {
TLSSigAPIv2 api = new TLSSigAPIv2(Constant.SDK_APPID, Constant.KEY);
String userSig = api.genSig(Constant.IDENTIFIER , 180 * 86400);
return userSig;
}

工具类TLSSigAPIv2.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package com.xy.goone.modules.sys.util;


import com.alibaba.fastjson.JSONObject;
import org.apache.commons.net.util.Base64;
import sun.misc.BASE64Encoder;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.nio.charset.Charset;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.zip.Deflater;


public class TLSSigAPIv2 {
private long sdkappid;
private String key;

public TLSSigAPIv2(long sdkappid, String key) {
this.sdkappid = sdkappid;
this.key = key;
}

private String hmacsha256(String identifier, long currTime, long expire, String base64Userbuf) {
String contentToBeSigned = "TLS.identifier:" + identifier + "\n"
+ "TLS.sdkappid:" + sdkappid + "\n"
+ "TLS.time:" + currTime + "\n"
+ "TLS.expire:" + expire + "\n";
if (null != base64Userbuf) {
contentToBeSigned += "TLS.userbuf:" + base64Userbuf + "\n";
}
try {
byte[] byteKey = key.getBytes("UTF-8");
Mac hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec keySpec = new SecretKeySpec(byteKey, "HmacSHA256");
hmac.init(keySpec);
byte[] byteSig = hmac.doFinal(contentToBeSigned.getBytes("UTF-8"));
//return new String(Base64.encodeBase64(byteSig)).replaceAll("\\s*", "");
return (new BASE64Encoder().encode(byteSig)).replaceAll("\\s*", "");
} catch (UnsupportedEncodingException e) {
return "";
} catch (NoSuchAlgorithmException e) {
return "";
} catch (InvalidKeyException e) {
return "";
}
}

private String genSig(String identifier, long expire, byte[] userbuf) {

long currTime = System.currentTimeMillis()/1000;

JSONObject sigDoc = new JSONObject();
sigDoc.put("TLS.ver", "2.0");
sigDoc.put("TLS.identifier", identifier);
sigDoc.put("TLS.sdkappid", sdkappid);
sigDoc.put("TLS.expire", expire);
sigDoc.put("TLS.time", currTime);

String base64UserBuf = null;
if (null != userbuf) {
//base64UserBuf = new String(Base64.encodeBase64(userbuf));
base64UserBuf = new BASE64Encoder().encode(userbuf);
sigDoc.put("TLS.userbuf", base64UserBuf);
}
String sig = hmacsha256(identifier, currTime, expire, base64UserBuf);
if (sig.length() == 0) {
return "";
}
sigDoc.put("TLS.sig", sig);
Deflater compressor = new Deflater();
compressor.setInput(sigDoc.toString().getBytes(Charset.forName("UTF-8")));
compressor.finish();
byte [] compressedBytes = new byte[2048];
int compressedBytesLength = compressor.deflate(compressedBytes);
compressor.end();
return (new String(Base64URL.base64EncodeUrl(Arrays.copyOfRange(compressedBytes,
0, compressedBytesLength)))).replaceAll("\\s*", "");
}

public String genSig(String identifier, long expire) {
return genSig(identifier, expire, null);
}

public String genSigWithUserBuf(String identifier, long expire, byte[] userbuf) {
return genSig(identifier, expire, userbuf);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package com.xy.goone.tengxim;

import com.xy.goone.common.Constant;
import com.xy.goone.common.util.MapBuild;
import com.xy.goone.modules.domain.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

/**
* @author fumei.jiang
* @date 2019-08-15
*/
@Slf4j
@Service
public class ImMessageService {

public static final String HOST = "https://console.tim.qq.com";

@Autowired
private RestTemplate restTemplate;

/**
* im注册
* @param nickName
* @param faceUrl
* @return
*/
public String registe(String uuid,String nickName,String faceUrl){
String userSig = getUserSig();
String url = formatUrl("im_open_login_svc","account_import",userSig);
Map<String,Object> jsonObj = new HashMap();
jsonObj.put("Identifier",uuid);
jsonObj.put("Nick",nickName);
jsonObj.put("FaceUrl",faceUrl);
Map<String, String> result = restTemplate.postForObject(url, jsonObj, Map.class);
return result.get("ActionStatus");
}

/**
* im修改头像
* @param
* @return
*/
public String updateImFaceUrl(User user) {
String userSig = getUserSig();
String url = formatUrl("profile", "portrait_set", userSig);
ArrayList<Object> profileItem = new ArrayList<>();
HashMap<String, Object> jsonObj = new HashMap<>();
jsonObj.put("Tag", "Tag_Profile_IM_Image");
jsonObj.put("Value", user.getAvatar());
profileItem.add(jsonObj);
MapBuild<String, String> obj = new MapBuild<String, String>().put("From_Account",user.getUuid()).put("ProfileItem", profileItem);
Map<String, String> result = restTemplate.postForObject(url, obj.build(), Map.class);
return result.get("ActionStatus");
}

public String updateImNick(String uuid,String nickName) {
String userSig = getUserSig();
String url = formatUrl("profile", "portrait_set", userSig);
ArrayList<Object> profileItem = new ArrayList<>();
HashMap<String, Object> jsonObj = new HashMap<>();
jsonObj.put("Tag", "Tag_Profile_IM_Nick");
jsonObj.put("Value", nickName);
profileItem.add(jsonObj);
MapBuild<String, String> obj = new MapBuild<String, String>().put("From_Account", uuid).put("ProfileItem", profileItem);
Map<String, String> result = restTemplate.postForObject(url, obj.build(), Map.class);
return result.get("ActionStatus");
}

public String getProfilePortrait(String uuid){
String userSig = getUserSig();
String url = formatUrl("profile","portrait_get",userSig);
MapBuild<String, String[]> obj = new MapBuild<String, String[]>().put("To_Account",new String[] {uuid})
.put("TagList",new String[] {"Tag_Profile_IM_Nick","Tag_Profile_IM_Image"});
Map<String, String> result = restTemplate.postForObject(url, obj.build(), Map.class);
return result.get("ActionStatus");
}

/**
* 获取用户签名
* @return
*/
public String getUserSig() {
TLSSigAPIv2 api = new TLSSigAPIv2(Constant.SDK_APPID, Constant.KEY);
String userSig = api.genSig(Constant.IDENTIFIER, 180 * 86400);
return userSig;
}

private String formatUrl(String serviceName, String cmdName, String usersig) {
double rd = Math.random() * 999_999_999;
String url = String.format("%s/v4/%s/%s?usersig=%s&identifier=%s&sdkappid=%s&random=%d&contenttype=json", HOST, serviceName, cmdName, usersig, Constant.IDENTIFIER, Constant.SDK_APPID,
(int) rd);
return url;
}


}

MapBuild.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import java.util.*;
import java.util.Map.Entry;

public class MapBuild<K, V> {

private final Map<K, V> map;

public MapBuild() {
this.map = new HashMap<>();
}

public MapBuild(Map<K, V> map) {
this.map = map;
}

public int size() {
return map.size();
}

public boolean isEmpty() {
return map.isEmpty();
}

public boolean containsKey(Object key) {
return map.containsKey(key);
}

public boolean containsValue(Object value) {
return map.containsValue(value);
}

public V get(Object key) {
return map.get(key);
}

public MapBuild<K, V> put(K key, V value) {
map.put(key, value);
return this;
}

@SuppressWarnings("unchecked")
public MapBuild<K, V> put(K key, List<Object> value) {
map.put(key, (V) value);
return this;
}

@SuppressWarnings("unchecked")
public MapBuild<K, V> put(K key, Integer integer) {
map.put(key, (V) integer);
return this;
}

public MapBuild<K, V> putAll(Map<? extends K, ? extends V> m) {
map.putAll(m);
return this;
}

public MapBuild<K, V> clear() {
map.clear();
return this;
}

public Set<K> keySet() {
return map.keySet();
}

public Collection<V> values() {
return map.values();
}

public Set<Entry<K, V>> entrySet() {
return map.entrySet();
}

public boolean equals(Object o) {
return map.equals(o);
}

public int hashCode() {
return map.hashCode();
}

public Map<K, V> build() {
return map;
}
}
欣赏此文?求鼓励,求支持!