在springboot项目中,我们经常需要把界面中的菜单来进行树状结构来展示,层次分明,条例清晰,本文章将从controller层到mapper层逐一编写代码来实现页面的树状结构展示
Controller层
/** 以下为controller层代码编写
/**
* 系统权限控制层
*/
@Api(tags = "系统权限管理")
@RequestMapping ("sys/mene")
@RestController
public Result<MenuAndAuth> loadUserMenuAndAuth(){
//获取当前登录用户的标识 //之前在各个资源服务器之前配置了token转换器,存放到了security上下文当中
//从security上下文当中获取用户标识
SecurityUser loginUser = AuthUtils.getLoginUser();
Long userId = loginUser.getUserId();
//根据用户标识查询操作权限集合
Set<String> loginUserPerms = AuthUtils.getLoginUserPerms();
//根据用户标识查询菜单权限集合
Set<SysMenu> sysMenusPerms = sysMenuService.queryUserMenuListByUserId(userId);
//把两种权限集合封装到视图对象,来进行返回
MenuAndAuth menuAndAuth = new MenuAndAuth(sysMenusPerms, loginUserPerms);
return Result.success(menuAndAuth);
}
}
Service层(主要操作)
以下为Service层代码编写
@Service
@CacheConfig(cacheNames = "com.powernode.service.impl.SysMenuServiceImpl")
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements SysMenuService{
@Autowired
private SysMenuMapper sysMenuMapper;
@Override
@Cacheable(key = "#loginUserId")
public Set<SysMenu> queryUserMenuListByUserId(Long loginUserId) {
// 根据用户标识查询菜单权限集合
Set<SysMenu> menus = sysMenuMapper.selectUserMenuListByUserId(loginUserId);
// 将菜单权限集合的数据转换为树结构(即:数据结构应该为层级关系的)
return transformTree(menus,0L);
}
/**
* 集合转换为树结构 很常见 让前端展示的页面是树状结构,分层显示
* 1.已知菜单深度 <=2
*
* 2.未知菜单深度 可能会一直往下写
*
* @param menus
* @param pid
* @return
*/
private Set<SysMenu> transformTree(Set<SysMenu> menus, Long pid) {
// 已知菜单深度<=2
// 从菜单集合中获取根节点集合 数据有,只是把表现形式换一下
/*Set<SysMenu> roots = menus.stream()
.filter(m -> m.getParentId().equals(pid))
.collect(Collectors.toSet());
// 循环遍历根节点集合
roots.forEach(root -> {
// 从菜单集合中过滤出它的父节点值与当前根节点的id值一致的菜单集合
Set<SysMenu> child = menus.stream()
.filter(m -> m.getParentId().equals(root.getMenuId()))
.collect(Collectors.toSet());
root.setList(child);
});*/
// 未知菜单深度
// 获取根节点集合
Set<SysMenu> roots = menus.stream()
.filter(m -> m.getParentId().equals(pid))
.collect(Collectors.toSet());
// 循环节点集合 利用递归,把子节点继续当为根节点,查找所有节点中父节点的id与当前
//根节点的id相同的节点,并setlist
roots.forEach(r -> r.setList(transformTree(menus,r.getMenuId())));
return roots;
}
}
SysMenu类 (菜单类)
/**
* 菜单管理
*/
@ApiModel(value="com-powernode-domain-SysMenu")
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "sys_menu")
public class SysMenu implements Serializable {
@TableId(value = "menu_id", type = IdType.AUTO)
@ApiModelProperty(value="")
private Long menuId;
/**
* 父菜单ID,一级菜单为0
*/
@TableField(value = "parent_id")
@ApiModelProperty(value="父菜单ID,一级菜单为0")
private Long parentId;
/**
* 菜单名称
*/
@TableField(value = "name")
@ApiModelProperty(value="菜单名称")
private String name;
/**
* 菜单URL
*/
@TableField(value = "url")
@ApiModelProperty(value="菜单URL")
private String url;
/**
* 授权(多个用逗号分隔,如:user:list,user:create)
*/
@TableField(value = "perms")
@ApiModelProperty(value="授权(多个用逗号分隔,如:user:list,user:create)")
private String perms;
/**
* 类型 0:目录 1:菜单 2:按钮
*/
@TableField(value = "type")
@ApiModelProperty(value="类型 0:目录 1:菜单 2:按钮")
private Integer type;
/**
* 菜单图标
*/
@TableField(value = "icon")
@ApiModelProperty(value="菜单图标")
private String icon;
/**
* 排序
*/
@TableField(value = "order_num")
@ApiModelProperty(value="排序")
private Integer orderNum;
// 子节点集合
@TableField(exist = false) //告诉mybatisplus 该属性没有在数据库表中存在映射
@ApiModelProperty("子节点集合")
private Set<SysMenu> list;
private static final long serialVersionUID = 1L;
}
Mapper层
Mapper层
public interface SysMenuMapper extends BaseMapper<SysMenu> {
/**
* 根据用户标识查询菜单权限集合
* @param loginUserId
* @return
*/
Set<SysMenu> selectUserMenuListByUserId(Long loginUserId);
}
Mapper.xml文件
<select id="selectUserMenuListByUserId" resultType="com.powernode.domain.SysMenu">
SELECT
t1.*
FROM
sys_menu t1
JOIN sys_role_menu t2
JOIN sys_user_role t3 ON ( t1.menu_id = t2.menu_id AND t2.role_id = t3.role_id )
WHERE
t3.user_id = #{loginUserId}
AND ( t1.type = 0 OR t1.type = 1 );
</select>
封装的返回给前端的视图对象
/**
* 菜单和操作权限对象
*/
@ApiModel("菜单和操作权限对象")
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class MenuAndAuth {
@ApiModelProperty("菜单权限集合")
private Set<SysMenu> menuList;
@ApiModelProperty("操作权限集合")
private Set<String> authorities;
}
以上即为页面展示树状结构的全部代码实现,主要为在service层中对查询到的菜单集合进行操作