课程说明

  • 了解什么是即时通信
  • 了解探花交友的消息功能
  • 了解即时通信的技术方案
  • 了解环信的即时通讯
  • 实现环信的用户体系集成
  • 实现添加联系人、联系人列表功能
  • 实现点赞列表
  • 实现评论列表
  • 实现喜欢列表
  • 实现公告列表

1、即时通信

1.1、什么是即时通信?

day06-即时通讯功能实现 - 图1

1.2、功能说明

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

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

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

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

day06-即时通讯功能实现 - 图2

day06-即时通讯功能实现 - 图3

day06-即时通讯功能实现 - 图4

2、技术方案

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

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

  • 方案一:

    • 自主实现,从设计到架构,再到实现。
    • 技术方面可以采用:Netty + WebSocket + RocketMQ + MongoDB + Redis + ZooKeeper + MySQL
    • day06-即时通讯功能实现 - 图5
  • 方案二:

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

如何选择呢?

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

探花交友项目选择方案二进行实现。

3、环信

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

day06-即时通讯功能实现 - 图6

day06-即时通讯功能实现 - 图7

3.1、开发简介

平台架构:

day06-即时通讯功能实现 - 图8

集成:

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

day06-即时通讯功能实现 - 图9

探花集成:

3.2、环信Console

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

企业版价格:

day06-即时通讯功能实现 - 图10

创建应用:(注意:注册模式应该勾选授权注册)

day06-即时通讯功能实现 - 图11

创建完成:

day06-即时通讯功能实现 - 图12

4、用户体系集成

4.1、Appkey 数据结构

当您申请了 AppKey 后,会得到一个 xxxx#xxxx 格式的字符串,字符串只能由小写字母数字组成,AppKey是环信应用的唯一标识。前半部分 org_name 是在多租户体系下的唯一租户标识,后半部分 app_name 是租户下的app唯一标识(在环信后台创建一个app时填写的应用 id 即是 app_name )。下述的 REST API 中,/{org_name}/{app_name}的请求,均是针对一个唯一的appkey进行的。目前环信注册的appkey暂不能由用户自己完成删除操作,如果对 APP 删除需要联系环信操作完成。

Appkey xxxx 分隔符 xxxx
环信应用的唯一标识 org_name # app_name

4.2、环信 ID 数据结构

环信作为一个聊天通道,只需要提供环信 ID (也就是 IM 用户名)和密码就够了。

名称 字段名 数据类型 描述
环信 ID username String 在 AppKey 的范围内唯一用户名。
用户密码 password String 用户登录环信使用的密码。

4.3、环信 ID 使用规则

当 APP 和环信集成的时候,需要把 APP 系统内的已有用户和新注册的用户和环信集成,为每个已有用户创建一个环信的账号(环信 ID),并且 APP 有新用户注册的时候,需要同步的在环信中注册。

在注册环信账户的时候,需要注意环信 ID 的规则:

  • 使用英文字母和(或)数字的组合
  • 不能使用中文
  • 不能使用 email 地址
  • 不能使用 UUID
  • 用户ID的长度在255字节以内
  • 中间不能有空格或者井号(#)等特殊字符
  • 允许的用户名正则 “[a-zA-Z0-9_-.]”(a~z大小写字母/数字/下划线/横线/英文句号),其他都不允许 *如果是大写字母会自动转成小写
  • 不区分大小写。系统忽略大小写,认为 AA、Aa、aa、aA 都是一样的。如果系统已经存在了环信 ID 为 AA 的用户,再试图使用 aa 作为环信 ID 注册新用户,系统返回用户名重复,以此类推。但是请注意:环信 ID 在数据上的表现形式还是用户最初注册的形式,注册时候使用的大写就保存大写,是小写就保存小写。即:使用 AA 注册,环信保存的 ID 就是 AA;使用 Aa 注册,环信保存的 ID 就是 Aa,以此类推。

另:本文档中可能会交错使用“环信 ID”和“环信用户名”两个术语,但是请注意,这里两个的意思是一样的。

因为一个用户的环信 ID 和他的在 APP 中的用户名并不需要一致,只需要有一个明确的对应关系。例如,用户名是 example@easemob.com,当这个用户登录到 APP 的时候,可以登录成功之后,再登录环信的服务器,所以这时候,只需要能够从 example@easemob.com 推导出这个用户的环信 ID 即可。

4.4、获取管理员权限

环信提供的 REST API 需要权限才能访问,权限通过发送 HTTP 请求时携带 token 来体现,下面描述获取 token 的方式。说明:API 描述的时候使用到的 {APP 的 client_id} 之类的这种参数需要替换成具体的值。

重要提醒:获取 token 时服务器会返回 token 有效期,具体值参考接口返回的 expires_in 字段值。由于网络延迟等原因,系统不保证 token 在此值表示的有效期内绝对有效,如果发现 token 使用异常请重新获取新的 token,比如“http response code”返回 401。另外,请不要频繁向服务器发送获取 token 的请求,同一账号发送此请求超过一定频率会被服务器封号,切记,切记!!

client_id 和 client_secret 可以在环信管理后台的 APP 详情页面看到。

HTTP Request

day06-即时通讯功能实现 - 图13 /{org_name}/{app_name}/token

Request Headers

参数 说明
Content-Type application/json

Request Body

参数 说明
grant_type client_credentials
client_id App的client_id,可在app详情页找到
client_secret App的client_secret,可在app详情页找到

Response Body

参数 说明
access_token 有效的token字符串
expires_in token 有效时间,以秒为单位,在有效期内不需要重复获取
application 当前 App 的 UUID 值

day06-即时通讯功能实现 - 图14

4.4.1、配置

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

huanxin.properties

  1. tanhua.huanxin.url=http://a1.easemob.com/
  2. tanhua.huanxin.orgName=1105190515097562
  3. tanhua.huanxin.appName=tanhua
  4. tanhua.huanxin.clientId=YXA67ZofwHblEems-_Fh-17T2g
  5. tanhua.huanxin.clientSecret=YXA60r45rNy2Ux5wQ7YYoEPwynHmUZk

说明:这配置在控制台可以找到。

  1. package com.tanhua.sso.config;
  2. import lombok.Data;
  3. import org.springframework.boot.context.properties.ConfigurationProperties;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.context.annotation.PropertySource;
  6. @Configuration
  7. @PropertySource("classpath:huanxin.properties")
  8. @ConfigurationProperties(prefix = "tanhua.huanxin")
  9. @Data
  10. public class HuanXinConfig {
  11. private String url;
  12. private String orgName;
  13. private String appName;
  14. private String clientId;
  15. private String clientSecret;
  16. }

4.4.2、获取token

  1. package com.tanhua.sso.service;
  2. import com.fasterxml.jackson.databind.JsonNode;
  3. import com.fasterxml.jackson.databind.ObjectMapper;
  4. import com.tanhua.sso.config.HuanXinConfig;
  5. import org.apache.commons.lang3.StringUtils;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.boot.context.properties.ConfigurationProperties;
  8. import org.springframework.data.redis.core.RedisTemplate;
  9. import org.springframework.http.ResponseEntity;
  10. import org.springframework.stereotype.Service;
  11. import org.springframework.web.client.RestTemplate;
  12. import java.time.Duration;
  13. import java.util.HashMap;
  14. import java.util.Map;
  15. @Service
  16. public class HuanXinTokenService {
  17. private static final ObjectMapper MAPPER = new ObjectMapper();
  18. @Autowired
  19. private HuanXinConfig huanXinConfig;
  20. @Autowired
  21. private RestTemplate restTemplate;
  22. public static final String REDIS_KEY = "HX_TOKEN";
  23. @Autowired
  24. private RedisTemplate<String, String> redisTemplate;
  25. private String refreshToken() {
  26. String targetUrl = this.huanXinConfig.getUrl() + this.huanXinConfig.getOrgName() + "/" + this.huanXinConfig.getAppName() + "/token";
  27. Map<String, String> param = new HashMap<>();
  28. param.put("grant_type", "client_credentials");
  29. param.put("client_id", this.huanXinConfig.getClientId());
  30. param.put("client_secret", this.huanXinConfig.getClientSecret());
  31. //请求环信接口
  32. ResponseEntity<String> responseEntity =
  33. this.restTemplate.postForEntity(targetUrl, param, String.class);
  34. if (responseEntity.getStatusCodeValue() != 200) {
  35. return null;
  36. }
  37. String body = responseEntity.getBody();
  38. try {
  39. JsonNode jsonNode = MAPPER.readTree(body);
  40. String accessToken = jsonNode.get("access_token").asText();
  41. if (StringUtils.isNotBlank(accessToken)) {
  42. // 将token保存到redis,有效期为5天,环信接口返回的有效期为6天
  43. this.redisTemplate.opsForValue().set(REDIS_KEY, accessToken, Duration.ofDays(5));
  44. return accessToken;
  45. }
  46. } catch (Exception e) {
  47. e.printStackTrace();
  48. }
  49. return null;
  50. }
  51. public String getToken() {
  52. String token = this.redisTemplate.opsForValue().get(REDIS_KEY);
  53. if (StringUtils.isBlank(token)) {
  54. return this.refreshToken();
  55. }
  56. return token;
  57. }
  58. }

4.5、注册环信用户

注册环信用户分为2种,开放注册、授权注册,区别在于开发注册不需要token,授权注册需要token。

我们使用的授权注册:

  1. package com.tanhua.sso.vo;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. @Data
  6. @NoArgsConstructor
  7. @AllArgsConstructor
  8. public class HuanXinUser {
  9. private String username;
  10. private String password;
  11. }
  1. package com.tanhua.sso.service;
  2. import com.fasterxml.jackson.databind.ObjectMapper;
  3. import com.tanhua.sso.config.HuanXinConfig;
  4. import com.tanhua.sso.vo.HuanXinUser;
  5. import org.apache.commons.codec.digest.DigestUtils;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.http.HttpEntity;
  8. import org.springframework.http.HttpHeaders;
  9. import org.springframework.http.ResponseEntity;
  10. import org.springframework.stereotype.Service;
  11. import org.springframework.web.client.RestTemplate;
  12. import java.util.Arrays;
  13. @Service
  14. public class HuanXinService {
  15. private static final ObjectMapper MAPPER = new ObjectMapper();
  16. @Autowired
  17. private HuanXinTokenService huanXinTokenService;
  18. @Autowired
  19. private RestTemplate restTemplate;
  20. @Autowired
  21. private HuanXinConfig huanXinConfig;
  22. /**
  23. * 注册环信用户
  24. *
  25. * @param userId
  26. * @return
  27. */
  28. public boolean register(Long userId) {
  29. String targetUrl = this.huanXinConfig.getUrl()
  30. + this.huanXinConfig.getOrgName() + "/"
  31. + this.huanXinConfig.getAppName() + "/users";
  32. String token = this.huanXinTokenService.getToken();
  33. try {
  34. // 请求体
  35. HuanXinUser huanXinUser = new HuanXinUser(String.valueOf(userId), DigestUtils.md5Hex(userId + "_itcast_tanhua"));
  36. String body = MAPPER.writeValueAsString(Arrays.asList(huanXinUser));
  37. // 请求头
  38. HttpHeaders headers = new HttpHeaders();
  39. headers.add("Content-Type", "application/json");
  40. headers.add("Authorization", "Bearer " + token);
  41. HttpEntity<String> httpEntity = new HttpEntity<>(body, headers);
  42. ResponseEntity<String> responseEntity = this.restTemplate.postForEntity(targetUrl, httpEntity, String.class);
  43. return responseEntity.getStatusCodeValue() == 200;
  44. } catch (Exception e) {
  45. e.printStackTrace();
  46. }
  47. // 注册失败
  48. return false;
  49. }
  50. }

加入到登录逻辑中:

day06-即时通讯功能实现 - 图15

4.6、测试

day06-即时通讯功能实现 - 图16

可以看到已经注册到了环信。

4.7、查询环信用户信息

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

mock地址: https://mock.boxuegu.com/project/164/interface/api/66955 day06-即时通讯功能实现 - 图17

实现:

  1. package com.tanhua.server.controller;
  2. import com.tanhua.server.pojo.User;
  3. import com.tanhua.server.utils.UserThreadLocal;
  4. import com.tanhua.server.vo.HuanXinUser;
  5. import org.apache.commons.codec.digest.DigestUtils;
  6. import org.springframework.http.ResponseEntity;
  7. import org.springframework.web.bind.annotation.GetMapping;
  8. import org.springframework.web.bind.annotation.RequestMapping;
  9. import org.springframework.web.bind.annotation.RestController;
  10. @RestController
  11. @RequestMapping("huanxin")
  12. public class HuanXinController {
  13. @GetMapping("user")
  14. public ResponseEntity<HuanXinUser> queryHuanXinUser(){
  15. User user = UserThreadLocal.get();
  16. HuanXinUser huanXinUser = new HuanXinUser();
  17. huanXinUser.setUsername(user.getId().toString());
  18. huanXinUser.setPassword(DigestUtils.md5Hex(user.getId() + "_itcast_tanhua"));
  19. return ResponseEntity.ok(huanXinUser);
  20. }
  21. }

测试: day06-即时通讯功能实现 - 图18

4.8、发送消息给客户端

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

day06-即时通讯功能实现 - 图19

点击“聊一下”,就会给对方发送一条陌生人信息,这个消息由系统发送完成。

我们暂时通过环信的控制台进行发送: day06-即时通讯功能实现 - 图20

消息内容:

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

day06-即时通讯功能实现 - 图21

day06-即时通讯功能实现 - 图22

day06-即时通讯功能实现 - 图23

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

5、 添加联系人

点击“聊一下”,就会成为联系人(好友)。

实现:

  • 将好友写入到MongoDB中
  • 将好友关系注册到环信

5.1、mock接口

地址: https://mock.boxuegu.com/project/164/interface/api/77980

day06-即时通讯功能实现 - 图24

5.2、定义dubbo服务

  1. package com.tanhua.dubbo.server.pojo;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. import org.bson.types.ObjectId;
  6. import org.springframework.data.mongodb.core.mapping.Document;
  7. import java.util.Date;
  8. @Data
  9. @NoArgsConstructor
  10. @AllArgsConstructor
  11. @Document(collection = "tanhua_users")
  12. public class Users implements java.io.Serializable{
  13. private static final long serialVersionUID = 6003135946820874230L;
  14. private ObjectId id;
  15. private Long userId; //用户id
  16. private Long friendId; //好友id
  17. private Long date; //时间
  18. }
  1. package com.tanhua.dubbo.server.api;
  2. import com.tanhua.dubbo.server.pojo.Users;
  3. public interface UsersApi {
  4. /**
  5. * 保存好友
  6. *
  7. * @param users
  8. * @return
  9. */
  10. String saveUsers(Users users);
  11. /**
  12. * 删除好友数据
  13. *
  14. * @param users
  15. * @return
  16. */
  17. boolean removeUsers(Users users);
  18. }

实现:

  1. package com.tanhua.dubbo.server.api;
  2. import com.alibaba.dubbo.config.annotation.Service;
  3. import com.tanhua.dubbo.server.pojo.Users;
  4. import org.bson.types.ObjectId;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.data.mongodb.core.MongoTemplate;
  7. import org.springframework.data.mongodb.core.query.Criteria;
  8. import org.springframework.data.mongodb.core.query.Query;
  9. @Service(version = "1.0.0")
  10. public class UsersApiImpl implements UsersApi {
  11. @Autowired
  12. private MongoTemplate mongoTemplate;
  13. @Override
  14. public String saveUsers(Users users) {
  15. if (users.getFriendId() == null || users.getUserId() == null) {
  16. return null;
  17. }
  18. Long userId = users.getUserId();
  19. Long friendId = users.getFriendId();
  20. // 检测是否该好友关系是否存在
  21. Query query = Query.query(Criteria.where("userId").is(userId).and("friendId").is(friendId));
  22. Users oldUsers = this.mongoTemplate.findOne(query, Users.class);
  23. if (null != oldUsers) {
  24. return null;
  25. }
  26. users.setId(ObjectId.get());
  27. users.setDate(System.currentTimeMillis());
  28. //注册我与好友的关系
  29. this.mongoTemplate.save(users);
  30. //注册好友与我的关系
  31. users.setId(ObjectId.get());
  32. users.setUserId(friendId);
  33. users.setFriendId(userId);
  34. this.mongoTemplate.save(users);
  35. return users.getId().toHexString();
  36. }
  37. @Override
  38. public boolean removeUsers(Users users) {
  39. Long userId = users.getUserId();
  40. Long friendId = users.getFriendId();
  41. Query query1 = Query.query(Criteria.where("userId").is(userId)
  42. .and("friendId").is(friendId));
  43. //删除我与好友的关系数据
  44. long count1 = this.mongoTemplate.remove(query1, Users.class).getDeletedCount();
  45. Query query2 = Query.query(Criteria.where("userId").is(friendId)
  46. .and("friendId").is(userId));
  47. //删除好友与我的关系数据
  48. long count2 = this.mongoTemplate.remove(query2, Users.class).getDeletedCount();
  49. return count1 > 0 && count2 > 0;
  50. }
  51. }

5.3、注册好友到环信

对接环信api的操作在sso工程中完成。

  1. package com.tanhua.sso.controller;
  2. import com.tanhua.sso.service.HuanXinService;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.http.HttpStatus;
  5. import org.springframework.http.ResponseEntity;
  6. import org.springframework.web.bind.annotation.PathVariable;
  7. import org.springframework.web.bind.annotation.PostMapping;
  8. import org.springframework.web.bind.annotation.RequestMapping;
  9. import org.springframework.web.bind.annotation.RestController;
  10. @RestController
  11. @RequestMapping("user/huanxin")
  12. public class HuanXinController {
  13. @Autowired
  14. private HuanXinService huanXinService;
  15. /**
  16. * 添加联系人
  17. *
  18. * @param userId
  19. * @param friendId
  20. * @return
  21. */
  22. @PostMapping("contacts/{owner_username}/{friend_username}")
  23. public ResponseEntity<Void> contactUsers(@PathVariable("owner_username") Long userId,
  24. @PathVariable("friend_username") Long friendId) {
  25. try {
  26. boolean result = this.huanXinService.contactUsers(userId, friendId);
  27. if (result) {
  28. return ResponseEntity.ok(null);
  29. }
  30. } catch (Exception e) {
  31. e.printStackTrace();
  32. }
  33. return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
  34. }
  35. }
  1. package com.tanhua.sso.service;
  2. import com.fasterxml.jackson.databind.ObjectMapper;
  3. import com.tanhua.sso.config.HuanXinConfig;
  4. import com.tanhua.sso.vo.HuanXinUser;
  5. import org.apache.commons.codec.digest.DigestUtils;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.http.HttpEntity;
  8. import org.springframework.http.HttpHeaders;
  9. import org.springframework.http.ResponseEntity;
  10. import org.springframework.stereotype.Service;
  11. import org.springframework.web.client.RestTemplate;
  12. import java.util.Arrays;
  13. @Service
  14. public class HuanXinService {
  15. private static final ObjectMapper MAPPER = new ObjectMapper();
  16. @Autowired
  17. private HuanXinTokenService huanXinTokenService;
  18. @Autowired
  19. private RestTemplate restTemplate;
  20. @Autowired
  21. private HuanXinConfig huanXinConfig;
  22. /**
  23. * 添加好友
  24. *
  25. * @param userId
  26. * @param friendId
  27. * @return
  28. */
  29. public boolean contactUsers(Long userId, Long friendId) {
  30. String targetUrl = this.huanXinConfig.getUrl()
  31. + this.huanXinConfig.getOrgName() + "/"
  32. + this.huanXinConfig.getAppName() + "/users/" +
  33. userId + "/contacts/users/" + friendId;
  34. try {
  35. String token = this.huanXinTokenService.getToken();
  36. // 请求头
  37. HttpHeaders headers = new HttpHeaders();
  38. headers.add("Authorization", "Bearer " + token);
  39. HttpEntity<String> httpEntity = new HttpEntity<>(headers);
  40. ResponseEntity<String> responseEntity = this.restTemplate.postForEntity(targetUrl, httpEntity, String.class);
  41. return responseEntity.getStatusCodeValue() == 200;
  42. } catch (Exception e) {
  43. e.printStackTrace();
  44. }
  45. // 添加失败
  46. return false;
  47. }
  48. }

5.4、编写服务

在itcast-tanhua-server中完成。

  1. package com.tanhua.server.controller;
  2. import com.tanhua.server.service.IMService;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.http.HttpStatus;
  7. import org.springframework.http.ResponseEntity;
  8. import org.springframework.web.bind.annotation.PostMapping;
  9. import org.springframework.web.bind.annotation.RequestBody;
  10. import org.springframework.web.bind.annotation.RequestMapping;
  11. import org.springframework.web.bind.annotation.RestController;
  12. import java.util.Map;
  13. @RestController
  14. @RequestMapping("messages")
  15. public class IMController {
  16. private static final Logger LOGGER = LoggerFactory.getLogger(IMController.class);
  17. @Autowired
  18. private IMService imService;
  19. /**
  20. * 添加好友
  21. *
  22. * @param param
  23. * @return
  24. */
  25. @PostMapping("contacts")
  26. public ResponseEntity<Void> contactUser(@RequestBody Map<String, Object> param) {
  27. try {
  28. Long userId = Long.valueOf(param.get("userId").toString());
  29. boolean result = this.imService.contactUser(userId);
  30. if (result) {
  31. return ResponseEntity.ok(null);
  32. }
  33. } catch (Exception e) {
  34. LOGGER.error("添加联系人失败! param = " + param, e);
  35. }
  36. return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
  37. }
  38. }
  1. package com.tanhua.server.service;
  2. import com.alibaba.dubbo.common.utils.StringUtils;
  3. import com.alibaba.dubbo.config.annotation.Reference;
  4. import com.tanhua.dubbo.server.api.UsersApi;
  5. import com.tanhua.dubbo.server.pojo.Users;
  6. import com.tanhua.server.pojo.User;
  7. import com.tanhua.server.utils.UserThreadLocal;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.beans.factory.annotation.Value;
  10. import org.springframework.http.ResponseEntity;
  11. import org.springframework.stereotype.Service;
  12. import org.springframework.web.client.RestTemplate;
  13. @Service
  14. public class IMService {
  15. @Reference(version = "1.0.0")
  16. private UsersApi usersApi;
  17. @Autowired
  18. private RestTemplate restTemplate;
  19. @Value("${tanhua.sso.url}")
  20. private String url;
  21. /**
  22. * 添加好友
  23. *
  24. * @param userId
  25. */
  26. public boolean contactUser(Long userId) {
  27. User user = UserThreadLocal.get();
  28. Users users = new Users();
  29. users.setUserId(user.getId());
  30. users.setFriendId(userId);
  31. String id = this.usersApi.saveUsers(users);
  32. if (StringUtils.isNotEmpty(id)) {
  33. //注册好友关系到环信
  34. try {
  35. String targetUrl = url + "/user/huanxin/contacts/" + users.getUserId() + "/" + users.getFriendId();
  36. ResponseEntity<Void> responseEntity = this.restTemplate.postForEntity(targetUrl, null, Void.class);
  37. if (responseEntity.getStatusCode().is2xxSuccessful()) {
  38. return true;
  39. }
  40. } catch (Exception e) {
  41. //添加好友失败,删除Mongodb中的好友数据
  42. this.usersApi.removeUsers(users);
  43. log.error("添加环信好友失败!userId = "+ user.getId()+", friendId = " + userId);
  44. }
  45. return false;
  46. }
  47. return false;
  48. }
  49. }

5.5、测试

day06-即时通讯功能实现 - 图25

day06-即时通讯功能实现 - 图26

可以看到好友已经添加成功。

6、联系人列表

6.1、mock接口

day06-即时通讯功能实现 - 图27

响应数据结构:

day06-即时通讯功能实现 - 图28

6.2、定义Contacts

  1. package com.tanhua.server.vo;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. @Data
  6. @NoArgsConstructor
  7. @AllArgsConstructor
  8. public class Contacts {
  9. private Long id;
  10. private String userId; //好友的id
  11. private String avatar; //好友头像
  12. private String nickname; //好友昵称
  13. private String gender; //好友性别
  14. private Integer age; //好友年龄
  15. private String city; //所在城市
  16. }

6.4、dubbo接口

  1. package com.tanhua.dubbo.server.api;
  2. import com.tanhua.dubbo.server.pojo.Users;
  3. import com.tanhua.dubbo.server.vo.PageInfo;
  4. import java.util.List;
  5. public interface UsersApi {
  6. /**
  7. * 保存好友
  8. *
  9. * @param users
  10. * @return
  11. */
  12. String saveUsers(Users users);
  13. /**
  14. * 根据用户id查询Users列表
  15. *
  16. * @param userId
  17. * @return
  18. */
  19. List<Users> queryAllUsersList(Long userId);
  20. /**
  21. * 根据用户id查询Users列表(分页查询)
  22. *
  23. * @param userId
  24. * @return
  25. */
  26. PageInfo<Users> queryUsersList(Long userId, Integer page, Integer pageSize);
  27. }

实现:

  1. package com.tanhua.dubbo.server.api;
  2. import com.alibaba.dubbo.config.annotation.Service;
  3. import com.tanhua.dubbo.server.pojo.Publish;
  4. import com.tanhua.dubbo.server.pojo.Users;
  5. import com.tanhua.dubbo.server.vo.PageInfo;
  6. import org.bson.types.ObjectId;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.data.domain.PageRequest;
  9. import org.springframework.data.domain.Sort;
  10. import org.springframework.data.mongodb.core.MongoTemplate;
  11. import org.springframework.data.mongodb.core.query.Criteria;
  12. import org.springframework.data.mongodb.core.query.Query;
  13. import java.util.List;
  14. @Service(version = "1.0.0")
  15. public class UsersApiImpl implements UsersApi {
  16. @Autowired
  17. private MongoTemplate mongoTemplate;
  18. @Override
  19. public List<Users> queryAllUsersList(Long userId) {
  20. Query query = Query.query(Criteria.where("userId").is(userId));
  21. return this.mongoTemplate.find(query, Users.class);
  22. }
  23. @Override
  24. public PageInfo<Users> queryUsersList(Long userId, Integer page, Integer pageSize) {
  25. PageRequest pageRequest = PageRequest.of(page - 1, pageSize, Sort.by(Sort.Order.desc("created")));
  26. Query query = Query.query(Criteria.where("userId").is(userId)).with(pageRequest);
  27. List<Users> usersList = this.mongoTemplate.find(query, Users.class);
  28. PageInfo<Users> pageInfo = new PageInfo<>();
  29. pageInfo.setPageNum(page);
  30. pageInfo.setPageSize(pageSize);
  31. pageInfo.setRecords(usersList);
  32. pageInfo.setTotal(0); //不提供总数
  33. return pageInfo;
  34. }
  35. }

6.5、编写接口服务

  1. package com.tanhua.server.controller;
  2. import com.tanhua.dubbo.server.vo.PageInfo;
  3. import com.tanhua.server.service.IMService;
  4. import com.tanhua.server.vo.Contacts;
  5. import com.tanhua.server.vo.PageResult;
  6. import org.slf4j.Logger;
  7. import org.slf4j.LoggerFactory;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.http.HttpStatus;
  10. import org.springframework.http.ResponseEntity;
  11. import org.springframework.web.bind.annotation.*;
  12. import java.util.Map;
  13. @RestController
  14. @RequestMapping("messages")
  15. public class IMController {
  16. private static final Logger LOGGER = LoggerFactory.getLogger(IMController.class);
  17. @Autowired
  18. private IMService imService;
  19. /**
  20. * 查询联系人列表
  21. *
  22. * @param page
  23. * @param pageSize
  24. * @param keyword
  25. * @return
  26. */
  27. @GetMapping("contacts")
  28. public ResponseEntity<PageResult> queryContactsList(@RequestParam(value = "page", defaultValue = "1") Integer page,
  29. @RequestParam(value = "pagesize", defaultValue = "10") Integer pageSize,
  30. @RequestParam(value = "keyword", required = false) String keyword) {
  31. PageResult pageResult = this.imService.queryContactsList(page, pageSize, keyword);
  32. return ResponseEntity.ok(pageResult);
  33. }
  34. }
  1. package com.tanhua.server.service;
  2. import com.alibaba.dubbo.config.annotation.Reference;
  3. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  4. import com.tanhua.dubbo.server.api.UsersApi;
  5. import com.tanhua.dubbo.server.pojo.Users;
  6. import com.tanhua.dubbo.server.vo.PageInfo;
  7. import com.tanhua.server.pojo.User;
  8. import com.tanhua.server.pojo.UserInfo;
  9. import com.tanhua.server.utils.UserThreadLocal;
  10. import com.tanhua.server.vo.Contacts;
  11. import com.tanhua.server.vo.PageResult;
  12. import org.apache.commons.lang3.StringUtils;
  13. import org.springframework.beans.factory.annotation.Autowired;
  14. import org.springframework.beans.factory.annotation.Value;
  15. import org.springframework.http.ResponseEntity;
  16. import org.springframework.stereotype.Service;
  17. import org.springframework.web.client.RestTemplate;
  18. import java.util.ArrayList;
  19. import java.util.List;
  20. @Service
  21. public class IMService {
  22. @Reference(version = "1.0.0")
  23. private UsersApi usersApi;
  24. @Autowired
  25. private RestTemplate restTemplate;
  26. @Value("${tanhua.sso.url}")
  27. private String url;
  28. @Autowired
  29. private UserInfoService userInfoService;
  30. public PageResult queryContactsList(Integer page, Integer pageSize, String keyword) {
  31. User user = UserThreadLocal.get();
  32. List<Users> usersList = null;
  33. if (StringUtils.isNotEmpty(keyword)) {
  34. //关键不为空,查询所有的好友,在后面进行关键字过滤
  35. usersList = this.usersApi.queryAllUsersList(user.getId());
  36. } else {
  37. //关键字为空,进行分页查询
  38. PageInfo<Users> usersPageInfo = this.usersApi.queryUsersList(user.getId(), page, pageSize);
  39. usersList = usersPageInfo.getRecords();
  40. }
  41. List<Long> userIds = new ArrayList<>();
  42. for (Users users : usersList) {
  43. userIds.add(users.getFriendId());
  44. }
  45. QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
  46. queryWrapper.in("user_id", userIds);
  47. if (StringUtils.isNotEmpty(keyword)) {
  48. queryWrapper.like("nick_name", keyword);
  49. }
  50. List<UserInfo> userInfoList = this.userInfoService.queryUserInfoList(queryWrapper);
  51. List<Contacts> contactsList = new ArrayList<>();
  52. //填充用户信息
  53. for (UserInfo userInfo : userInfoList) {
  54. Contacts contacts = new Contacts();
  55. contacts.setAge(userInfo.getAge());
  56. contacts.setAvatar(userInfo.getLogo());
  57. contacts.setGender(userInfo.getSex().name().toLowerCase());
  58. contacts.setNickname(userInfo.getNickName());
  59. contacts.setUserId(String.valueOf(userInfo.getUserId()));
  60. contacts.setCity(StringUtils.substringBefore(userInfo.getCity(), "-"));
  61. contactsList.add(contacts);
  62. }
  63. PageResult pageResult = new PageResult();
  64. pageResult.setPage(page);
  65. pageResult.setPages(0);
  66. pageResult.setCounts(0);
  67. pageResult.setPagesize(pageSize);
  68. pageResult.setItems(contactsList);
  69. return pageResult;
  70. }
  71. }

6.6、测试

day06-即时通讯功能实现 - 图29

day06-即时通讯功能实现 - 图30

day06-即时通讯功能实现 - 图31

7、点赞列表

7.1、mock接口

地址: https://mock.boxuegu.com/project/164/interface/api/63966

day06-即时通讯功能实现 - 图32

day06-即时通讯功能实现 - 图33

7.2、MessageLike

根据接口定义vo对象。

  1. package com.tanhua.server.vo;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. @Data
  6. @NoArgsConstructor
  7. @AllArgsConstructor
  8. public class MessageLike {
  9. private String id;
  10. private String avatar;
  11. private String nickname;
  12. private String createDate;
  13. }

7.3、dubbo接口

  1. //QuanZiApi
  2. /**
  3. * 查询用户的评论数据
  4. *
  5. * @return
  6. */
  7. PageInfo<Comment> queryCommentListByUser(Long userId, Integer type, Integer page, Integer pageSize);

实现:

  1. @Override
  2. public PageInfo<Comment> queryCommentListByUser(Long userId, Integer type, Integer page, Integer pageSize) {
  3. PageRequest pageRequest = PageRequest.of(page - 1, pageSize, Sort.by(Sort.Order.desc("created")));
  4. //根据用户id和类型查询评论表
  5. Query query = new Query(Criteria
  6. .where("userId").is(userId)
  7. .and("commentType").is(type)).with(pageRequest);
  8. List<Comment> commentList = this.mongoTemplate.find(query, Comment.class);
  9. //封装数据
  10. PageInfo<Comment> pageInfo = new PageInfo<>();
  11. pageInfo.setPageNum(page);
  12. pageInfo.setPageSize(pageSize);
  13. pageInfo.setRecords(commentList);
  14. pageInfo.setTotal(0); //不提供总数
  15. return pageInfo;
  16. }

7.4、编写接口服务

  1. package com.tanhua.server.controller;
  2. import com.tanhua.dubbo.server.vo.PageInfo;
  3. import com.tanhua.server.service.IMService;
  4. import com.tanhua.server.vo.Contacts;
  5. import com.tanhua.server.vo.PageResult;
  6. import org.slf4j.Logger;
  7. import org.slf4j.LoggerFactory;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.http.HttpStatus;
  10. import org.springframework.http.ResponseEntity;
  11. import org.springframework.web.bind.annotation.*;
  12. import java.util.Map;
  13. @RestController
  14. @RequestMapping("messages")
  15. public class IMController {
  16. private static final Logger LOGGER = LoggerFactory.getLogger(IMController.class);
  17. @Autowired
  18. private IMService imService;
  19. /**
  20. * 查询点赞列表
  21. *
  22. * @param page
  23. * @param pageSize
  24. * @return
  25. */
  26. @GetMapping("likes")
  27. public ResponseEntity<PageResult> queryMessageLikeList(@RequestParam(value = "page", defaultValue = "1") Integer page,
  28. @RequestParam(value = "pagesize", defaultValue = "10") Integer pageSize) {
  29. PageResult pageResult = this.imService.queryMessageLikeList(page, pageSize);
  30. return ResponseEntity.ok(pageResult);
  31. }
  32. }
  1. package com.tanhua.server.service;
  2. import com.alibaba.dubbo.config.annotation.Reference;
  3. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  4. import com.tanhua.dubbo.server.api.QuanZiApi;
  5. import com.tanhua.dubbo.server.api.UsersApi;
  6. import com.tanhua.dubbo.server.pojo.Comment;
  7. import com.tanhua.dubbo.server.pojo.Users;
  8. import com.tanhua.dubbo.server.vo.PageInfo;
  9. import com.tanhua.server.pojo.User;
  10. import com.tanhua.server.pojo.UserInfo;
  11. import com.tanhua.server.utils.UserThreadLocal;
  12. import com.tanhua.server.vo.Contacts;
  13. import com.tanhua.server.vo.MessageLike;
  14. import com.tanhua.server.vo.PageResult;
  15. import org.apache.commons.lang3.StringUtils;
  16. import org.joda.time.DateTime;
  17. import org.springframework.beans.factory.annotation.Autowired;
  18. import org.springframework.beans.factory.annotation.Value;
  19. import org.springframework.http.ResponseEntity;
  20. import org.springframework.stereotype.Service;
  21. import org.springframework.web.client.RestTemplate;
  22. import java.util.ArrayList;
  23. import java.util.List;
  24. @Service
  25. public class IMService {
  26. @Reference(version = "1.0.0")
  27. private UsersApi usersApi;
  28. @Autowired
  29. private RestTemplate restTemplate;
  30. @Value("${tanhua.sso.url}")
  31. private String url;
  32. @Autowired
  33. private UserInfoService userInfoService;
  34. @Reference(version = "1.0.0")
  35. private QuanZiApi quanZiApi;
  36. public PageResult queryMessageLikeList(Integer page, Integer pageSize) {
  37. User user = UserThreadLocal.get();
  38. PageInfo<Comment> pageInfo = this.quanZiApi.queryCommentListByUser(user.getId(), 1, page, pageSize);
  39. PageResult pageResult = new PageResult();
  40. pageResult.setPage(page);
  41. pageResult.setPages(0);
  42. pageResult.setCounts(0);
  43. pageResult.setPagesize(pageSize);
  44. List<Comment> records = pageInfo.getRecords();
  45. List<Long> userIds = new ArrayList<>();
  46. for (Comment comment : records) {
  47. userIds.add(comment.getUserId());
  48. }
  49. QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
  50. queryWrapper.in("user_id", userIds);
  51. List<UserInfo> userInfoList = this.userInfoService.queryList(queryWrapper);
  52. List<MessageLike> messageLikeList = new ArrayList<>();
  53. for (Comment record : records) {
  54. for (UserInfo userInfo : userInfoList) {
  55. if(userInfo.getUserId().longValue() == record.getUserId().longValue()){
  56. MessageLike messageLike = new MessageLike();
  57. messageLike.setId(record.getId().toHexString());
  58. messageLike.setAvatar(userInfo.getLogo());
  59. messageLike.setNickname(userInfo.getNickName());
  60. messageLike.setCreateDate(new DateTime(record.getCreated()).toString("yyyy-MM-dd HH:mm"));
  61. messageLikeList.add(messageLike);
  62. break;
  63. }
  64. }
  65. }
  66. pageResult.setItems(messageLikeList);
  67. return pageResult;
  68. }
  69. }

7.5、测试

day06-即时通讯功能实现 - 图34

day06-即时通讯功能实现 - 图35

8、评论、喜欢列表

8.1、IMController

  1. /**
  2. * 查询评论列表
  3. *
  4. * @param page
  5. * @param pageSize
  6. * @return
  7. */
  8. @GetMapping("comments")
  9. public ResponseEntity<PageResult> queryMessageCommentList(@RequestParam(value = "page", defaultValue = "1") Integer page,
  10. @RequestParam(value = "pagesize", defaultValue = "10") Integer pageSize) {
  11. PageResult pageResult = this.imService.queryMessageCommentList(page, pageSize);
  12. return ResponseEntity.ok(pageResult);
  13. }
  14. /**
  15. * 查询喜欢列表
  16. *
  17. * @param page
  18. * @param pageSize
  19. * @return
  20. */
  21. @GetMapping("loves")
  22. public ResponseEntity<PageResult> queryMessageLoveList(@RequestParam(value = "page", defaultValue = "1") Integer page,
  23. @RequestParam(value = "pagesize", defaultValue = "10") Integer pageSize) {
  24. PageResult pageResult = this.imService.queryMessageLoveList(page, pageSize);
  25. return ResponseEntity.ok(pageResult);
  26. }

8.2、IMService

  1. public PageResult queryMessageLikeList(Integer page, Integer pageSize) {
  2. return this.messageCommentList(1, page, pageSize);
  3. }
  4. public PageResult queryMessageCommentList(Integer page, Integer pageSize) {
  5. return this.messageCommentList(2, page, pageSize);
  6. }
  7. public PageResult queryMessageLoveList(Integer page, Integer pageSize) {
  8. return this.messageCommentList(3, page, pageSize);
  9. }
  10. private PageResult messageCommentList(Integer type, Integer page, Integer pageSize) {
  11. User user = UserThreadLocal.get();
  12. PageInfo<Comment> pageInfo = this.quanZiApi.queryCommentListByUser(user.getId(), type, page, pageSize);
  13. PageResult pageResult = new PageResult();
  14. pageResult.setPage(page);
  15. pageResult.setPages(0);
  16. pageResult.setCounts(0);
  17. pageResult.setPagesize(pageSize);
  18. List<Comment> records = pageInfo.getRecords();
  19. List<Long> userIds = new ArrayList<>();
  20. for (Comment comment : records) {
  21. userIds.add(comment.getUserId());
  22. }
  23. QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
  24. queryWrapper.in("user_id", userIds);
  25. List<UserInfo> userInfoList = this.userInfoService.queryList(queryWrapper);
  26. List<MessageLike> messageLikeList = new ArrayList<>();
  27. for (Comment record : records) {
  28. for (UserInfo userInfo : userInfoList) {
  29. if (userInfo.getUserId().longValue() == record.getUserId().longValue()) {
  30. MessageLike messageLike = new MessageLike();
  31. messageLike.setId(record.getId().toHexString());
  32. messageLike.setAvatar(userInfo.getLogo());
  33. messageLike.setNickname(userInfo.getNickName());
  34. messageLike.setCreateDate(new DateTime(record.getCreated()).toString("yyyy-MM-dd HH:mm"));
  35. messageLikeList.add(messageLike);
  36. break;
  37. }
  38. }
  39. }
  40. pageResult.setItems(messageLikeList);
  41. return pageResult;
  42. }

8.3、解决bug

点赞、评论、喜欢列表应该是别人对我发布的信息做了操作之后显示的数据,所以查询条件是发布人的id作为查询条件。

第一步:修改Comment对象,增加 publishUserId 字段。

  1. package com.tanhua.dubbo.server.pojo;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. import org.bson.types.ObjectId;
  6. import org.springframework.data.mongodb.core.mapping.Document;
  7. import java.util.Date;
  8. /**
  9. * 评论表
  10. */
  11. @Data
  12. @NoArgsConstructor
  13. @AllArgsConstructor
  14. @Document(collection = "quanzi_comment")
  15. public class Comment implements java.io.Serializable{
  16. private static final long serialVersionUID = -291788258125767614L;
  17. private ObjectId id;
  18. private ObjectId publishId; //发布id
  19. private Integer commentType; //评论类型,1-点赞,2-评论,3-喜欢
  20. private String content; //评论内容
  21. private Long userId; //评论人
  22. private Long publishUserId; //发布人的用户id
  23. private Boolean isParent = false; //是否为父节点,默认是否
  24. private ObjectId parentId; // 父节点id
  25. private Long created; //发表时间
  26. }

第二步:修改保存Comment逻辑

  1. @Override
  2. public boolean saveComment(Long userId, String publishId, Integer type, String content) {
  3. try {
  4. Comment comment = new Comment();
  5. comment.setContent(content);
  6. comment.setIsParent(true);
  7. comment.setCommentType(type);
  8. comment.setPublishId(new ObjectId(publishId));
  9. comment.setUserId(userId);
  10. comment.setId(ObjectId.get());
  11. comment.setCreated(System.currentTimeMillis());
  12. // 设置发布人的id
  13. Publish publish = this.mongoTemplate.findById(comment.getPublishId(), Publish.class);
  14. if (null != publish) {
  15. comment.setPublishUserId(publish.getUserId());
  16. } else {
  17. Video video = this.mongoTemplate.findById(comment.getPublishId(), Video.class);
  18. if (null != video) {
  19. comment.setPublishUserId(video.getUserId());
  20. }
  21. }
  22. this.mongoTemplate.save(comment);
  23. return true;
  24. } catch (Exception e) {
  25. e.printStackTrace();
  26. }
  27. return false;
  28. }

第三步,修改查询条件

  1. @Override
  2. public PageInfo<Comment> queryCommentListByUser(Long userId, Integer type, Integer page, Integer pageSize) {
  3. PageRequest pageRequest = PageRequest.of(page - 1, pageSize, Sort.by(Sort.Order.desc("created")));
  4. Query query = new Query(Criteria
  5. .where("publishUserId").is(userId)
  6. .and("commentType").is(type)).with(pageRequest);
  7. List<Comment> commentList = this.mongoTemplate.find(query, Comment.class);
  8. PageInfo<Comment> pageInfo = new PageInfo<>();
  9. pageInfo.setPageNum(page);
  10. pageInfo.setPageSize(pageSize);
  11. pageInfo.setRecords(commentList);
  12. pageInfo.setTotal(0); //不提供总数
  13. return pageInfo;
  14. }

9、公告列表

公告是后台系统对所有用户发布的公告消息。

9.1、表结构

  1. CREATE TABLE `tb_announcement` (
  2. `id` bigint(20) NOT NULL AUTO_INCREMENT,
  3. `title` varchar(200) DEFAULT NULL COMMENT '标题',
  4. `description` text COMMENT '描述',
  5. `created` datetime DEFAULT NULL,
  6. `updated` datetime DEFAULT NULL,
  7. PRIMARY KEY (`id`),
  8. KEY `created` (`created`)
  9. ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='公告表';
  1. --插入数据
  2. INSERT INTO `tb_announcement` (`id`, `title`, `description`, `created`, `updated`) VALUES ('1', '探花新版本上线发布啦~,盛夏high趴开始了,赶紧来报名吧!', '探花App2019年7月23日起在苹果商店…,浓情夏日,清爽一聚,探花将吧大家聚…', '2019-10-14 11:06:34', '2019-10-14 11:06:37');
  3. INSERT INTO `tb_announcement` (`id`, `title`, `description`, `created`, `updated`) VALUES ('2', '探花交友的圈子功能正式上线啦~~', '探花交友的圈子功能正式上线啦,欢迎使用~', '2019-10-14 11:09:31', '2019-10-14 11:09:33');
  4. INSERT INTO `tb_announcement` (`id`, `title`, `description`, `created`, `updated`) VALUES ('3', '国庆放假期间,探花交友正常使用~', '国庆放假期间,探花交友正常使用~', '2019-10-14 11:10:01', '2019-10-14 11:10:04');

9.2、pojo

  1. package com.tanhua.server.pojo;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. @Data
  6. @NoArgsConstructor
  7. @AllArgsConstructor
  8. public class Announcement extends BasePojo {
  9. private Long id;
  10. private String title;
  11. private String description;
  12. }

9.3、AnnouncementMapper

  1. package com.tanhua.server.mapper;
  2. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
  3. import com.tanhua.server.pojo.Announcement;
  4. public interface AnnouncementMapper extends BaseMapper<Announcement> {
  5. }

9.4、AnnouncementService

  1. package com.tanhua.server.service;
  2. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  3. import com.baomidou.mybatisplus.core.metadata.IPage;
  4. import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
  5. import com.tanhua.server.mapper.AnnouncementMapper;
  6. import com.tanhua.server.pojo.Announcement;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.stereotype.Service;
  9. @Service
  10. public class AnnouncementService {
  11. @Autowired
  12. private AnnouncementMapper announcementMapper;
  13. public IPage<Announcement> queryList(Integer page, Integer pageSize) {
  14. QueryWrapper queryWrapper = new QueryWrapper();
  15. queryWrapper.orderByDesc("created");
  16. return this.announcementMapper.selectPage(new Page<Announcement>(page, pageSize), queryWrapper);
  17. }
  18. }

9.5、定义vo对象

  1. package com.tanhua.server.vo;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. @Data
  6. @NoArgsConstructor
  7. @AllArgsConstructor
  8. public class MessageAnnouncement {
  9. private String id;
  10. private String title;
  11. private String description;
  12. private String createDate;
  13. }

9.6、IMController

  1. /**
  2. * 查询公告列表
  3. *
  4. * @param page
  5. * @param pageSize
  6. * @return
  7. */
  8. @GetMapping("announcements")
  9. @NoAuthorization //优化,无需进行token校验
  10. public ResponseEntity<PageResult> queryMessageAnnouncementList(@RequestParam(value = "page", defaultValue = "1") Integer page,
  11. @RequestParam(value = "pagesize", defaultValue = "10") Integer pageSize) {
  12. PageResult pageResult = this.imService.queryMessageAnnouncementList(page, pageSize);
  13. return ResponseEntity.ok(pageResult);
  14. }

9.7、IMService

  1. public PageResult queryMessageAnnouncementList(Integer page, Integer pageSize) {
  2. IPage<Announcement> announcementPage = this.announcementService.queryList(page, pageSize);
  3. List<MessageAnnouncement> messageAnnouncementList = new ArrayList<>();
  4. for (Announcement record : announcementPage.getRecords()) {
  5. MessageAnnouncement messageAnnouncement = new MessageAnnouncement();
  6. messageAnnouncement.setId(record.getId().toString());
  7. messageAnnouncement.setTitle(record.getTitle());
  8. messageAnnouncement.setDescription(record.getDescription());
  9. messageAnnouncement.setCreateDate(new DateTime(record.getCreated()).toString("yyyy-MM-dd HH:mm"));
  10. messageAnnouncementList.add(messageAnnouncement);
  11. }
  12. PageResult pageResult = new PageResult();
  13. pageResult.setPage(page);
  14. pageResult.setPages(0);
  15. pageResult.setCounts(0);
  16. pageResult.setPagesize(pageSize);
  17. pageResult.setItems(messageAnnouncementList);
  18. return pageResult;
  19. }

9.8、测试

day06-即时通讯功能实现 - 图36

day06-即时通讯功能实现 - 图37

day06-即时通讯功能实现 - 图38