25.访客功能

news2024/11/28 0:39:59

访客功能

一、需求分析

用户在浏览我的主页时,需要记录访客数据,访客在一天内每个用户只记录一次。

首页展示最新5条访客记录

我的模块,分页展示所有的访客记录

二、数据库表

visitors(访客记录表)

{
“_id”: ObjectId(“636334b470603e72be5dbc8d”),
“userId”: NumberLong(“1”),
“visitorUserId”: NumberLong(“1”),
“from”: “首页”,
“date”: NumberLong(“1667445940900”),
“visitDate”: “20221103”,
“score”: 99,
“_class”: “com.tanhua.model.mongo.Visitors”
}

三,保存访客记录

用户在浏览我的主页时,需要记录访客数据

访客在一天内每个用户只记录一次。

思路:1.修改查看佳人详情接口

​ 2.构造访问信息,调用API保存访客数据

代码实现,在查看佳人详情时,保存一条我的访问记录


    /**
     * 根据id查看佳人详情
     * 这个userId是当前用户要查看的用户的id
     */
    public TodayBest queryToBestInfo(Long userId) {
        //当前用户id
        Long currentUserId = ThreadLocalUtils.getUserId();

        //1.根据用户id查询用户详情
        UserInfo userInfo = userInfoApi.selectUserInfo(userId);
        //2.根据当前用户的id,和当前用户要查看的用户id查询推荐人
        RecommendUser recommendUser = recommendUserApi.queryRecommendFriend(userId,currentUserId);



        //3.在查看用户详情页面的同时,保存一条当前用户的访问记录到visitor数据库表
        Visitors visitors = new Visitors();
        visitors.setUserId(userId);
        //当前用户未访客
        visitors.setVisitorUserId(currentUserId);
        visitors.setFrom("首页");
        visitors.setDate(System.currentTimeMillis());
        visitors.setVisitDate(new SimpleDateFormat("yyyyMMdd").format(new Date()));
        visitors.setScore(recommendUser.getScore());

        visitorsApi.saveVisitors(visitors);




        //构造返回值
        TodayBest todayBest = TodayBest.init(userInfo, recommendUser);
        return todayBest;
    }

VisitorApiImpl

 @Autowired
    private MongoTemplate mongoTemplate;

    /**
     *
     * 保存访客记录,
     * 同一个用户一天只能保存一次访客记录
     */
    public void saveVisitors(Visitors visitors) {

        //1.根据UserId和visitorUserId还有visitDate查询visitors表

        Criteria criteria =           Criteria.where("userId").is(visitors.getUserId())
                .and("visitorUserId").is(visitors.getVisitorUserId())
                .and("visitDate").is(visitors.getVisitDate());

        Query query = Query.query(criteria);



        if(!mongoTemplate.exists(query, Visitors.class)){
            mongoTemplate.save(visitors);
        }


    }

四、访客列表

vo对象

package com.tanhua.model.vo;

import com.tanhua.model.domain.UserInfo;
import com.tanhua.model.mongo.Visitors;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.beans.BeanUtils;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class VisitorsVo {

    private Long id; //用户id
    private String avatar;
    private String nickname;
    private String gender; //性别 man woman
    private Integer age;
    private String[] tags;
    private Long fateValue; //缘分值

    /**
     * 在vo对象中,补充一个工具方法,封装转化过程
     */
    public static VisitorsVo init(UserInfo userInfo, Visitors visitors) {
        VisitorsVo vo = new VisitorsVo();
        BeanUtils.copyProperties(userInfo,vo);
        if(userInfo.getTags() != null) {
            vo.setTags(userInfo.getTags().split(","));
        }
        vo.setFateValue(visitors.getScore().longValue());
        return vo;
    }
}

UsersController


    /**
     * 查询全部访客记录
     * 请求路径:/users/friends/:type
     * 请求方式:get
     * 请求参数:路径参数:type;
     *        page(当前页码),
     *        pagesize(每页展示数),
     *        nickname(昵称)
     * 响应数据:VisitorsVo
     */

    @GetMapping("/friends/{type}")
    public ResponseEntity queryVisitors(@PathVariable("type") Integer type,
                                        @RequestParam(defaultValue = "1") Integer page,
                                        @RequestParam(defaultValue = "10") Integer pagesize,
                                        @RequestParam(required = false) String nickname){

        PageResult pageResult = service.queryVisitors(page,pagesize,nickname);

        return ResponseEntity.ok(pageResult);
    }

UsersService



    /**
     *查看所有访客记录
     */
    public PageResult queryVisitors(Integer page, Integer pagesize, String nickname) {

        //1调用api查询所有访客
        Long currentUserId = ThreadLocalUtils.getUserId();
       List<Visitors>   visitors =  visitorsApi.queryVisitors(currentUserId,page,pagesize);

       //2.判断有无访客记录
        if(CollUtil.isEmpty(visitors)){
            return new PageResult();
        }

        //3.把查询全部的访客这次时间记录缓存进redis
        String key = Constants.VISITORS;
        String hashKey =String.valueOf(ThreadLocalUtils.getUserId());
        String timeMillis = String.valueOf(System.currentTimeMillis());
        redisTemplate.opsForHash().put(key, hashKey, timeMillis);

        //4.先获取全部访客的id,再根据id查询他们的用户详情
        List<Long> visitorUserIds = CollUtil.getFieldValues(visitors, "visitorUserId", Long.class);
        UserInfo info = new UserInfo();
        info.setNickname(nickname);

        Map<Long, UserInfo> userInfoMap = userInfoApi.batchQueryUserInfo(visitorUserIds, info);


        //5.遍历所有访客集合,构造vo对象

        List<VisitorsVo> vos = new ArrayList<>();

        for (Visitors visitor : visitors) {
            Long userId = visitor.getVisitorUserId();

            UserInfo userInfo = userInfoMap.get(userId);

            if(userInfo != null){
                VisitorsVo vo = VisitorsVo.init(userInfo, visitor);
                vos.add(vo);
            }
        }


        //6.构造返回值

        PageResult pageResult = new PageResult(page,pagesize,0,vos);
        return pageResult;

    }

VisitorApiImpl

 /**
     * 查看所有访客记录
     * @param currentUserId
     * @param page
     * @param pagesize
     * @return
     */
    public List<Visitors> queryVisitors(Long currentUserId, Integer page, Integer pagesize) {

        Criteria criteria = Criteria.where("userId").is(currentUserId);
        Query query = Query.query(criteria);
        query.skip((page - 1 ) * pagesize ).limit(pagesize).with(Sort.by(Sort.Order.desc("date")));

        List<Visitors> visitors = mongoTemplate.find(query, Visitors.class);

        return visitors;
    }

五,查看首页最新访客数据

业务流程

1667462390469

思路

1667462420461

代码实现,MovementController


    /**
     * 谁看过我
     * 请求路径:/movements/visitors
     * 请求方式:get
     * 响应数据:VisitorsVo
     */
    @GetMapping("visitors")
    public ResponseEntity queryVisitorsList(){
        List<VisitorsVo> list = movementsService.queryVisitorsList();
        return ResponseEntity.ok(list);
    }

MovementService


    /**
     * 首页访客列表
     * @return
     */
    public List<VisitorsVo> queryVisitorsList() {
        //1.从redis缓存中获取查看全部访客列表时间
        String key = Constants.VISITORS;
        String hashKey = String.valueOf(ThreadLocalUtils.getUserId());

        String value = (String) redisTemplate.opsForHash().get(key, hashKey);

        //三元运算符
        Long date = StringUtils.isEmpty(value) ? null:Long.valueOf(value);

        //2.调用api查询访客列表

       List<Visitors> visitors =  visitorsApi.queryLatestVisitors(date,ThreadLocalUtils.getUserId());

       //3.判断访客列表是否为空
        if(CollUtil.isEmpty(visitors)){
            return new ArrayList<>();
        }


        //4.提取访客的id,根据id查询用户详情
        List<Long> visitorUserIds = CollUtil.getFieldValues(visitors, "visitorUserId", Long.class);
        Map<Long, UserInfo> userInfoMap = userInfoApi.batchQueryUserInfo(visitorUserIds, null);


        //5.遍历访客列表集合,构造vo
        List<VisitorsVo> vos = new ArrayList<>();
        for (Visitors visitor : visitors) {
            Long visitorUserId = visitor.getVisitorUserId();
            UserInfo userInfo = userInfoMap.get(visitorUserId);

            if(userInfo != null){
                VisitorsVo vo = VisitorsVo.init(userInfo, visitor);
                vos.add(vo);
            }
        }

        return vos;
    }

VisitorApiImpl


    /**
     * 查看首页的访客
     * @param date
     * @param userId
     * @return
     */
    public List<Visitors> queryLatestVisitors(Long date, Long userId) {

        //1.构造条件
        Criteria criteria = Criteria.where("userId").is(userId);

        //2.判断redis中有没有缓存查看全部访客列表的时间,有则添加条件

        if(date != null){
            criteria.and("date").gt(date);
        }



        Query query = Query.query(criteria);
        query .limit(5).with(Sort.by(Sort.Order.desc("date")));

        List<Visitors> visitors = mongoTemplate.find(query, Visitors.class);
        return visitors;
    }
    //2.判断redis中有没有缓存查看全部访客列表的时间,有则添加条件

    if(date != null){
        criteria.and("date").gt(date);
    }



    Query query = Query.query(criteria);
    query .limit(5).with(Sort.by(Sort.Order.desc("date")));

    List<Visitors> visitors = mongoTemplate.find(query, Visitors.class);
    return visitors;
}

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

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

相关文章

尚医通 (三十五) --------- 预约下单

目录一、预约下单前端1. 封装 api 请求2. 页面修改二、后端逻辑1. 需求分析2. 搭建 service-order 模块3. 添加订单基础类4. 封装 Feign 调用获取就诊人接口5. 封装 Feign 调用获取排班下单信息接口6. 实现下单接口7. 预约成功后处理逻辑① rabbit-util 模块封装② 封装短信接口…

C++ Reference: Standard C++ Library reference: Containers: map: map: cend

C官网参考链接&#xff1a;https://cplusplus.com/reference/map/map/cend/ 公有成员函数 <map> std::map::cend const_iterator cend() const noexcept;返回指向结束的const_iterator 返回一个指向容器结束后元素的const_iterator。 const_iterator是指向const内容的it…

正弦交流电物理量表征

前言 这一讲主要来表征正弦交流电的物理量 文章目录前言一、周期和频率二、最大值、有效值和平均值一、周期和频率 周期&#xff1a;正弦交流电每重复变化1次所需要的时间称为周期&#xff0c;用符号T表示&#xff0c;单位是秒&#xff08;s&#xff09;。 频率&#xff1a;正…

web前端期末大作业 绿色环境保护(4个页面) HTML5网站模板农业展示网站 html5网页制作代码 html5网页设计作业代码 html制作网页案例代码

&#x1f380; 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业…

体育馆场地预约管理系统/球馆管理系统

摘 要 随着体育馆规模的不断扩大&#xff0c;人流数量的急剧增加&#xff0c;有关体育馆的各种信息量也在不断成倍增长。面对庞大的信息量&#xff0c;就需要有体育馆场地预约管理系统来提高体育馆工作的效率。通过这样的系统&#xff0c;我们可以做到信息的规范管理和快速查询…

TCP/IP网络原理 【IP篇】

&#x1f389;&#x1f389;&#x1f389;写在前面&#xff1a; 博主主页&#xff1a;&#x1f339;&#x1f339;&#x1f339;戳一戳&#xff0c;欢迎大佬指点&#xff01; 目标梦想&#xff1a;进大厂&#xff0c;立志成为一个牛掰的Java程序猿&#xff0c;虽然现在还是一个…

聚观早报 | 马斯克丢掉世界首富宝座;加密货币FTX创始人被捕

今日要闻&#xff1a;马斯克丢掉世界首富宝座&#xff1b;加密货币FTX创始人被捕&#xff1b;美团推出高峰打车极速版&#xff1b;魔兽制作组正研发新功能&#xff1b;SpaceX出售公司内部股票马斯克丢掉世界首富宝座 12 月 13 日消息&#xff0c;据国外媒体报道&#xff0c;受特…

7-54 孤岛营救问题——状压bfs+三维标记

1944 年&#xff0c;特种兵麦克接到国防部的命令&#xff0c;要求立即赶赴太平洋上的一个孤岛&#xff0c;营救被敌军俘虏的大兵瑞恩。瑞恩被关押在一个迷宫里&#xff0c;迷宫地形复杂&#xff0c;但幸好麦克得到了迷宫的地形图。迷宫的外形是一个长方形&#xff0c; 其南北方…

二、小程序框架

目录 框架 一、响应的数据绑定 二、页面管理 三、基础组件 四、丰富的API 模块化 一、模块化 二、文件作用域 三、API 视图层 View 一、WXML 事件 什么是事件 事件的使用方式 使用 WXS 函数响应事件 事件详解 框架 小程序开发框架的目标是通过尽可能简单、高效…

万字长文详解 YOLOv1-v5 系列模型

一&#xff0c;YOLOv1二&#xff0c;YOLOv2三&#xff0c;YOLOv3四&#xff0c;YOLOv4五&#xff0c;YOLOv5参考资料 一&#xff0c;YOLOv1 YOLOv1 出自 2016 CVPR 论文 You Only Look Once:Unified, Real-Time Object Detection. YOLO 系列算法的核心思想是将输入的图像经过…

同时安装python3和Python2

一刚开始我很疑惑&#xff0c;Python为何要并行两个版本呢&#xff1f;今天我算知道了&#xff0c;原来是因为有的项目一直在用python2。虽然我已经安装了python3但是那些使用python2进行部署的项目我仍然无法使用&#xff0c;这就导致我要在电脑上同时安装python2和Python3了。…

【无标题】SIP网络广播音频模块

SIP2101V和SIP2103V网络音频模块是一款通用的独立SIP音频功能模块&#xff0c;可以轻松地嵌入到OEM产品中。该模块对来自网络的SIP协议及RTP音频流进行编解码。 该模块支持多种网络协议和音频编解码协议&#xff0c;可用于VoIP和IP寻呼以及高质量音乐流媒体播放等应用。同时&a…

如何将onnx转ncnn供移动端推理使用

ncnn是一个为手机端极致优化的高性能神经网络前向计算框架。基于 ncnn&#xff0c;开发者能够将深度学习算法轻松移植到手机端高效执行&#xff0c;开发出人工智能 APP&#xff0c;将 AI 带到你的指尖。 但是onnx直接转ncnn会存在很多问题&#xff0c;所以一般考虑都是先将onn…

Mysql 进阶(面向面试篇)InnoDB引擎(redo log undolog readview mvcc)

1.1 逻辑存储结构 1). 表空间 表空间是InnoDB存储引擎逻辑结构的最高层&#xff0c; 如果用户启用了参数 innodb_file_per_table(在8.0版本中默认开启) &#xff0c;则每张表都会有一个表空间&#xff08;xxx.ibd&#xff09;&#xff0c;一个mysql实例可以对应多个表空间&…

【ElasticSearch 进阶】倒排索引 + FOR + RBM压缩算法

1. 倒排索引 如果有100w的数据&#xff0c;进行分词后&#xff0c;每个id按数字类型进行存储&#xff0c;假设每个行数据都包含相同的词&#xff0c;则每个词的 Posting List 需要占用约4M的空间&#xff1a; 1 int 4 Bytes 100W int 400W Bytes ≈ 4M 极大的浪费了空间。则需…

IDC:中国网络安全市场投资规模将在2026年达到319亿美元

近日&#xff0c;IDC咨询发布《IDC Market Forecast&#xff1a;中国网络安全市场预测&#xff0c;2022-2026》报告&#xff0c;对未来五年的中国网络安全市场发展走向做出分析预测。报告认为&#xff0c;中国IT安全市场投资规模逐年攀升&#xff0c;到2026年将达到319亿美元&a…

MySQL经典50题

MySQL经典50题 mysq经典50题拿来练手 文章目录MySQL经典50题创建表及信息录入1、查询"01"课程比"02"课程成绩高的学生的信息及课程分数2、查询"01"课程比"02"课程成绩低的学生的信息及课程分数3、查询平均成绩大于等于60分的同学的学生…

[阶段4 企业开发进阶] 5. Netty

文章目录1 Netty1.1 Netty介绍1.2 Netty应用场景2 Java BIO编程2.1 IO模型2.2 BIO、NIO、AIO 适用场景分析2.3 BIO3 Java NIO编程3.1 NIO基本介绍3.2 NIO和BIO的比较3.3 NIO三大核心原理1 Netty 1.1 Netty介绍 Netty 是由 JBOSS 提供的一个 Java 开源框架Netty 是一个异步的、…

技术分享 | 做为测试,那些必须掌握的测试技术体系

软件测试技术是软件开发过程中的一个重要组成部分&#xff0c;是贯穿整个软件开发生命周期、对软件产品&#xff08;包括阶段性产品&#xff09;进行验证和确认的活动过程。其目的是尽快尽早地发现在软件产品中所存在的各种问题&#xff0c;与用户需求、预先定义的不一致性。检…

Revit 中柱子附着屋顶小技巧和“柱断墙梁”方法

一、Revit 中柱子附着屋顶小技巧 Revit 中如何正确的使柱子附着于屋顶? 有的朋友绘制完结构柱后想要附着到屋顶上&#xff0c;这时候大家会选择把柱子顶部拉上去或者选择“附着顶部/底部”命令。但是这样会出现如图 1所示情况 此时柱子并未与屋顶完全相交&#xff0c;这时候有…