腾讯云>>云通信>>TLS后台API在mac上JAVA DEMO搭建
来源:互联网 发布:java捕获被0除的异常 编辑:程序博客网 时间:2024/06/06 20:09
云通信相关资料下载地址
https://share.weiyun.com/2b3abe0e3f185c440cf455647455f661
Java demo
根据官方提供的demo做了调整,更符合spring-boot的风格
import java.util.Map;/** * Created by saleson on 2017/10/24. */public class IMActionResult { private Map<String, Object> result; public IMActionResult(Map<String, Object> result) { this.result = result; } public boolean isSuccess() { return "OK".equals(getActionStatus()); } public String getActionStatus() { return (String) result.get("ActionStatus"); } public String getErrorInfo() { return (String) result.get("ErrorInfo"); } public int getErrorCode() { return (int) result.get("ErrorCode"); } public Map<String, Object> getResult() { return result; } public Object getObject(String name) { return result.get(name); } public <T> T get(String name) { return (T) result.get(name); }}
/** * Created by saleson on 2017/10/23. */public class TencentIMConfig { private String sdkAppid; private String jnisigcheckLibPath; private String privateKeyPath; private String privateKey; private String defaultImAdminAccount; public String getSdkAppid() { return sdkAppid; } public void setSdkAppid(String sdkAppid) { this.sdkAppid = sdkAppid; } public String getJnisigcheckLibPath() { return jnisigcheckLibPath; } public void setJnisigcheckLibPath(String jnisigcheckLibPath) { this.jnisigcheckLibPath = jnisigcheckLibPath; } public String getPrivateKeyPath() { return privateKeyPath; } public void setPrivateKeyPath(String privateKeyPath) { this.privateKeyPath = privateKeyPath; } public String getPrivateKey() { return privateKey; } public void setPrivateKey(String privateKey) { this.privateKey = privateKey; } public String getDefaultImAdminAccount() { return defaultImAdminAccount; } public void setDefaultImAdminAccount(String defaultImAdminAccount) { this.defaultImAdminAccount = defaultImAdminAccount; }}
import com.fasterxml.jackson.annotation.JsonProperty;/** * Created by saleson on 2017/10/23. */public class IMActionResponse { @JsonProperty("ActionStatus") private String ActionStatus; @JsonProperty("ErrorInfo") private String ErrorInfo; @JsonProperty("ErrorCode") private int ErrorCode; public boolean isSuccess() { return "OK".equals(ActionStatus); } public String getActionStatus() { return ActionStatus; } public void setActionStatus(String actionStatus) { ActionStatus = actionStatus; } public String getErrorInfo() { return ErrorInfo; } public void setErrorInfo(String errorInfo) { ErrorInfo = errorInfo; } public int getErrorCode() { return ErrorCode; } public void setErrorCode(int errorCode) { ErrorCode = errorCode; }}
import com.fasterxml.jackson.annotation.JsonProperty;import java.util.List;/** * Created by saleson on 2017/10/23. */public class IMMultiAccImportResponse extends IMActionResponse { @JsonProperty("FailAccounts") private List<String> FailAccounts; public List<String> getFailAccounts() { return FailAccounts; } public void setFailAccounts(List<String> failAccounts) { FailAccounts = failAccounts; }}
import com.fasterxml.jackson.core.JsonProcessingException;import com.fasterxml.jackson.core.type.TypeReference;import com.fasterxml.jackson.databind.ObjectMapper;import com.google.common.base.Joiner;import com.google.common.collect.ImmutableList;import com.google.common.collect.ImmutableMap;import com.google.common.collect.Maps;import com.tls.sigcheck.tls_sigcheck;import org.apache.commons.lang3.ObjectUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.web.client.RestTemplate;import java.io.IOException;import java.util.Arrays;import java.util.List;import java.util.Map;/** * Created by saleson on 2017/10/23. */public class TencentIMHelper { private static final Logger log = LoggerFactory.getLogger(TencentIMHelper.class); private TencentIMConfig config; private RestTemplate rest; private ObjectMapper objectMapper; private Joiner.MapJoiner joiner = Joiner.on("&").withKeyValueSeparator("="); public TencentIMHelper(TencentIMConfig config, RestTemplate rest, ObjectMapper objectMapper) { this.config = config; this.rest = rest; this.objectMapper = objectMapper; } /** * 生成usersig * * @param identifier * @return */ public String genUsersig(String identifier) { tls_sigcheck demo = new tls_sigcheck(); // 使用前请修改动态库的加载路径 demo.loadJniLib(config.getJnisigcheckLibPath()); int ret = demo.tls_gen_signature_ex2(config.getSdkAppid(), identifier, config.getPrivateKey()); if (0 != ret) { log.error("ret: {}, errMsg:{}", ret, demo.getErrMsg()); throw new ClientException(ResultCode.IM_ACCOUNT_LOGIN_FAILD); } else { String usersig = demo.getSig(); System.out.println("sig:\n" + demo.getSig()); log.debug("identifier '{}' take usersig is {}", identifier, usersig); return usersig; } } /** * 获取默认设置的im admin 账号的usersig * * @return */ public String getIMAdminUsersig() { if (StringUtils.isEmpty(config.getDefaultImAdminAccount())) { log.error("TencentIMConfig.defaultImAdminAccount不存在"); throw new ServerException(ResultCode.IM_ACCOUNT_LOGIN_FAILD.getResultCode(), "默认的IM admin账号不存在"); } return getIMAdminUsersig(config.getDefaultImAdminAccount()); } /** * 获取im admin 账号的usersig * * @param identifier * @return */ public String getIMAdminUsersig(String identifier) { String usersig = _getIMAdminUsersig(identifier); if (StringUtils.isEmpty(usersig)) { usersig = genUsersig(identifier); cacheIMAdminUsersig(identifier, usersig); } return usersig; } /** * 导入账号 * * @param accountId */ public void accountImport(String accountId) { String url = "https://console.tim.qq.com/v4/im_open_login_svc/account_import?"; String queryString = joiner.join(getDefaultParams()); Map<String, String> requestBody = ImmutableMap.of("Identifier", accountId); IMActionResponse res = request(url + queryString, requestBody, IMActionResponse.class); if (!res.isSuccess()) { log.error("导入'{}'到腾讯云IM失败, response message is: {}", toString(res)); throw new ClientException(ResultCode.IM_ACCOUNT_CREATE_FAILD); } } /** * 帐号批量导入 * * @param accountIds 用户名,单个用户名长度不超过 32 字节,单次最多导入100个用户名 * @return 返回导入失败的帐号列表 */ public List<String> multiAccountImport(String... accountIds) { String url = "https://console.tim.qq.com/v4/im_open_login_svc/multiaccount_import?"; String queryString = joiner.join(getDefaultParams()); Map<String, List<String>> requestBody = ImmutableMap.of("Accounts", Arrays.asList(accountIds)); IMMultiAccImportResponse res = request(url + queryString, requestBody, IMMultiAccImportResponse.class); if (!res.isSuccess()) { log.error("帐号批量导入失败:{}, response message is: {}", StringUtils.join(accountIds, ", "), toString(res)); throw new ClientException(ResultCode.IM_ACTION_FAILD); } return res.getFailAccounts(); } /** * 设置用户资料(IM) * * @param userDTO */ public void setAccountProfile(UserDTO userDTO) { String url = "https://console.tim.qq.com/v4/profile/portrait_set?"; String queryString = joiner.join(getDefaultParams()); String nikename = userDTO.getNickName() int gder = ObjectUtils.defaultIfNull(userDTO.getGender(), 0); String gender = gder == 1 ? "Gender_Type_Male" : gder == 2 ? "Gender_Type_Female" : "Gender_Type_Unknown"; Map<String, Object> requestBody = ImmutableMap.of("From_Account", userDTO.getLogin(), "ProfileItem", ImmutableList.of( ofProPortItem("Tag_Profile_IM_Nick", nikename), ofProPortItem("Tag_Profile_IM_Gender", gender), ofProPortItem("Tag_Profile_IM_Image", ResourceUtils.getFullResourceUrl(userDTO.getAvatar()))// ofProPortItem("", ""),// ofProPortItem("", ""),// ofProPortItem("", ""),// ofProPortItem("", "") )); IMActionResult res = request(url + queryString, requestBody); if (!res.isSuccess()) { log.error("调用'{}'的账号信息到腾讯云IM失败, response message is: {}", userDTO.getLogin(), toString(res.getResult())); throw new ClientException(ResultCode.IM_ACCOUNT_INFO_SET_FAILD); } } /** * @param tag * @param value * @return */ private Map<String, Object> ofProPortItem(String tag, Object value) { return ImmutableMap.of("tag", tag, "value", value); } /** * 默认值 * * @param obj * @param def * @return */ private Object defNull(Object obj, Object def) { return obj == null ? def : obj; } /** * 返回默认的参数 * * @return */ private Map<String, String> getDefaultParams() { Map<String, String> pathParams = Maps.newHashMap(); pathParams.put("usersig", getIMAdminUsersig()); pathParams.put("identifier", config.getDefaultImAdminAccount()); pathParams.put("sdkappid", config.getSdkAppid()); pathParams.put("random", StringUtils.uuid()); pathParams.put("contenttype", "json"); return pathParams; } private void initPrivateKey() { if (StringUtils.isNotEmpty(config.getPrivateKey())) { return; } if (StringUtils.isEmpty(config.getPrivateKeyPath())) { throw new ServerException(ResultCode.OPERATION_FAILD.getResultCode(), "腾讯云通讯无法找到privateKey"); } //todo } private <T> T request(String url, Object params, Class<T> cls) { return toBean(requestInvoke(url, params), cls); } private IMActionResult request(String url, Object params) { Map<String, Object> map = toBean(requestInvoke(url, params), new TypeReference<Map<String, Object>>() { }); return new IMActionResult(map); } private String requestInvoke(String url, Object params) { String json = rest.postForObject(url, params, String.class); try { log.info("request url {}, the params is: {}, and response: {}", url, objectMapper.writeValueAsString(params), json); } catch (IOException e) { } return json; } private <T> T toBean(String json, Class<T> cls) { try { return objectMapper.readValue(json, cls); } catch (IOException e) { log.error("json:{} 转换类型失败: {} ", json, cls); log.error(e.getMessage(), e); throw new ServerException(ResultCode.OPERATION_FAILD.getResultCode(), "转换json失败"); } } private <T> T toBean(String json, TypeReference<T> type) { try { return objectMapper.readValue(json, type); } catch (IOException e) { log.error("json:{} 转换类型失败: {} ", json, type.getType()); log.error(e.getMessage(), e); throw new ServerException(ResultCode.OPERATION_FAILD.getResultCode(), "转换json失败"); } } private String _getIMAdminUsersig(String identifier) { //todo return null; } private void cacheIMAdminUsersig(String identifier, String usersig) { //todo } private String toString(Object obj) { if (obj == null) { return null; } else if ("".equals(obj)) { return ""; } try { return objectMapper.writeValueAsString(obj); } catch (JsonProcessingException e) { return obj.toString(); } }}
Test
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;import com.fasterxml.jackson.databind.ObjectMapper;import com.tls.sigcheck.tls_sigcheck;import org.junit.Test;import org.springframework.http.MediaType;import org.springframework.http.client.ClientHttpRequestFactory;import org.springframework.http.client.ClientHttpResponse;import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;import org.springframework.web.client.RestTemplate;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.util.List;/** * Created by saleson on 2017/10/23. */public class TencentIMTest { @Test public void testHelper() throws IOException { TencentIMConfig config = new TencentIMConfig(); config.setDefaultImAdminAccount("testadmin"); config.setSdkAppid("1400046172"); //config.setJnisigcheckLibPath("tencent_im/tls_sig_api-src/src/jnisigcheck.so"); config.setJnisigcheckLibPath("tencent_im/jnisigcheck_mt_x64.so"); InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("thirdparty/tencent/im/private_key"); BufferedReader br = new BufferedReader(new InputStreamReader(is)); StringBuilder strBuilder = new StringBuilder(); String s = ""; while ((s = br.readLine()) != null) { strBuilder.append(s + '\n'); } br.close(); String priKey = strBuilder.toString(); config.setPrivateKey(priKey);// config.setPrivateKeyPath("");// RestTemplate rest = new RestTemplate();// rest.setMessageConverters(Arrays.asList(new MappingJackson2HttpMessageConverter())); RestTemplate rest = jsonRestTemplate(); TencentIMHelper helper = new TencentIMHelper(config, rest, new ObjectMapper()); String adminUsersig = helper.getIMAdminUsersig(); System.out.println("adminUsersig:\n" + adminUsersig); helper.accountImport("test10"); List<String> list = helper.multiAccountImport("test2jalsdkfjaoisdufo32jkleoflkjasdkfjasdiufowerquwlkj0", "test21", "test22", "test23"); System.out.println(list); } public RestTemplate jsonRestTemplate() { RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory()); restTemplate.getMessageConverters().add(0, new FastJsonHttpMessageConverter()); restTemplate.getInterceptors().add((request, body, execution) -> { System.out.println(new String(body)); ClientHttpResponse response = execution.execute(request, body); response.getHeaders().setContentType(MediaType.APPLICATION_JSON); return response; }); return restTemplate; } private ClientHttpRequestFactory clientHttpRequestFactory() { HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); factory.setReadTimeout(30000); factory.setConnectTimeout(30000); return factory; }}
上面的代码在linux环境上是可能正常运行了。
但是要在mac上运行调试, 会报错:
java.lang.UnsatisfiedLinkError: /Users/saleson/Downloads/tencent_im/jnisigcheck_mt_x64.so: dlopen(/Users/saleson/Downloads/tencent_im/jnisigcheck_mt_x64.so, 1): no suitable image found. Did find: /Users/saleson/Downloads/tencent_im/jnisigcheck_mt_x64.so: unknown file type, first eight bytes: 0x7F 0x45 0x4C 0x46 0x02 0x01 0x01 0x00 /Users/saleson/Downloads/tencent_im/jnisigcheck_mt_x64.so: unknown file type, first eight bytes: 0x7F 0x45 0x4C 0x46 0x02 0x01 0x01 0x00 at java.lang.ClassLoader$NativeLibrary.load(Native Method) at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1941) at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1824) at java.lang.Runtime.load0(Runtime.java:809) at java.lang.System.load(System.java:1086) at com.tls.sigcheck.tls_sigcheck.loadJniLib(tls_sigcheck.java:9) at com.thirdparty.tencent.im.TencentIMHelper.genUsersig(TencentIMHelper.java:48) at com.thirdparty.tencent.im.TencentIMHelper.getIMAdminUsersig(TencentIMHelper.java:85) at com.thirdparty.tencent.im.TencentIMHelper.getIMAdminUsersig(TencentIMHelper.java:72) at com.thirdparty.TencentIMTest.testHelper(TencentIMTest.java:123)
因此在mac上,需要重新编译生成jnisigcheck.so文件。
编译jnisigcheck.so
下载并解压tls_sig_api-src.tar.gz
进入src目录,查看Makefile
$ tar -zxvf tls_sig_api_src.tar.gz$ cd tls_sig_api-src/src$ vim Makefile
Makefile
CPP = g++CC = gccARCH=$(shell getconf LONG_BIT)CFLAGS= -g -I../include -I../include/tls_sig_api -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux -Wall -fPICLIBS= ../linux/$(ARCH)/lib/jsoncpp/libjsoncpp.a ../openssl-dynamic/lib/libcrypto.a -ldl -lzTARGETS = libtlsignature.a sigcheck.so signatureall: $(TARGETS)libtlsignature.a: tls_signature.o multi_thread.o base64.o base64_url.o ar -rs $@ $^# jni 库编译前请安装 jdk,并且配置 JAVA_HOME 环境变量jni: com_tls_sigcheck_tls_sigcheck.o libtlsignature.a g++ -shared -o jnisigcheck.so $^ ../linux/$(ARCH)/lib/jsoncpp/libjsoncpp.a ../openssl-dynamic/lib/libcrypto.a -lzsignature: signature.o libtlsignature.a g++ -o $@ $^ ../linux/$(ARCH)/lib/jsoncpp/libjsoncpp.a ../openssl-dynamic/lib/libcrypto.a -ldl -lzsigcheck.so: sigcheck.o libtlsignature.a sigcheck.h g++ -shared -fPIC -o $@ $^ ../linux/$(ARCH)/lib/jsoncpp/libjsoncpp.a ../openssl-dynamic/lib/libcrypto.a -ldl -lz.cpp.o: $(CPP) $(CFLAGS) -c $*.cpp.c.o: $(CC) $(CFLAGS) -c $*.cclean: -rm -f *.o *.so *.a tls_licence_tools TAGS $(TARGETS)
可以看到使用make jni生成jnisigcheck.so。执行命令之后,并没有像我们想象那样生成了jnisigcheck.so,需要解决部分依赖库问题:jni_md.h,代码中的../linux/$(ARCH)/lib/jsoncpp/libjsoncpp.a ($(ARCH)=64)和../openssl-dynamic/lib/libcrypto.a文件缺失问题。
解决问题
解决jni_md.h的问题(复制jni_md.h)
$ cd $JAVA_HOME/include$ sudo cp darwin/jni_md.h .
编译jsoncpp
$ brew install scons$ cd tls_sig_api-src/jsoncpp-src-0.5.0$ python /usr/local/bin/scons platform=linux-gcc
执行的结果是在libs目录下生成了
linux-gcc-4.2.1/libjson_linux-gcc-4.2.1_libmt.a
linux-gcc-4.2.1/libjson_linux-gcc-4.2.1_libmt.dylib
编译openssl
// 进入tls_sig_api-src目录$ tar -zxvf openssl-1.0.2a.tar.gz$ mv openssl-1.0.2a openssl_x86_64$ cd openssl_x86_64$ ./Configure darwin64-x86_64-cc -shared$ make
这就在当前目录生成了libcrypto.a
创建软链
进入tls_sig_api-src/src
$ mkdir -p ../linux/64/lib/jsoncpp$ ln -s `cd ..;pwd`/jsoncpp-src-0.5.0/libs/linux-gcc-4.2.1/libjson_linux-gcc-4.2.1_libmt.a ../linux/64/lib/jsoncpp/libjsoncpp.a$ mkdir -p ../openssl-dynamic/lib/$ ln -s `cd ..;pwd`/openssl_x86_64/libcrypto.a ../openssl-dynamic/lib/libcrypto.a
创建link的时候,source需要填写绝对路径,所以才有上述cd ..;pwd。
编译jnisigcheck.so
//在src目录下,执行一下命令,则生成`jnisigcheck.so`$ make clean$ make jni
这时在src目录下就有jnisigcheck.so文件了,
将jnisigcheckLibPath改为”tls_sig_api-src/src/jnisigcheck.so”,
就可以在mac上运行了。
转载:http://www.cnblogs.com/javaDeveloper/p/6098145.html
- 腾讯云>>云通信>>TLS后台API在mac上JAVA DEMO搭建
- 在腾讯云上搭建服务器
- 云通信-腾讯云,TLS独立模式公私钥生成
- 腾讯 云通信 如何启动Demo
- 如何用Baas快速在腾讯云上开发小程序-系列1:搭建API & WEB WebSocket 服务器
- 如何在腾讯云上搭建一个人力资源Saas
- 在腾讯云上搭建基于Nodejs的网站
- 如何在腾讯云上快速搭建Web服务器
- 在腾讯云上搭建个人静态博客
- 腾讯云、阿里云上搭建JAVA、MariaDB、Tomcat环境
- 利用云主机在mac上搭建网站
- 在腾讯云上部署tomcat+java+mysql项目
- 在腾讯云的Linux系统上跑Java服务器
- 腾讯云服务器上搭建wordpress博客
- 如何用Baas快速在腾讯云上开发小程序-系列3 :实现腾讯云COS API调用
- MQTT 在 mac 上搭建
- 在MAC上搭建SVN
- 在MAC上搭建CrossAPP
- 微信小程序具有在线支付功能
- 进程之间的通讯之管道
- 关于面试中常遇到的与框架(SSM、SSH)有关的问题
- 学习篇:asp.net mvc 管道模型
- 解决CSS3动画首次渲染或结束时会闪烁的问题
- 腾讯云>>云通信>>TLS后台API在mac上JAVA DEMO搭建
- 程序和软件有和不同?
- tomcat6,tomcat7或者更高版本的tomcat点击startup.bat时候出现闪退或者运行后闪退的解决办法
- c++继承
- Python(十二)元类
- 【无用】摘抄
- mysql 批量插入,存在则不插入该条数据
- 日常写BUG——MYSQL用户创建及权限管理GRANT使用
- navicat连接Oracle步骤(cannot load oci dll,193、 87)