目录
一、什么是递归?
递归调用是一种特殊的嵌套调用,是某个函数调用自己或者是调用其他函数后再次调用自己的,只要函数之间互相调用能产生循环的则一定是递归调用,递归调用一种解决方案,一种是逻辑思想,将一个大工作分为逐渐减小的小工作,比如说一个和尚要搬50块石头,他想,只要先搬走49块,那剩下的一块就能搬完了,然后考虑那49块,只要先搬走48块,那剩下的一块就能搬完了,递归是一种思想,只不过在程序中,就是依靠函数嵌套这个特性来实现了。
递归调用就是在当前的函数中调用当前的函数并传给相应的参数,这是一个动作,这一动作是层层进行的,直到满足一般情况的的时候,才停止递归调用,开始从最后一个递归调用返回。
二、示例分析
案例1:递归删除菜单及其所有子菜单
- 菜单实体类
java
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 系统菜单
*/
@Data
@TableName(value = "menu")
public class Menu implements Serializable {
private static final long serialVersionUID = 1L;
/*** 菜单ID*/
@TableId(type = IdType.INPUT)
private Long menuId;
/*** 父级菜单ID*/
private Long upMenuId;
/*** 菜单编码*/
private String menuCode;
/*** 菜单名称*/
private String menuName;
/*** 菜单级别(默认1级)*/
private Integer menuLevel;
/*** 菜单页面打开方式(1-本页面打开 2 新标签页打开 3-新窗口打开)*/
private Integer pageOpenType;
/*** 菜单类型(1-菜单 2-权限按钮)*/
private Integer menuType;
/*** 菜单图标*/
private String menuIcon;
/*** 菜单URL*/
private String menuUrl;
/*** 菜单序号*/
private Integer menuOrder;
/*** 菜单描述*/
private String menuDesc;
/*** 数据状态(0-删除 1-正常) */
private Integer dataFlag;
/*** 是否禁用(0-否 1-是)*/
private Integer isDisable;
/*** 创建人ID*/
private Long createId;
/*** 创建时间*/
private Date createTime;
}
- 实现代码
java
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.test.java.domain.entity.Menu;
import com.test.java.mapper.MenuMapper;
import com.test.java.service.MenuService;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
public class MenuServiceImpl implements MenuService {
@Resource
private MenuMapper menuMapper;
@Override
public Integer deleteMenuById(Long menuId) {
// 校验当前要删除的菜单是否存在
Menu menu = menuMapper.selectById(menuId);
if (null == menu) {
throw new RuntimeException("菜单已删除");
}
// 创建list集合,用于封装所有要删除的菜单ID
List<Long> menuIdList = new ArrayList<>();
// 向menuIdList集合设置删除菜单id(根据id删除菜单)
this.queryMenuChildById(menuId, menuIdList);
// 把当前菜单id封装到idList里面
menuIdList.add(menuId);
// 批量删除当前菜单 及其所有子菜单
return menuMapper.deleteBatchIds(menuIdList);
}
// 根据当前菜单id,查询其所有子菜单id,再封装到idList集合
private void queryMenuChildById(Long menuId, List<Long> idList) {
// 查询菜单里面子菜单id
QueryWrapper<Menu> wrapper = new QueryWrapper<>();
wrapper.eq("up_menu_id", menuId);
List<Menu> childMenuList = menuMapper.selectList(wrapper);
if (!CollectionUtils.isEmpty(childMenuList)) {
// 把childMenuList里面菜单id值获取出来,封装idList里面,做递归查询
childMenuList.forEach(item -> {
//封装idList里面
idList.add(item.getMenuId());
//递归查询
this.queryMenuChildById(item.getMenuId(), idList);
});
}
}
}
案例2:递归删除目录及其目录中所有文件
- 实现代码
java
import lombok.extern.slf4j.Slf4j;
import java.io.File;
/**
* 文件相关工具类
*/
@Slf4j
public class FileUtils {
/**
* 删除文件或文件夹
*
* @param path 文件路径
* @return 返回true(删除成功), 返回false(删除失败)
*/
public static boolean deleteFileOrDirectory(String path) {
File file = new File(path);
// 判断文件是否存在
if (file.exists()) {
// 判断是否为文件
if (file.isFile()) {
// 删除文件
return deleteFile(path);
} else {
// 删除文件夹
return deleteDirectory(path);
}
} else {
return false;
}
}
/**
* 删除文件
*
* @param path 文件路径
* @return 返回true(删除成功), 返回false(删除失败)
*/
public static boolean deleteFile(String path) {
boolean result = false;
File file = new File(path);
if (file.isFile() && file.exists()) {
result = file.delete();
log.info("删除文件成功:{}", path);
return result;
} else {
log.info("删除文件失败:{}", path);
return result;
}
}
/**
* 删除文件夹(先删文件再删目录)
*
* @param path 文件夹路径
* @return 返回true(删除成功), 返回false(删除失败/文件夹不存在)
*/
public static boolean deleteDirectory(String path) {
if (!path.endsWith(File.separator)) {
// 补齐文件分隔符
path = path + File.separator;
}
File directoryFile = new File(path);
// 文件不存在、不是一个目录就打印退出返回false
if (!directoryFile.exists() || !directoryFile.isDirectory()) {
log.info("文件夹不存在,{}", path);
return false;
}
boolean flag = true;
// 获取所有的子文件及子文件夹
File[] files = directoryFile.listFiles();
if (files != null) {
// 循环删除
for (File file : files) {
// 删除子文件
if (file.isFile()) {
flag = deleteFile(file.getAbsolutePath());
if (!flag) {
break;
}
} else {// 删除子文件夹
flag = deleteDirectory(file.getAbsolutePath());
if (!flag) {
break;
}
}
}
}
if (!flag) {
log.info("删除文件夹失败");
return false;
}
// 最后删除当前文件夹
if (directoryFile.delete()) {
log.info("删除文件夹成功,{}", path);
return true;
} else {
log.info("删除文件夹失败,{}", path);
return false;
}
}
}
以上代码直接粘贴复制即可直接使用。
如果这篇文章对您有所帮助,或者有所启发的话,求一键三连:点赞、评论、收藏➕关注,您的支持是我坚持写作最大的动力。