- 借鉴微信的置顶与取消置顶的实现思路:



会看到这个微信的聊天记录的排序规则是以时间降序来进行排序的,如果要实现置顶与取消置顶? 一下子是想不到的,需要思路

由此可以确信的是,我们平时使用微信时,最新的聊天记录总是在前面的,多久不聊的聊天是在最后面的。

在项目中需要实现置顶与取消置顶的功能,刚开始没有思路,苦思冥想了半天,以前也没有做过类似的需求。

于是我一直在使用微信的置顶与取消置顶的功能,玩着玩着还挺好玩,我只要最后点击某条聊天记录置顶,那么这条记录就一定会在第一条显示,并且在它前面置顶的聊天记录会依次在它的下面显示。如果我取消了某条 (置顶过) 的聊天记录,那么它的位置就是在它(聊天记录)的 创建的时间点上。当时就特别好奇,这到底要怎么实现?

一直写SQL语句反复尝试还没有思路,整个人都快傻了,这应该是个很简单的功能,为什么就是写不出来,又想不对啊,怎么可能在一个字段中就 实现置顶与取消置顶,并且还要排序? 终于,我在测试表中仅有的字段又加了一个标记字段 is_top(是否置顶), 神奇的现象发生了, 我想要的结果出来了 ,哈哈哈

(这是类似于微信的,先以是否置顶降序排,再以排序字段降序排(盲猜我这个对应微信的聊天记录的创建时间,哈哈哈))SELECT * FROM tb_test ORDER BY is_top DESC,sort_num DESC

(这是我,应该更容易理解,嗯)
SELECT * FROM `tb_test` ORDER BY is_top DESC,sort_num ASC

从结果可以看出来,这句SQL语句再执行的时候,先排第一个字段,再排第二个字段,所有从这个思路,思路逐渐清晰:

当前文稿置顶:

@Overridepublic Map<Integer, String> stick(Long publishId) {// 1: 获取 is_top字段 的最大值Integer isTopMax = publishInfoMapper.getIsTopMax();// 2: 查询当前文稿PublishInfo publishInfoUpdate = new PublishInfo();publishInfoUpdate.setPublishId(publishId);// 创建查询对象QueryWrapper<PublishInfo> queryWrapper = Wrappers.query(publishInfoUpdate);PublishInfo publishInfo = null;try {publishInfo = publishInfoMapper.selectOne(queryWrapper);} catch (Exception e) {throw new RuntimeException(e);}Map<Integer, String> resultMap = new HashMap<>();if (ObjectUtils.isEmpty(publishInfo)) {throw new OperationException(OperationExEnum.ABSENT, "无法找到对应id的文稿,无法进行置顶显示,请确认id是否正确 !");} else {Integer isTop = publishInfo.getIsTop();if (isTop.equals(isTopMax)) {resultMap.put(OperationExEnum.MODIFICATION_FAILURE.getStatusCode(), "当前文稿已经置顶,请重新选择 !");} else if (isTop < 0) {// 说明数据发生了人为改变!throw new OperationException(OperationExEnum.ERROR.getStatusCode(), "数据错误,请联系工作人员 !");}if (!isTop.equals(isTopMax) && isTop >= 0) {// 更新UpdateWrapper<PublishInfo> updateWrapper = Wrappers.update();// 更新的字段 is_top字段值加一,当前的文档置顶!updateWrapper.set(OperationConst.IS_TOP, isTopMax + 1);// 指定条件updateWrapper.eq(OperationConst.PUBLISH_ID, publishInfo.getPublishId());int update = publishInfoMapper.update(publishInfoUpdate, updateWrapper);if (update != 1) {throw new OperationException(OperationExEnum.MODIFICATION_FAILURE, "置顶文稿失败 ! 请稍后操作 !");} else {resultMap.put(OperationExEnum.MODIFICATION_ACCESS.getStatusCode(), "置顶文稿成功 ! ~~~");}}}return resultMap;}

is_top 从前端传过来只是0或1的值, (0代表取消置顶按钮的点击事件,1代表当前置顶按钮的点击事件) 而数据库中is_top 是在业务层自己处理逻辑的,经过反复测试没有什么问题


取消文稿置顶:

@Overridepublic Map<Integer, String> cancelStick(Long publishId) {// 1: 根据文稿id查询当前这个文稿是否置顶PublishInfo publishInfoUpdate = new PublishInfo();publishInfoUpdate.setPublishId(publishId);// 创建查询对象QueryWrapper<PublishInfo> queryWrapper = Wrappers.query(publishInfoUpdate);PublishInfo publishInfo = null;try {publishInfo = publishInfoMapper.selectOne(queryWrapper);} catch (Exception e) {e.printStackTrace();}Map<Integer, String> resultMap = new HashMap<>();if (ObjectUtils.isEmpty(publishInfo)) {throw new OperationException(OperationExEnum.ABSENT, "无法找到对应id的文稿,请确认再操作 !");} else {Integer isTop = publishInfo.getIsTop();if (isTop > 0) {// 更新UpdateWrapper<PublishInfo> updateWrapper = Wrappers.update();// 更新的字段updateWrapper.set(OperationConst.IS_TOP, 0);// 指定条件updateWrapper.eq(OperationConst.PUBLISH_ID, publishInfo.getPublishId());int update = publishInfoMapper.update(publishInfoUpdate, updateWrapper);if (update != 1) {throw new OperationException(OperationExEnum.MODIFICATION_FAILURE, "取消置顶失败 ! 请稍后操作 !");} else {resultMap.put(OperationExEnum.MODIFICATION_ACCESS.getStatusCode(), "取消置顶成功 ! ~~~");}}//如果就是0,说明该文稿本身就没有置顶!else if (isTop.equals(0)) {resultMap.put(OperationExEnum.ABSENT.getStatusCode(), "该文稿不是置顶显示,请重新选择 !");} else {// 说明数据发生了人为改变!throw new OperationException(OperationExEnum.ERROR.getStatusCode(), "数据错误,请联系工作人员 !");}}return resultMap;}

取消置顶的思路完全就是取决于置顶的思路, 只是把is_top的值改为不可再排序的默认值,

使用MybatisPlus 的API 拼接的分页排序语句:

// 1: 创建分页前的数据IPage<PublishInfo> pageNoAndPageSize = new Page<>(pageNo, pageSize);// 2: 封装查询条件 ,(如果该文稿置顶,就按照)is_top字段降序排序 然后再按照 指定sort_num字段 升序排序// (如果文稿不置顶就按照 它指定的sort_num 的值排序 ) 按照 指定sort_num字段 升序排序QueryWrapper<PublishInfo> query = Wrappers.query();query.orderByDesc(OperationConst.IS_TOP).orderByAsc(OperationConst.SORT_NUM);// 3: 查询IPage<PublishInfo> publishInfoPage = publishInfoMapper.selectPage(pageNoAndPageSize, query);// ....................省略................................

如果在添加某个文稿的时候就需要 (置顶) 代码:

if (isTop.equals(1)) {// 拿到当前isTop的最大值Integer isTopMax = publishInfoMapper.getIsTopMax();// 如果当前isTop的最大值是0 , 说明还没有文稿置顶if (isTopMax.equals(0)) {// 当前文稿的isTop值为 1publishInfo.setIsTop(1);} else {// 否则当前文稿的isTop值就是最大值加1publishInfo.setIsTop(isTopMax + 1);}}
// ..............................省略..............................

(如果想让每个文稿sort_num的值不与数据库中的sort_num字段的重复代码):

// 3: 判断当前添加的文稿对象的sort_num 值 在数据库中是否存在Integer sortNum = publishInfo.getSortNum();// 拿到所有的sort_num的值 , 并升序排序ArrayList<Integer> sortNumList = publishInfoMapper.getSortNums();Collections.sort(sortNumList);Map<Integer, String> resultMap = new HashMap<>();// 4: 如果文稿的排序字段不为空, 则判断当前的数据库的sort_num中有没有 新加的文稿的排序字段,// 如果包含了, 就是 sort_num字段 最大值 + 1, 并返回友好提示信息, 如果没有就是添加的排序字段if (sortNum != null) {for (int i = 0; i < sortNumList.size(); i++) {if (sortNum.equals(sortNumList.get(i))) {publishInfo.setSortNum(sortNumList.get(sortNumList.size() - 1) + 1);if (isTop.equals(1)) {resultMap.put(OperationExEnum.ALREADY_EXISTS.getStatusCode(), "您添加的排序字段已经存在,您的排序字段默认为末序,当前是置顶显示 ! ");break;} else {resultMap.put(OperationExEnum.ALREADY_EXISTS.getStatusCode(), "您添加的排序字段已经存在,您的排序字段默认为末序 ! ");break;}}}} else {publishInfo.setSortNum(sortNumList.get(sortNumList.size() - 1) + 1);if (isTop.equals(1)) {resultMap.put(OperationExEnum.ABSENT.getStatusCode(), "您添加的排序字段为空(您未添加排序字段), 默认为末序, 当前是置顶显示 ! ");} else {resultMap.put(OperationExEnum.ABSENT.getStatusCode(), "您添加的排序字段为空(您未添加排序字段), 默认为末序 ! ");}}

Sum up:

1: 没有置顶的数据的is_top字段的值都是一样的(比如默认都是0,或者默认是一样的值)

2: 如果默认的是0,初始置顶值是1 , 或者是2 …

3: 如果默认的是1,初始置顶值是2 , 或者是3 …

4: 当前置顶的数据is_top字段的值永远是所有数据is_top字段中的最大值

5: 当前置顶的数据的is_top字段的值一定是比上一个置顶的数据 大1…, 或者大 2 …

6: 取消置顶那么就是设置为默认值就好了,使它不能再以is_top排序

7: order by is_top ASC|DESC , (sort_num ASC|DESC 或者create_time ASC|DESC ),以你的需求来定

8: is_top的值是随时都会变化的 , 建议使用 bigint 数据类型,对应Java的 Long | long类型

MybatisPlus生成的 SQL语句日志

 ==>  Preparing: SELECT publish_id,publisher,status,sort_num,title_detail,title,title_image_url,service_dir_ids,mountings_dir_ids,belong_category_name,is_top,belong_category_id,create_time,after_update_time FROM tb_publish_info ORDER BY is_top DESC , sort_num ASC LIMIT ?,? ==> Parameters: 0(Long), 8(Long)<==      Total: 8

这篇文章对你有帮助吗?作为一名程序工程师,在评论区留下你的困惑或你的见解,大家一起来交流吧! ~~~~~~~~~

如何在项目中实现类似于微信的置顶与取消置顶的功能?相关推荐

  1. Vue 项目中实现的微信、微博、QQ空间分享功能(亲测有效)

    需求:文章添加分享功能(包括微信.微博.QQ空间) 如下图所示: 点击图标分别跳转到如下界面:(实现效果如下) 话不多说直接代码(可以封装成组件) <template><div cl ...

  2. vue项目中,使用微信js-sdk打开微信内置导航,唤醒第三方导航,

    vue项目中,使用微信js-sdk打开微信内置导航,唤醒第三方导航 一.准备工作 二.开发须知 三.开始安装sdk 四.通过微信的config接口注入权限验证配置 附上代码 最近在搞vue项目需要在手 ...

  3. 从原理到实践:装饰器模式如何在项目中落地详解(给原对象增加新的行为和功能)

    装饰器模式---- 不修改原始对象,给原对象增加新的行为和功能. 2.1.概念 装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许动态地向对象添加额外的功能,而无需修改其原始 ...

  4. 项目中如何整合微信支付

  5. 在vue-cli项目中使用微信sdk的解决方案

    在vue-cli 创建的项目中,引入微信分享的sdk的方法. 说明: 仅将官方 js-sdk 发布到 npm,便于 browserify 使用 js源码: https://res.wx.qq.com/ ...

  6. 【转】Web API项目中使用Area对业务进行分类管理

    在之前开发的很多Web API项目中,为了方便以及快速开发,往往把整个Web API的控制器放在基目录的Controllers目录中,但随着业务越来越复杂,这样Controllers目录中的文件就增加 ...

  7. vue 项目中 自动生成 二维码

    vue 项目中 自动生成 二维码 ​ 最近在写一个vue项目,要求根据卡号可以自动生成一个二维码,并渲染在指定位置,因为第一次做类似业务,小编在网上找了找,发现了很多,具体起来主要用的就两种: QRc ...

  8. h5支付不能打开支付宝 ios_iOS支付宝支付(Alipay)详细接入流程以及项目中遇到的问题分析...

    最近在项目中接入了微信支付和支付宝支付,总的来说没有那么坑,很多人都说文档不全什么的,确实没有面面 俱到,但是认真一步一步测试下还是妥妥的,再配合懂得后台,效率也是很高的,看了这篇文章,你也只要几分钟 ...

  9. iOS支付宝支付(Alipay)详细接入流程以及项目中遇到的问题分析

    最近在项目中接入了微信支付和支付宝支付,总的来说没有那么坑,很多人都说文档不全什么的,确实没有面面俱到,但是认真一步一步测试下还是妥妥的,再配合懂得后台,效率也是很高的,看了这篇文章,你也只要几分钟, ...

最新文章

  1. java多线程w3c_Java创建多线程的三种方式
  2. ceph-deploy rpm包的制作
  3. 云脑人力资源管理软件EHR选型手记(即时连载)
  4. android7.1增加一个开机自启动的bin应用遇到的权限问题
  5. matlab显示的图片,手动保存时四周有白边
  6. graph 关系图 设置
  7. html写个用户协议,五分钟学会HTML5的WebSocket协议
  8. 材料成形计算机辅助设计,材料成型及计算机辅助设计(综述)
  9. java dubbo swagger_Dubbo 的 Swagger 服务文档 swagger-dubbo
  10. JSP 高校后勤报修管理系统myeclipse开发mysql数据库bs框架java编程serlvet(MVC)结构详细设计
  11. 软件选择,iDreamPiano、freepiano、EveryonePiano
  12. 小白用C语言编写贪吃蛇
  13. Java封装、继承、多态、super杂糅在一起的小练习,公司雇员员工工资问题(Employee),练习扩展:创建一个Employee数组,分别创建不同的Employee对象,并打印某个月的工资
  14. matlab与测绘数据处理,MATLAB与测绘数据处理
  15. 我们应不应该继续学习python
  16. WebAssembly:系统编程语言的逆袭
  17. 学习Python人工智能前景如何
  18. 计算机设备选型的基本原则,设备选型的概念和选型依据
  19. 强制打印方法,输出重定向解决
  20. 青少年护眼灯哪个牌子好?儿童护眼灯品牌推荐

热门文章

  1. java代码实现移动或者剪切功能
  2. 判断浏览器类型 是否是微信浏览器
  3. 不要骗我了,这能有多难嘛!
  4. Android 使用 style 给 Activity 设置背景(background 和 windowBackground的区别)
  5. docker、nvidia-docker间的关系与安装
  6. 用了华为手机多年,你却不知道的,10个手机实用小技巧
  7. 5种获取JavaScript时间戳函数的方法
  8. 笔记本设置合上不睡眠
  9. elementUI 显示局部加载loading
  10. “问世间情为何物,直教生死相许"是写人间爱情吗?