探花交友_第7章_即时通信(新版)

news2024/10/1 3:27:47

探花交友_第7章_即时通信

文章目录

  • 探花交友_第7章_即时通信
    • 1.1 什么是即时通信
    • 1.2 功能说明
    • 1.3 技术方案
  • 2. 环信
    • 2.1 开发简介
    • 2.2 环信Console
    • 2.3 环信API介绍
      • 初始化
      • 基础API
  • 3. 抽取环信组件
    • 3.1 编写Properties对象
    • 3.2 编写HuanXinTemplate
    • 3.3 编写自动配置类
    • 3.4 环信集成测试
  • 4. 用户体系集成
    • 4.1 注册环信用户
      • 4.1.1 注册时注册环信
        • **UserService**
      • 4.1.2 批量注册环信
        • **HuanXinTest**
    • 4.2 查询用户环信账号
      • 4.2.1 API接口
      • 4.2.2 vo对象
      • 4.2.3 代码实现
        • **HuanXinController**
        • **UserService**
    • 4.3 环信ID查询用户信息
        • **tanhua-app-server**
          • MessageController
          • MessagesService
        • **tanhua-dubbo-interface**
        • **tanhua-dubbo-db**
    • 4.4 测试消息
  • 5. 联系人管理
    • 5.1 需求分析
      • 5.1.1 好友申请
      • 5.1.2 添加好友
    • 5.2 查看佳人信息
      • 5.2.1 接口说明
      • 5.2.2 代码实现
        • tanhua-app-server
          • **TanhuaController**
          • **TanhuaService**
        • tanhua-dubbo-interface
        • tanhua-dubbo-mongo
    • 5.3 查看陌生人消息
      • 5.3.1 接口说明
      • 5.3.2 代码实现
        • TanhuaController
        • TanhuaService
    • 5.4 回复陌生人消息
      • 5.4.1 接口说明
      • 5.4.2 代码实现
        • TanhuaController
        • TanhuaService
    • 5.5 添加联系人
      • 5.5.1 接口说明
      • 5.5.2 代码实现
        • tanhua-app-server
          • **MessageController**
          • **MessagesService**
        • tanhua-dubbo-interface
        • tanhua-dubbo-mongo
    • 5.6 联系人列表
      • 5.6.1 接口说明
      • 5.6.2 代码实现
        • 定义ContactVo
        • tanhua-app-server
        • tanhua-dubbo-interface
        • tanhua-dubbo-mongo
        • tanhua-dubbo-mongo

1.1 什么是即时通信

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

1.2 功能说明

在探花交友项目中也提供了类似微信的聊天功能,用户可以和好友或陌生人聊天。

如果是陌生人,通过《聊一下》功能进行打招呼,如果对方同意后,就成为了好友,可以进行聊天了。

陌生人之间如果相互喜欢,那么就会成为好友,也就可以聊天了。

在消息界面中也可以查看:点赞 评论 喜欢 公告等消息信息。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.3 技术方案

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

对于现实即时通讯往往有两种方案:

  • 方案一:自主实现

技术方面可以采用:Netty + WebSocket + RocketMQ + MongoDB + Redis + ZooKeeper + MySQL

在这里插入图片描述

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

如何选择?

  • 如果是中大型企业做项目可以选择自主研发。方案一需要有大量的人力 物力的支持,开发周期长,成本高,但可控性强。
  • 如果是中小型企业研发中小型的项目,选择第二种方案即可。方案二,成本低,开发周期短,能够快速的集成起来进行功能的开发,只是在可控性方面来说就差了一些。

2. 环信

官网:https://www.easemob.com/ 稳定健壮,消息必达,亿级并发的即时通讯云。

黑马学员注册地址:https://datayi.cn/w/woVL50vR

在这里插入图片描述

2.1 开发简介

环信和用户体系的集成主要发生在2个地方,服务器端集成和客户端集成。

在这里插入图片描述

探花集成:

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

2.2 环信Console

需要使用环信平台,那么必须要进行注册,登录之后即可创建应用。环信100以内的用户免费使用,100以上就要注册企业版了。

创建应用:

在这里插入图片描述

创建完成:

在这里插入图片描述

2.3 环信API介绍

为了方便用户集成, 环信为开发者提供了Server SDK,是对环信IM 服务端API 的封装,这样做是为了节省服务器端开发者对接环信API的时间,只需要配置自己的appkey相关信息即可使用。

文档地址:https://docs-im.easemob.com/im/server/ready/sdk

初始化

EMProperties properties = EMProperties.builder()
        .setAppkey("您的AppKey")
        .setClientId("您的ClientId")
        .setClientSecret("您的ClientSecret")
        .build();

EMService service = new EMService(properties);

基础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();

3. 抽取环信组件

抽取环信组件到tanhua-autoconfig工程中

3.1 编写Properties对象

创建HuanXinProperties配置对象

package com.tanhua.autoconfig.properties;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

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

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

3.2 编写HuanXinTemplate

创建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 java.util.Set;

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;
    }
}

3.3 编写自动配置类

修改自动装配类TanhuaAutoConfiguration,添加HuanXinTemplate部分内容

package com.tanhua.autoconfig;


import com.tanhua.autoconfig.properties.*;
import com.tanhua.autoconfig.template.*;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;

@EnableConfigurationProperties({
		//其他省略
        HuanXinProperties.class
})
public class TanhuaAutoConfiguration {
	//其他省略
    @Bean
    public HuanXinTemplate huanXinTemplate(HuanXinProperties properties) {
        return new HuanXinTemplate(properties);
    }
}

3.4 环信集成测试

tanhua-app-server工程的application.yml文件加入配置如下

tanhua:
  huanxin:
    appkey: 1110201018107234#tanhua
    clientId: YXA6nxJJ_pdEQ_eYUlqcRicS4w
    clientSecret: YXA6GMUxVEZhAvxlMn4OvHSXbWuEUTE

编写测试类进行测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class HuanXinTest {

    @Autowired
    private HuanXinTemplate template;

    @Test
    public void testRegister() {
        template.createUser("user01","123456");
    }
}

4. 用户体系集成

将用户体系集成的逻辑写入到tanhua-server系统中。

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

4.1 注册环信用户

4.1.1 注册时注册环信

在用户登录逻辑中,当第一次注册时,将用户信息注册到环信

修改tanhua-app-server中注册登录方法UserService#loginVerification(),当新用户注册时,将用户信息推送到环信。

UserService

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 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.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;
}

4.1.2 批量注册环信

对于已经存在的老用户而言,也需要注册到环信。我们这里自己编写一个单元测试类来实现。

注意:使用测试账号最多支持100个用户

HuanXinTest

tanhua-app-serverHuanXinTest中配置批量注册方法

//批量注册
@Test
public void register() {
    List<User> users = userApi.findAll();
    for (User user : users) {
        Boolean create = template.createUser("hx" + user.getId(), "123456");
        if (create){
            user.setHxUser("hx" + user.getId());
            user.setHxPassword(Constants.INIT_PASSWORD);
            userApi.update(user);
        }
    }
}

UserApi

tanhua-dubbo-interfaceUserApi中补充查询所有方法

/**
 * 查询所有用户信息
 *
 * @return
 */
List<User> findAll();

UserApiImpl

tanhua-dubbo-dbUserApiImpl中补充查询所有方法

@Override
public List<User> findAll() {
    return userMapper.selectList(Wrappers.emptyWrapper());
}

4.2 查询用户环信账号

探花APP端调用服务端后台接口,获取当前用户在环信的账号/密码,自动与环信服务器登录。

4.2.1 API接口

api地址:http://192.168.136.160:3000/project/19/interface/api/85

在这里插入图片描述

4.2.2 vo对象

package com.tanhua.model.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

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

4.2.3 代码实现

tanhua-app-server中配置HuanXinControllerHuanXinService进行代码实现

HuanXinController

package com.tanhua.server.controller;


import com.tanhua.model.vo.HuanXinUserVo;
import com.tanhua.server.service.HuanXinService;
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("/huanxin")
public class HuanXinController {

    @Autowired
    private HuanXinService huanXinService;

    @GetMapping("/user")
    public ResponseEntity user() {
        HuanXinUserVo vo = huanXinService.findHuanXinUser();
        return ResponseEntity.ok(vo);
    }
}

UserService

package com.tanhua.server.service;

import com.tanhua.dubbo.api.UserApi;
import com.tanhua.model.domain.User;
import com.tanhua.model.vo.HuanXinUserVo;
import com.tanhua.server.interceptor.UserHolder;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;

@Service
public class HuanXinService {

    @DubboReference
    private UserApi userApi;

    /**
     * 查询当前用户的环信账号
     *  1、获取用户id,根据账号规则拼接
     *  2、获取用户id,查询用户对象
     */
    public HuanXinUserVo findHuanXinUser() {
        Long userId = UserHolder.getUserId();
        User user = userApi.findById(userId);
        if(user == null) {
            return null;
        }
        return new HuanXinUserVo(user.getHxUser(),user.getHxPassword());
    }
}

4.3 环信ID查询用户信息

在好友聊天时,完全基于环信服务器实现。为了更好的页面效果,需要展示出用户的基本信息,这是需要通过环信用户id查询用户。

接口说明

在这里插入图片描述

tanhua-app-server

tanhua-app-server中配置MessagesControllerMessagesService完成代码编写

MessageController

创建MessageController类, 定义方法接收请求

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;

    /**
     * 根据环信ID查询用户详细信息
     */
    @GetMapping("/userinfo")
    public ResponseEntity userinfo(String huanxinId) {
        UserInfoVo vo = messagesService.findUserInfoByHuanxin(huanxinId);
        return ResponseEntity.ok(vo);
    }
}
MessagesService

创建MessagesService类, 定义方法查询用户信息

package com.tanhua.server.service;

import com.tanhua.dubbo.api.db.UserApi;
import com.tanhua.dubbo.api.db.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;

    @DubboReference
    private FriendApi friendApi;

    @Autowired
    private HuanXinTemplate huanXinTemplate;

    /**
     * 根据环信id查询用户详情
     */
    public UserInfoVo findUserInfoByHuanxin(String huanxinId) {
        //1、根据环信id查询用户
        User user = userApi.findByHuanxin(huanxinId);
        //2、根据用户id查询用户详情
        UserInfo userInfo = userInfoApi.findById(user.getId());
        UserInfoVo vo = new UserInfoVo();
        BeanUtils.copyProperties(userInfo,vo); //copy同名同类型的属性
        if(userInfo.getAge() != null) {
            vo.setAge(userInfo.getAge().toString());
        }
        return vo;
    }
}

tanhua-dubbo-interface

tanhua-dubbo-interface中的UserApi中定义根据hxid查询环信用户信息的方法

/**
 * 根据环信用户名查询用户信息
 */
User findByHuanxin(String huanxinId);

tanhua-dubbo-db

tanhua-dubbo-db中的UserApiImpl中实现根据hxid查询环信用户信息的方法

@Override
public User findByHuanxin(String huanxinId) {
    QueryWrapper<User> qw = new QueryWrapper<>();
    qw.eq("hx_user",huanxinId);
    return userMapper.selectOne(qw);
}

4.4 测试消息

目前已经完成了用户体系的对接,下面我们进行测试发送消息,场景是这样的:

在这里插入图片描述

我们暂时通过环信的控制台进行发送:
在这里插入图片描述

消息内容:

{"userId":106,"huanXinId":"hx106","nickname":"黑马小妹","strangerQuestion":"你喜欢去看蔚蓝的大海还是去爬巍峨的高山?","reply":"我喜欢秋天的落叶,夏天的泉水,冬天的雪地,只要有你一切皆可~"}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

可以看到已经接收到了消息。

5. 联系人管理

5.1 需求分析

5.1.1 好友申请

在这里插入图片描述
在这里插入图片描述在这里插入图片描述

  • 客户端查看感兴趣用户的信息

  • 点击“聊一下”,获取对方的陌生人问题,

  • 填写答案,服务端调用环信发送消息到对方手机

在这里插入图片描述

5.1.2 添加好友

在这里插入图片描述

5.2 查看佳人信息

5.2.1 接口说明

在首页可以查看感兴趣人的详细资料。点击“聊一下”,可以查看对方的问题

接口信息如下 :

地址:http://192.168.136.160:3000/project/19/interface/api/103

在这里插入图片描述

5.2.2 代码实现

tanhua-app-server

tanhua-app-server中的TanhuaControllerTanhuaService中添加查询佳人信息的方法

TanhuaController
/**
 * 查询佳人信息
 */
@GetMapping("/{id}/personalInfo")
public ResponseEntity personalInfo(@PathVariable("id") Long userId) {
    TodayBest best = tanhuaService.personalInfo(userId);
    return ResponseEntity.ok(best);
}
TanhuaService
//查看佳人详情
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);
}

tanhua-dubbo-interface

tanhua-dubbo-interface中的RecommendUserApi中定义查询登录用户与点击用户的推荐信息方法

/**
 * 查询用户之间的推荐信息
 */
RecommendUser queryByUserId(Long userId, Long toUserId);

tanhua-dubbo-mongo

tanhua-dubbo-mongo中的RecommendUserApiImpl中实现查询登录用户与点击用户的推荐信息方法

@Override
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;
}

5.3 查看陌生人消息

5.3.1 接口说明

点击“聊一下”,可以查看对方的问题

接口地址:http://192.168.136.160:3000/project/19/interface/api/124

在这里插入图片描述

5.3.2 代码实现

TanhuaController

tanhua-app-server中的TanhuaControllerTanhuaService中添加查看陌生人问题方法

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

TanhuaService

/**
 * 查询用户陌生人问题
 */
public String strangerQuestions(Long userId) {
    Question question = questionApi.findByUserId(userId);
    return question == null ? "你喜欢java编程吗?" : question.getTxt();
}

5.4 回复陌生人消息

5.4.1 接口说明

需求:用户输入答案 , 点击聊一下 , 通过服务器端,给目标用户发送一条陌生人消息

接口地址:http://192.168.136.160:3000/project/19/interface/api/106
在这里插入图片描述

5.4.2 代码实现

tanhua-app-server中的TanhuaControllerTanhuaService中添加回复陌生人问题方法

TanhuaController

/**
 * 回复陌生人问题
*/
@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);
}

TanhuaService

创建TanhuaService并编写方法,完成回复陌生人消息功能

//回复陌生人问题
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 = template.sendMsg(Constants.HX_USER_PREFIX + userId, message);//1、接受方的环信id,2、消息
    if(!aBoolean) {
        throw  new BusinessException(ErrorResult.error());
    }
}

需要注意消息格式

{
	"userId": 106,
	"huanXinId": "hx106",
	"nickname": "黑马小妹",
	"strangerQuestion": "你喜欢去看蔚蓝的大海还是去爬巍峨的高山?",
	"reply": "我喜欢秋天的落叶,夏天的泉水,冬天的雪地,只要有你一切皆可~"
}

5.5 添加联系人

5.5.1 接口说明

用户获取陌生人消息后,点击“确认添加”,就会成为联系人(好友)。

服务端需要做二件事情 :

  1. 将好友关系写入到MongoDB中

  2. 将好友关系注册到环信

接口说明如下所示 :

地址: http://192.168.136.160:3000/project/19/interface/api/205

在这里插入图片描述

5.5.2 代码实现

tanhua-app-server

tanhua-app-server中的MessageControllerMessagesService中完成添加联系人方法

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

MessagesService
/**
 * 添加联系人
 *
 * @param friendId
 */
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);
}

tanhua-dubbo-interface

tanhua-dubbo-interface中的创建FriendApi,定义添加好友的方法

public interface FriendApi {
    //添加好友
    void save(Long userId, Long friendId);
}

tanhua-dubbo-mongo

tanhua-dubbo-mongo中的创建创建FriendApiImpl,实现添加好友的方法

package com.tanhua.dubbo.api;

import com.tanhua.dubbo.api.mongo.FriendApi;
import com.tanhua.model.mongo.Friend;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;


@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("frinedId").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("frinedId").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);
        }
    }
}

5.6 联系人列表

5.6.1 接口说明

联系人列表:分页查询好友列表数据 (tanhua-users:好友关系表)

接口说明如下 :

地址:http://192.168.136.160:3000/project/19/interface/api/202

在这里插入图片描述

5.6.2 代码实现

定义ContactVo

tanhua-model模块中定义ContactVo对象

package com.tanhua.domain.vo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@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;
    }
}

tanhua-app-server

tanhua-app-server中的MessageControllerMessagesService中完成查询联系人列表方法

MessageController

/**
 * 分页查询联系人列表
*/
@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);
}

MessagesService

//分页查询联系人列表
public PageResult findFriends(Integer page, Integer pagesize, String keyword) {
    //1、调用API查询当前用户的好友数据 -- List<Friend>
    List<Friend> list = friendApi.findByUserId(UserHolder.getUserId(),page,pagesize);
    if(CollUtil.isEmpty(list)) {
        return new PageResult();
    }
    //2、提取数据列表中的好友id
    List<Long> userIds = CollUtil.getFieldValues(list, "friendId", Long.class);
    //3、调用UserInfoAPI查询好友的用户详情
    UserInfo info = new UserInfo();
    info.setNickname(keyword);
    Map<Long, UserInfo> map = userInfoApi.findByIds(userIds, info);
    //4、构造VO对象
    List<ContactVo> vos = new ArrayList<>();
    for (Friend friend : list) {
        UserInfo userInfo = map.get(friend.getFriendId());
        if(userInfo != null) {
            ContactVo vo = ContactVo.init(userInfo);
            vos.add(vo);
        }
    }
    return new PageResult(page,pagesize,0l,vos);
}

tanhua-dubbo-interface

tanhua-dubbo-interface中的FriendApi定义查询用户好友列表方法

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

tanhua-dubbo-mongo

tanhua-dubbo-interface中的FriendApiImpl中定义查询用户好友列表方法

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

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


#### tanhua-dubbo-interface

在<font color=red><b>`tanhua-dubbo-interface`</b></font>中的`FriendApi`定义查询用户好友列表方法

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

tanhua-dubbo-mongo

tanhua-dubbo-interface中的FriendApiImpl中定义查询用户好友列表方法

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/95920.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Windows Defender 绕过(RTO I Lab环境实测)

背景 15号这天我通过了 RTO I 的考试。细想 RTO I 考试的 Lab&#xff0c;好像 Windows Defender&#xff08;以下简称 WD&#xff09;的保护做的比 OSEP 考试时还要好&#xff0c;更加严格。 回想起 9 月考 OSEP 的时候&#xff0c;只要你的 Payload 在文件创建&#xff08;…

这可能是Github 最全的Java面试笔记, 简直把所有 Java 知识面试题写出来了

前言 作为一个 Java 程序员&#xff0c;你平时总是陷在业务开发里&#xff0c;每天噼里啪啦忙敲着代码&#xff0c;上到系统开发&#xff0c;下到 Bug 修改&#xff0c;你感觉自己无所不能。然而偶尔的一次聚会&#xff0c;你听说和自己一起出道的同学早已经年薪 50 万&#x…

大数据 Hadoop集群配置

配置Hadoop集群 在master虚拟机上配置hadoop 编辑Hadoop环境配置文件 - hadoop-env.sh 命令&#xff1a;cd $HADOOP_HOME/etc/hadoop&#xff0c;进入hadoop配置目录 命令&#xff1a;vim hadoop-env.sh 命令source hadoop-env.sh&#xff0c;让配置生效 编辑Hadoop核心配…

项目的可交付成果

目录 概述 定义 形式 评审与验收 概述 概念来自PMBOK,这书真的要细嚼慢咽,“可交付成果”多次出现,全书总共出现了288次,贯穿全书,绝对是个核心概念。 定义 可交付成果是在某一过程、阶段或项目完成时,必须产出的任何独特并可核实的产品、成果或服务能力。它通常是…

2022吴恩达机器学习课程——第二课(神经网络)

注&#xff1a;参考B站视频教程 视频链接&#xff1a;【(强推|双字)2022吴恩达机器学习Deeplearning.ai课程】 文章目录第一周一、神经元二、神经网络三、代码实现 & Tensorflow四、前向传播五、强人工智能六、矩阵乘法 (简单&#xff0c;可以跳过)第二周一、用Tensorflow训…

20221217英语学习

今日新词 haul v.&#xff08;人&#xff09;拖&#xff0c;拉 herd n.人群&#xff1b;&#xff08;尤指有蹄的哺乳动物&#xff09;兽群&#xff0c;牧群 focus v.把注意力集中于&#xff0c;重视&#xff1b;集中&#xff1b;&#xff08;使&#xff09;调节焦距 result…

代码随想录刷题记录day44 股票问题3 4

代码随想录刷题记录day44 股票问题3 4 123. 买卖股票的最佳时机 III 思想 dp数组定义 递推公式 dp[i][0] 第i天不操作股票手头最大的现金 i从0开始 dp[i][1] 第i天第一次持有股票的手头最大的现金 dp[i][1] max: i-1天不操作&#xff0c;第i天才买入&#xff1a;dp[i-1][0…

港科夜闻|香港科技大学(广州)拟获批首个省级重点实验室

关注并星标每周阅读港科夜闻建立新视野 开启新思维1、香港科技大学(广州)拟获批首个省级重点实验室。2022年12月6日&#xff0c;广东省科学技术厅发布关于2023年度平台基地及科技基础条件建设、高水平科技期刊建设拟立项目清单的公示&#xff0c;香港科大(广州)申报的广东省通感…

「Spring Cloud Alibaba官方手册」首发爆火,Github上标星243k

几年前 Dubbo被 SpringCloud所取代&#xff0c;相同的剧本&#xff0c;可惜阿里巴巴和 Spring社区都是巨头&#xff0c;巨头之间战斗要考虑很多&#xff0c;于是它们想到了合作&#xff0c; SpringCloud与alibaba相结合&#xff0c;技术上有人负责更新新的组件&#xff0c;也还…

今年面试太难,我凭借这份Java架构面试指南,成功跳槽涨薪10K

见字如面&#xff0c;这里是阿鑫~ 时光飞逝&#xff0c;转眼2022已经快结束了&#xff0c;最近内卷严重&#xff0c;大环境并不是很好&#xff0c;相信很多小伙伴也在准备明年金三银四的面试计划 ​跳槽加薪 职场中加薪有个屡试不爽的方法&#xff0c;那就是跳槽 每每听到周围…

浮点数运算不精确的问题解决和注意事项(BigDecimal)

总结&#xff1a;浮点数运算不精确的问题本质上是在存储的时候就不精确&#xff0c;这个问题会持续到即使使用到专业的工具类BigDecimal来使用时&#xff0c;如果仅仅只是传double类型做入参时依然会导致运算不精确&#xff0c;所以即使在使用BigDecimal工具类进行构造时也要使…

论文浅尝 | Knowledge Graph Contrastive Learning for Recommendation

笔记整理&#xff1a;刘尧锟&#xff0c;天津大学硕士链接&#xff1a;https://arxiv.org/pdf/2205.00976.pdf动机知识图谱已被用作有用的辅助信息来提高推荐质量。在这些推荐系统中&#xff0c;知识图谱信息通常包含丰富的事实和项目之间的内在语义相关性。然而&#xff0c;此…

Python源码学习新手攻略

Python源码学习是许多编程初学者在学习Python过程中十分重要的一个必经步骤&#xff0c;不仅如此&#xff0c;一些有一定开发经验的程序员想要提升自身&#xff0c;也常常需要阅读并学习优秀核心技术栈的源码。那么我们应该如何开始Python源码学习呢&#xff1f;下面小编就来和…

自学Web前端开发学习讲解 – 入门篇

很多人都对web前端感兴趣&#xff0c;这一期主要聊关于如何入门学习Web前端开发的过程分享&#xff0c;此篇适合想入门初学者&#xff0c;大佬就不用看了。主要内容是以本人这一路自学web前端的一些经验和建议&#xff0c;学习哪些知识&#xff0c;以及如何正确的去学&#xff…

AI绘画火爆,到现在还只是冰山一角?AIGC掀起当代新艺术浪潮

前言&#xff1a; hello&#xff0c;大家好我是Dream。近日&#xff0c;各大社交平台掀起了一股“AI绘图”风潮&#xff0c;很多同学朋友纷纷在社交平台上晒出了属于自己的AI照片&#xff0c;一时间AI相关话题热度高涨。那对于AI绘画以及开启AI内容创作新时代的昆仑万维你究竟了…

东北大学2023分布式操作系统考试题目及答案

Note&#xff1a;答案仅供参考&#xff0c;自己所写&#xff0c;不是标准答案&#xff0c;若发现错误&#xff0c;请指正&#xff0c;谢谢&#xff01; 文章目录考试题目参考答案考试题目 1、简述分布式系统的设计目标中开放性的特点有哪些&#xff1f; 、 、 、 、 、 、 、…

​燕东微科创板上市:市值276亿 亦庄国投与京东方是股东

雷递网 雷建平 12月16日北京燕东微电子股份有限公司&#xff08;简称&#xff1a;“燕东微”&#xff0c;股票代码为&#xff1a;“688172”&#xff09;今日在科创板上市&#xff0c;燕东微本次发行17986.5617万股&#xff0c;发行价21.98元&#xff0c;募资总额39.56亿元。燕…

关于hcaptcha (vm wasm ob)三合一

该文章主要提供交流学习使用&#xff0c;请勿利用其进行不当行为&#xff01; 如本篇文章侵犯了贵公司的隐私&#xff0c;请联系我立刻删除&#xff01; 如因滥用解密技术而产生的风险与本人无关&#xff01; 1 Hcaptcha hCaptcha 旨在解决机器学习中最劳动密集型的问题&am…

毕业设计 - 基于 java web的网上花店销售系统设计与实现【源码+论文】

文章目录前言一、项目设计1. 模块设计数据流图功能模块2. 实现效果二、部分源码项目源码前言 今天学长向大家分享一个 毕业设计项目: 网上花店销售系统的设计与实现 一、项目设计 1. 模块设计 数据流图 功能模块 1、首页&#xff08;主界面&#xff09; 提供简洁美观的主界…

Jenkins+Kubernetes企业级DevOps容器云平台

一、Kubernetes在DevOps中的作用 1、DevOps DevOps假导所有新的功能特性可以像流动的水一样,迭代到用户的终端,而水是不能讲流的,为了保证水流的质量,我们就必须在水流动的途中治理,直到最终交付到用户的手中。 DevOps是一套方法论、一系列的原则和实践,其主要目标为帮…