SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)

陌上花开,可缓缓归矣



系列文章目录

1. 项目介绍及环境配置
2. 短信验证码登录
3. 用户信息
4. MongoDB
5. 推荐好友列表/MongoDB集群/动态发布与查看
6. 圈子动态/圈子互动
7. 即时通讯(基于第三方API)
8. 附近的人(百度地图APi)
9. 小视频
10.网关配置
11.后台管理


文章目录

  • 系列文章目录
  • 一、环信
    • 1. 即使通信
      • ⑴. 功能需求
      • ⑵. 技术方案
    • 2. 环信
      • ⑴. 概述
      • ⑵. 概述API文档
      • ⑶. 工作流程
      • ⑷. 创建探花应用
        • ①. 注册账号
        • ②. 创建应用
    • 3. 基础API
      • ⑴. 测试类
      • ⑵. 后台数据
    • 4. 抽取工具
      • ⑴. 添加相关配置信息
      • ⑵. 编写properties对象,添加配置属性
      • ⑶. 编写template对象,配置组件方法
      • ⑷. 定义自动装配类型
      • ⑸. 编写测试类
  • 二、用户体系集成
    • 1. 环信用户注册
      • ⑴. 需求分析
      • ⑵. 编码实现
        • ①. 实体类 - 添加环信用户信息字段
        • ②. Service - 工具类完成用户信息注册
        • ③. API接口
        • ④. API接口实现类 - 调用工具类注册到环信
      • ⑶. 雷电模拟器测试
        • ①. 安装雷电模拟器
        • ②. 安装新探花交友APP
        • ③. 注册新用户
        • ④. 测试结果
    • 2. 查询环信用户信息
      • ⑴. 接口文档
      • ⑵. 编码实现
        • ①. Controller
        • ②. Service
        • ③. vo对象
        • ④. API接口
        • ⑤. API实现类
      • ⑶. 雷电模拟器测试
    • 3. 环信后台发送消息测试
      • ⑴. 后台
      • ⑵. APP(雷电模拟器)
    • 4. 根据id查询用户信息
      • ⑴. 编码实现
        • ①. Controller
        • ②. Service
        • ③. Api接口
        • ④. Api实现类
      • ⑵. Postman测试
    • 5. 同步用户账号到环信
      • ⑴. 整理数据库
      • ⑵. 编写测试类
      • ⑶. 同步结果
  • 三、联系人管理
    • 1. 发送好友申请
      • ⑴. 查看佳人详情
        • ①. 接口文档
        • ②. 编码实现
          • Ⅰ. Controller
          • Ⅱ. Service
          • Ⅲ. API
          • Ⅳ. ApiImpl
        • ③. 测试
      • ⑵. 查看陌生人问题
        • ①. 接口文档
        • ②. 编码实现
          • Ⅰ. Controller
          • Ⅱ. Service
        • ③. 页面效果
      • ⑶. 回复陌生人问题
        • ①. 接口文档
        • ②. 编码实现
          • Ⅰ. Controller
          • Ⅱ. Service
        • ③. 页面效果
    • 2. 添加好友
      • ⑴. 接口文档
      • ⑵. 编码实现
        • ①. Controller
        • ②. Service
        • ③. API
        • ④. API实现类
      • ⑶. 页面效果
    • 3. 联系人列表
      • ⑴. 接口文档
      • ⑵. 编码实现
        • ①. Controller
        • ②. vo对象
        • ③. Service
        • ④. API接口
        • ⑤. API实现类
        • ⑥. 添加昵称检索功能
      • ⑶. 页面效果


一、环信

1. 即使通信

实时通信(Instant Messaging,简称IM)是一个实时通信系统,允许两人或多人使用网络实时的传递文字消息、文件、语音与视频交流。

⑴. 功能需求

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第1张图片

  • 探花交友项目中也提供了类似微信的聊天功能,用户可以和好友或陌生人聊天
  • 如果是陌生人,通过【聊一下】功能进行打招呼,如果对方同意后,就成为了好友,可以进行聊天了
  • 陌生人之间如果相互喜欢,那么就会成为好友,也就可以聊天了
  • 在消息界面中也可以查看:点赞、评论、喜欢、公告等消息信息

⑵. 技术方案

对于高并发的即时通讯实现,还是很有挑战的,所需要考虑的点非常多,除了要实现功能,还要考虑并发、流量、负载、服务器、容灾等等。虽然有难度也并不是高不可攀。

  • 方案一:
    • 自主实现,从设计到架构,再到实现。
    • 技术方面可以采用:Netty + WebSocket + RocketMQ + MongoDB + Redis + ZooKeeper + MySQL

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第2张图片

  • 方案二:
    • 对接第三方服务完成。
    • 这种方式简单,只需要按照第三方的api进行对接就可以了。
    • 如:环信、网易、容联云通讯等。

2. 环信

⑴. 概述

官网: https://www.easemob.com/

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第3张图片

平台架构:
SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第4张图片

集成:
SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第5张图片

⑵. 概述API文档

  • 探花前端使用AndroidSDK进行集成 - 文档:http://docs-im.easemob.com/im/android/sdk/import
  • 后端集成用户体系 - 文档:http://docs-im.easemob.com/im/server/ready/user
  • 集成文档: https://docs-im-beta.easemob.com/document/android/quickstart.html

⑶. 工作流程

工作流程:

  • 客户端用户注册
    SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第6张图片

  • 注册用户好友关系(联系人)
    SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第7张图片

  • 客户端获取环信身份信息
    SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第8张图片

  • 手机端在线聊天
    SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第9张图片

APP端:

  • 在APP端与服务端,都需要完成与环信的集成。
  • 在APP端,通过服务端查询用户在环信的账号密码。
  • APP端,登录环信,进行好友聊天

服务端:

  • 将用户信息同步注册到环信
  • 将用户好友信息同步到环信

⑷. 创建探花应用

①. 注册账号

注册地址: https://datayi.cn/w/woVL50vR
SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第10张图片

②. 创建应用

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第11张图片

3. 基础API

⑴. 测试类

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第12张图片

新增 tanhua-app-server/src/test/java/com/tanhua/test/HuanXinTest.java 文件:

public class HuanXinTest {

    private EMService service;

    @Before
    public void init() {
        EMProperties properties = EMProperties.builder()
                .setAppkey("填写上图的 APPKEY")
                .setClientId("填写上图的 Client ID")
                .setClientSecret("填写上图的 ClientSecret")
                .build();

        service = new EMService(properties);
    }

    @Test
    public void test() {
        // 注册用户
        // service.user().create("user001", "123456").block();
        // service.user().create("user002", "123456").block();

        // 添加联系人
        // service.contact().add("user001", "user002").block();

        // 发送消息
        Set<String> set = CollUtil.newHashSet("user002");
        service.message().send("user001","users", set,
                new EMTextMessage().text("吃了吗?"),
                null).block();
    }
}

⑵. 后台数据

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第13张图片
SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第14张图片
SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第15张图片


4. 抽取工具

⑴. 添加相关配置信息

编辑 tanhua-app-server/src/main/resources/application.yml 文件:

...
tanhua:
...
  huanxin:
    appkey: 填写 APPKEY
    clientId: 填写 Client ID
    clientSecret: 填写 ClientSecret

⑵. 编写properties对象,添加配置属性

编辑 tanhua-autoconfig/src/main/java/com/tanhua/autoconfig/properties/HuanXinProperties.java 文件:

@Configuration
@ConfigurationProperties(prefix = "tanhua.huanxin")
@Data
public class HuanXinProperties {

    private String appkey;
    private String clientId;
    private String clientSecret;
    
}

⑶. 编写template对象,配置组件方法

编辑 tanhua-autoconfig/src/main/java/com/tanhua/autoconfig/template/HuanXinTemplate.java 文件:

@Slf4j
public class HuanXinTemplate {

    private EMService service;

    public HuanXinTemplate(HuanXinProperties properties) {
        EMProperties emProperties = EMProperties.builder()
                .setAppkey(properties.getAppkey())
                .setClientId(properties.getClientId())
                .setClientSecret(properties.getClientSecret())
                .build();
        service = new EMService(emProperties);
    }

    //创建环信用户
    public Boolean createUser(String username,String password) {
        try {
            //创建环信用户
            service.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 {
            //创建环信用户
            service.contact().add(username1,username2)
                    .block();
            return true;
        }catch (Exception e) {
            log.error("添加联系人失败~");
        }
        return false;
    }

    //删除联系人
    public Boolean deleteContact(String username1,String username2) {
        try {
            //创建环信用户
            service.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);
            //发送消息  from:admin是管理员发送
            service.message().send("admin","users",
                    set,message,null).block();
            return true;
        }catch (Exception e) {
            log.error("删除联系人失败~");
        }
        return false;
    }
}

⑷. 定义自动装配类型

编辑 tanhua-autoconfig/src/main/java/com/tanhua/autoconfig/TanhuaAutoConfiguration.java 文件:

@EnableConfigurationProperties({
        SmsProperties.class,
        OssProperties.class,
        AipFaceProperties.class,
        HuanXinProperties.class
})
public class TanhuaAutoConfiguration {

    @Bean
    public SmsTemplate smsTemplate(SmsProperties properties) {
        return new SmsTemplate(properties);
    }

    @Bean
    public OssTemplate ossTemplate(OssProperties properties) {return new OssTemplate(properties);}

    @Bean
    public AipFaceTemplate aipFaceTemplate() {return new AipFaceTemplate();}

    @Bean
    public HuanXinTemplate huanXinTemplate(HuanXinProperties properties) {return new HuanXinTemplate(properties);}
}

⑸. 编写测试类

编辑 tanhua-app-server/src/test/java/com/tanhua/test/HuanXinTest2.java 文件:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = AppServerApplication.class)
public class HuanXinTest2 {

    @Autowired
    private HuanXinTemplate template;

    @Test
    public void testCreateUser() {
        template.createUser("user003", "123456");
    }
}

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第16张图片


二、用户体系集成

1. 环信用户注册

⑴. 需求分析

  • 探花用户注册时需要将用户信息注册到环信系统中
    • 对于老数据:编写单元测试方法批量的注册到环信
    • 对于新用户:改造代码(用户注册的时候,自动注册到环信
  • APP从服务端获取当前用户的环信用户密码,自动登入环信系统
    • 编写一个接口,获取当前用户在环信的用户名密码
    • APP自动获取环信服务器发送的信息数据

⑵. 编码实现

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第17张图片

①. 实体类 - 添加环信用户信息字段

编辑 tanhua-model/src/main/java/com/tanhua/model/domain/User.java 文件:

@Data
@AllArgsConstructor  //满参构造方法
@NoArgsConstructor   //无参构造方法
public class User extends BasePojo {

    private Long id;
    private String mobile;
    private String password;

    // 环信用户信息
    private String hxUser;
    private String hxPassword;
}

②. Service - 工具类完成用户信息注册

编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/UserService.java 文件:

...

    /**
     * 验证登录
     * @param phone
     * @param code
     */
    public Map loginVerification(String phone, String code) {
        // 1. 从redis中获取验证码
        String redisCode = redisTemplate.opsForValue().get("CHECK_CODE_" + phone);

        // 2. 对验证码进行校验
        if(StringUtils.isEmpty(redisCode) || !redisCode.equals(code)) {
            // throw new RuntimeException("验证码错误");
            throw new BusinessException(ErrorResult.loginError());
        }

        // 3. 删除redis中的验证码
        redisTemplate.delete("CHECK_CODE_" + phone);

        // 4. 通过手机号查询用户
        User user = userApi.findByMobile(phone);
        boolean isNew = false;

        // 5. 如果用户不存在,创建用户保存到数据库
        if(user == null) {
            user = new User();
            user.setMobile(phone);
            // user.setCreated(new Date());
            // user.setUpdated(new Date());
            user.setPassword(DigestUtils.md5Hex("123456"));
            Long userId = userApi.save(user);
            user.setId(userId);
            isNew = true;

            // 注册环信用户
            String hxUser = "hx" + user.getId();
            Boolean create = huanXinTemplate.createUser(hxUser, Constants.INIT_PASSWORD);
            if(create) {
                user.setHxUser(hxUser);
                user.setHxPassword(Constants.INIT_PASSWORD);
                userApi.update(user);
            }
        }

        // 6. 通过JWT生成token(存入手机号和用户ID)
        Map tokenMap = new HashMap();
        tokenMap.put("id", user.getId());
        tokenMap.put("mobile", phone);
        String token = JwtUtils.getToken(tokenMap);

        // 7. 构造返回值
        Map retMap = new HashMap();
        retMap.put("token", token);
        retMap.put("isNew", isNew);

        return retMap;
    }
}

③. API接口

编辑 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/UserApi.java 文件:

public interface UserApi {
    // 根据手机号查询用户
    User findByMobile(String phone);

    // 保存用户, 返回用户ID
    Long save(User user);

    // 更新环信用户
    void update(User user);
}

④. API接口实现类 - 调用工具类注册到环信

编辑 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/api/UserApiImpl.java 文件:

@DubboService
public class UserApiImpl implements UserApi {

    @Autowired
    private UserMapper userMapper;

    // 根据手机号查询用户
    public User findByMobile(String mobile) {
        QueryWrapper<User> qw = new QueryWrapper<>();
        qw.eq("mobile", mobile);
        return userMapper.selectOne(qw);
    }

    // 保存用户,返回用户ID
    @Override
    public Long save(User user) {
        userMapper.insert(user);
        return user.getId();
    }

    // 更新环信用户
    @Override
    public void update(User user) {
        userMapper.updateById(user);
    }
}

⑶. 雷电模拟器测试

①. 安装雷电模拟器

网盘资源地址(不需要密码): https://pan.baidu.com/s/1daL566ehyZuQ6s5vzXYNpA?pwd=java

在这里插入图片描述


②. 安装新探花交友APP

网盘资源地址(不需要密码): https://pan.baidu.com/s/1daL566ehyZuQ6s5vzXYNpA?pwd=java

APK文件:

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第18张图片


③. 注册新用户

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第19张图片
SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第20张图片


④. 测试结果

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第21张图片
SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第22张图片


2. 查询环信用户信息

在app中,用户登录后需要根据用户名密码登录环信,由于环信的用户名密码保存在后台,所以需要提供接口进行返回

⑴. 接口文档

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第23张图片

⑵. 编码实现

①. Controller

新增 tanhua-app-server/src/main/java/com/tanhua/server/controller/HuanXinController.java 文件:

@RestController
@RequestMapping("/huanxin")
public class HuanXinController {

    @Autowired
    private HuanXinService huanXinService;

    /**
     * 查询环信账号密码
     */
    @GetMapping("/user")
    public ResponseEntity user() {
        HuanXinUserVo vo = huanXinService.findHuanXinUser();
        return ResponseEntity.ok(vo);
    }
}

②. Service

新增 tanhua-app-server/src/main/java/com/tanhua/server/service/HuanXinService.java 文件:

@Service
public class HuanXinService {

    @DubboReference
    private UserApi userApi;

    /**
     * 查询当前用户的环信账号密码
      */
    public HuanXinUserVo findHuanXinUser() {
        // 1. 获取当前用户id, 根据规则拼接
        Long userId = UserHolder.getUserId();

        // 2. 根据当前用户id,查询用户
        User user = userApi.findById(userId);
        if(user == null) {
            return null;
        }
        return new HuanXinUserVo(user.getHxUser(), user.getHxPassword());
    }
}

③. vo对象

新增 tanhua-model/src/main/java/com/tanhua/model/vo/HuanXinUserVo.java 文件:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class HuanXinUserVo {
    private String username;
    private String password;
}

④. API接口

编辑 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/UserApi.java 文件:

public interface UserApi {
    // 根据手机号查询用户
    User findByMobile(String phone);

    // 保存用户, 返回用户ID
    Long save(User user);

    // 更新环信用户
    void update(User user);

    // 根据id,查询用户
    User findById(Long userId);
}

⑤. API实现类

编辑 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/api/UserApiImpl.java 文件:

@DubboService
public class UserApiImpl implements UserApi {

    @Autowired
    private UserMapper userMapper;

    // 根据手机号查询用户
    public User findByMobile(String mobile) {
        QueryWrapper<User> qw = new QueryWrapper<>();
        qw.eq("mobile", mobile);
        return userMapper.selectOne(qw);
    }

    // 保存用户,返回用户ID
    @Override
    public Long save(User user) {
        userMapper.insert(user);
        return user.getId();
    }

    // 更新环信用户
    @Override
    public void update(User user) {
        userMapper.updateById(user);
    }

    // 根据id查询用户
    @Override
    public User findById(Long userId) {
        return userMapper.selectById(userId);
    }
}

⑶. 雷电模拟器测试

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第24张图片


3. 环信后台发送消息测试

⑴. 后台

# userId、huanXinId、nickname需要根据数据库做调整
{"userId":120,"huanXinId":"hx120","nickname":"小宇","strangerQuestion":"你喜欢去看蔚蓝的大海还是去爬巍峨的高山?","reply":"我喜欢秋天的落叶,夏天的泉水,冬天的雪地,只要有你一切皆可~"}

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第25张图片


⑵. APP(雷电模拟器)

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第26张图片


4. 根据id查询用户信息

⑴. 编码实现

①. Controller

新建 tanhua-app-server/src/main/java/com/tanhua/server/controller/MessagesController.java 文件:

@RestController
@RequestMapping("/messages")
public class MessagesController {

    @Autowired
    private MessagesService messagesService;

    /**
     * 根据环信用户id,查询环信用户详情
     */
    @GetMapping("/userinfo")
    public ResponseEntity userinfo(String huanxinId) {
        UserInfoVo vo = messagesService.findUserInfoByHuanXin(huanxinId);
        return ResponseEntity.ok(vo);
    }
}

②. Service

新建 tanhua-app-server/src/main/java/com/tanhua/server/service/MessagesService.java 文件:

@Service
public class MessagesService {

    @DubboReference
    private UserApi userApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    // 根据环信用户id,查询用户详情
    public UserInfoVo findUserInfoByHuanXin(String huanxinId) {
        // 1. 根据环信id查询用户
        User user = userApi.findByHuanXin(huanxinId);

        // 2. 根据用户id,查询用户详情
        UserInfo userInfo = userInfoApi.findById(user.getId());

        // 3. 构建vo返回值
        UserInfoVo vo = new UserInfoVo();
        BeanUtils.copyProperties(userInfo, vo); // 只会copy同名同类型的属性
        if(userInfo.getAge() != null) {
            vo.setAge(userInfo.getAge().toString());
        }
        return vo;
    }
}

③. Api接口

编辑 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/UserApi.java 文件:

public interface UserApi {
    // 根据手机号查询用户
    User findByMobile(String phone);

    // 保存用户, 返回用户ID
    Long save(User user);

    // 更新环信用户
    void update(User user);

    // 根据id,查询用户
    User findById(Long userId);

    // 根据环信id查询用户
    User findByHuanXin(String huanxinId);
}


④. Api实现类

编辑 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/api/UserApiImpl.java 文件:

@DubboService
public class UserApiImpl implements UserApi {

    @Autowired
    private UserMapper userMapper;

    // 根据手机号查询用户
    public User findByMobile(String mobile) {
        QueryWrapper<User> qw = new QueryWrapper<>();
        qw.eq("mobile", mobile);
        return userMapper.selectOne(qw);
    }

    // 保存用户,返回用户ID
    @Override
    public Long save(User user) {
        userMapper.insert(user);
        return user.getId();
    }

    // 更新环信用户
    @Override
    public void update(User user) {
        userMapper.updateById(user);
    }

    // 根据id查询用户
    @Override
    public User findById(Long userId) {
        return userMapper.selectById(userId);
    }

    // 根据环信id查询用户
    @Override
    public User findByHuanXin(String huanxinId) {
        QueryWrapper<User> qw = new QueryWrapper<>();
        qw.eq("hx_user", huanxinId);
        return userMapper.selectOne(qw);
    }
}

⑵. Postman测试

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第27张图片


5. 同步用户账号到环信

⑴. 整理数据库

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第28张图片

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第29张图片


⑵. 编写测试类

编辑 tanhua-app-server/src/test/java/com/tanhua/test/HuanXinTest2.java 文件:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = AppServerApplication.class)
public class HuanXinTest2 {

    @Autowired
    private HuanXinTemplate template;

    @DubboReference
    private UserApi userApi;

    @Test
    public void testCreateUser() {
        template.createUser("user003", "123456");
    }

    // 同步用户账号到环信
    @Test
    public void register() {
        for (int i = 1; i < 106; i++) {
            User user = userApi.findById(Long.valueOf(i));
            if(user != null) {
                Boolean create = template.createUser("hx" + user.getId(), Constants.INIT_PASSWORD);
                if (create){
                    user.setHxUser("hx" + user.getId());
                    user.setHxPassword(Constants.INIT_PASSWORD);
                    userApi.update(user);
                }
            }
        }
    }
}

⑶. 同步结果

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第30张图片
SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第31张图片



三、联系人管理

1. 发送好友申请

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第32张图片

⑴. 查看佳人详情

①. 接口文档

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第33张图片

②. 编码实现

Ⅰ. Controller

编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/TanhuaController.java 文件:

@RestController
@RequestMapping("/tanhua")
public class TanhuaController {

    @Autowired
    private TanhuaService tanhuaService;

    /**
     * 今日佳人
     */
    @GetMapping("/todayBest")
    public ResponseEntity todayBest() {
        TodayBest vo = tanhuaService.todayBest();
        return ResponseEntity.ok(vo);
    }

    /**
     * 查询分页推荐好友列表
     */
    @GetMapping("recommendation")
    public ResponseEntity recommendation(RecommendUserDto dto) {
        PageResult pr = tanhuaService.recommendation(dto);
        return ResponseEntity.ok(pr);
    }

    /**
     * 查看佳人详情
     */
    @GetMapping("/{id}/personalInfo")
    public ResponseEntity personalInfo(@PathVariable("id") Long userId) {
        TodayBest best = tanhuaService.personalInfo(userId);
        return ResponseEntity.ok(best);
    }
}

Ⅱ. Service

编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/TanhuaService.java 文件:

@Service
public class TanhuaService {

    @DubboReference
    private RecommendUserApi recommendUserApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    // 查询今日佳人数据
    public TodayBest todayBest() {
        // 1. 获取用户id
        Long userId = UserHolder.getUserId();

        // 2. 调用api查询
        RecommendUser recommendUser = recommendUserApi.queryWithMaxScore(userId);

        // 3. 设置默认值
        if(recommendUser == null) {
            recommendUser = new RecommendUser();
            recommendUser.setUserId(1l);
            recommendUser.setScore(99d);
        }

        // 4. 将recommendUser 转化成 todayBest对象
        UserInfo userInfo = userInfoApi.findById(recommendUser.getUserId());
        TodayBest vo = TodayBest.init(userInfo, recommendUser);

        // 5. 返回
        return vo;
    }

    // 查询分页推荐好友列表
    public PageResult recommendation(RecommendUserDto dto) {
        // 1. 获取用户id
        Long userId = UserHolder.getUserId();

        // 2. 调用RecommendUserApi查询数据列表(PageResult -- RecommendUser)
        PageResult pr = recommendUserApi.queryRecommendUserList(dto.getPage(), dto.getPagesize(), userId);

        // 3. 获取分页中的RecommendUser数据列表
        List<RecommendUser> items = (List<RecommendUser>) pr.getItems();

        // 4. 判断列表数据是否为空
        if (items == null) {
            return pr;
        }

//        // 5. 循环RecommendUser推荐列表,根据推荐的用户id查询用户详情
//        List list = new ArrayList<>();
//        for (RecommendUser item : items) {
//            Long recommendUserId = item.getUserId();
//            UserInfo userInfo = userInfoApi.findById(recommendUserId);
//            if(userInfo != null) {
//                // 条件判断
//                if(!StringUtils.isEmpty(dto.getGender()) && !dto.getGender().equals(userInfo.getGender())) {
//                    continue;
//                }
//                if (dto.getAge() != null && dto.getAge() < userInfo.getAge()) {
//                    continue;
//                }
//                TodayBest vo = TodayBest.init(userInfo, item);
//                list.add(vo);
//            }
//        }
//


        // 5. 提取所有推荐的用户id列表
        List<Long> ids = CollUtil.getFieldValues(items, "userId", Long.class);
        UserInfo userInfo = new UserInfo();
        userInfo.setAge(dto.getAge());
        userInfo.setGender(dto.getGender());

        // 6. 构建查询条件,批量查询所有的用户详情
        Map<Long, UserInfo> map = userInfoApi.findByIds(ids, userInfo);

        // 7. 循环推荐的数据列表,构建vo对象
        List<TodayBest> list = new ArrayList<>();
        for (RecommendUser item : items) {
            UserInfo info = map.get(item.getUserId());
            if(info != null) {
                TodayBest vo = TodayBest.init(info, item);
                list.add(vo);
            }
        }

        // 6. 构造返回值
        pr.setItems(list);
        return pr;
    }

    // 查看佳人详情
    public TodayBest personalInfo(Long userId) {
        // 1. 根据用户id,查询用户详情
        UserInfo userInfo = userInfoApi.findById(userId);
        // 2. 根据操作人id, 和查看的用户id,查询两者的推荐数据(缘分值)
        RecommendUser user = recommendUserApi.queryByUserId(userId, UserHolder.getUserId());
        // 3. 构造返回值
        return TodayBest.init(userInfo, user);
    }
}

Ⅲ. API

编辑 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/RecommendUserApi.java 文件:

public interface RecommendUserApi {

    // 查询今日佳人
    RecommendUser queryWithMaxScore(Long toUserId);

    // 分页查询推荐好友列表
    PageResult queryRecommendUserList(Integer page, Integer pagesize, Long toUserId);

    // 根据操作人id, 和查看的用户id,查询两者的推荐数据(缘分值)
    RecommendUser queryByUserId(Long userId, Long toUserId);
}

Ⅳ. ApiImpl

编辑 tanhua-dubbo/tanhua-dubbo-mongo/src/main/java/com/tanhua/dubbo/api/RecommendUserApiImpl.java 文件:

@DubboService
public class RecommendUserApiImpl implements RecommendUserApi{

    @Autowired
    private MongoTemplate mongoTemplate;

    // 查询今日佳人
    public RecommendUser queryWithMaxScore(Long toUserId) {

        // 根据toUserId查询,根据评分score排序,获取第一条
        // 1. 构建Criteria
        Criteria criteria = Criteria.where("toUserId").is(toUserId);

        // 2. 构建Query
        Query query = Query.query(criteria).with(Sort.by(Sort.Order.desc("score")))
                .limit(1); // 查询第一条(第一页第一条)

        // 3. 调用mongoTemplate查询
        return mongoTemplate.findOne(query, RecommendUser.class);
    }

    // 分页查询推荐好友列表
    public PageResult queryRecommendUserList(Integer page, Integer pagesize, Long toUserId) {
        // 1. 构建Criteria对象
        Criteria criteria = Criteria.where("toUserId").is(toUserId);

        // 2. 构造query对象
        Query query = Query.query(criteria);

        // 3. 查询总数
        long count = mongoTemplate.count(query, RecommendUser.class);

        // 4. 查询数据列表
        query.with(Sort.by(Sort.Order.desc("score"))).limit(pagesize).skip((page - 1) * pagesize);
        List<RecommendUser> list = mongoTemplate.find(query, RecommendUser.class);

        // 5. 构造返回值
        return new PageResult(page, pagesize, count, list);
    }

    // 根据操作人id, 和查看的用户id,查询两者的推荐数据(缘分值)
    public RecommendUser queryByUserId(Long userId, Long toUserId) {
        Criteria criteria = Criteria.where("toUserId").is(toUserId).and("userId").is(userId);
        Query query = Query.query(criteria);
        RecommendUser user = mongoTemplate.findOne(query, RecommendUser.class);
        if(user == null) {
            user = new RecommendUser();
            user.setUserId(userId);
            user.setToUserId(toUserId);
            // 构建缘分值
            user.setScore(95d);
        }
        return user;
    }
}

③. 测试

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第34张图片


⑵. 查看陌生人问题

①. 接口文档

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第35张图片

②. 编码实现

Ⅰ. Controller

编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/TanhuaController.java 文件:

@RestController
@RequestMapping("/tanhua")
public class TanhuaController {

    @Autowired
    private TanhuaService tanhuaService;

    /**
     * 今日佳人
     */
    @GetMapping("/todayBest")
    public ResponseEntity todayBest() {
        TodayBest vo = tanhuaService.todayBest();
        return ResponseEntity.ok(vo);
    }

    /**
     * 查询分页推荐好友列表
     */
    @GetMapping("recommendation")
    public ResponseEntity recommendation(RecommendUserDto dto) {
        PageResult pr = tanhuaService.recommendation(dto);
        return ResponseEntity.ok(pr);
    }

    /**
     * 查看佳人详情
     */
    @GetMapping("/{id}/personalInfo")
    public ResponseEntity personalInfo(@PathVariable("id") Long userId) {
        TodayBest best = tanhuaService.personalInfo(userId);
        return ResponseEntity.ok(best);
    }

    /**
     * 查看陌生人问题
     */
    @GetMapping("/strangerQuestions")
    public ResponseEntity strangerQuestions(Long userId) {
        String questions = tanhuaService.strangerQuestions(userId);
        return ResponseEntity.ok(questions);
    }
}

Ⅱ. Service

编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/TanhuaService.java 文件:

@Service
public class TanhuaService {

    @DubboReference
    private RecommendUserApi recommendUserApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private QuestionApi questionApi;

    // 查询今日佳人数据
    public TodayBest todayBest() {
        // 1. 获取用户id
        Long userId = UserHolder.getUserId();

        // 2. 调用api查询
        RecommendUser recommendUser = recommendUserApi.queryWithMaxScore(userId);

        // 3. 设置默认值
        if(recommendUser == null) {
            recommendUser = new RecommendUser();
            recommendUser.setUserId(1l);
            recommendUser.setScore(99d);
        }

        // 4. 将recommendUser 转化成 todayBest对象
        UserInfo userInfo = userInfoApi.findById(recommendUser.getUserId());
        TodayBest vo = TodayBest.init(userInfo, recommendUser);

        // 5. 返回
        return vo;
    }

    // 查询分页推荐好友列表
    public PageResult recommendation(RecommendUserDto dto) {
        // 1. 获取用户id
        Long userId = UserHolder.getUserId();

        // 2. 调用RecommendUserApi查询数据列表(PageResult -- RecommendUser)
        PageResult pr = recommendUserApi.queryRecommendUserList(dto.getPage(), dto.getPagesize(), userId);

        // 3. 获取分页中的RecommendUser数据列表
        List<RecommendUser> items = (List<RecommendUser>) pr.getItems();

        // 4. 判断列表数据是否为空
        if (items == null) {
            return pr;
        }

//        // 5. 循环RecommendUser推荐列表,根据推荐的用户id查询用户详情
//        List list = new ArrayList<>();
//        for (RecommendUser item : items) {
//            Long recommendUserId = item.getUserId();
//            UserInfo userInfo = userInfoApi.findById(recommendUserId);
//            if(userInfo != null) {
//                // 条件判断
//                if(!StringUtils.isEmpty(dto.getGender()) && !dto.getGender().equals(userInfo.getGender())) {
//                    continue;
//                }
//                if (dto.getAge() != null && dto.getAge() < userInfo.getAge()) {
//                    continue;
//                }
//                TodayBest vo = TodayBest.init(userInfo, item);
//                list.add(vo);
//            }
//        }
//


        // 5. 提取所有推荐的用户id列表
        List<Long> ids = CollUtil.getFieldValues(items, "userId", Long.class);
        UserInfo userInfo = new UserInfo();
        userInfo.setAge(dto.getAge());
        userInfo.setGender(dto.getGender());

        // 6. 构建查询条件,批量查询所有的用户详情
        Map<Long, UserInfo> map = userInfoApi.findByIds(ids, userInfo);

        // 7. 循环推荐的数据列表,构建vo对象
        List<TodayBest> list = new ArrayList<>();
        for (RecommendUser item : items) {
            UserInfo info = map.get(item.getUserId());
            if(info != null) {
                TodayBest vo = TodayBest.init(info, item);
                list.add(vo);
            }
        }

        // 6. 构造返回值
        pr.setItems(list);
        return pr;
    }

    // 查看佳人详情
    public TodayBest personalInfo(Long userId) {
        // 1. 根据用户id,查询用户详情
        UserInfo userInfo = userInfoApi.findById(userId);
        // 2. 根据操作人id, 和查看的用户id,查询两者的推荐数据(缘分值)
        RecommendUser user = recommendUserApi.queryByUserId(userId, UserHolder.getUserId());
        // 3. 构造返回值
        return TodayBest.init(userInfo, user);
    }

    // 查看陌生人问题
    public String strangerQuestions(Long userId) {
        Question question = questionApi.findByUserId(userId);
        return question == null ? "你喜欢吃青椒吗?" : question.getTxt();
    }
}

③. 页面效果


⑶. 回复陌生人问题

①. 接口文档

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第36张图片


②. 编码实现

Ⅰ. Controller

编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/TanhuaController.java 文件:

@RestController
@RequestMapping("/tanhua")
public class TanhuaController {

    @Autowired
    private TanhuaService tanhuaService;

    /**
     * 今日佳人
     */
    @GetMapping("/todayBest")
    public ResponseEntity todayBest() {
        TodayBest vo = tanhuaService.todayBest();
        return ResponseEntity.ok(vo);
    }

    /**
     * 查询分页推荐好友列表
     */
    @GetMapping("recommendation")
    public ResponseEntity recommendation(RecommendUserDto dto) {
        PageResult pr = tanhuaService.recommendation(dto);
        return ResponseEntity.ok(pr);
    }

    /**
     * 查看佳人详情
     */
    @GetMapping("/{id}/personalInfo")
    public ResponseEntity personalInfo(@PathVariable("id") Long userId) {
        TodayBest best = tanhuaService.personalInfo(userId);
        return ResponseEntity.ok(best);
    }

    /**
     * 查看陌生人问题
     */
    @GetMapping("/strangerQuestions")
    public ResponseEntity strangerQuestions(Long userId) {
        String questions = tanhuaService.strangerQuestions(userId);
        return ResponseEntity.ok(questions);
    }

    /**
     * 回复陌生人问题
     */
    @PostMapping("/strangerQuestions")
    public ResponseEntity replyQuestions(@RequestBody Map map) {
        // 前端传递的userId是 Integer类型
        String obj = map.get("userId").toString();
        Long userId = Long.valueOf(obj);
        String reply = map.get("reply").toString();
        tanhuaService.replyQuestions(userId, reply);
        return ResponseEntity.ok(null);
    }
}

Ⅱ. Service

编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/TanhuaService.java 文件:

@Service
public class TanhuaService {

    @DubboReference
    private RecommendUserApi recommendUserApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private QuestionApi questionApi;

    @Autowired
    private HuanXinTemplate huanXinTemplate;

    // 查询今日佳人数据
    public TodayBest todayBest() {
        // 1. 获取用户id
        Long userId = UserHolder.getUserId();

        // 2. 调用api查询
        RecommendUser recommendUser = recommendUserApi.queryWithMaxScore(userId);

        // 3. 设置默认值
        if(recommendUser == null) {
            recommendUser = new RecommendUser();
            recommendUser.setUserId(1l);
            recommendUser.setScore(99d);
        }

        // 4. 将recommendUser 转化成 todayBest对象
        UserInfo userInfo = userInfoApi.findById(recommendUser.getUserId());
        TodayBest vo = TodayBest.init(userInfo, recommendUser);

        // 5. 返回
        return vo;
    }

    // 查询分页推荐好友列表
    public PageResult recommendation(RecommendUserDto dto) {
        // 1. 获取用户id
        Long userId = UserHolder.getUserId();

        // 2. 调用RecommendUserApi查询数据列表(PageResult -- RecommendUser)
        PageResult pr = recommendUserApi.queryRecommendUserList(dto.getPage(), dto.getPagesize(), userId);

        // 3. 获取分页中的RecommendUser数据列表
        List<RecommendUser> items = (List<RecommendUser>) pr.getItems();

        // 4. 判断列表数据是否为空
        if (items == null) {
            return pr;
        }

//        // 5. 循环RecommendUser推荐列表,根据推荐的用户id查询用户详情
//        List list = new ArrayList<>();
//        for (RecommendUser item : items) {
//            Long recommendUserId = item.getUserId();
//            UserInfo userInfo = userInfoApi.findById(recommendUserId);
//            if(userInfo != null) {
//                // 条件判断
//                if(!StringUtils.isEmpty(dto.getGender()) && !dto.getGender().equals(userInfo.getGender())) {
//                    continue;
//                }
//                if (dto.getAge() != null && dto.getAge() < userInfo.getAge()) {
//                    continue;
//                }
//                TodayBest vo = TodayBest.init(userInfo, item);
//                list.add(vo);
//            }
//        }
//


        // 5. 提取所有推荐的用户id列表
        List<Long> ids = CollUtil.getFieldValues(items, "userId", Long.class);
        UserInfo userInfo = new UserInfo();
        userInfo.setAge(dto.getAge());
        userInfo.setGender(dto.getGender());

        // 6. 构建查询条件,批量查询所有的用户详情
        Map<Long, UserInfo> map = userInfoApi.findByIds(ids, userInfo);

        // 7. 循环推荐的数据列表,构建vo对象
        List<TodayBest> list = new ArrayList<>();
        for (RecommendUser item : items) {
            UserInfo info = map.get(item.getUserId());
            if(info != null) {
                TodayBest vo = TodayBest.init(info, item);
                list.add(vo);
            }
        }

        // 6. 构造返回值
        pr.setItems(list);
        return pr;
    }

    // 查看佳人详情
    public TodayBest personalInfo(Long userId) {
        // 1. 根据用户id,查询用户详情
        UserInfo userInfo = userInfoApi.findById(userId);
        // 2. 根据操作人id, 和查看的用户id,查询两者的推荐数据(缘分值)
        RecommendUser user = recommendUserApi.queryByUserId(userId, UserHolder.getUserId());
        // 3. 构造返回值
        return TodayBest.init(userInfo, user);
    }

    // 查看陌生人问题
    public String strangerQuestions(Long userId) {
        Question question = questionApi.findByUserId(userId);
        return question == null ? "你喜欢吃青椒吗?" : question.getTxt();
    }

    // 回复陌生人问题
    public void replyQuestions(Long userId, String reply) {
        // 1. 构造消息数据
        Long currentUserId = UserHolder.getUserId();
        UserInfo userInfo = userInfoApi.findById(currentUserId);
        Map map = new HashMap<>();
        map.put("userId", currentUserId);
        map.put("huanXinId", Constants.HX_USER_PREFIX + currentUserId);
        map.put("nickname", userInfo.getNickname());
        map.put("strangerQuestion", strangerQuestions(userId));
        map.put("reply", reply);
        String message = JSON.toJSONString(map);

        // 2. 调用template对象,发送消息
        Boolean aBoolean = huanXinTemplate.sendMsg(Constants.HX_USER_PREFIX + userId, message);

        // 3. 异常处理
        if (!aBoolean) {
           throw new BusinessException(ErrorResult.error());
        }
    }
}


③. 页面效果

使用雷电模拟器进行多开,一个用户向另一个用户在线发送消息
SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第37张图片


2. 添加好友

⑴. 接口文档

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第38张图片


⑵. 编码实现

①. Controller

编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/MessagesController.java 文件:

@RestController
@RequestMapping("/messages")
public class MessagesController {

    @Autowired
    private MessagesService messagesService;

    /**
     * 根据环信用户id,查询环信用户详情
     */
    @GetMapping("/userinfo")
    public ResponseEntity userinfo(String huanxinId) {
        UserInfoVo vo = messagesService.findUserInfoByHuanXin(huanxinId);
        return ResponseEntity.ok(vo);
    }

    /**
     * 添加好友
     */
    @PostMapping("/contacts")
    public ResponseEntity contacts(@RequestBody Map map) {
        Long friendId = Long.valueOf(map.get("userId").toString());
        messagesService.contacts(friendId);
        return ResponseEntity.ok(null);
    }
}

②. Service

编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/MessagesService.java 文件:

@Service
public class MessagesService {

    @DubboReference
    private UserApi userApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @Autowired
    private HuanXinTemplate huanXinTemplate;

    @DubboReference
    private FriendApi friendApi;

    // 根据环信用户id,查询用户详情
    public UserInfoVo findUserInfoByHuanXin(String huanxinId) {
        // 1. 根据环信id查询用户
        User user = userApi.findByHuanXin(huanxinId);

        // 2. 根据用户id,查询用户详情
        UserInfo userInfo = userInfoApi.findById(user.getId());

        // 3. 构建vo返回值
        UserInfoVo vo = new UserInfoVo();
        BeanUtils.copyProperties(userInfo, vo); // 只会copy同名同类型的属性
        if(userInfo.getAge() != null) {
            vo.setAge(userInfo.getAge().toString());
        }
        return vo;
    }

    // 添加好友
    public void contacts(Long friendId) {
        // 1. 好友关系记录到环信
        Boolean aBoolean = huanXinTemplate.addContact(Constants.HX_USER_PREFIX + UserHolder.getUserId(),
                Constants.HX_USER_PREFIX + friendId);
        if(!aBoolean) {
            throw new BusinessException(ErrorResult.error());
        }

        // 2. 记录好友关系到MongoDB
        friendApi.save(UserHolder.getUserId(), friendId);
    }
}

③. API

新建 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/FriendApi.java 文件:

public interface FriendApi {

    // 添加好友
    void save(Long userId, Long friendId);
}

④. API实现类

编辑 tanhua-dubbo/tanhua-dubbo-mongo/src/main/java/com/tanhua/dubbo/api/FriendApiImpl.java 文件:

@DubboService
public class FriendApiImpl implements FriendApi {

    @Autowired
    private MongoTemplate mongoTemplate;

    // 添加好友
    @Override
    public void save(Long userId, Long friendId) {
        // 1. 保存自己的好友数据
        Query query1 = Query.query(Criteria.where("userId").is(userId).and("friendId").is(friendId));
        // 1.1 判断好友关系是否存在
        if(!mongoTemplate.exists(query1, Friend.class)) {
            // 1.2 如果不存在,保存
            Friend friend1 = new Friend();
            friend1.setUserId(userId);
            friend1.setFriendId(friendId);
            friend1.setCreated(System.currentTimeMillis());
            mongoTemplate.save(friend1);
        }

        // 2. 保存好友的数据
        Query query2 = Query.query(Criteria.where("userId").is(friendId).and("friendId").is(userId));
        // 2.1 判断好友关系是否存在
        if(!mongoTemplate.exists(query2, Friend.class)) {
            // 2.2 如果不存在,保存
            Friend friend1 = new Friend();
            friend1.setUserId(friendId);
            friend1.setFriendId(userId);
            friend1.setCreated(System.currentTimeMillis());
            mongoTemplate.save(friend1);
        }
    }
}

⑶. 页面效果

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第39张图片


3. 联系人列表

⑴. 接口文档

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第40张图片


⑵. 编码实现

①. Controller

编辑 tanhua-app-server/src/main/java/com/tanhua/server/controller/MessagesController.java 文件:

@RestController
@RequestMapping("/messages")
public class MessagesController {

    @Autowired
    private MessagesService messagesService;

    /**
     * 根据环信用户id,查询环信用户详情
     */
    @GetMapping("/userinfo")
    public ResponseEntity userinfo(String huanxinId) {
        UserInfoVo vo = messagesService.findUserInfoByHuanXin(huanxinId);
        return ResponseEntity.ok(vo);
    }

    /**
     * 添加好友
     */
    @PostMapping("/contacts")
    public ResponseEntity contacts(@RequestBody Map map) {
        Long friendId = Long.valueOf(map.get("userId").toString());
        messagesService.contacts(friendId);
        return ResponseEntity.ok(null);
    }

    /**
     * 分页查询联系人列表
     */
    @GetMapping("/contacts")
    public ResponseEntity contacts(@RequestParam(defaultValue = "1") Integer page,
                                   @RequestParam(defaultValue = "10") Integer pagesize,
                                   String keyword) {
        PageResult pr = messagesService.findFriends(page, pagesize, keyword);
        return ResponseEntity.ok(pr);
    }
}

②. vo对象

新建 tanhua-model/src/main/java/com/tanhua/model/vo/ContactVo.java 文件:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ContactVo implements Serializable {

    private Long id;
    private String userId;
    private String avatar;
    private String nickname;
    private String gender;
    private Integer age;
    private String city;

    public static ContactVo init(UserInfo userInfo) {
        ContactVo vo = new ContactVo();
        if(userInfo != null) {
        	BeanUtils.copyProperties(userInfo,vo);
        	vo.setUserId("hx"+userInfo.getId().toString());
        }
        return vo;
    }
}

③. Service

编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/MessagesService.java 文件:

@Service
public class MessagesService {

    @DubboReference
    private UserApi userApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @Autowired
    private HuanXinTemplate huanXinTemplate;

    @DubboReference
    private FriendApi friendApi;

    // 根据环信用户id,查询用户详情
    public UserInfoVo findUserInfoByHuanXin(String huanxinId) {
        // 1. 根据环信id查询用户
        User user = userApi.findByHuanXin(huanxinId);

        // 2. 根据用户id,查询用户详情
        UserInfo userInfo = userInfoApi.findById(user.getId());

        // 3. 构建vo返回值
        UserInfoVo vo = new UserInfoVo();
        BeanUtils.copyProperties(userInfo, vo); // 只会copy同名同类型的属性
        if(userInfo.getAge() != null) {
            vo.setAge(userInfo.getAge().toString());
        }
        return vo;
    }

    // 添加好友
    public void contacts(Long friendId) {
        // 1. 好友关系记录到环信
        Boolean aBoolean = huanXinTemplate.addContact(Constants.HX_USER_PREFIX + UserHolder.getUserId(),
                Constants.HX_USER_PREFIX + friendId);
        if(!aBoolean) {
            throw new BusinessException(ErrorResult.error());
        }

        // 2. 记录好友关系到MongoDB
        friendApi.save(UserHolder.getUserId(), friendId);
    }

    // 分页查询联系人列表
    public PageResult findFriends(Integer page, Integer pagesize, String keyword) {
        // 1. 调用API查询当前用户的好友数据 -- List
        List<Friend> list = friendApi.findUserById(UserHolder.getUserId(), page, pagesize);
        if(CollUtil.isEmpty(list)) {
            return new PageResult();
        }

        // 2. 提取数据列表中的好友id
        List<Long> friendIds = CollUtil.getFieldValues(list, "friendId", Long.class);

        // 3. 调用UserInfoApi查询用户好友的详情
        UserInfo userInfo = new UserInfo();
        userInfo.setNickname(keyword);
        Map<Long, UserInfo> map = userInfoApi.findByIds(friendIds, userInfo);

        // 4. 构造vo对象
        List<ContactVo> vos = new ArrayList<>();
        for (Friend friend : list) {
            UserInfo info = map.get(friend.getFriendId());
            if(info != null) {
                ContactVo vo = ContactVo.init(info);
                vos.add(vo);
            }
        }
        return new PageResult(page, pagesize, 0l, vos);
    }
}

④. API接口

编辑 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/FriendApi.java 文件:

public interface FriendApi {

    // 添加好友
    void save(Long userId, Long friendId);

    // 查询好友列表
    List<Friend> findUserById(Long userId, Integer page, Integer pagesize);
}

⑤. API实现类

编辑 tanhua-dubbo/tanhua-dubbo-mongo/src/main/java/com/tanhua/dubbo/api/FriendApiImpl.java 文件:

@DubboService
public class FriendApiImpl implements FriendApi {

    @Autowired
    private MongoTemplate mongoTemplate;

    // 添加好友
    @Override
    public void save(Long userId, Long friendId) {
        // 1. 保存自己的好友数据
        Query query1 = Query.query(Criteria.where("userId").is(userId).and("friendId").is(friendId));
        // 1.1 判断好友关系是否存在
        if(!mongoTemplate.exists(query1, Friend.class)) {
            // 1.2 如果不存在,保存
            Friend friend1 = new Friend();
            friend1.setUserId(userId);
            friend1.setFriendId(friendId);
            friend1.setCreated(System.currentTimeMillis());
            mongoTemplate.save(friend1);
        }

        // 2. 保存好友的数据
        Query query2 = Query.query(Criteria.where("userId").is(friendId).and("friendId").is(userId));
        // 2.1 判断好友关系是否存在
        if(!mongoTemplate.exists(query2, Friend.class)) {
            // 2.2 如果不存在,保存
            Friend friend1 = new Friend();
            friend1.setUserId(friendId);
            friend1.setFriendId(userId);
            friend1.setCreated(System.currentTimeMillis());
            mongoTemplate.save(friend1);
        }
    }

    // 查询好友列表
    @Override
    public List<Friend> findUserById(Long userId, Integer page, Integer pagesize) {
        Query query = Query.query(Criteria.where("userId").is(userId))
                .skip((page - 1) * pagesize)
                .limit(pagesize)
                .with(Sort.by(Sort.Order.desc("created")));
        return mongoTemplate.find(query, Friend.class);
    }
}

⑥. 添加昵称检索功能

编辑 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/api/UserInfoApiImpl.java 文件:

@DubboService
public class UserInfoApiImpl implements UserInfoApi{
    @Autowired
    private UserInfoMapper userInfoMapper;

    @Override
    public void save(UserInfo userInfo) {
        userInfoMapper.insert(userInfo);
    }

    @Override
    public void update(UserInfo userInfo) {
        userInfoMapper.updateById(userInfo);
    }

    @Override
    public UserInfo findById(Long id) {
        return userInfoMapper.selectById(id);
    }

    /**
     * 批量查询用戶详情
     * @param userIds 用户id列表
     * @param info 用户详情信息
     * @return
     */
    @Override
    public Map<Long, UserInfo> findByIds(List<Long> userIds, UserInfo info) {
        // 1. 用户id列表
        QueryWrapper qw = new QueryWrapper<>();
        qw.in("id", userIds);

        // 2. 添加筛选条件
        if(info != null) {
            if(info.getAge() != null) {
                qw.lt("age", info.getAge());
            }
            if(!StringUtils.isEmpty(info.getGender())) {
                qw.eq("gender", info.getGender());
            }
            if(!StringUtils.isEmpty(info.getNickname())) {
                qw.like("nickname", info.getNickname());
            }
        }

        // 3. 获取用户详情列表 转换成map集合
        List<UserInfo> list = userInfoMapper.selectList(qw);
        Map<Long, UserInfo> map = CollUtil.fieldValueMap(list, "id");

        // 4. 返回
        return map;
    }
}

⑶. 页面效果

SpringBoot交友APP项目实战(详细介绍+案例源码) - 7.即时通讯(基于第三方API)_第41张图片


你可能感兴趣的:(Java,1024程序员节,微服务,后端,java,spring,boot)