先上代码
首先权限数据结构
package com.sakura.user.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.sakura.common.api.Update;
import com.sakura.common.base.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotNull;
import java.util.Date;
/**
* 权限表
*
* @author Sakura
* @since 2023-08-28
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "权限信息")
public class PermissionVo extends BaseEntity {
private static final long serialVersionUID = 1L;
@NotNull(message = "id不能为空", groups = {Update.class})
@ApiModelProperty("自增ID")
private Integer id;
@ApiModelProperty("父ID,顶层为0")
private Integer parentId;
@ApiModelProperty("权限code")
private String code;
@ApiModelProperty("权限名称")
private String name;
@ApiModelProperty("请求url")
private String url;
@ApiModelProperty("类型:菜单menu 按钮button")
private String type;
@ApiModelProperty("描述")
private String description;
@ApiModelProperty("是否是公共权限: 1是 0否")
private Integer isPublic;
@ApiModelProperty("创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createDt;
}
然后对应的权限树数据结构和上面那个差不多,就多了个list用来装子权限的
package com.sakura.user.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.sakura.common.api.Update;
import com.sakura.common.base.BaseEntity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotNull;
import java.util.Date;
import java.util.List;
/**
* 权限表
*
* @author Sakura
* @since 2023-08-28
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "权限树信息")
public class PermissionTreeVo extends BaseEntity {
private static final long serialVersionUID = 1L;
@NotNull(message = "id不能为空", groups = {Update.class})
@ApiModelProperty("自增ID")
private Integer id;
@ApiModelProperty("父ID,顶层为0")
private Integer parentId;
@ApiModelProperty("权限code")
private String code;
@ApiModelProperty("权限名称")
private String name;
@ApiModelProperty("请求url")
private String url;
@ApiModelProperty("类型:菜单menu 按钮button")
private String type;
@ApiModelProperty("描述")
private String description;
@ApiModelProperty("是否是公共权限: 1是 0否")
private Integer isPublic;
@ApiModelProperty("创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createDt;
@ApiModelProperty("子权限")
private List<PermissionTreeVo> childList;
}
Controller的方法
@GetMapping("/tree/{parentId}")
@OperationLog(name = "权限树", type = OperationLogType.PAGE)
@ApiOperation(value = "权限树 顶层parentId为0", response = Permission.class)
public ApiResult<List<PermissionTreeVo>> getPermissionTree(@PathVariable("parentId") Integer parentId) throws Exception {
List<PermissionTreeVo> permissionTreeVos = permissionService.getPermissionTree(parentId);
return ApiResult.ok(permissionTreeVos);
}
Service方法
@Override
public List<PermissionTreeVo> getPermissionTree(Integer parentId) throws Exception {
// 先获取所有的权限
List<PermissionVo> permissionVos = permissionMapper.findAllPermission();
// 递归遍历所有权限信息
int num = 0; // 添加一个遍历层数,防止数据异常导致递归死循环
List<PermissionTreeVo> permissionTreeVos = getChildPermissions(parentId, permissionVos, num);
return permissionTreeVos;
}
/**
* @description: 递归获取子权限
* @param parentId 父ID
* @param permissionVos 所有权限集合
* @param num 最大遍历层数
* @author: Sakura
* @date: 2023/8/28 16:18
*/
private List<PermissionTreeVo> getChildPermissions(Integer parentId, List<PermissionVo> permissionVos, int num) throws Exception {
num++;// 控制遍历次数,防止因数据问题导致无限循环内存溢出,目前最大支持5层
if (num > 5) {
log.error("权限信息异常parentId:" + parentId);
throw new BusinessException(500, "权限数据异常,请联系管理人员");
}
List<PermissionTreeVo> resultList = new ArrayList<>();
for (PermissionVo permissionVo : permissionVos) {
if (parentId.equals(permissionVo.getParentId())) {
PermissionTreeVo permissionTreeVo = new PermissionTreeVo();
BeanUtils.copyProperties(permissionVo, permissionTreeVo);
// 通过当前ID获取子权限
List<PermissionTreeVo> childPermissionTreeVos = getChildPermissions(permissionVo.getId(), permissionVos, num);
permissionTreeVo.setChildList(childPermissionTreeVos);
resultList.add(permissionTreeVo);
}
}
return resultList;
}
Mapper主要是为了拿到所有权限
<select id="findAllPermission" resultType="com.sakura.user.vo.PermissionVo" >
SELECT id, parent_id, code, name, url, type, description, is_public, create_dt
FROM t_permission
WHERE status = 1
</select>
注意我这里是先拿到所有权限然后在程序里面再去遍历数据的,还有一种写法是每次都根据parentId去数据库查,我试过了,因为访问数据库次数太多速度上慢很多,不建议使用!