SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)

和所有以梦为马的诗人一样,我借此火得度一生的茫茫黑夜

SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第1张图片


系列文章目录

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


文章目录

  • 系列文章目录
  • 一、探花功能
    • 1. 需求
    • 2. 查询卡片列表
      • ⑴. 接口文档
      • ⑵. 编码实现
        • ①. 实体对象
        • ②. Controller
        • ③. yml 配置
        • ④. Service
        • ⑤. Api
        • ⑥. APiImpl
      • ⑶. Postman
      • ⑷. 页面效果
    • 3. 喜欢
      • ⑴. 接口文档
      • ⑵. 编码实现
        • ①. Controller
        • ②. Constants
        • ③. Service
        • ④. API
        • ⑤. ApiImpl
      • ⑶. Postman
    • 4. 不喜欢
      • ⑴. 接口文档
      • ⑵. 编码实现
        • ①. Controller
        • ②. Service
      • ⑶. 页面效果
  • 二、地理位置查询
    • 1. 环境准备
    • 2. 地理位置-检索附近
    • 3. 地理位置-检索附近获取距离
  • 三、搜附近
    • 1. 需求分析
    • 2. 上报地理位置
      • ⑴. 获取地理位置信息
      • ⑵. 接口文档
      • ⑶. 编码实现
        • ①. 搭建提供者环境
          • Ⅰ. 实体类
          • Ⅱ. Api
          • Ⅲ. ApiImpl
        • ②. 编写Controller接受请求参数
        • ③. 编写Service调用API完成上报地理位置功能
        • ④. 在API层完成更新或者保存操作
          • Ⅰ. Api
          • Ⅱ. ApiImpl
      • ⑷. Postman测试
      • ⑸. 模拟器修改定位
    • 3. 搜附近
      • ⑴. 需求分析
      • ⑵. 接口文档
      • ⑶. 编码实现
        • ①. vo对象
        • ②. Controller接收请求参数
        • ③. Service层调用API查询获取附近用户的ID集合,构造返回
        • ④. API层使用MongoDB的地理位置方法查询
          • Ⅰ. Api接口
          • Ⅱ. Api实现类
      • ⑷. 添加地理位置数据
      • ⑸. 页面效果


一、探花功能

1. 需求

  • 探花功能是将推荐的好友随机的通过卡片的形式展现出来
  • 用户可以选择左滑、右滑操作,左滑:不喜欢,右滑:喜欢
  • 喜欢: 如果双方喜欢,那么就会成为好友

SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第2张图片

数据库表:user_like(用户喜欢数据表)
SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第3张图片


2. 查询卡片列表

⑴. 接口文档

SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第4张图片

⑵. 编码实现

SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第5张图片

①. 实体对象

新建 tanhua-model/src/main/java/com/tanhua/model/mongo/UserLike.java 文件:

@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "user_like")
public class UserLike implements java.io.Serializable {

    private static final long serialVersionUID = 6739966698394686523L;

    private ObjectId id;
    @Indexed
    private Long userId; //用户id,自己
    @Indexed
    private Long likeUserId; //喜欢的用户id,对方
    private Boolean isLike; // 是否喜欢
    private Long created; //创建时间
    private Long updated; // 更新时间

}

②. Controller

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

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

    @Autowired
    private TanhuaService tanhuaService;

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

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

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

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

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

    /**
     * 探花 - 推荐用户列表
     */
    @GetMapping("cards")
    public ResponseEntity queryCardsList() {
        List<TodayBest> list = this.tanhuaService.queryCardsList();
        return ResponseEntity.ok(list);
    }
}

③. yml 配置

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

#服务端口
server:
  port: 18080
spring:
  application:
    name: tanhua-app-server
  redis:  #redis配置
    port: 6379
    host: 192.168.136.160
  cloud:  #nacos配置
    nacos:
      discovery:
        server-addr: 192.168.136.160:8848
dubbo:    #dubbo配置
  registry:
    address: spring-cloud://localhost
  consumer:
    check: false
tanhua:
  # 默认推荐列表
  default:
    recommend:
      users: 2,3,8,10,18,20,24,29,27,32,36,37,56,64,75,88
  sms:
    signName: 物流云商
    templateCode: SMS_106590012
    accessKey: 略
    secret: LHLBvXmILRoyw0niRSBuXBZewQ30la
  oss:
    accessKey: 略
    secret: LHLBvXmILRoyw0niRSBuXBZewQ30la
    endpoint: oss-cn-beijing.aliyuncs.com
    bucketName: tanhua001
    url: https://tanhua001.oss-cn-beijing.aliyuncs.com/
  aip:
    appId: 略
    apiKey: 略
    secretKey: 略
  huanxin:
    appkey: 略
    clientId: 略
    clientSecret:

④. Service

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

@Service
public class TanhuaService {

    @DubboReference
    private RecommendUserApi recommendUserApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private QuestionApi questionApi;

    @Autowired
    private HuanXinTemplate huanXinTemplate;

    @Value("${tanhua.default.recommend.users}")
    private String recommendUser;

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

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

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

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

        // 5. 返回
        return vo;
    }

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

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

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

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

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


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

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

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

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

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

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

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

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

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

    // 探花 - 推荐用户列表
    public List<TodayBest> queryCardsList() {
        // 1. 调用推荐API查询数据列表(排除 喜欢/不喜欢 的用户, 数量限制)
        List<RecommendUser> users = recommendUserApi.queryCardsList(UserHolder.getUserId(), 10);

        // 2. 判断数据是否存在,如果不存在,构造默认数据 1,2,3...
        if(CollUtil.isEmpty(users)) {
            users = new ArrayList<>();
            String[] userIds = recommendUser.split(",");
            for (String userId : userIds) {
                RecommendUser recommendUser = new RecommendUser();
                recommendUser.setUserId(Convert.toLong(userId));
                recommendUser.setToUserId(UserHolder.getUserId());
                recommendUser.setScore(RandomUtil.randomDouble(60, 90));
                users.add(recommendUser);
            }
        }

        // 3. 构造vo
        List<Long> ids = CollUtil.getFieldValues(users, "userId", Long.class);
        Map<Long, UserInfo> infoMap = userInfoApi.findByIds(ids, null);
        List<TodayBest> vos = new ArrayList<>();
        for (RecommendUser user : users) {
            UserInfo userInfo = infoMap.get(user.getUserId());
            if(userInfo != null) {
                TodayBest vo = TodayBest.init(userInfo, user);
                vos.add(vo);
            }
        }
        return vos;
    }
}

⑤. Api

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

public interface RecommendUserApi {

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

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

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

    // 探花 - 查询推荐用户列表
    List<RecommendUser> queryCardsList(Long userId, int counts);
}

⑥. APiImpl

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

@DubboService
public class RecommendUserApiImpl implements RecommendUserApi{

    @Autowired
    private MongoTemplate mongoTemplate;

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

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

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

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

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

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

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

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

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

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

    // 探花 - 查询推荐用户列表
    @Override
    public List<RecommendUser> queryCardsList(Long userId, int counts) {
        // 1. 查询不喜欢的用户id
        List<UserLike> likeList = mongoTemplate.find(Query.query(Criteria.where("userId").is(userId)), UserLike.class);
        List<Long> likeUserIds = CollUtil.getFieldValues(likeList, "likeUserId", Long.class);

        // 2. 构造查询推荐用户的条件
        Criteria criteria = Criteria.where("toUserId").is(userId).and("userId").nin(likeUserIds);

        // 3. 使用统计函数,随机获取推荐的用户列表
        TypedAggregation<RecommendUser> newAggregation = TypedAggregation.newAggregation(RecommendUser.class,
                Aggregation.match(criteria), // 指定查询条件
                Aggregation.sample(counts)
        );
        AggregationResults<RecommendUser> results = mongoTemplate.aggregate(newAggregation, RecommendUser.class);

        // 4. 构造返回
        return results.getMappedResults();
    }
}

⑶. Postman

SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第6张图片


⑷. 页面效果

SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第7张图片

3. 喜欢

⑴. 接口文档

SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第8张图片


⑵. 编码实现

SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第9张图片

①. Controller

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

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

    @Autowired
    private TanhuaService tanhuaService;

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

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

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

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

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

    /**
     * 探花 - 推荐用户列表
     */
    @GetMapping("cards")
    public ResponseEntity queryCardsList() {
        List<TodayBest> list = this.tanhuaService.queryCardsList();
        return ResponseEntity.ok(list);
    }

    /**
     * 探花 - 喜欢
     */
    @GetMapping("{id}/love")
    public ResponseEntity<Void> likeUser(@PathVariable("id") Long likeUserId) {
        this.tanhuaService.likeUser(likeUserId);
        return ResponseEntity.ok(null);
    }
}

②. Constants

编辑 tanhua-commons/src/main/java/com/tanhua/commons/utils/Constants.java 文件:

//常量定义
public class Constants {

    //手机APP短信验证码CHECK_CODE_
    public static final String SMS_CODE = "CHECK_CODE_";

	//推荐动态
	public static final String MOVEMENTS_RECOMMEND = "MOVEMENTS_RECOMMEND_";

    //推荐视频
    public static final String VIDEOS_RECOMMEND = "VIDEOS_RECOMMEND_";

	//圈子互动KEY
	public static final String MOVEMENTS_INTERACT_KEY = "MOVEMENTS_INTERACT_";

    //动态点赞用户HashKey
    public static final String MOVEMENT_LIKE_HASHKEY = "MOVEMENT_LIKE_";

    //动态喜欢用户HashKey
    public static final String MOVEMENT_LOVE_HASHKEY = "MOVEMENT_LOVE_";

    //视频点赞用户HashKey
    public static final String VIDEO_LIKE_HASHKEY = "VIDEO_LIKE";

    //访问用户
    public static final String VISITORS = "VISITORS";

    //关注用户
    public static final String FOCUS_USER = "FOCUS_USER_{}_{}";

	//初始化密码
    public static final String INIT_PASSWORD = "123456";

    //环信用户前缀
    public static final String HX_USER_PREFIX = "hx";

    //jwt加密盐
    public static final String JWT_SECRET = "itcast";

    //jwt超时时间
    public static final int JWT_TIME_OUT = 3_600;

    //用户喜欢Redis的key
    public static final String USER_LIKE_KEY="USER_LIKE_SET_";

    //用户不喜欢Redis的key
    public static final String USER_NOT_LIKE_KEY="USER_NOT_LIKE_SET_";
}

③. Service

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

@Service
public class TanhuaService {

    @DubboReference
    private RecommendUserApi recommendUserApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private QuestionApi questionApi;

    @Autowired
    private HuanXinTemplate huanXinTemplate;

    @DubboReference
    private UserLikeApi userLikeApi;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private MessagesService messagesService;

    @Value("${tanhua.default.recommend.users}")
    private String recommendUser;

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

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

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

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

        // 5. 返回
        return vo;
    }

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

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

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

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

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


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

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

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

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

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

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

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

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

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

    // 探花 - 推荐用户列表
    public List<TodayBest> queryCardsList() {
        // 1. 调用推荐API查询数据列表(排除 喜欢/不喜欢 的用户, 数量限制)
        List<RecommendUser> users = recommendUserApi.queryCardsList(UserHolder.getUserId(), 10);

        // 2. 判断数据是否存在,如果不存在,构造默认数据 1,2,3...
        if(CollUtil.isEmpty(users)) {
            users = new ArrayList<>();
            String[] userIds = recommendUser.split(",");
            for (String userId : userIds) {
                RecommendUser recommendUser = new RecommendUser();
                recommendUser.setUserId(Convert.toLong(userId));
                recommendUser.setToUserId(UserHolder.getUserId());
                recommendUser.setScore(RandomUtil.randomDouble(60, 90));
                users.add(recommendUser);
            }
        }

        // 3. 构造vo
        List<Long> ids = CollUtil.getFieldValues(users, "userId", Long.class);
        Map<Long, UserInfo> infoMap = userInfoApi.findByIds(ids, null);
        List<TodayBest> vos = new ArrayList<>();
        for (RecommendUser user : users) {
            UserInfo userInfo = infoMap.get(user.getUserId());
            if(userInfo != null) {
                TodayBest vo = TodayBest.init(userInfo, user);
                vos.add(vo);
            }
        }
        return vos;
    }

    // 探花 - 喜欢
    public void likeUser(Long likeUserId) {
        // 1. 调用API,保存喜欢的数据(写入MongoDB)
        Boolean save = userLikeApi.saveOrUpdate(UserHolder.getUserId(), likeUserId, true);
        if(!save) {
            throw new BusinessException(ErrorResult.error());
        }

        // 2. 操作redis,写入喜欢的数据,删除不喜欢的数据
        redisTemplate.opsForSet().remove(Constants.USER_NOT_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());
        redisTemplate.opsForSet().add(Constants.USER_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());

        // 3. 判断是否双向喜欢
        if(isLike(likeUserId, UserHolder.getUserId())) {
            // 4. 如果是,则添加好友
            messagesService.contacts(likeUserId);
        }
    }

    // 公共方法 - 判断 id 是否在集合当中
    public Boolean isLike(Long userId, Long likeUserId) {
        String key = Constants.USER_LIKE_KEY + userId;
        return redisTemplate.opsForSet().isMember(key, likeUserId.toString());
    }
}

④. API

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

public interface UserLikeApi {

    // 保存或者更新
    Boolean saveOrUpdate(Long userId, Long likeUserId, boolean isLike);
}

⑤. ApiImpl

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

@DubboService
public class UserLikeApiImpl implements UserLikeApi{

    @Autowired
    private MongoTemplate mongoTemplate;

    // 保存或者更新
    @Override
    public Boolean saveOrUpdate(Long userId, Long likeUserId, boolean isLike) {
        try {
            // 1. 查询数据
            Query query = Query.query(Criteria.where("userId").is(userId).and("likeUserId").is(likeUserId));
            UserLike userLike = mongoTemplate.findOne(query, UserLike.class);
            // 2. 如果不存在,保存
            if(userLike == null) {
                userLike = new UserLike();
                userLike.setUserId(userId);
                userLike.setLikeUserId(likeUserId);
                userLike.setCreated(System.currentTimeMillis());
                userLike.setUpdated(System.currentTimeMillis());
                userLike.setIsLike(isLike);
                mongoTemplate.save(userLike);
            } else {
                // 3. 如果存在,更新
                Update update = Update.update("isLike", isLike).set("update", System.currentTimeMillis());
                mongoTemplate.updateFirst(query, update, UserLike.class);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}

⑶. Postman

SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第10张图片
SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第11张图片


4. 不喜欢

⑴. 接口文档

SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第12张图片


⑵. 编码实现

①. Controller

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

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

    @Autowired
    private TanhuaService tanhuaService;

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

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

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

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

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

    /**
     * 探花 - 推荐用户列表
     */
    @GetMapping("cards")
    public ResponseEntity queryCardsList() {
        List<TodayBest> list = this.tanhuaService.queryCardsList();
        return ResponseEntity.ok(list);
    }

    /**
     * 探花 - 喜欢
     */
    @GetMapping("{id}/love")
    public ResponseEntity<Void> likeUser(@PathVariable("id") Long likeUserId) {
        this.tanhuaService.likeUser(likeUserId);
        return ResponseEntity.ok(null);
    }


    /**
     * 不喜欢
     */
    @GetMapping("{id}/unlove")
    public ResponseEntity<Void> notLikeUser(@PathVariable("id") Long likeUserId) {
        this.tanhuaService.notLikeUser(likeUserId);
        return ResponseEntity.ok(null);
    }
}

②. Service

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

@Service
public class TanhuaService {

    @DubboReference
    private RecommendUserApi recommendUserApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private QuestionApi questionApi;

    @Autowired
    private HuanXinTemplate huanXinTemplate;

    @DubboReference
    private UserLikeApi userLikeApi;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private MessagesService messagesService;

    @Value("${tanhua.default.recommend.users}")
    private String recommendUser;

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

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

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

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

        // 5. 返回
        return vo;
    }

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

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

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

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

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


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

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

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

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

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

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

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

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

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

    // 探花 - 推荐用户列表
    public List<TodayBest> queryCardsList() {
        // 1. 调用推荐API查询数据列表(排除 喜欢/不喜欢 的用户, 数量限制)
        List<RecommendUser> users = recommendUserApi.queryCardsList(UserHolder.getUserId(), 10);

        // 2. 判断数据是否存在,如果不存在,构造默认数据 1,2,3...
        if(CollUtil.isEmpty(users)) {
            users = new ArrayList<>();
            String[] userIds = recommendUser.split(",");
            for (String userId : userIds) {
                RecommendUser recommendUser = new RecommendUser();
                recommendUser.setUserId(Convert.toLong(userId));
                recommendUser.setToUserId(UserHolder.getUserId());
                recommendUser.setScore(RandomUtil.randomDouble(60, 90));
                users.add(recommendUser);
            }
        }

        // 3. 构造vo
        List<Long> ids = CollUtil.getFieldValues(users, "userId", Long.class);
        Map<Long, UserInfo> infoMap = userInfoApi.findByIds(ids, null);
        List<TodayBest> vos = new ArrayList<>();
        for (RecommendUser user : users) {
            UserInfo userInfo = infoMap.get(user.getUserId());
            if(userInfo != null) {
                TodayBest vo = TodayBest.init(userInfo, user);
                vos.add(vo);
            }
        }
        return vos;
    }

    // 探花 - 喜欢
    public void likeUser(Long likeUserId) {
        // 1. 调用API,保存喜欢的数据(写入MongoDB)
        Boolean save = userLikeApi.saveOrUpdate(UserHolder.getUserId(), likeUserId, true);
        if(!save) {
            throw new BusinessException(ErrorResult.error());
        }

        // 2. 操作redis,写入喜欢的数据,删除不喜欢的数据
        redisTemplate.opsForSet().remove(Constants.USER_NOT_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());
        redisTemplate.opsForSet().add(Constants.USER_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());

        // 3. 判断是否双向喜欢
        if(isLike(likeUserId, UserHolder.getUserId())) {
            // 4. 如果是,则添加好友
            messagesService.contacts(likeUserId);
        }
    }

    // 公共方法 - 判断 id 是否在集合当中
    public Boolean isLike(Long userId, Long likeUserId) {
        String key = Constants.USER_LIKE_KEY + userId;
        return redisTemplate.opsForSet().isMember(key, likeUserId.toString());
    }

    // 探花 - 不喜欢
    public void notLikeUser(Long likeUserId) {
        // 1. 调用API,保存喜欢的数据(写入MongoDB)
        Boolean save = userLikeApi.saveOrUpdate(UserHolder.getUserId(), likeUserId, false);
        if(!save) {
            throw new BusinessException(ErrorResult.error());
        }

        // 2. 操作redis,写入喜欢的数据,删除不喜欢的数据
        redisTemplate.opsForSet().add(Constants.USER_NOT_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());
        redisTemplate.opsForSet().remove(Constants.USER_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());

        // 3. 判断是否双向不喜欢(删除双向好友)
    }
}

⑶. 页面效果

SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第13张图片


二、地理位置查询

随着互联网5G网络的发展, 定位技术越来越精确,地理位置的服务(Location Based Services,LBS)已经渗透到各个软件应用中。如网约车平台,外卖,社交软件,物流等

1. 环境准备

Gitee仓库地址: https://gitee.com/yuan0_0/tanhua_lbs_demo.git

SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第14张图片

百度地图开发平台: https://lbsyun.baidu.com/jsdemo.htm#localSearchKeyCircle

SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第15张图片


2. 地理位置-检索附近

SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第16张图片

3. 地理位置-检索附近获取距离

SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第17张图片



三、搜附近

1. 需求分析

在首页中点击“搜附近”可以搜索附近的好友
SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第18张图片

业务流程:
SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第19张图片
用户地理位置表(user_location):
SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第20张图片


2. 上报地理位置

⑴. 获取地理位置信息

  • 客户端定位获取地理位置信息
  • 客户端定时发送定位数据(5分钟)
  • 客户端检测移动距离发送定位数据(大于500米)

⑵. 接口文档

SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第21张图片

⑶. 编码实现

①. 搭建提供者环境

Ⅰ. 实体类

新建 tanhua-model/src/main/java/com/tanhua/model/mongo/UserLocation.java 文件:

@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "user_location")
@CompoundIndex(name = "location_index", def = "{'location': '2dsphere'}")
public class UserLocation implements java.io.Serializable{

    private static final long serialVersionUID = 4508868382007529970L;

    @Id
    private ObjectId id;
    @Indexed
    private Long userId; //用户id
    private GeoJsonPoint location; //x:经度 y:纬度
    private String address; //位置描述
    private Long created; //创建时间
    private Long updated; //更新时间
    private Long lastUpdated; //上次更新时间
}

Ⅱ. Api

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

public interface UserLocationApi {
}

Ⅲ. ApiImpl

新建 tanhua-dubbo/tanhua-dubbo-mongo/src/main/java/com/tanhua/dubbo/api/UserLocationApiImpl.java 文件:

@DubboService
public class UserLocationApiImpl implements UserLocationApi{

    @Autowired
    private MongoTemplate mongoTemplate;
}

②. 编写Controller接受请求参数

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

@RestController
@RequestMapping("/baidu")
public class BaiduController {

    @Autowired
    private BaiduService baiduService;

    /**
     * 更新位置
     */
    @PostMapping("/location")
    public ResponseEntity updateLocation(@RequestBody Map param) {
        Double longitude = Double.valueOf(param.get("longitude").toString());
        Double latitude = Double.valueOf(param.get("latitude").toString());
        String address = param.get("addrStr").toString();
        this.baiduService.updateLocation(longitude, latitude,address);
        return ResponseEntity.ok(null);
    }
}

③. 编写Service调用API完成上报地理位置功能

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

@Service
public class BaiduService {

    @DubboReference
    private UserLocationApi userLocationApi;

    // 更新地理位置
    public void updateLocation(Double longitude, Double latitude, String address) {
        Boolean flag = userLocationApi.updateLocation(UserHolder.getUserId(), longitude, latitude, address);
        if(!flag) {
            throw new BusinessException(ErrorResult.error());
        }
    }
}

④. 在API层完成更新或者保存操作

Ⅰ. Api

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

public interface UserLocationApi {

    // 更新地理位置
    Boolean updateLocation(Long userId, Double longitude, Double latitude, String address);
}

Ⅱ. ApiImpl

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

@DubboService
public class UserLocationApiImpl implements UserLocationApi{

    @Autowired
    private MongoTemplate mongoTemplate;

    // 更新地理位置
    public Boolean updateLocation(Long userId, Double longitude, Double latitude, String address) {
        try {
            // 1. 根据用户id查询地址位置信息
            Query query = Query.query(Criteria.where("userId").is(userId));
            UserLocation location = mongoTemplate.findOne(query, UserLocation.class);
            // 2. 判断是否存在地址位置信息
            if(location == null) {
                // 3. 如果不存在, 保存
                location = new UserLocation();
                location.setUserId(userId);
                location.setAddress(address);
                location.setCreated(System.currentTimeMillis());
                location.setUpdated(System.currentTimeMillis());
                location.setLastUpdated(System.currentTimeMillis());
                location.setLocation(new GeoJsonPoint(longitude, latitude));
                mongoTemplate.save(location);
            } else {
                // 4. 如果存在, 更新
                Update update = Update.update("location", new GeoJsonPoint(longitude, latitude))
                        .set("update", System.currentTimeMillis())
                        .set("lastUpdated", location.getUpdated());
                mongoTemplate.updateFirst(query, update, UserLocation.class);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}

⑷. Postman测试

SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第22张图片
SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第23张图片

⑸. 模拟器修改定位

SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第24张图片


3. 搜附近

⑴. 需求分析

  • 搜索附近范围内的用户并展示
  • 以当前用户位置为圆心查询
  • 查询指定半径范围内所有用户

SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第25张图片

⑵. 接口文档

SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第26张图片

⑶. 编码实现

①. vo对象

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

//附近的人vo对象
@Data
@NoArgsConstructor
@AllArgsConstructor
public class NearUserVo {

    private Long userId;
    private String avatar;
    private String nickname;

    public static NearUserVo init(UserInfo userInfo) {
        NearUserVo vo = new NearUserVo();
        vo.setUserId(userInfo.getId());
        vo.setAvatar(userInfo.getAvatar());
        vo.setNickname(userInfo.getNickname());
        return vo;
    }
}

②. Controller接收请求参数

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

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

    @Autowired
    private TanhuaService tanhuaService;

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

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

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

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

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

    /**
     * 探花 - 推荐用户列表
     */
    @GetMapping("cards")
    public ResponseEntity queryCardsList() {
        List<TodayBest> list = this.tanhuaService.queryCardsList();
        return ResponseEntity.ok(list);
    }

    /**
     * 探花 - 喜欢
     */
    @GetMapping("{id}/love")
    public ResponseEntity<Void> likeUser(@PathVariable("id") Long likeUserId) {
        this.tanhuaService.likeUser(likeUserId);
        return ResponseEntity.ok(null);
    }


    /**
     * 不喜欢
     */
    @GetMapping("{id}/unlove")
    public ResponseEntity<Void> notLikeUser(@PathVariable("id") Long likeUserId) {
        this.tanhuaService.notLikeUser(likeUserId);
        return ResponseEntity.ok(null);
    }

    /**
     * 搜附近
     */
    @GetMapping("/search")
    public ResponseEntity<List<NearUserVo>> queryNearUser(String gender,
                                                          @RequestParam(defaultValue = "2000") String distance) {
        List<NearUserVo> list = this.tanhuaService.queryNearUser(gender, distance);
        return ResponseEntity.ok(list);
    }
}

③. Service层调用API查询获取附近用户的ID集合,构造返回

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

@Service
public class TanhuaService {

    @DubboReference
    private RecommendUserApi recommendUserApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private QuestionApi questionApi;

    @Autowired
    private HuanXinTemplate huanXinTemplate;

    @DubboReference
    private UserLikeApi userLikeApi;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    private MessagesService messagesService;

    @DubboReference
    private UserLocationApi userLocationApi;

    @Value("${tanhua.default.recommend.users}")
    private String recommendUser;

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

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

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

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

        // 5. 返回
        return vo;
    }

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

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

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

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

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


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

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

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

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

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

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

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

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

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

    // 探花 - 推荐用户列表
    public List<TodayBest> queryCardsList() {
        // 1. 调用推荐API查询数据列表(排除 喜欢/不喜欢 的用户, 数量限制)
        List<RecommendUser> users = recommendUserApi.queryCardsList(UserHolder.getUserId(), 10);

        // 2. 判断数据是否存在,如果不存在,构造默认数据 1,2,3...
        if(CollUtil.isEmpty(users)) {
            users = new ArrayList<>();
            String[] userIds = recommendUser.split(",");
            for (String userId : userIds) {
                RecommendUser recommendUser = new RecommendUser();
                recommendUser.setUserId(Convert.toLong(userId));
                recommendUser.setToUserId(UserHolder.getUserId());
                recommendUser.setScore(RandomUtil.randomDouble(60, 90));
                users.add(recommendUser);
            }
        }

        // 3. 构造vo
        List<Long> ids = CollUtil.getFieldValues(users, "userId", Long.class);
        Map<Long, UserInfo> infoMap = userInfoApi.findByIds(ids, null);
        List<TodayBest> vos = new ArrayList<>();
        for (RecommendUser user : users) {
            UserInfo userInfo = infoMap.get(user.getUserId());
            if(userInfo != null) {
                TodayBest vo = TodayBest.init(userInfo, user);
                vos.add(vo);
            }
        }
        return vos;
    }

    // 探花 - 喜欢
    public void likeUser(Long likeUserId) {
        // 1. 调用API,保存喜欢的数据(写入MongoDB)
        Boolean save = userLikeApi.saveOrUpdate(UserHolder.getUserId(), likeUserId, true);
        if(!save) {
            throw new BusinessException(ErrorResult.error());
        }

        // 2. 操作redis,写入喜欢的数据,删除不喜欢的数据
        redisTemplate.opsForSet().remove(Constants.USER_NOT_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());
        redisTemplate.opsForSet().add(Constants.USER_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());

        // 3. 判断是否双向喜欢
        if(isLike(likeUserId, UserHolder.getUserId())) {
            // 4. 如果是,则添加好友
            messagesService.contacts(likeUserId);
        }
    }

    // 公共方法 - 判断 id 是否在集合当中
    public Boolean isLike(Long userId, Long likeUserId) {
        String key = Constants.USER_LIKE_KEY + userId;
        return redisTemplate.opsForSet().isMember(key, likeUserId.toString());
    }

    // 探花 - 不喜欢
    public void notLikeUser(Long likeUserId) {
        // 1. 调用API,保存喜欢的数据(写入MongoDB)
        Boolean save = userLikeApi.saveOrUpdate(UserHolder.getUserId(), likeUserId, false);
        if(!save) {
            throw new BusinessException(ErrorResult.error());
        }

        // 2. 操作redis,写入喜欢的数据,删除不喜欢的数据
        redisTemplate.opsForSet().add(Constants.USER_NOT_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());
        redisTemplate.opsForSet().remove(Constants.USER_LIKE_KEY + UserHolder.getUserId(), likeUserId.toString());

        // 3. 判断是否双向不喜欢(删除双向好友)
    }

    // 搜附近
    public List<NearUserVo> queryNearUser(String gender, String distance) {
        // 1. 调用API查询附近的用户(返回附近所有用户的id, 包含当前用户的id)
        List<Long> userIds = userLocationApi.queryNearUser(UserHolder.getUserId(), Double.valueOf(distance));
        // 2. 判断集合是否为空
        if(CollUtil.isEmpty(userIds)) {
            return new ArrayList<>();
        }
        // 3. 调用UserInfoApi根据用户id查询用户详情
        UserInfo userInfo = new UserInfo();
        userInfo.setGender(gender);
        Map<Long, UserInfo> map = userInfoApi.findByIds(userIds, userInfo);
        // 4. 构造返回值
        List<NearUserVo> vos = new ArrayList<>();
        for (Long userId : userIds) {
            // 过滤当前用户
            if(userId == UserHolder.getUserId()) {
                continue;
            }
            UserInfo info = map.get(userId);
            if(info != null) {
                NearUserVo vo = NearUserVo.init(info);
                vos.add(vo);
            }
        }
        return vos;
    }
}

④. API层使用MongoDB的地理位置方法查询

Ⅰ. Api接口

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

public interface UserLocationApi {

    // 更新地理位置
    Boolean updateLocation(Long userId, Double longitude, Double latitude, String address);

    // 查询附近的人所有的用户id
    List<Long> queryNearUser(Long userId, Double metre);
}

Ⅱ. Api实现类

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

@DubboService
public class UserLocationApiImpl implements UserLocationApi{

    @Autowired
    private MongoTemplate mongoTemplate;

    // 更新地理位置
    public Boolean updateLocation(Long userId, Double longitude, Double latitude, String address) {
        try {
            // 1. 根据用户id查询地址位置信息
            Query query = Query.query(Criteria.where("userId").is(userId));
            UserLocation location = mongoTemplate.findOne(query, UserLocation.class);
            // 2. 判断是否存在地址位置信息
            if(location == null) {
                // 3. 如果不存在, 保存
                location = new UserLocation();
                location.setUserId(userId);
                location.setAddress(address);
                location.setCreated(System.currentTimeMillis());
                location.setUpdated(System.currentTimeMillis());
                location.setLastUpdated(System.currentTimeMillis());
                location.setLocation(new GeoJsonPoint(longitude, latitude));
                mongoTemplate.save(location);
            } else {
                // 4. 如果存在, 更新
                Update update = Update.update("location", new GeoJsonPoint(longitude, latitude))
                        .set("update", System.currentTimeMillis())
                        .set("lastUpdated", location.getUpdated());
                mongoTemplate.updateFirst(query, update, UserLocation.class);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    // 查询附近的人所有的用户id
    @Override
    public List<Long> queryNearUser(Long userId, Double metre) {
        // 1. 根据用户id查询用户的位置信息
        Query query = Query.query(Criteria.where("userId").is(userId));
        UserLocation location = mongoTemplate.findOne(query, UserLocation.class);
        if (location == null) {
            return null;
        }
        // 2. 以当前用户的位置信息绘制圆心
        GeoJsonPoint point = location.getLocation();
        // 3. 绘制半径
        Distance distance = new Distance(metre / 1000, Metrics.KILOMETERS);
        // 4. 绘制圆形
        Circle circle = new Circle(point, distance);
        // 5. 查询
        Query locationQuery = Query.query(Criteria.where("location").withinSphere(circle));
        List<UserLocation> list = mongoTemplate.find(locationQuery, UserLocation.class);
        return CollUtil.getFieldValues(list, "userId", Long.class);
    }
}

⑷. 添加地理位置数据

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

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

    @DubboReference
    private UserLocationApi userLocationApi;

    @Test
    public void testUpdateUserLocation() {
        this.userLocationApi.updateLocation(1L, 116.353885,40.065911, "育新地铁站");
        this.userLocationApi.updateLocation(2L, 116.352115,40.067441, "北京石油管理干部学院");
        this.userLocationApi.updateLocation(3L, 116.336438,40.072505, "回龙观医院");
        this.userLocationApi.updateLocation(4L, 116.396797,40.025231, "奥林匹克森林公园");
        this.userLocationApi.updateLocation(5L, 116.323849,40.053723, "小米科技园");
        this.userLocationApi.updateLocation(6L, 116.403963,39.915119, "天安门");
        this.userLocationApi.updateLocation(7L, 116.328103,39.900835, "北京西站");
        this.userLocationApi.updateLocation(8L, 116.609564,40.083812, "北京首都国际机场");
        this.userLocationApi.updateLocation(9L, 116.459958,39.937193, "德云社(三里屯店)");
        this.userLocationApi.updateLocation(10L, 116.333374,40.009645, "清华大学");
        this.userLocationApi.updateLocation(41L, 116.316833,39.998877, "北京大学");
        this.userLocationApi.updateLocation(42L, 117.180115,39.116464, "天津大学(卫津路校区)");
    }
}

SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第27张图片

⑸. 页面效果

SpringBoot交友APP项目实战(详细介绍+案例源码) - 8.附近的人(百度地图APi)_第28张图片


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