java 探花交友项目day5 推荐好友列表 MongoDB集群 发布动态,查询动态 圈子功能

news2024/12/24 23:58:52

推荐好友列表

需求分析

推荐好友:分页形式查询推荐的用户列表,根据评分排序显示

 代码实现:

tanhuaController:

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

tanhuaService:

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、提取所有推荐的用户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对象
    Long count=0L;
    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);
            count++;
        }
    }

    pr.setCounts(count);
    //8、构造返回值
    pr.setItems(list);
    log.info("最终推荐表:{}",pr);
    return pr;
}

RecommendUserApiImpl

//分页查询
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).with(Sort.by(Sort.Order.desc("score"))).limit(pagesize)
            .skip((page - 1) * pagesize);
    //3、调用mongoTemplate查询
    List<RecommendUser> list = mongoTemplate.find(query, RecommendUser.class);
    long count = mongoTemplate.count(query, RecommendUser.class);
    //4、构建返回值PageResult
    return  new PageResult(page,pagesize,count,list);
}

请求dto对象

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class RecommendUserDto {

    private Integer page = 1; //当前页数
    private Integer pagesize = 10; //页尺寸
    private String gender; //性别 man woman
    private String lastLogin; //近期登陆时间
    private Integer age; //年龄
    private String city; //居住地
    private String education; //学历
}

我们定义了一个userInfoApi的查询多个userinfo的功能,这样在查询出推荐用户表的时候,我们根据多个id在userInfoApi直接一次性查询到,而且可以增加年龄性别等条件,这样查询出再在controller层进行筛选

MongoDB集群

问题分析: 

集群概述:

 

 副本集群:多个服务器存储相同的数据保证可靠性。但是不能解决海量数据问题

分片集群

 

 为了保证每个服务的高可用,需要服务配置副本集群,这里仅以单节点为例

路由服务如何获取文档的分片服务器位置呢?

分片集群:分片策略

圈子功能

需求分析

探花交友项目中的圈子功能,类似微信的朋友圈

发布动态

浏览好友、个人、推荐动态

动态互动如:点赞、评论、喜欢等

 

表结构设计

优点 :开发难度较小 易于理解

缺点 :动态对特定好友可见/不可见,实现难度较大 效率较低 

优点 开发难度较小 可以完成所有业务功能

缺点 效率较低 索引空间占用 

 也就是,我们另外创建个时间线表,来存放动态表的id ,用户 及其好友

 

 

环境搭建

Mongodb中实现字段的自增:两种解决方法(1、使用redis保证自动增长,2、使用mongodb自定义表)  redis在用户端,我们使用第二种

mongo主键自增

1.创建实体类

@Document(collection = "sequence")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Sequence {

    private ObjectId id;

    private long seqId; //自增序列

    private String collName;  //集合名称
}

2.编写service

@Component
public class IdWorker {

    @Autowired
    private MongoTemplate mongoTemplate;

    public Long getNextId(String collName) {
        Query query = new Query(Criteria.where("collName").is(collName));

        Update update = new Update();
        update.inc("seqId", 1);

        FindAndModifyOptions options = new FindAndModifyOptions();
        options.upsert(true);
        options.returnNew(true);

        Sequence sequence = mongoTemplate.findAndModify(query, update, options, Sequence.class);
        return sequence.getSeqId();
    }
}

实体类

Movement:发布信息表(总记录表数据)

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


    private ObjectId id; //主键id
    private Long pid; //Long类型,用于推荐系统的模型(自动增长)
    private Long created; //发布时间
    private Long userId;
    private String textContent; //文字
    private List<String> medias; //媒体数据,图片或小视频 url
    private String longitude; //经度
    private String latitude; //纬度
    private String locationName; //位置名称
    private Integer state = 0;//状态 0:未审(默认),1:通过,2:驳回
}

MovementTimeLine:好友时间线表,用于存储好友发布(或推荐)的数据,每一个用户一张表进行存储


/**
 * 好友时间线表,用于存储好友发布的数据
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "movement_timeLine")
public class MovementTimeLine implements java.io.Serializable {

    private static final long serialVersionUID = 9096178416317502524L;
    private ObjectId id;
    private ObjectId movementId;//动态id
    private Long userId;   //发布动态用户id
    private Long friendId; // 可见好友id
    private Long created; //发布的时间
}
 

Friend 好友关系表


/**
 * 好友表:好友关系表
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Document(collection = "friend")
public class Friend implements java.io.Serializable{

    private static final long serialVersionUID = 6003135946820874230L;
    private ObjectId id;
    private Long userId; //用户id
    private Long friendId; //好友id
    private Long created; //时间

}
 

MovementApiImpl:

@DubboService
public class MovementApiImpl implements MovementApi{
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private IdWorker idWorker;
    @Override
    public void publish(Movement movement) {
        //1.保存动态详情
        //设置PID和发布时间
        movement.setPid(idWorker.getNextId("movement"));
        movement.setCreated(System.currentTimeMillis());
        //id会自动生成 我们定义的时候用了ObjectId
        mongoTemplate.save(movement);

        //2.查询当前用户的好友数据
        Criteria criteria=Criteria.where("userId").is(movement.getUserId());
        Query query=Query.query(criteria);
        List<Friend> friends = mongoTemplate.find(query, Friend.class);
        log.info("friends:{}",friends);
        //3.循环好友数据,构建时间线数据存入数据库
        for (Friend friend : friends) {
            MovementTimeLine timeLine =new MovementTimeLine();
            timeLine.setMovementId(movement.getId());
            timeLine.setUserId(friend.getUserId());
            timeLine.setFriendId(friend.getFriendId());
            timeLine.setCreated(System.currentTimeMillis());
            log.info("timeline:{}",timeLine);
            mongoTemplate.save(timeLine);
        }


    }
}

MovementController

@RestController
@RequestMapping("/movements")
public class MovementController {
    @Autowired
    private MovementService movementService;
    /**
     * 发布动态
     */
    @PostMapping
    public ResponseEntity movements(Movement movement,
                                    MultipartFile imageContent[]
                                    ) throws IOException {
        movementService.publishMovement(movement,imageContent);

        return ResponseEntity.ok(null);
    }
}

MovementService

@Service
public class MovementService {

    @Autowired
    private OssTemplate ossTemplate;

    @DubboReference
    private MovementApi movementApi;
    /**
     * 发布动态
     * @param movement
     * @param imageContent
     */
    public void publishMovement(Movement movement, MultipartFile[] imageContent) throws IOException {
        //1.判断发布动态内容是否存在
        if (StringUtils.isEmpty(movement.getTextContent())){
            throw new BusinessException(ErrorResult.contentError());
        }
        //2.获取当前登录用户id
        Long userId = UserHolder.getUserId();

        //3.将文件内容上传到阿里云,获取请求地址
        List<String> medias=new ArrayList<>();
        for (MultipartFile multipartFile : imageContent) {
            String upload =ossTemplate.upload(multipartFile.getOriginalFilename(),multipartFile.getInputStream());
            medias.add(upload);
        }

        //4.将数据封装到movement对象

        movement.setUserId(userId);
        movement.setMedias(medias);
        //5.调用API完成发布动态
        movementApi.publish(movement);
    }
}

大量的时间线数据同步写入的问题如何解决?

我们在保存时间线数据的时候,用的循环保存,如果好友量特别大,那么进程就会特别慢

发布动态-异步处理

@Async: Spring提供的异步处理注解,被此注解标注的方法会在新的线程中执行,其实就相当于我们自己new Thread。

解决:

我们将需要新开线程的内容提出成一个类:

@Component
public class TimeLineService {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Async
    public void saveTimeLine(Long userId, ObjectId movementId) {
        //2、查询当前用户的好友数据
        Criteria criteria = Criteria.where("userId").is(userId);
        Query query = Query.query(criteria);
        List<Friend> friends = mongoTemplate.find(query, Friend.class);
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //3、循环好友数据,构建时间线数据存入数据库
        for (Friend friend : friends) {
            MovementTimeLine timeLine = new MovementTimeLine();
            timeLine.setMovementId(movementId);
            timeLine.setUserId(friend.getUserId());
            timeLine.setFriendId(friend.getFriendId());
            timeLine.setCreated(System.currentTimeMillis());
            mongoTemplate.save(timeLine);
        }
    }
}

我的动态

 

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

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

相关文章

回归模型评价指标原理与基于sklearn的实现

1 前言 回归任务是机器学习中常见的任务&#xff0c;特别是涉及到具体的发电量预测、风力预测等工业任务时&#xff0c;有非常多的应用场景。回归任务不同于分类任务&#xff0c;回归任务的预测值一般是连续的数&#xff0c;分类任务的预测值则是离散的值&#xff08;比如0、1分…

ssh2.js+Shell一套组合拳下来,一年要花2080分钟做的工作竟然节省到52分钟~

前言 进入了新的一年&#xff0c;团队被分配了新的工作内容——每周巡检。 巡检工作简单&#xff0c;但需要人工重复性地登陆远程服务器、输入重复的命令&#xff0c;然后将命令的结果记录下来。每做一次估计花40分钟&#xff0c;但要每周做&#xff0c;一年52周&#xff0c;…

Java---微服务---分布式搜索引擎elasticsearch(3)

分布式搜索引擎elasticsearch&#xff08;3&#xff09;1.数据聚合1.1.聚合的种类1.2.DSL实现聚合1.2.1.Bucket聚合语法1.2.2.聚合结果排序1.2.3.限定聚合范围1.2.4.Metric聚合语法1.2.5.小结1.3.RestAPI实现聚合1.3.1.API语法1.3.2.业务需求1.3.3.业务实现2.自动补全2.1.拼音分…

51单片机学习笔记-15 红外遥控

15 红外遥控 [toc] 注&#xff1a;笔记主要参考B站江科大自化协教学视频“51单片机入门教程-2020版 程序全程纯手打 从零开始入门”。 注&#xff1a;工程及代码文件放在了本人的Github仓库。 15.1 红外遥控与外部中断 15.1.1 红外遥控器 红外遥控是利用红外光进行通信的设备…

【MyBatis】| MyBatis参数处理(核心知识)

目录 一&#xff1a;MyBatis参数处理 1. 单个简单类型参数 2. Map参数 3. 实体类参数&#xff08;PoJo类&#xff09; 4. 多参数 5. Param注解&#xff08;命名参数&#xff09; 一&#xff1a;MyBatis参数处理 接口中方法的参数专栏&#xff01; 1. 单个简单类型参数 简…

RSA加密算法

RSA算法原理 非对称加密算法&#xff0c;有公钥和私钥之分通过公钥加密的数据必须通过私钥才能解密&#xff0c;反之&#xff0c;私钥加密的数据需要通过公钥解私钥能生成公钥&#xff0c;当公钥不能推导出私钥 欧拉函数 指小于n的正整数中与n互质的数的总个数&#xff08;记…

基于蜣螂算法优化的核极限学习机(KELM)回归预测-附代码

基于蜣螂算法优化的核极限学习机(KELM)回归预测 文章目录基于蜣螂算法优化的核极限学习机(KELM)回归预测1.KELM理论基础2.回归问题数据处理4.基于蜣螂算法优化的KELM5.测试结果6.Matlab代码摘要&#xff1a;本文利用蜣螂算法对核极限学习机(KELM)进行优化&#xff0c;并用于回归…

C 语言零基础入门教程(十九)

C 文件读写 上一章我们讲解了 C 语言处理的标准输入和输出设备。本章我们将介绍 C 程序员如何创建、打开、关闭文本文件或二进制文件。 一个文件&#xff0c;无论它是文本文件还是二进制文件&#xff0c;都是代表了一系列的字节。C 语言不仅提供了访问顶层的函数&#xff0c;也…

激光SLAM闭环方案总结

高质量的闭环是建图必不可少的元素之一。而激光SLAM不像视觉那样可以提供细致的纹理信息&#xff0c;因此常常出现误检和漏检的情况。最近&#xff0c;看了不少关于激光SLAM闭环方法的论文&#xff0c;总结一下。一、构建点云的描述子1、Scan Context&#xff08;2018&#xff…

抗抑郁药如何帮助细菌抵抗抗生素

谷禾健康 迄今为止最全面的全球抗菌素耐药性 (AMR) 研究发现&#xff0c;由耐药菌引起的感染是所有年龄段人群死亡的主要原因之一。 22年发表在《柳叶刀》杂志上的分析估计&#xff0c;2019 年有 495 万人死于细菌性 AMR 发挥作用的疾病。其中&#xff0c;127 万人死亡是 AMR 的…

如何使用matlab对时间序列进行ADF检验?|adftest函数(获取不同显著性下的统计结果)

ADF检验 迪基富勒检验&#xff08;ADF检验&#xff09;是一种常见的统计检验&#xff0c;用于检验给定时间序列是否平稳。在分析序列的平稳性时&#xff0c;它是最常用的统计检验之一。matlab中提供了函数adftest可以完成该检验&#xff0c;本文重点介绍该函数的用法。 Matla…

创建表和管理表

文章目录基础知识一条数据存储的过程标识符命名规则MySQL中的数据类型创建和管理数据库创建数据库使用数据库修改数据库删除数据库创建表创建方式1创建方式2查看数据表结构修改表追加一个列修改一个列重命名一个列删除一个列重命名表删除表清空表内容拓展拓展1&#xff1a;阿里…

setState的使用+React更新机制+events+受控和非受控组件

setState是异步更新 总结&#xff1a; 1.setState设计为异步&#xff0c;可以显著的提升性能 如果每次调用 setState都进行一次更新&#xff0c;那么意味着render函数会被频繁调用&#xff0c;界面重新染&#xff0c;这样效率是很低的&#xff1b;最好的办法应该是获取到多个更…

单片机开发---ESP32S3移植lvgl+触摸屏

书接上文 《单片机开发—ESP32-S3模块上手》 本章内容 熟悉一下ESP32S3的开发&#xff0c;修改范例程序的lvgl&#xff0c;使之能够匹配现在的显示屏。 具体工作大概为通过SPI接口连接一块SPI串口屏幕&#xff0c;并且适配lvgl&#xff0c;最后加上触摸屏作为输入。 屏幕 …

【计算机网络】第一章 计算机网络结构

文章目录第一章 体系结构1.1 计算机网络概述1.1.1 计算机网络的概念1.1.2 计算机网络的组成1.1.3 计算机网络的功能1.1.4 计算机网络的分类*1.1.5 计算机网络的标准化工作1.1.6 计算机网络的性能指标1.2 计算机网络体系结构与参考模型1.2.1 计算机网络分层结构1.2.2 计算机网络…

#8链表的中间结点#

链表的中间结点 1题目链接 链接 2思路 思路1:遍历一遍 计数 然后/2 再遍历一遍 思路2:slow fast指针 slow指针一次走1步 fast指针一次走2步 当fast为空的时候 slow的位置就是中间结点 奇数个: 1 2 3 4 5 fast走完第三次为空 slow走完第三次就是3 偶数个: 1 2 3 4 5 6 fast走完…

智慧型物业管理系统功能解析

随着当前社会经济的发展与科技发达&#xff0c;物业管理系统化已经成为常态了。尤其是随着智慧物业管理系统功能越来越多&#xff0c;人们对智慧物业管理系统的依赖就更明显了。毕竟系统真的可以给生活带来很多的便利之处&#xff1a; 业主可通过该系统查询自己住房的详细信息…

“揾”钱,最紧要系稳

我是腾讯安全的樊自磊。我们团队在腾讯主要负责金融风控产品&#xff0c;解决相关产品交付和服务维护工作&#xff0c;像国内知名大型国有银行、城商行、互联网金融公司等&#xff0c;都是我们的服务对象。今年春节&#xff0c;我和我的的同事们都在深圳为金融行业的网络安全进…

连续多输入多输出对象最优控制

连续多输入多输出对象最优控制 控制对象:平面二自由度机械臂 动力学模型: M ( q ) q + C ( q , q ) + G ( q ) =

【HDRP】自动生成的光照探针——Probe Volume

HDRP中&#xff0c;增加了Probe Volume&#xff0c;可代替旧版的光照探针Light Probe Group。 使用此功能的物体&#xff0c;不再需要光照贴图。 一、优缺点比较 详细说明可查看官方说明。 1.Probe Volume按像素而不是按对象发光&#xff0c;这意味着 HDRP 可以更准确地照亮…