IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> java实现列表拖动排序 -> 正文阅读

[Java知识库]java实现列表拖动排序

需求:最近项目需求中产品提到了列表需要支持拖动排序的问题,而当前系统中的列表是支持分页+条件搜索的,也就是说我们列表返回的orderNum肯定不是连续的。

动态效果如图:

20220427_112316

方案一?

实现方案一: 不管数据向上还是向下移动,只会改变目标数据当前的位置和目标数据最后存放位置的之前的数据的orderNum值,其他数据的orderNum保持不变

  • 向上移动

  • 向下移动

?代码实现


/**
 * 前端传递的body
 * @Author xiaosuhe
 * @Date 2022/4/11 11:05
 * @Version 1.0
 */
@Data
public class MoveSortRequest {
    /**
     * 页码
     */
    @ApiModelProperty("页码")
    private Integer pageNum;

    /**
     * 条数
     */
    @ApiModelProperty("条数")
    private Integer pageSize;

    /**
     * 对象所属当前的 下标 索引位置
     */
    @ApiModelProperty("对象所属当前的 下标 索引位置")
    private Integer startIndex;

    /**
     * 对象所属 拖拽后所属的 下标 索引的 位置
     */
    @ApiModelProperty("对象所属 拖拽后所属的 下标 索引的 位置")
    private Integer endIndex;

    /**
     *  targetId(拖拽的对象)
     */
    @ApiModelProperty("targetId(拖拽的对象)")
    private Long targetId;

    /**
     * 名称搜索
     */
    private String name;

   
}

因为系统的列表是数据size是支持自己选择的,所以前端移动的数据要跟后端查询的数据对应上?,所以需要前端传递pageSize和pageNum

?排序代码如下:

 /**
     * @param allList    排序序 的集合(跟列表顺序保持一致,数据保存一直,也就是我们需要前端传递pageSize和pageNum的原因)
     * @param targetId   目标对象的Id(需要移动数据的ID)
     * @param startIndex 对象在列表的开始索引值[索引值从0 开始
     * @param endIndex   移动后的目标索引值[索引值从0 开始
     * @param isAsc      集合列表 是否正序 TRUE 正序
     * @Description: 构建 需要 排序的 list集合
     * @Return: java.util.List<T> 返回sort值变动的数据集合
     */
    public static <T> List<T> getNeedUpdateSortList(List<T> allList, Long targetId, Integer startIndex, Integer endIndex, boolean isAsc) throws NoSuchFieldException, IllegalAccessException {
        List<T> buildList = new ArrayList<>();
        if (targetId == null || startIndex == null || endIndex == null) {
            throw new ServiceException(ErrorCodeEnum.PARAM_MISSING);
        }
        if (CollectionUtils.isEmpty(allList) || startIndex.equals(endIndex)) {
            return buildList;
        }
        //需要 修改排序值得 数据集合 不包含 目标对象 本身
        List<T> excludeList = new ArrayList();
        //目标 对象
        T targetBean = null;
        //截取的 开始 索引  和 结束 索引 之间的 list 包含 targetBean(拖拽排序目标自身) 的一个 集合
        List<T> subList = null;

        //需改排序规则 (只修改 索引区间的值)
        //== ================获取 索引区间的 数据集合begin ==================
        boolean flag = endIndex > startIndex;
        //不管上移还是下移,值改变目标当前位置和移动之后位置的orderNum
        if (flag) {
            //下移
            subList = allList.subList(Integer.parseInt(startIndex.toString()), Integer.parseInt(endIndex.toString()) + 1);
        } else {
            // 上移  subList左闭右开
            subList = allList.subList(Integer.parseInt(endIndex.toString()), Integer.parseInt(startIndex.toString()) + 1);
        }
        //================获取 索引区间的 数据集合   end  ==================

        if (CollectionUtils.isEmpty(subList)) {
            return buildList;
        }

        //===================   获取 排序区间 里面的 目标对象 + 排出目标对象之后的集合 begin =============
        for (T bean : subList) {
            Field idField = bean.getClass().getDeclaredField("id");
            idField.setAccessible(true);
            Object currentId = idField.get(bean);
            //目标对象
            if (targetId.equals((Long) (currentId))) {
                targetBean = bean;
            } else {
                //区间数据(不包含目标对象)
                excludeList.add(bean);
            }
        }
        if (targetBean == null) {
            throw new ServiceException(ErrorCodeEnum.CHECKTABLE_IS_NULL);
        }
        //===================   获取 排序区间 里面的 目标对象 + 排出目标对象之后的集合 end 

        //============获取 拖拽对象  上移/下移 之后的 sort 值   
        //需要修改自己的排序值
        //需要 对索引区间的排序值(不包含排序对象自身) 进行 加1 或者 减 1
        T tempBean = null;
        if (flag) {
            //下移
            tempBean = excludeList.get(excludeList.size() - 1);
        } else {
            //上移动
            tempBean = excludeList.get(0);
        }
        Field sortField = tempBean.getClass().getDeclaredField("orderNum");
        sortField.setAccessible(true);
        Integer sort = (Integer) sortField.get(tempBean);
        //============获取 拖拽对象  上移/下移 之后的 sort 值   end========================

        //===================修改 目标对象  排序值  begin ==============
        Field targetBeanSortField = targetBean.getClass().getDeclaredField("orderNum");
        targetBeanSortField.setAccessible(true);
        //保存tagBean的orderNum值
        targetBeanSortField.set(targetBean, sort);
        //===================修改 目标对象  排序值  begin ==============

        //================修改  需要排序 区间(排序目标对象自身) 排序值  begin ========
        //处理
        for (T bean : excludeList) {
            sortField = bean.getClass().getDeclaredField("orderNum");
            sortField.setAccessible(true);
            sort = (Integer) sortField.get(bean);
            //flag true : 下移 非拖动对象 自身 排序索引值 需要 -1; false 反之
            if (isAsc) {
                //正序
                sortField.set(bean, flag ? (sort - 1) : (sort + 1));
            } else {
                //倒叙
                sortField.set(bean, flag ? (sort + 1) : (sort - 1));
            }
        }


        //================修改  需要排序 区间(排序目标对象自身) 排序值  end  ========
        buildList.addAll(excludeList);
        buildList.add(targetBean);
        return buildList;
    }

细心的可以发现,方案一功能是能实现的,但是存在2个问题

  • 当在移动列表的时候,有人新增数据,那么展示的列表和调用移动排序回数据库查的数据就不会一一对应,导致潜在的移动排序失败。
  • 拖动排序的时候是支持条件搜索的,那说明我们列表展示的数据orderNum不是连续的数值,只是相对有序,我们对区间数据orderNum进行+1或者-1的时候可能导致数据表中的orderNum重复。

?如图:经过筛选的数据移动出现orderNum重复的情况

一系列操作之后,清除筛选条件之后,发现orderNum经过上面的操作之后出现了多个orderNum重复的情况,所以对应orderNum不连续的,使用这种方式并不友好。

?

?方案二

实现方案二、前端将移动前后列表的数据都给到后端,其实是一种数据平移的思想。

这种做法对排序的列表数据完全可靠,移动排序不会受到新增数据的影响,也解决了orderNum出现重复的问题?

下面是代码实现,相对简单

请求body

@Data
public class MoveSortRequest {
    @ApiModelProperty("移动之前集合,需要传递orderNum")
    List<TableDTO> preMoveSortList;
    @ApiModelProperty("移动之后集合,不需要传递orderNum")
    List<TableDTO> afterMoveSortList;

}


@Data
public class TableDTO {

    private Long Id;

    private Integer orderNum;
}

逻辑处理之后批量更新

        List<TableDO> list = new ArrayList<>();
        List<TableDTO> afterMoveSortList = request.getAfterMoveSortList();
        List<TableDTO> preMoveSortList = request.getPreMoveSortList();
        if (CollectionUtils.isEmpty(afterMoveSortList )||CollectionUtils.isEmpty(preMoveSortList )){
            throw new ServiceException(ErrorCodeEnum.PARAM_MISSING);
        }
        for (int i = Constants.INDEX_ONE; i < afterMoveSortList .size(); i++) {
            TableDO tableDO = new TableDO();
            tableDO .setId(afterMoveSortList .get(i).getId());
            tableDO .setOrderNum(preMoveSortList .get(i).getOrderNum());
            list.add(tableDO);
        }
        return list;

总结

  • 方案一对于数据量比较大、排序准确度一般、容错较高的列表,
  • 方案一适合增删操作较少的列表
  • 方案二适合数据量一般,数据排序准确度较高,容错较低的列表
  • 方案二对操作列表不受限制
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-04-29 11:57:32  更:2022-04-29 12:00:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:05:35-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码