18.查询好友动态和推荐动态

查询好友动态和推荐动态

一、查询好友动态

代码步骤

  • Controller层接受请求参数
  • Service数据封装
    • 调用API查询好友动态详情数据
    • 调用API查询动态发布人详情
    • 构造VO对象
  • API层根据用户ID查询好友发布动态详情
    • 查询好友时间线表
    • 查询动态详情

1.1Controller


    /**
     * 查看好友动态
     * 1.请求路径::/movements
     * 2.请求方式:get
     * 3.请求参数:page,当前页码;pagesize,每页展示数
     * 4.响应数据:PageResult
     */

    @GetMapping
    public ResponseEntity viewSocialUpdates(@RequestParam(defaultValue = "1") Integer page,
                                            @RequestParam(defaultValue = "10") Integer pageSize){

        //1.接收参数,调用业务层完成查询
       PageResult pageResult = movementsService.viewSocialUpdates(page,pageSize);

       //2.构造返回值
        return ResponseEntity.ok(pageResult);
    }

1.2、Service

/**
     *  查看好友动态
     */
    public PageResult viewSocialUpdates(Integer page, Integer pageSize) {

        //1.获取当前登录的用户id
        Long userId = ThreadLocalUtils.getUserId();
        //2.调用api查看好友的动态详情集合
        List<Movement> movements = movementsApi.viewSocialUpdates(userId, page, pageSize);

        //3.判断movements是否为空,为空直接new一个PageResult返回,为空的意思是当前登录的用户没有好友发布动态
        if(CollUtil.isEmpty(movements)){
            //ddd,这个害我搞了半天,之前我用的是movements == null,害死人//走到  这步movements为空的时候程序会一直往下走,不会停掉返回;然后就会在下面掉用userInfo的时候因为movements为空报mysql的sql语法错误
            return new PageResult();
        }

        //4.先批量获取好友动态详情表中的用户id,再根据批量的用户id批量获取用户详情
        List<Long> userIds = CollUtil.getFieldValues(movements, "userId", Long.class);
        Map<Long, UserInfo> userInfoMap = userInfoApi.batchQueryUserInfo(userIds, null);//null参数位置为条件


        //5.遍历movements集合,每遍历一个动态详情表就构造一个vo对象
        List<MovementsVo> movementsVos = new ArrayList<>();

        for (Movement movement : movements) {
            Long id = movement.getUserId();
            UserInfo userInfo = userInfoMap.get(id);
            if(userInfo != null){
                MovementsVo movementsVo = MovementsVo.init(userInfo, movement);

                //修复动态点赞bug
                String key = Constants.MOVEMENTS_INTERACT_KEY + movement.getId().toHexString();//动态id
                String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + ThreadLocalUtils.getUserId();

                if(redisTemplate.opsForHash().hasKey(key, hashKey)){
                    movementsVo.setHasLiked(1);
                }

                String loveHashKey = Constants.MOVEMENT_LOVE_HASHKEY  + ThreadLocalUtils.getUserId();
                if(redisTemplate.opsForHash().hasKey(key, loveHashKey)){
                    movementsVo.setHasLoved(1);
                }

                    movementsVos.add(movementsVo);
            }
        }

        //6.构造返回条件
        return new PageResult(page,pageSize,0,movementsVos);
    }

1.3、Api层

 /**
     *查看好友动态
     */
    public List<Movement> viewSocialUpdates(Long friendId, Integer page, Integer pageSize) {

        //1.根据用户id查询时间线表

        //1.1创建Criteria对象,构造查询条件
        Criteria criteria = Criteria.where("friendId").is(friendId);
        //1.2根据Criteria创建Query对象
        Query query = Query.query(criteria)
                .skip((page - 1) * pageSize)
                .limit(pageSize).with(Sort.by(Sort.Order.desc("created")));

        List<MovementTimeLine> timeLines = mongoTemplate.find(query, MovementTimeLine.class);


        //2.在时间线表批量获取动态详情的id
        //这个list集合装的是好友的动态详情id
        List<ObjectId> movementIds = CollUtil.getFieldValues(timeLines, "movementId", ObjectId.class);

        //3.根据动态详情id查询动态

        Criteria criteria1 = Criteria.where("id").in(movementIds);
        Query query1 = Query.query(criteria1);

        List<Movement> movements = mongoTemplate.find(query1, Movement.class);

        return movements;

    }

二、推荐动态

推荐动态是通过推荐系统计算出的结果,现在我们只需要实现查询即可,推荐系统在后面的课程中完成。

推荐系统计算完成后,会将结果数据写入到Redis中,数据如下:

key: MOVEMENTS_RECOMMEND_1
value:  "2562,3639,2063,3448,2128,2597,2893,2333,3330,2642,2541,3002,3561,3649,2384,2504,3397,2843,2341,2249"

可以看到,在Redis中的数据是有多个发布id组成(pid)由逗号分隔。所以实现中需要自己对这些数据做分页处理。

代码步骤

  • Controller层接受请求参数
  • Service数据封装
    • 从redis获取当前用户的推荐PID列表
    • 如果不存在,调用API随机获取10条动态数据
    • 如果存在,调用API根据PID列表查询动态数据
    • 构造VO对象
  • API层编写方法
    • 随机获取
    • 根据pid列表查询

2.1Controller


    /**
     * 查看推荐动态:
     * 1.请求路径:/movements/recommend
     * 2.请求方式:get
     * 3.请求参数:page,当前页码;pageSize,每页展示数
     * 4.响应数据:MovementsVO
     */

    @GetMapping("/recommend")
    public ResponseEntity               lookRecommendMoments(@RequestParam(defaultValue = "1") Integer page,
                                               @RequestParam(defaultValue = "10") Integer pageSize ){

        //1.调用业务层完成业务逻辑
        PageResult pageResult = movementsService.lookRecommendMoments(page,pageSize);
        //2.构造返回值
        return ResponseEntity.ok(pageResult);

    }

2.2Service


    /**
     *
     * 查看大数据系统推荐的动态
     */
    public PageResult lookRecommendMoments(Integer page, Integer pageSize) {

        //1.从Redis中获取大数据推荐系统要推送的动态详情存入的动态详情pid
        //1.1先获取当前登录的用户id
        Long userId = ThreadLocalUtils.getUserId();
       String redisKey = Constants.MOVEMENTS_RECOMMEND + userId;
        String redisValue = redisTemplate.opsForValue().get(redisKey);

        //2.判断大数据推荐系统有没有推荐动态详情
        // 判断redisValue是否为空,为空则自己随机推荐几条动态详情给用户

        List<Movement> movements = Collections.EMPTY_LIST;

        if (StringUtils.isEmpty(redisValue)){
            movements = movementsApi.randomMoments(pageSize);
        }else{
            //3.大数据系统根据用户的行为特征计算出要推送给用户的动态详情
            //处理pid
            String[] pids = redisValue.split(",");

            if( (page - 1) * pageSize < pids.length) {

                //这两行没有注释,因为我自己也不怎么理解
                List<Long> longPids = Arrays.stream(pids).skip((page - 1) * pageSize).limit(pageSize)
                        .map(e -> Long.valueOf(e))
                        .collect(Collectors.toList());


                //4.调用api完成批量查询动态详情
                movements =movementsApi.lookRecommendMoments(longPids);
            }
        }


        //5.先从查询出来的要推荐给用户的动态详情集合里获取全部用户id
        //调用UserInfo查询全部用户的用户详情
        List<Long> userIds = CollUtil.getFieldValues(movements, "userId", Long.class);
        Map<Long, UserInfo> userInfoMap = userInfoApi.batchQueryUserInfo(userIds, null);

        //6.遍历查出来要推荐给用户的动态详情集合,每一个动态详情集合构建一个vo对象

        List<MovementsVo> movementsVos = new ArrayList<>();
        for (Movement movement : movements) {
            //获取用户id
            Long id = movement.getUserId();
            //根据用户id获取用户详情
            UserInfo userInfo = userInfoMap.get(id);
            if(userInfo != null){
                MovementsVo movementsVo = MovementsVo.init(userInfo, movement);

                String key = Constants.MOVEMENTS_INTERACT_KEY + movement.getId().toHexString();
                String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + ThreadLocalUtils.getUserId();

                if(redisTemplate.opsForHash().hasKey(key, hashKey)){
                    movementsVo.setHasLiked(1);
                }

                String loveHashKey = Constants.MOVEMENT_LOVE_HASHKEY  + ThreadLocalUtils.getUserId();
                if(redisTemplate.opsForHash().hasKey(key, loveHashKey)){
                    movementsVo.setHasLoved(1);
                }
                movementsVos.add(movementsVo);
            }

        }

        //7.构造返回值
        PageResult pageResult = new PageResult(page, pageSize ,0,movementsVos);
        return pageResult;

    }

2.3ApiC层


    /**
     *  大数据推荐系统没有推荐的动态详情,自己随机推荐,保证用户使用体验
     */
    public List<Movement> randomMoments(Integer pageSize) {

        //
        TypedAggregation<Movement> aggregation = Aggregation.newAggregation(Movement.class, Aggregation.sample(pageSize));

        AggregationResults<Movement> results = mongoTemplate.aggregate(aggregation, Movement.class);

        List<Movement> mappedResults = results.getMappedResults();
        return mappedResults;
    }

    /**
     *   大数据系统根据用户的行为特征计算出要推送给用户的动态详情
     */
    public List<Movement> lookRecommendMoments(List<Long> longPids) {
        //1.创建Criteria对象,设置查询条件,根据pid查询动态详情表
        Criteria criteria = Criteria.where("pid").in(longPids);
        //2.根据criteria创建Query对象
        Query query = Query.query(criteria);

        List<Movement> movements = mongoTemplate.find(query, Movement.class);
        return movements;
    }

三、查询单条动态

一、 Controller


    /**
     * 根据动态详情对象的id查询单条用户动态:
     * 请求路径:/movements/:id
     * 请求方式:get
     * 请求参数:路径参数id,动态id
     * 响应数据:MovementsVo
     */
    @GetMapping("/{id}")
    public ResponseEntity lookOneMoment(@PathVariable("id") String id){
        //1.调用业务层完成业务逻辑
      MovementsVo movementsVo =  movementsService.lookOneMoment(id);
        //2.构建返回数据
        return ResponseEntity.ok(movementsVo);
    }

二、Service

 /**
     *
     * 查看单条动态
     */
    public MovementsVo lookOneMoment(String movementId) {

        //1.调用api查询动态
        Movement movement = movementsApi.lookOneMoment(movementId);

        MovementsVo movementsVo =null;

        //2.非空校验
        if (movement == null) {
            return null;
        } else {
            //调用userInfoApi查用户详情
            UserInfo userInfo = userInfoApi.selectUserInfo(movement.getUserId());
            if (userInfo != null) {

                 movementsVo = MovementsVo.init(userInfo, movement);

                String key = Constants.MOVEMENTS_INTERACT_KEY + movement.getId().toHexString();
                String hashKey = Constants.MOVEMENT_LIKE_HASHKEY + ThreadLocalUtils.getUserId();

                if (redisTemplate.opsForHash().hasKey(key, hashKey)) {
                    movementsVo.setHasLiked(1);
                    movementsVo.setLikeCount(1);
                }

                String loveHashKey = Constants.MOVEMENT_LOVE_HASHKEY + ThreadLocalUtils.getUserId();
                if (redisTemplate.opsForHash().hasKey(key, loveHashKey)) {
                    movementsVo.setHasLoved(1);
                }



            }

        }

        return movementsVo;
    }

三、api

  /**
     *
     *查询单条动态
     */
    public Movement lookOneMoment(String movementId) {

        Movement movement = mongoTemplate.findById(movementId, Movement.class);
        return movement;
    }
posted @ 2022-10-30 12:09  给我手牵你走  阅读(293)  评论(0编辑  收藏  举报