- 借鉴微信的置顶与取消置顶的实现思路:
会看到这个微信的聊天记录的排序规则是以时间降序来进行排序的,如果要实现置顶与取消置顶? 一下子是想不到的,需要思路
由此可以确信的是,我们平时使用微信时,最新的聊天记录总是在前面的,多久不聊的聊天是在最后面的。
在项目中需要实现置顶与取消置顶的功能,刚开始没有思路,苦思冥想了半天,以前也没有做过类似的需求。
于是我一直在使用微信的置顶与取消置顶的功能,玩着玩着还挺好玩,我只要最后点击某条聊天记录置顶,那么这条记录就一定会在第一条显示,并且在它前面置顶的聊天记录会依次在它的下面显示。如果我取消了某条 (置顶过) 的聊天记录,那么它的位置就是在它(聊天记录)的 创建的时间点上。当时就特别好奇,这到底要怎么实现?
一直写SQL语句反复尝试还没有思路,整个人都快傻了,这应该是个很简单的功能,为什么就是写不出来,又想不对啊,怎么可能在一个字段中就 实现置顶与取消置顶,并且还要排序? 终于,我在测试表中仅有的字段又加了一个标记字段 is_top(是否置顶), 神奇的现象发生了, 我想要的结果出来了 ,哈哈哈
(这是类似于微信的,先以是否置顶降序排,再以排序字段降序排(盲猜我这个对应微信的聊天记录的创建时间,哈哈哈))
SELECT * FROM tb_test ORDER BY is_top DESC,sort_num DESC
从结果可以看出来,这句SQL语句再执行的时候,先排第一个字段,再排第二个字段,所有从这个思路,思路逐渐清晰:
@Override
public 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 是在业务层自己处理逻辑的,经过反复测试没有什么问题
取消文稿置顶:
@Override
public 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值为 1
publishInfo.setIsTop(1);
} else {
// 否则当前文稿的isTop值就是最大值加1
publishInfo.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