课程说明

  • 首页好友推荐的功能实现
  • 谁看过我的功能实现
  • 今日佳人的功能实现
  • 聊一下的功能实现
  • 上报地理位置的功能实现

1、首页好友推荐

1.1、默认推荐列表

如果查询不到推荐列表,那就需要给出默认的推荐列表。

1.1.1、配置默认推荐的用户

  1. #application.properties
  2. tanhua.sso.default.recommend.users=2,3,4,5,6,7,8,9,10,11,12,13

1.1.2、修改查询逻辑

  1. //TodayBestService
  2. /**
  3. * 查询推荐用户列表
  4. *
  5. * @param queryParam
  6. * @param token
  7. * @return
  8. */
  9. public PageResult queryRecommendUserList(RecommendUserQueryParam queryParam, String token) {
  10. //查询当前的登录信息
  11. User user = this.userService.queryUserByToken(token);
  12. if (null == user) {
  13. return null;
  14. }
  15. PageResult pageResult = new PageResult();
  16. PageInfo<RecommendUser> pageInfo = this.recommendUserService.queryRecommendUserList(user.getId(), queryParam.getPage(), queryParam.getPagesize());
  17. pageResult.setCounts(0); //前端不参与计算,仅需要返回字段
  18. pageResult.setPage(queryParam.getPage());
  19. pageResult.setPagesize(queryParam.getPagesize());
  20. List<RecommendUser> records = pageInfo.getRecords();
  21. if(CollectionUtils.isEmpty(records)){
  22. //默认推荐列表
  23. String[] ss = StringUtils.split(defaultRecommendUsers, ',');
  24. for (String s : ss) {
  25. RecommendUser recommendUser = new RecommendUser();
  26. recommendUser.setUserId(Long.valueOf(s));
  27. recommendUser.setToUserId(user.getId());
  28. recommendUser.setScore(RandomUtils.nextDouble(70, 99));
  29. records.add(recommendUser);
  30. }
  31. }
  32. List<Long> userIds = new ArrayList<>();
  33. for (RecommendUser record : records) {
  34. userIds.add(record.getUserId());
  35. }
  36. QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
  37. queryWrapper.in("user_id", userIds);
  38. if (StringUtils.isNotEmpty(queryParam.getGender())) { //性别条件
  39. if (queryParam.getGender().equals("man")) {
  40. queryWrapper.eq("sex", 1);
  41. } else {
  42. queryWrapper.eq("sex", 2);
  43. }
  44. }
  45. if (StringUtils.isNotEmpty(queryParam.getCity())) { //居住城市
  46. queryWrapper.eq("city", queryParam.getCity());
  47. }
  48. if (queryParam.getAge() != null) { //年龄
  49. queryWrapper.lt("age", queryParam.getAge());
  50. }
  51. List<UserInfo> userInfos = this.userInfoService.queryList(queryWrapper);
  52. List<TodayBest> todayBests = new ArrayList<>();
  53. for (UserInfo userInfo : userInfos) {
  54. TodayBest todayBest = new TodayBest();
  55. todayBest.setId(userInfo.getUserId());
  56. todayBest.setAge(userInfo.getAge());
  57. todayBest.setAvatar(userInfo.getLogo());
  58. todayBest.setGender(userInfo.getSex().name().toLowerCase());
  59. todayBest.setNickname(userInfo.getNickName());
  60. todayBest.setTags(StringUtils.split(userInfo.getTags(), ','));
  61. //设置缘分值
  62. for (RecommendUser record : records) {
  63. if(userInfo.getUserId().longValue() == record.getUserId().longValue()){
  64. double score = Math.floor(record.getScore());
  65. todayBest.setFateValue(Double.valueOf(score).longValue());
  66. break;
  67. }
  68. }
  69. todayBests.add(todayBest);
  70. }
  71. //排序集合,按照score倒序排序
  72. Collections.sort(todayBests, (o1, o2) -> new Long(o2.getFateValue() - o1.getFateValue()).intValue());
  73. pageResult.setItems(todayBests);
  74. return pageResult;
  75. }

1.1.3、测试

day08-好友推荐以及地理位置 - 图1

响应结果:

  1. {
  2. "counts": 0,
  3. "pagesize": 10,
  4. "pages": 0,
  5. "page": 1,
  6. "items": [
  7. {
  8. "id": 4,
  9. "avatar": "https://itcast-tanhua.oss-cn-shanghai.aliyuncs.com/images/logo/4.jpg",
  10. "nickname": "heima_4",
  11. "gender": "man",
  12. "age": 22,
  13. "tags": [
  14. "单身",
  15. "本科",
  16. "年龄相仿"
  17. ],
  18. "fateValue": 95
  19. },
  20. {
  21. "id": 9,
  22. "avatar": "https://itcast-tanhua.oss-cn-shanghai.aliyuncs.com/images/logo/8.jpg",
  23. "nickname": "heima_9",
  24. "gender": "man",
  25. "age": 23,
  26. "tags": [
  27. "单身",
  28. "本科",
  29. "年龄相仿"
  30. ],
  31. "fateValue": 95
  32. },
  33. {
  34. "id": 5,
  35. "avatar": "https://itcast-tanhua.oss-cn-shanghai.aliyuncs.com/images/logo/5.jpg",
  36. "nickname": "heima_5",
  37. "gender": "man",
  38. "age": 23,
  39. "tags": [
  40. "单身",
  41. "本科",
  42. "年龄相仿"
  43. ],
  44. "fateValue": 94
  45. },
  46. {
  47. "id": 6,
  48. "avatar": "https://itcast-tanhua.oss-cn-shanghai.aliyuncs.com/images/logo/9.jpg",
  49. "nickname": "heima_6",
  50. "gender": "man",
  51. "age": 23,
  52. "tags": [
  53. "单身",
  54. "本科",
  55. "年龄相仿"
  56. ],
  57. "fateValue": 94
  58. },
  59. {
  60. "id": 2,
  61. "avatar": "https://itcast-tanhua.oss-cn-shanghai.aliyuncs.com/images/logo/22.jpg",
  62. "nickname": "heima_2",
  63. "gender": "man",
  64. "age": 30,
  65. "tags": [
  66. "单身",
  67. "本科",
  68. "年龄相仿"
  69. ],
  70. "fateValue": 93
  71. },
  72. {
  73. "id": 8,
  74. "avatar": "https://itcast-tanhua.oss-cn-shanghai.aliyuncs.com/images/logo/12.jpg",
  75. "nickname": "heima_8",
  76. "gender": "man",
  77. "age": 26,
  78. "tags": [
  79. "单身",
  80. "本科",
  81. "年龄相仿"
  82. ],
  83. "fateValue": 92
  84. },
  85. {
  86. "id": 11,
  87. "avatar": "https://itcast-tanhua.oss-cn-shanghai.aliyuncs.com/images/logo/11.jpg",
  88. "nickname": "heima_11",
  89. "gender": "man",
  90. "age": 46,
  91. "tags": [
  92. "单身",
  93. "本科",
  94. "年龄相仿"
  95. ],
  96. "fateValue": 86
  97. },
  98. {
  99. "id": 12,
  100. "avatar": "https://itcast-tanhua.oss-cn-shanghai.aliyuncs.com/images/logo/10.jpg",
  101. "nickname": "heima_12",
  102. "gender": "man",
  103. "age": 40,
  104. "tags": [
  105. "单身",
  106. "本科",
  107. "年龄相仿"
  108. ],
  109. "fateValue": 86
  110. },
  111. {
  112. "id": 13,
  113. "avatar": "https://itcast-tanhua.oss-cn-shanghai.aliyuncs.com/images/logo/5.jpg",
  114. "nickname": "heima_13",
  115. "gender": "man",
  116. "age": 46,
  117. "tags": [
  118. "单身",
  119. "本科",
  120. "年龄相仿"
  121. ],
  122. "fateValue": 85
  123. },
  124. {
  125. "id": 7,
  126. "avatar": "https://itcast-tanhua.oss-cn-shanghai.aliyuncs.com/images/logo/18.jpg",
  127. "nickname": "heima_7",
  128. "gender": "man",
  129. "age": 42,
  130. "tags": [
  131. "单身",
  132. "本科",
  133. "年龄相仿"
  134. ],
  135. "fateValue": 78
  136. },
  137. {
  138. "id": 3,
  139. "avatar": "https://itcast-tanhua.oss-cn-shanghai.aliyuncs.com/images/logo/19.jpg",
  140. "nickname": "heima_3",
  141. "gender": "man",
  142. "age": 45,
  143. "tags": [
  144. "单身",
  145. "本科",
  146. "年龄相仿"
  147. ],
  148. "fateValue": 77
  149. },
  150. {
  151. "id": 10,
  152. "avatar": "https://itcast-tanhua.oss-cn-shanghai.aliyuncs.com/images/logo/4.jpg",
  153. "nickname": "heima_10",
  154. "gender": "man",
  155. "age": 46,
  156. "tags": [
  157. "单身",
  158. "本科",
  159. "年龄相仿"
  160. ],
  161. "fateValue": 76
  162. }
  163. ]
  164. }

1.2、好友推荐

对于好友的推荐,需要找出每个用户之间的相似性,具体规则如下:

字段 权重分
年龄差 0-2岁 30分 3-5 20分 5-10岁 10分 10岁以上 0分
性别 异性 30分 同性 0分
位置 同城 20分 不同 0分
学历 相同 20分 不同 0分

1.2.1、部署好友推荐服务

  1. #拉取镜像
  2. docker pull registry.cn-hangzhou.aliyuncs.com/itcast/tanhua-spark-recommend-user:1.0
  3. #创建容器
  4. docker create --name tanhua-spark-recommend-user --restart=always \
  5. --env MONGODB_HOST=192.168.31.81 \
  6. --env MONGODB_PORT=27017 \
  7. --env MONGODB_USERNAME=tanhua \
  8. --env MONGODB_PASSWORD=l3SCjl0HvmSkTtiSbN0Swv40spYnHhDV \
  9. --env MONGODB_DATABASE=tanhua \
  10. --env MONGODB_COLLECTION=recommend_user \
  11. --env JDBC_URL="jdbc:mysql://192.168.31.81:3306/mytanhua?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL=false" \
  12. --env JDBC_DRIVER=com.mysql.jdbc.Driver \
  13. --env JDBC_USER=root \
  14. --env JDBC_PASSWORD=root \
  15. --env JDBC_TABLE=tb_user_info \
  16. --env SCHEDULE_PERIOD=3 \
  17. registry.cn-hangzhou.aliyuncs.com/itcast/tanhua-spark-recommend-user:1.0
  18. #参数说明
  19. #MONGODB_HOST mongodb服务的地址
  20. #MONGODB_PORT mongodb服务的端口
  21. #MONGODB_USERNAME mongodb服务的认证用户名
  22. #MONGODB_PASSWORD mongodb服务的认证密码
  23. #MONGODB_DATABASE mongodb连接的数据库
  24. #MONGODB_COLLECTION 操作表
  25. #JDBC_URL mysql数据库连接地址
  26. #JDBC_DRIVER jdbc驱动
  27. #JDBC_USER 数据库连接用户名
  28. #JDBC_PASSWORD 数据库连接密码
  29. #JDBC_TABLE 数据库表名
  30. #SCHEDULE_PERIOD 下次执行时间间隔,但是为分,默认为10分钟
  31. #启动服务
  32. docker start tanhua-spark-recommend-user
  33. #查看日志
  34. docker logs -f tanhua-spark-recommend-user

1.2.2、测试

执行完成后,数据会写入到mongodb中:

day08-好友推荐以及地理位置 - 图2

解决推荐自己的问题:

  1. #使用1.0.1版本的镜像,同时还增加了推荐数量的参数控制
  2. docker create --name tanhua-spark-recommend-user --restart=always \
  3. --env MONGODB_HOST=192.168.31.81 \
  4. --env MONGODB_PORT=27017 \
  5. --env MONGODB_USERNAME=tanhua \
  6. --env MONGODB_PASSWORD=l3SCjl0HvmSkTtiSbN0Swv40spYnHhDV \
  7. --env MONGODB_DATABASE=tanhua \
  8. --env MONGODB_COLLECTION=recommend_user \
  9. --env JDBC_URL="jdbc:mysql://192.168.31.81:3306/mytanhua?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true&useSSL=false" \
  10. --env JDBC_DRIVER=com.mysql.jdbc.Driver \
  11. --env JDBC_USER=root \
  12. --env JDBC_PASSWORD=root \
  13. --env JDBC_TABLE=tb_user_info \
  14. --env SCHEDULE_PERIOD=3 \
  15. --env RECOMMEND_COUNT=50 \
  16. registry.cn-hangzhou.aliyuncs.com/itcast/tanhua-spark-recommend-user:1.0.1

2、谁看过我

记录别人来访了我的主页的信息。

2.1、编写pojo

  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. @Data
  8. @NoArgsConstructor
  9. @AllArgsConstructor
  10. @Document(collection = "visitors")
  11. public class Visitors implements java.io.Serializable{
  12. private static final long serialVersionUID = 2811682148052386573L;
  13. private ObjectId id;
  14. private Long userId; //我的id
  15. private Long visitorUserId; //来访用户id
  16. private String from; //来源,如首页、圈子等
  17. private Long date; //来访时间
  18. private Double score; //得分
  19. }

2.2、定义接口

  1. package com.tanhua.dubbo.server.api;
  2. import com.tanhua.dubbo.server.pojo.Visitors;
  3. import java.util.List;
  4. public interface VisitorsApi {
  5. /**
  6. * 保存来访记录
  7. *
  8. * @param visitors
  9. * @return
  10. */
  11. String saveVisitor(Visitors visitors);
  12. /**
  13. * 按照时间倒序排序,查询最近的访客信息
  14. *
  15. * @param userId
  16. * @param num
  17. * @return
  18. */
  19. List<Visitors> topVisitor(Long userId, Integer num);
  20. /**
  21. * 按照时间倒序排序,查询最近的访客信息
  22. *
  23. * @param userId
  24. * @param date
  25. * @return
  26. */
  27. List<Visitors> topVisitor(Long userId, Long date);
  28. }

2.3、实现接口

  1. package com.tanhua.dubbo.server.api;
  2. import com.alibaba.dubbo.config.annotation.Service;
  3. import com.tanhua.dubbo.server.pojo.RecommendUser;
  4. import com.tanhua.dubbo.server.pojo.Visitors;
  5. import org.bson.types.ObjectId;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.data.domain.PageRequest;
  8. import org.springframework.data.domain.Pageable;
  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 VisitorsApiImpl implements VisitorsApi {
  16. @Autowired
  17. private MongoTemplate mongoTemplate;
  18. @Override
  19. public String saveVisitor(Visitors visitors) {
  20. visitors.setId(ObjectId.get());
  21. visitors.setDate(System.currentTimeMillis());
  22. this.mongoTemplate.save(visitors);
  23. return visitors.getId().toHexString();
  24. }
  25. @Override
  26. public List<Visitors> topVisitor(Long userId, Integer num) {
  27. Pageable pageable = PageRequest.of(0, num, Sort.by(Sort.Order.desc("date")));
  28. Query query = Query.query(Criteria.where("userId").is(userId)).with(pageable);
  29. return this.queryVisitorList(query);
  30. }
  31. @Override
  32. public List<Visitors> topVisitor(Long userId, Long date) {
  33. Query query = Query.query(Criteria
  34. .where("userId").is(userId)
  35. .and("date").gte(date));
  36. return this.queryVisitorList(query);
  37. }
  38. private List<Visitors> queryVisitorList(Query query) {
  39. List<Visitors> visitors = this.mongoTemplate.find(query, Visitors.class);
  40. // 查询得分
  41. for (Visitors visitor : visitors) {
  42. Query queryRecommend = Query.query(Criteria
  43. .where("toUserId").is(visitor.getUserId())
  44. .and("userId").is(visitor.getVisitorUserId()));
  45. RecommendUser recommendUser = this.mongoTemplate.findOne(queryRecommend, RecommendUser.class);
  46. if (null != recommendUser) {
  47. visitor.setScore(recommendUser.getScore());
  48. } else {
  49. visitor.setScore(30d);
  50. }
  51. }
  52. return visitors;
  53. }
  54. }

2.4、测试

  1. package com.tanhua.dubbo.server.api;
  2. import com.tanhua.dubbo.server.pojo.Visitors;
  3. import org.apache.commons.lang3.RandomUtils;
  4. import org.bson.types.ObjectId;
  5. import org.junit.Test;
  6. import org.junit.runner.RunWith;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.boot.test.context.SpringBootTest;
  9. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
  10. @RunWith(SpringJUnit4ClassRunner.class)
  11. @SpringBootTest
  12. public class TestVisitors {
  13. @Autowired
  14. private VisitorsApi visitorsApi;
  15. @Test
  16. public void testSave(){
  17. for (int i = 0; i < 100; i++) {
  18. Visitors visitors = new Visitors();
  19. visitors.setFrom("首页");
  20. visitors.setUserId(RandomUtils.nextLong(1,10));
  21. visitors.setVisitorUserId(RandomUtils.nextLong(11,50));
  22. this.visitorsApi.saveVisitor(visitors);
  23. }
  24. System.out.println("ok");
  25. }
  26. }

2.5、mock接口

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

day08-好友推荐以及地理位置 - 图3

day08-好友推荐以及地理位置 - 图4

2.6、MovementsController

  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 VisitorsVo {
  9. private Long id; //主键id(非必须)
  10. private String avatar; //头像
  11. private String nickname; //昵称
  12. private String gender; //性别
  13. private Integer age; //年龄
  14. private String[] tags; //标签
  15. private Integer fateValue; //缘分值
  16. }
  1. /**
  2. * 谁看过我
  3. *
  4. * @return
  5. */
  6. @GetMapping("visitors")
  7. public ResponseEntity<List<VisitorsVo>> queryVisitorsList(){
  8. try {
  9. List<VisitorsVo> list = this.movementsService.queryVisitorsList();
  10. return ResponseEntity.ok(list);
  11. } catch (Exception e) {
  12. e.printStackTrace();
  13. }
  14. return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
  15. }

2.7、MovementsService

  1. public List<VisitorsVo> queryVisitorsList() {
  2. User user = UserThreadLocal.get();
  3. String redisKey = "visitor_date_" + user.getId();
  4. // 如果redis中存在上次查询的时间,就按照这个时间之后查询,如果没有就查询前5个
  5. List<Visitors> visitors = null;
  6. String value = this.redisTemplate.opsForValue().get(redisKey);
  7. if(StringUtils.isEmpty(value)){
  8. visitors = this.visitorsApi.topVisitor(user.getId(), 5);
  9. }else{
  10. visitors = this.visitorsApi.topVisitor(user.getId(), Long.valueOf(value));
  11. }
  12. if(CollectionUtils.isEmpty(visitors)){
  13. return Collections.emptyList();
  14. }
  15. List<Long> userIds = new ArrayList<>();
  16. for (Visitors visitor : visitors) {
  17. userIds.add(visitor.getVisitorUserId());
  18. }
  19. QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
  20. queryWrapper.in("user_id", userIds);
  21. List<UserInfo> userInfoList = this.userInfoService.queryList(queryWrapper);
  22. List<VisitorsVo> visitorsVoList = new ArrayList<>();
  23. for (Visitors visitor : visitors) {
  24. for (UserInfo userInfo : userInfoList) {
  25. if(visitor.getVisitorUserId().longValue() == userInfo.getUserId().longValue()){
  26. VisitorsVo visitorsVo = new VisitorsVo();
  27. visitorsVo.setAge(userInfo.getAge());
  28. visitorsVo.setAvatar(userInfo.getLogo());
  29. visitorsVo.setGender(userInfo.getSex().name().toLowerCase());
  30. visitorsVo.setId(userInfo.getUserId());
  31. visitorsVo.setNickname(userInfo.getNickName());
  32. visitorsVo.setTags(StringUtils.split(userInfo.getTags(), ','));
  33. visitorsVo.setFateValue(visitor.getScore().intValue());
  34. visitorsVoList.add(visitorsVo);
  35. break;
  36. }
  37. }
  38. }
  39. return visitorsVoList;
  40. }

2.8、测试

day08-好友推荐以及地理位置 - 图5

数据:

  1. [{"id":20,"avatar":"https://itcast-tanhua.oss-cn-shanghai.aliyuncs.com/images/logo/12.jpg","nickname":"heima_20","gender":"man","age":44,"tags":["单身","本科","年龄相仿"],"fateValue":30},{"id":19,"avatar":"https://itcast-tanhua.oss-cn-shanghai.aliyuncs.com/images/logo/4.jpg","nickname":"heima_19","gender":"woman","age":40,"tags":["单身","本科","年龄相仿"],"fateValue":76},{"id":36,"avatar":"https://itcast-tanhua.oss-cn-shanghai.aliyuncs.com/images/logo/8.jpg","nickname":"heima_36","gender":"woman","age":37,"tags":["单身","本科","年龄相仿"],"fateValue":64},{"id":33,"avatar":"https://itcast-tanhua.oss-cn-shanghai.aliyuncs.com/images/logo/18.jpg","nickname":"heima_33","gender":"man","age":49,"tags":["单身","本科","年龄相仿"],"fateValue":30},{"id":12,"avatar":"https://itcast-tanhua.oss-cn-shanghai.aliyuncs.com/images/logo/18.jpg","nickname":"heima_12","gender":"man","age":23,"tags":["单身","本科","年龄相仿"],"fateValue":30}]

3、 佳人信息

首页显示的今日佳人,点击之后可以查看今日佳人的详情。

3.1、mock接口

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

day08-好友推荐以及地理位置 - 图6

day08-好友推荐以及地理位置 - 图7

3.2、TodayBestController

  1. /**
  2. * 查询今日佳人详情
  3. *
  4. * @param userId
  5. * @return
  6. */
  7. @GetMapping("{id}/personalInfo")
  8. public ResponseEntity<TodayBest> queryTodayBest(@PathVariable("id") Long userId) {
  9. try {
  10. TodayBest todayBest = this.todayBestService.queryTodayBest(userId);
  11. return ResponseEntity.ok(todayBest);
  12. } catch (Exception e) {
  13. e.printStackTrace();
  14. }
  15. return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
  16. }

3.3、TodayBestService

  1. public TodayBest queryTodayBest(Long userId) {
  2. User user = UserThreadLocal.get();
  3. TodayBest todayBest = new TodayBest();
  4. //补全信息
  5. UserInfo userInfo = this.userInfoService.queryById(userId);
  6. todayBest.setId(userId);
  7. todayBest.setAge(userInfo.getAge());
  8. todayBest.setAvatar(userInfo.getLogo());
  9. todayBest.setGender(userInfo.getSex().name().toLowerCase());
  10. todayBest.setNickname(userInfo.getNickName());
  11. todayBest.setTags(StringUtils.split(userInfo.getTags(), ','));
  12. double score = this.recommendUserService.queryScore(userId, user.getId());
  13. if(score == 0){
  14. score = 98; //默认分值
  15. }
  16. todayBest.setFateValue(Double.valueOf(score).longValue());
  17. return todayBest;
  18. }

3.4、查询缘分值

3.4.1、recommendUserApi

  1. /**
  2. * 查询推荐好友的缘分值
  3. *
  4. * @param userId
  5. * @param toUserId
  6. * @return
  7. */
  8. double queryScore(Long userId, Long toUserId);

3.4.2、RecommendUserApiImpl

  1. @Override
  2. public double queryScore(Long userId, Long toUserId) {
  3. Query query = Query.query(Criteria
  4. .where("toUserId").is(toUserId)
  5. .and("userId").is(userId));
  6. RecommendUser recommendUser = this.mongoTemplate.findOne(query, RecommendUser.class);
  7. if (null == recommendUser) {
  8. return 0;
  9. }
  10. return recommendUser.getScore();
  11. }

3.4.3、RecommendUserService

在server工程中完成。

  1. /**
  2. * 查询推荐好友的缘分值
  3. *
  4. * @param userId
  5. * @param toUserId
  6. * @return
  7. */
  8. double queryScore(Long userId, Long toUserId) {
  9. return this.recommendUserApi.queryScore(userId, toUserId);
  10. }

3.5、查询自己相册

3.5.1、mock接口

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

day08-好友推荐以及地理位置 - 图8

3.5.2、定义dubbo接口

  1. //QuanZiApi
  2. /**
  3. * 查询相册表
  4. *
  5. * @param userId
  6. * @param page
  7. * @param pageSize
  8. * @return
  9. */
  10. PageInfo<Publish> queryAlbumList(Long userId, Integer page, Integer pageSize);

3.5.3、dubbo接口实现

  1. //QuanZiApiImpl
  2. @Override
  3. public PageInfo<Publish> queryAlbumList(Long userId, Integer page, Integer pageSize) {
  4. PageInfo<Publish> pageInfo = new PageInfo<>();
  5. pageInfo.setPageNum(page);
  6. pageInfo.setPageSize(pageSize);
  7. pageInfo.setTotal(0); //不提供总数
  8. PageRequest pageRequest = PageRequest.of(page - 1, pageSize, Sort.by(Sort.Order.desc("created")));
  9. Query query = new Query().with(pageRequest);
  10. List<Album> albumList = this.mongoTemplate.find(query, Album.class, "quanzi_album_" + userId);
  11. if(CollectionUtils.isEmpty(albumList)){
  12. return pageInfo;
  13. }
  14. List<ObjectId> publishIds = new ArrayList<>();
  15. for (Album album : albumList) {
  16. publishIds.add(album.getPublishId());
  17. }
  18. //查询发布信息
  19. Query queryPublish = Query.query(Criteria.where("id").in(publishIds)).with(Sort.by(Sort.Order.desc("created")));
  20. List<Publish> publishList = this.mongoTemplate.find(queryPublish, Publish.class);
  21. pageInfo.setRecords(publishList);
  22. return pageInfo;
  23. }

3.5.3、MovementsController

  1. /**
  2. * 自己的所有动态
  3. *
  4. * @return
  5. */
  6. @GetMapping("all")
  7. public ResponseEntity<PageResult> queryAlbumList(@RequestParam(value = "page", defaultValue = "1") Integer page,
  8. @RequestParam(value = "pagesize", defaultValue = "10") Integer pageSize,
  9. @RequestParam(value = "userId") Long userId) {
  10. try {
  11. PageResult pageResult = this.movementsService.queryAlbumList(userId, page, pageSize);
  12. return ResponseEntity.ok(pageResult);
  13. } catch (Exception e) {
  14. e.printStackTrace();
  15. }
  16. return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
  17. }

3.5.4、MovementsService

  1. public PageResult queryAlbumList(Long userId, Integer page, Integer pageSize) {
  2. PageResult pageResult = new PageResult();
  3. pageResult.setPage(page);
  4. pageResult.setPagesize(pageSize);
  5. PageInfo<Publish> albumPageInfo = this.quanZiApi.queryAlbumList(userId, page, pageSize);
  6. List<Publish> records = albumPageInfo.getRecords();
  7. if(CollectionUtils.isEmpty(records)){
  8. return pageResult;
  9. }
  10. List<Movements> movementsList = new ArrayList<>();
  11. for (Publish record : records) {
  12. Movements movements = new Movements();
  13. movements.setId(record.getId().toHexString());
  14. movements.setImageContent(record.getMedias().toArray(new String[]{}));
  15. movements.setTextContent(record.getText());
  16. movements.setUserId(record.getUserId());
  17. movements.setCreateDate(RelativeDateFormat.format(new Date(record.getCreated())));
  18. movementsList.add(movements);
  19. }
  20. List<Long> userIds = new ArrayList<>();
  21. for (Movements movements : movementsList) {
  22. if (!userIds.contains(movements.getUserId())) {
  23. userIds.add(movements.getUserId());
  24. }
  25. }
  26. QueryWrapper<UserInfo> queryWrapper = new QueryWrapper<>();
  27. queryWrapper.in("user_id", userIds);
  28. List<UserInfo> userInfos = this.userInfoService.queryList(queryWrapper);
  29. for (Movements movements : movementsList) {
  30. for (UserInfo userInfo : userInfos) {
  31. if (movements.getUserId().longValue() == userInfo.getUserId().longValue()) {
  32. this.fillValueToMovements(movements, userInfo);
  33. break;
  34. }
  35. }
  36. }
  37. pageResult.setItems(movementsList);
  38. return pageResult;
  39. }

3.5.5、测试

day08-好友推荐以及地理位置 - 图9

day08-好友推荐以及地理位置 - 图10

3.5、整合测试

day08-好友推荐以及地理位置 - 图11

4、聊一下

聊一下功能包含了2个接口:

  • 查询对方设置的问题
  • 提交答案
    • 提交答案后要发送消息给对方


mock接口: https://mock.boxuegu.com/project/164/interface/api/77973

day08-好友推荐以及地理位置 - 图12

4.1、表结构

  1. CREATE TABLE `tb_question` (
  2. `id` bigint(20) NOT NULL AUTO_INCREMENT,
  3. `user_id` bigint(20) DEFAULT NULL COMMENT '用户id',
  4. `txt` varchar(200) DEFAULT NULL COMMENT '问题内容',
  5. `created` datetime DEFAULT NULL,
  6. `updated` datetime DEFAULT NULL,
  7. PRIMARY KEY (`id`),
  8. KEY `user_id` (`user_id`)
  9. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  10. -- 插入数据
  11. INSERT INTO `tb_question` (`id`, `user_id`, `txt`, `created`, `updated`) VALUES ('1', '1', '你喜欢去看蔚蓝的大海还是去爬巍峨的高山?', '2019-10-20 17:25:58', '2019-10-20 17:26:01');
  12. INSERT INTO `tb_question` (`id`, `user_id`, `txt`, `created`, `updated`) VALUES ('2', '57', '你喜欢什么颜色?', '2019-10-20 23:17:39', '2019-10-20 23:17:41');

4.2、编写Question

  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 Question extends BasePojo {
  9. private Long id;
  10. private Long userId;
  11. //问题内容
  12. private String txt;
  13. }

4.3、QuestionMapper

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

4.4、QuestionService

  1. package com.tanhua.server.service;
  2. import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
  3. import com.tanhua.server.mapper.QuestionMapper;
  4. import com.tanhua.server.pojo.Question;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.stereotype.Service;
  7. @Service
  8. public class QuestionService {
  9. @Autowired
  10. private QuestionMapper questionMapper;
  11. public Question queryQuestion(Long userId) {
  12. QueryWrapper queryWrapper = new QueryWrapper();
  13. queryWrapper.eq("user_id", userId);
  14. return this.questionMapper.selectOne(queryWrapper);
  15. }
  16. }

4.5、查询陌生人问题

4.5.1、TodayBestController

  1. /**
  2. * 查询陌生人问题
  3. *
  4. * @param userId
  5. * @return
  6. */
  7. @GetMapping("strangerQuestions")
  8. public ResponseEntity<String> queryQuestion(@RequestParam("userId") Long userId) {
  9. try {
  10. String question = this.todayBestService.queryQuestion(userId);
  11. return ResponseEntity.ok(question);
  12. } catch (Exception e) {
  13. e.printStackTrace();
  14. }
  15. return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
  16. }

4.5.2、TodayBestService

  1. public String queryQuestion(Long userId) {
  2. Question question = this.questionService.queryQuestion(userId);
  3. if (null != question) {
  4. return question.getTxt();
  5. }
  6. return "";
  7. }

4.5.3、测试

day08-好友推荐以及地理位置 - 图13

day08-好友推荐以及地理位置 - 图14

4.6、回复陌生人问题

4.6.1、mock接口

day08-好友推荐以及地理位置 - 图15

4.6.2、发送消息给环信

在sso系统中完成。

4.6.2.1、HuanXinController
  1. /**
  2. * 发送系统消息
  3. *
  4. * @param target
  5. * @param msg
  6. * @param type
  7. * @return
  8. */
  9. @PostMapping("messages")
  10. public ResponseEntity<Void> sendMsg(@RequestParam("target") String target,
  11. @RequestParam("msg") String msg,
  12. @RequestParam(value = "type", defaultValue = "txt") String type) {
  13. try {
  14. boolean result = this.huanXinService.sendMsg(target, type, msg);
  15. if (result) {
  16. return ResponseEntity.ok(null);
  17. }
  18. } catch (Exception e) {
  19. e.printStackTrace();
  20. }
  21. return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
  22. }

4.6.2.2、HuanXinService
  1. public boolean sendMsg(String target, String type, String msg) {
  2. String targetUrl = this.huanXinConfig.getUrl()
  3. + this.huanXinConfig.getOrgName() + "/"
  4. + this.huanXinConfig.getAppName() + "/messages";
  5. try {
  6. String token = this.huanXinTokenService.getToken();
  7. // 请求头
  8. HttpHeaders headers = new HttpHeaders();
  9. headers.add("Authorization", "Bearer " + token);
  10. Map<String, Object> paramMap = new HashMap<>();
  11. paramMap.put("target_type", "users");
  12. paramMap.put("target", Arrays.asList(target));
  13. Map<String, Object> msgMap = new HashMap<>();
  14. msgMap.put("type", type);
  15. msgMap.put("msg", msg);
  16. paramMap.put("msg", msgMap);
  17. //表示消息发送者;无此字段Server会默认设置为“from”:“admin”,有from字段但值为空串(“”)时请求失败
  18. // msgMap.put("from", type);
  19. HttpEntity<String> httpEntity = new HttpEntity<>(MAPPER.writeValueAsString(paramMap), headers);
  20. ResponseEntity<String> responseEntity = this.restTemplate.postForEntity(targetUrl, httpEntity, String.class);
  21. return responseEntity.getStatusCodeValue() == 200;
  22. } catch (Exception e) {
  23. e.printStackTrace();
  24. }
  25. return false;
  26. }

4.6.2.3、测试

day08-好友推荐以及地理位置 - 图16

4.6.3、实现服务接口

4.6.3.1、TodayBestController
  1. /**
  2. * 回复陌生人问题
  3. *
  4. * @return
  5. */
  6. @PostMapping("strangerQuestions")
  7. public ResponseEntity<Void> replyQuestion(@RequestBody Map<String, Object> param) {
  8. try {
  9. Long userId = Long.valueOf(param.get("userId").toString());
  10. String reply = param.get("reply").toString();
  11. Boolean result = this.todayBestService.replyQuestion(userId, reply);
  12. if (result) {
  13. return ResponseEntity.ok(null);
  14. }
  15. } catch (Exception e) {
  16. e.printStackTrace();
  17. }
  18. return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
  19. }

4.6.3.2、TodayBestService
  1. /**
  2. * 回复陌生人问题,发送消息给对方
  3. *
  4. * @param userId
  5. * @param reply
  6. * @return
  7. */
  8. public Boolean replyQuestion(Long userId, String reply) {
  9. User user = UserThreadLocal.get();
  10. UserInfo userInfo = this.userInfoService.queryById(user.getId());
  11. //构建消息内容
  12. Map<String, Object> msg = new HashMap<>();
  13. msg.put("userId", user.getId().toString());
  14. msg.put("nickname", this.queryQuestion(userId));
  15. msg.put("strangerQuestion", userInfo.getNickName());
  16. msg.put("reply", reply);
  17. try {
  18. String msgStr = MAPPER.writeValueAsString(msg);
  19. String targetUrl = this.url + "/user/huanxin/messages";//url为sso的访问路径
  20. HttpHeaders headers = new HttpHeaders();
  21. headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
  22. MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
  23. params.add("target", userId.toString());
  24. params.add("msg", msgStr);
  25. HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(params, headers);
  26. ResponseEntity<Void> responseEntity = this.restTemplate.postForEntity(targetUrl, httpEntity, Void.class);
  27. return responseEntity.getStatusCodeValue() == 200;
  28. } catch (Exception e) {
  29. e.printStackTrace();
  30. }
  31. return false;
  32. }

4.6.4、测试

day08-好友推荐以及地理位置 - 图17

day08-好友推荐以及地理位置 - 图18

5、地理位置

客户端检测用户的地理位置,当变化大于500米时或每隔5分钟,向服务端发送地理位置。

6.1、定义pojo

  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.annotation.Id;
  7. import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
  8. import org.springframework.data.mongodb.core.index.CompoundIndex;
  9. import org.springframework.data.mongodb.core.index.Indexed;
  10. import org.springframework.data.mongodb.core.mapping.Document;
  11. @Data
  12. @NoArgsConstructor
  13. @AllArgsConstructor
  14. @Document(collection = "user_location")
  15. @CompoundIndex(name = "location_index", def = "{'location': '2dsphere'}")
  16. public class UserLocation implements java.io.Serializable{
  17. private static final long serialVersionUID = 4508868382007529970L;
  18. @Id
  19. private ObjectId id;
  20. @Indexed
  21. private Long userId; //用户id
  22. private GeoJsonPoint location; //x:经度 y:纬度
  23. private String address; //位置描述
  24. private Long created; //创建时间
  25. private Long updated; //更新时间
  26. private Long lastUpdated; //上次更新时间
  27. }

6.2、定义dubbo接口

  1. package com.tanhua.dubbo.server.api;
  2. public interface UserLocationApi {
  3. /**
  4. * 更新用户地理位置
  5. *
  6. * @return
  7. */
  8. String updateUserLocation(Long userId, Double longitude, Double latitude, String address);
  9. }

6.3、编写实现

  1. package com.tanhua.dubbo.server.api;
  2. import com.alibaba.dubbo.config.annotation.Service;
  3. import com.tanhua.dubbo.server.pojo.UserLocation;
  4. import com.tanhua.dubbo.server.vo.UserLocationVo;
  5. import org.bson.types.ObjectId;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.data.mongodb.core.MongoTemplate;
  8. import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
  9. import org.springframework.data.mongodb.core.query.Criteria;
  10. import org.springframework.data.mongodb.core.query.Query;
  11. import org.springframework.data.mongodb.core.query.Update;
  12. @Service(version = "1.0.0")
  13. public class UserLocationApiImpl implements UserLocationApi {
  14. @Autowired
  15. private MongoTemplate mongoTemplate;
  16. @Override
  17. public String updateUserLocation(Long userId, Double longitude, Double latitude, String address) {
  18. UserLocation userLocation = new UserLocation();
  19. userLocation.setAddress(address);
  20. userLocation.setLocation(new GeoJsonPoint(longitude, latitude));
  21. userLocation.setUserId(userId);
  22. Query query = Query.query(Criteria.where("userId").is(userLocation.getUserId()));
  23. UserLocation ul = this.mongoTemplate.findOne(query, UserLocation.class);
  24. if (ul == null) {
  25. //新增
  26. userLocation.setId(ObjectId.get());
  27. userLocation.setCreated(System.currentTimeMillis());
  28. userLocation.setUpdated(userLocation.getCreated());
  29. userLocation.setLastUpdated(userLocation.getCreated());
  30. this.mongoTemplate.save(userLocation);
  31. return userLocation.getId().toHexString();
  32. } else {
  33. //更新
  34. Update update = Update
  35. .update("location", userLocation.getLocation())
  36. .set("updated", System.currentTimeMillis())
  37. .set("address", userLocation.getAddress())
  38. .set("lastUpdated", ul.getUpdated());
  39. this.mongoTemplate.updateFirst(query, update, UserLocation.class);
  40. }
  41. return ul.getId().toHexString();
  42. }
  43. }

6.4、mock接口

day08-好友推荐以及地理位置 - 图19

6.5、实现服务接口

  1. package com.tanhua.server.controller;
  2. import com.tanhua.dubbo.server.pojo.UserLocation;
  3. import com.tanhua.dubbo.server.vo.UserLocationVo;
  4. import com.tanhua.server.service.BaiduService;
  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.*;
  9. import java.util.Map;
  10. @RestController
  11. @RequestMapping("baidu")
  12. public class BaiduController {
  13. @Autowired
  14. private BaiduService baiduService;
  15. /**
  16. * 更新位置
  17. *
  18. * @param param
  19. * @return
  20. */
  21. @PostMapping("location")
  22. public ResponseEntity<Void> updateLocation(@RequestBody Map<String, Object> param) {
  23. try {
  24. Double longitude = Double.valueOf(param.get("longitude").toString());
  25. Double latitude = Double.valueOf(param.get("latitude").toString());
  26. String address = param.get("addrStr").toString();
  27. Boolean bool = this.baiduService.updateLocation(longitude, latitude, address);
  28. if (bool) {
  29. return ResponseEntity.ok(null);
  30. }
  31. } catch (Exception e) {
  32. e.printStackTrace();
  33. }
  34. return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
  35. }
  36. }
  1. package com.tanhua.server.service;
  2. import com.alibaba.dubbo.config.annotation.Reference;
  3. import com.tanhua.dubbo.server.api.UserLocationApi;
  4. import com.tanhua.dubbo.server.pojo.UserLocation;
  5. import com.tanhua.server.pojo.User;
  6. import com.tanhua.server.utils.UserThreadLocal;
  7. import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
  8. import org.springframework.stereotype.Service;
  9. @Service
  10. public class BaiduService {
  11. @Reference(version = "1.0.0")
  12. private UserLocationApi userLocationApi;
  13. public Boolean updateLocation(Double longitude, Double latitude, String address) {
  14. try {
  15. User user = UserThreadLocal.get();
  16. this.userLocationApi.updateUserLocation(user.getId(), longitude, latitude, address);
  17. return true;
  18. } catch (Exception e) {
  19. e.printStackTrace();
  20. }
  21. return false;
  22. }
  23. }

6.6、测试

day08-好友推荐以及地理位置 - 图20

day08-好友推荐以及地理位置 - 图21

查看索引:

day08-好友推荐以及地理位置 - 图22