一维模块移动逻辑后端实现
- 移动的逻辑,前端有专门的框架sortable.js提供了API进行实现,但是有些场景需要后端实现动态拖动排序,所以记录一下实现过程,后面如果有类似需求直接进行复用。
核心逻辑部分
- 当前模块里面调整顺序:变动区间重新排序
- 从另一个模块组移动到当前模块组:当前模块组重排序,原有模块组进行重排序
- 删除某个元素:模块组内进行冲排序
- 同个模块组中的移动分为两种:上移和下移
- 移动的本质:是进行修改操作,修改对应数据的排序
移动操作
定义业务操作接口
- 定义业务需要操作的接口 及 业务数据透传的实体类
- 这个实体类只做标识作用,具体业务继承这个实体类增加透传字段
public interface OsDesignerMoveOperationService<T extends MoveBusinessDto> {
/**
* 批量更新移动
*
* @param moveChangedDto
*/
void batchUpdateMove(List<MoveDto> moveChangedDto);
/**
* 获取移动的列表
* @param t
* @param parent
* @return
*/
List<MoveDto> getMoveList(T t, Long parent);
}
@Data
@Accessors(chain = true)
public class MoveBusinessDto {
}
移动逻辑
- 进行排序
- 重排后的顺序进行更新
public interface MoveService<T> {
public void move(T t, Long id, MoveRequestDto dto, MoveOperationService service);
public List<MoveDto> moveOldParentModule(T t, Long oldParent, MoveOperationService service);
}
@Service
public class MoveServiceImpl implements MoveService<MoveBusinessDto> {
public void move(MoveBusinessDto t, Long id, MoveRequestDto dto, MoveOperationService service) {
Long oldParent = dto.getOldParent();
Long parent = dto.getParent();
Long brother = dto.getBrother();
List<MoveDto> dtos = service.getMoveList(t, parent);
List<MoveDto> moveChangedDto = new ArrayList<>();
//module sort
// no sub module
if (CollectionUtils.isEmpty(dtos)) {
MoveDto moveDto = new MoveDto();
moveDto.setOrdering(1).setId(id).setParent(parent);
moveChangedDto.add(moveDto);
} else {
moveChangedDto = getMoveChangeModuleDtos(id, oldParent, parent, brother, dtos);
}
service.batchUpdateMove(moveChangedDto);
// old parent sort
if (!Objects.equals(oldParent, parent)) {
List<MoveDto> moveOldParentModule = moveOldParentModule(t, oldParent, service);
service.batchUpdateMove(moveOldParentModule);
}
}
public List<MoveDto> moveOldParentModule(MoveBusinessDto t, Long oldParent, OsDesignerMoveOperationService service) {
List<MoveDto> oldModuleMoveDto = service.getMoveList(t, oldParent);
if (!CollectionUtils.isEmpty(oldModuleMoveDto)) {
oldModuleMoveDto.forEach(v -> v.setOrdering(v.getRowNum()));
}
return oldModuleMoveDto;
}
public List<MoveDto> getMoveChangeModuleDtos(Long id, Long oldParent, Long parent, Long brother, List<MoveDto> dtos) {
List<MoveDto> moveChangedDto;
if (Objects.equals(oldParent, parent)) {//同组
MoveDto moveDto = dtos.stream().filter(v -> v.getId().equals(id)).findFirst().get();
Integer oldMoveRowNum = moveDto.getRowNum();
Integer oldBrotherRowNum = getOldBrotherMoveRowNum(brother, dtos);
if (oldMoveRowNum < oldBrotherRowNum) {//下移
moveChangedDto = dtos.subList(oldMoveRowNum, oldBrotherRowNum);
moveChangedDto.stream().forEach(v -> v.setOrdering(v.getRowNum() - 1));
moveDto.setOrdering(oldBrotherRowNum);
} else {//上移
moveChangedDto = dtos.subList(oldBrotherRowNum, oldMoveRowNum);
moveChangedDto.stream().forEach(v -> v.setOrdering(v.getRowNum() + 1));
moveDto.setOrdering(oldBrotherRowNum + 1);
}
moveChangedDto.add(moveDto);
} else {//跨组
Integer oldBrotherMoveDtoRowNum = getOldBrotherMoveRowNum(brother, dtos);
//上移
moveChangedDto = dtos.subList(oldBrotherMoveDtoRowNum, dtos.size());
moveChangedDto.stream().forEach(v -> v.setOrdering(v.getRowNum() + 1));
MoveDto moduleMoveDto = new MoveDto();
moduleMoveDto.setOrdering(oldBrotherMoveDtoRowNum + 1).setId(id).setParent(parent);
moveChangedDto.add(moduleMoveDto);
}
return moveChangedDto;
}
public Integer getOldBrotherMoveRowNum(Long brother, List<MoveDto> dtos) {
Integer oldBrotherMoveDtoRowNum = 0;
if (Objects.nonNull(brother) && brother > 0) {
MoveDto brotherMoveDto = dtos.stream().filter(v -> v.getId().equals(brother)).findFirst().orElse(null);
if (Objects.nonNull(brotherMoveDto)) {
oldBrotherMoveDtoRowNum = brotherMoveDto.getRowNum();
}
}
return oldBrotherMoveDtoRowNum;
}
}
需要业务类实现的接口
继承接口,实现业务方法
public class A implements MoveOperationService<MoveBusinessDto>{
}
获取排序
- 根据row_num确定排序的序号
- 旧的组获取也是同一个方法
select
row_number() over () as row_num,
id,
ordering,
parent,
from os_module
where 1 = 1 and parent = #{parent}
order by ordering;
批量更新
按照move业务类的参数要求进行封装
对实现过程进行记录,方便后面出现直接代码复用
分类:
业务相关
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· 葡萄城 AI 搜索升级:DeepSeek 加持,客户体验更智能
· 什么是nginx的强缓存和协商缓存
· 一文读懂知识蒸馏