环信即时通信
即时通信,简称IM(InstantMessaging),是指能够即时发送和接收互联网消息等的业务。
市场上有大量的即时通信产品,如:QQ,微信等
环信即时通讯云为开发者提供基于移动互联网的即时通讯能力,如单聊、群聊、发语音、发图片、发位置、实时音频、实时视频等,让开发者摆脱繁重的移动IM通讯底层开发,24小时即可让App拥有稳定健壮的内置IM能力
官网:https://www.easemob.com/
一、工作流程
APP端
- 在APP端与服务端,都需要完成与环信的集成。
- 在APP端,通过服务端查询用户在环信的账号密码。
- APP端,登录环信,进行好友聊天
服务端
- 将用户信息同步注册到环信
- 将用户好友信息同步到环信
二、基础api
初始化
| EMProperties emProperties = EMProperties.builder() |
| .setAppkey("yourAppkey") |
| .setClientId("yourClientId") |
| .setClientSecret("yourClientSecret") |
| .build(); |
| EMService service = new EMService(emProperties); |
api
| |
| service.user().create("user01", "123456").block(); |
| |
| |
| service.contact().add("user01","user02").block(); |
| |
| service.contact().remove("user01","user02").block(); |
| |
| Set<String> set = CollUtil.newHashSet("123"); |
| service.message().send("user01","users", |
| set, |
| new EMTextMessage().text("java"),null).block(); |
| |
三、项目抽取组件
1.先在tanhua-app-server的application.yml配置环信信息
| tanhua: |
| huanxin: |
| appkey: yourAppkey |
| clientId: yourClientId |
| clientSecret: yourClientSecret |
2.在tanhua-autoconfig创建与配置信息对应的配置类
| package com.tanhua.autoconfig.properties; |
| |
| import lombok.Data; |
| import org.springframework.boot.context.properties.ConfigurationProperties; |
| import org.springframework.context.annotation.Configuration; |
| |
| |
| |
| |
| @Data |
| @Configuration |
| @ConfigurationProperties(prefix = "tanhua.huanxin") |
| public class HuanXinProperties { |
| |
| private String appkey; |
| private String clientId; |
| private String clientSecret; |
| } |
| |
3. 编写HuanXinTemplate
| |
| package com.tanhua.autoconfig.template; |
| |
| import cn.hutool.core.collection.CollUtil; |
| import com.easemob.im.server.EMProperties; |
| import com.easemob.im.server.EMService; |
| import com.easemob.im.server.model.EMTextMessage; |
| import com.tanhua.autoconfig.properties.HuanXinProperties; |
| import lombok.extern.slf4j.Slf4j; |
| |
| import java.util.Set; |
| |
| |
| |
| |
| @Slf4j |
| public class HuanXinTemplate { |
| |
| private EMService emService; |
| |
| |
| |
| public HuanXinTemplate(HuanXinProperties huanXinProperties) { |
| EMProperties emPro = EMProperties.builder() |
| .setAppkey(huanXinProperties.getAppkey()) |
| .setClientId(huanXinProperties.getClientId()) |
| .setClientSecret(huanXinProperties.getClientSecret()) |
| .build(); |
| |
| emService = new EMService(emPro); |
| |
| } |
| |
| |
| |
| public Boolean createUser(String username,String password) { |
| try { |
| |
| emService.user().create(username.toLowerCase(), password) |
| .block(); |
| return true; |
| }catch (Exception e) { |
| e.printStackTrace(); |
| log.error("创建环信用户失败~"); |
| } |
| return false; |
| } |
| |
| |
| |
| |
| public Boolean addContact(String username1,String username2) { |
| try { |
| |
| emService.contact().add(username1,username2) |
| .block(); |
| return true; |
| }catch (Exception e) { |
| log.error("添加联系人失败~"); |
| } |
| return false; |
| } |
| |
| |
| |
| |
| public Boolean deleteContact(String username1,String username2) { |
| try { |
| |
| emService.contact().remove(username1,username2) |
| .block(); |
| return true; |
| }catch (Exception e) { |
| log.error("删除联系人失败~"); |
| } |
| return false; |
| } |
| |
| |
| |
| public Boolean sendMsg(String username,String content) { |
| try { |
| |
| Set<String> set = CollUtil.newHashSet(username); |
| |
| EMTextMessage message = new EMTextMessage().text(content); |
| |
| emService.message().send("admin","users", |
| set,message,null).block(); |
| return true; |
| }catch (Exception e) { |
| log.error("删除联系人失败~"); |
| } |
| return false; |
| } |
| |
| |
| } |
| |
4.在启动类中把HuanXinTemplate对象注入到spring容器中管理
| package com.tanhua.autoconfig; |
| |
| import com.tanhua.autoconfig.properties.AipFaceProperties; |
| import com.tanhua.autoconfig.properties.HuanXinProperties; |
| import com.tanhua.autoconfig.properties.OssProperties; |
| import com.tanhua.autoconfig.properties.SmsProperties; |
| import com.tanhua.autoconfig.template.AipFaceTemplate; |
| import com.tanhua.autoconfig.template.HuanXinTemplate; |
| import com.tanhua.autoconfig.template.OssTemplate; |
| import com.tanhua.autoconfig.template.SmsTemplate; |
| import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| import org.springframework.context.annotation.Bean; |
| |
| |
| |
| |
| |
| @EnableConfigurationProperties({ |
| HuanXinProperties.class |
| }) |
| public class TanhuaAutoConfiguration { |
| |
| |
| |
| |
| |
| |
| @Bean |
| public HuanXinTemplate emTemplate(HuanXinProperties huanXinProperties){ |
| return new HuanXinTemplate(huanXinProperties); |
| } |
| } |
| |
5.测试
| package com.itheima.test; |
| |
| import com.tanhua.autoconfig.template.HuanXinTemplate; |
| import com.tanhua.server.AppServerApplication; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.springframework.beans.factory.annotation.Autowired; |
| import org.springframework.boot.test.context.SpringBootTest; |
| import org.springframework.test.context.junit4.SpringRunner; |
| |
| |
| |
| |
| @RunWith(SpringRunner.class) |
| @SpringBootTest(classes = AppServerApplication.class) |
| public class ImApiTest { |
| |
| |
| @Autowired |
| private HuanXinTemplate huanXinTemplate; |
| |
| @Test |
| public void testFindByMobile() { |
| |
| huanXinTemplate.createUser("user", "123"); |
| } |
| } |
| |
四、用户体系集成
将用户体系集成的逻辑写入到tanhua-server
系统中。
- 探花用户注册时需要将用户信息注册到环信系统中
- 对于老数据:编写单元测试方法批量的注册到环信
- 对于新用户:改造代码(用户注册的时候,自动注册到环信)
- APP从服务端获取当前用户的环信用户密码,自动登入环信系统
- APP自动获取环信服务器发送的信息数据
1.注册环信用户
在用户登录逻辑中,当第一次注册时,将用户信息注册到环信
登录的LoginControllerController
| |
| |
| |
| |
| |
| |
| @PostMapping("/loginVerification") |
| public ResponseEntity loginVerification(@RequestBody Map map){ |
| |
| String phone = (String) map.get("phone"); |
| String code = (String) map.get("verificationCode"); |
| |
| |
| |
| Map result = userService.loginVerification(phone, code); |
| |
| return ResponseEntity.ok(result); |
| } |
LoginService
| |
| |
| |
| |
| |
| |
| public Map loginVerification(String phone, String code) { |
| |
| String redisCode = redisTemplate.opsForValue().get("CHECK_CODE_" + phone); |
| |
| |
| if(StringUtils.isEmpty(code) || ! redisCode.equals(code)){ |
| |
| throw new BusinessException(ErrorResult.loginError()); |
| } |
| |
| redisTemplate.delete("CHECK_CODE_" + phone); |
| |
| |
| User user = userApi.selectByPhoneNumber(phone); |
| |
| boolean isNew = false; |
| |
| |
| if(user == null){ |
| user =new User(); |
| user.setMobile(phone); |
| |
| |
| user.setPassword(DigestUtils.md5Hex("123456")); |
| Long userId = userApi.addNewUser(user); |
| user.setId(userId); |
| isNew =true; |
| |
| |
| |
| |
| |
| String hx = "hx" +user.getId(); |
| |
| String passWord = Constants.INIT_PASSWORD; |
| |
| |
| Boolean result = huanXinTemplate.createUser(hx, passWord); |
| |
| if(result){ |
| user.setHxUser(hx); |
| user.setHxPassword(passWord); |
| userApi.update(user); |
| } |
| |
| |
| } |
| |
| Map userToken = new HashMap(); |
| userToken.put("id", user.getId()); |
| userToken.put("phone",phone); |
| |
| String token = JwtUtils.getToken(userToken); |
| |
| |
| Map resultMap = new HashMap(); |
| |
| resultMap.put("token", token); |
| resultMap.put("isNew", isNew); |
| |
| return resultMap; |
| } |
UserApiImpl
用户注册到环信之后要更新user表中相应的字段
| |
| |
| public void update(User user) { |
| userMapper.updateById(user); |
| } |
2.查询环信用户信息
用户在注册探花交友项目的账号时,同时我们的服务端为用户注册了环信账号
现在我们要查询用户环信账号的信息,返回到客户端;客户端会自动登录环信
1.HuanXinController
| |
| |
| |
| |
| |
| |
| |
| @GetMapping("/user") |
| public ResponseEntity queryHuanXinInfo(){ |
| |
| HuanXinUserVo huanXinUserVo = huanXinService.queryHuanXinInfo(); |
| return ResponseEntity.ok(huanXinUserVo); |
| } |
2.HuanXinService
| package com.tanhua.server.service; |
| |
| import com.tanhua.dubbo.api.UserApi; |
| import com.tanhua.model.vo.HuanXinUserVo; |
| import com.tanhua.server.interceptor.ThreadLocalUtils; |
| import org.apache.dubbo.config.annotation.DubboReference; |
| import org.springframework.stereotype.Service; |
| |
| @Service |
| public class HuanXinService { |
| |
| |
| @DubboReference |
| private UserApi userApi; |
| |
| |
| public HuanXinUserVo queryHuanXinInfo() { |
| |
| HuanXinUserVo huanXinUserVo = new HuanXinUserVo(); |
| huanXinUserVo.setUsername("hx"+ThreadLocalUtils.getUserId()); |
| huanXinUserVo.setPassword("123456"); |
| |
| |
| return huanXinUserVo; |
| |
| } |
| } |
| |
vo对象
| |
| import lombok.AllArgsConstructor; |
| import lombok.Data; |
| import lombok.NoArgsConstructor; |
| |
| @Data |
| @NoArgsConstructor |
| @AllArgsConstructor |
| public class HuanXinUserVo { |
| private String username; |
| private String password; |
| } |
3. 环信用户ID查询用户信息
在好友聊天时,完全基于环信服务器实现。为了更好的页面效果,需要展示出用户的基本信息,这是需要通过环信用户id查询用户。
MessagesController
| package com.tanhua.server.controller; |
| |
| import com.tanhua.model.vo.UserInfoVo; |
| import com.tanhua.server.service.MessagesService; |
| import org.springframework.beans.factory.annotation.Autowired; |
| import org.springframework.http.ResponseEntity; |
| import org.springframework.web.bind.annotation.GetMapping; |
| import org.springframework.web.bind.annotation.RequestMapping; |
| import org.springframework.web.bind.annotation.RestController; |
| |
| @RestController |
| @RequestMapping("/messages") |
| public class MessagesController { |
| |
| @Autowired |
| private MessagesService messagesService; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| @GetMapping("/userinfo") |
| public ResponseEntity queryInfoByHuanXin(String huanxinId){ |
| |
| UserInfoVo userInfoVo = messagesService.queryInfoByHuanXin(huanxinId); |
| |
| return ResponseEntity.ok(userInfoVo); |
| } |
| } |
| |
MessagesController
| package com.tanhua.server.service; |
| |
| import com.tanhua.dubbo.api.UserApi; |
| import com.tanhua.dubbo.api.UserInfoApi; |
| import com.tanhua.model.domain.User; |
| import com.tanhua.model.domain.UserInfo; |
| import com.tanhua.model.vo.UserInfoVo; |
| import org.apache.dubbo.config.annotation.DubboReference; |
| import org.springframework.beans.BeanUtils; |
| import org.springframework.stereotype.Service; |
| |
| @Service |
| public class MessagesService { |
| |
| @DubboReference |
| private UserApi userApi; |
| |
| @DubboReference |
| private UserInfoApi userInfoApi; |
| |
| |
| public UserInfoVo queryInfoByHuanXin(String huanxinId) { |
| |
| |
| User user =userApi.queryUserByHuanXin(huanxinId); |
| |
| UserInfo userInfo = userInfoApi.selectUserInfo(user.getId()); |
| |
| |
| UserInfoVo userInfoVo = new UserInfoVo(); |
| BeanUtils.copyProperties(userInfo, userInfoVo); |
| if(userInfo.getAge() != null) { |
| userInfoVo.setAge(userInfo.getAge().toString()); |
| } |
| |
| return userInfoVo; |
| } |
| } |
| |
UserApiImpl
| |
| public User queryUserByHuanXin(String huanxinId) { |
| QueryWrapper<User> qw = new QueryWrapper<>(); |
| qw.eq("hx_user",huanxinId); |
| User user = userMapper.selectOne(qw); |
| return user; |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理