网站导航是用户访问网站的主要方式,它帮助用户轻松地找到他们想要的内容。如果导航菜单能够根据用户权限从数据库动态生成,那么这将是网站的一个加分项。本文将解释如何根据网站管理员赋予的权限,为用户从数据库生成菜单。
前端生成菜单的方式与从数据库生成菜单相似。这里将修改后端部分,仅从那里生成菜单项。在转向后端之前,让先了解一些基本的数据库生成菜单的方法。在创建这个菜单时,使用了一些基本功能,例如:
从数据库获取菜单数据。这个函数用于获取特定用户的菜单项(这里硬编码了UserID为K010,可以在这里设置会话值)。
private DataTable GetMenuData()
{
try
{
using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["MenuWithCustomPrivs"].ConnectionString))
{
SqlCommand cmd = new SqlCommand("spMenuItem", con);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@UserID", "K010");
DataTable dtMenuItems = new DataTable();
SqlDataAdapter sda = new SqlDataAdapter(cmd);
sda.Fill(dtMenuItems);
cmd.Dispose();
sda.Dispose();
return dtMenuItems;
}
}
catch (Exception ex)
{
// 显示错误信息
}
return null;
}
添加顶级/父菜单项。这里将添加Parent ID为NULL的菜单项。同时,还将调用一个函数来绑定子菜单。在这个函数中,调用了另一个函数AddChildMenuItems,它将为该菜单项绑定子项。
private void AddTopMenuItems(DataTable menuData)
{
DataView view = null;
try
{
view = new DataView(menuData);
view.RowFilter = "ParentID IS NULL";
foreach (DataRowView row in view)
{
MenuItem newMenuItem = new MenuItem(row["Text"].ToString(), row["MenuID"].ToString());
menuBar.Items.Add(newMenuItem);
AddChildMenuItems(menuData, newMenuItem);
}
}
catch (Exception ex)
{
// 显示错误信息
}
finally
{
view = null;
}
}
添加子菜单项。这里使用这段代码来绑定子项。在这里根据从上面函数传递的Parent ID过滤菜单项。
private void AddChildMenuItems(DataTable menuData, MenuItem parentMenuItem)
{
DataView view = null;
try
{
view = new DataView(menuData);
view.RowFilter = "ParentID=" + parentMenuItem.Value;
foreach (DataRowView row in view)
{
MenuItem newMenuItem = new MenuItem(row["Text"].ToString(), row["MenuID"].ToString());
newMenuItem.NavigateUrl = row["NavigateUrl"].ToString();
parentMenuItem.ChildItems.Add(newMenuItem);
AddChildMenuItems(menuData, newMenuItem);
}
}
catch (Exception ex)
{
// 显示错误信息
}
finally
{
view = null;
}
}
以上就是绑定菜单控件的基本函数。
现在,来到主要部分,数据库结构。这里有五个不同的表,它们包含了用户、组(角色)、其权限和菜单项的详细信息。
tblGroupPrivMst:这个表包含了组/角色和适用的权限位的信息。
tblMenuMst:这个表包含了菜单描述、菜单ID和导航URL字段。
tblUserGrpMap:这是一个映射表,它将负责用户与相应组的关系。
tblDesgMst:这个表包含了用户在网站上的职位。
tblUserMst:这个表包含了用户详细信息。
角色/组的权限位将存储在tblGroupPrivMst表中,权限位的长度将等于菜单项的总长度。这些权限位不过是0和1的组合。假设总共有10个菜单项,那么权限位将是0101011100,并且将按照这样的方式排列,以便菜单项将连续对应到位位置。第一位的0表示该角色不适用第一个位置的项。
生成菜单。可能会喜欢编写简单的SQL存储过程来生成菜单。使用的SP,根据用户权限生成菜单项如下:
CREATE PROCEDURE [dbo].[spMenuItem]
@UserID [varchar](50)
WITH EXECUTE AS CALLER
AS
BEGIN
-- 声明变量
DECLARE @GroupCode VARCHAR(5)
SET @GroupCode=(SELECT DISTINCT GroupCode FROM tblUserGrpMap WHERE UserID=@UserID)
CREATE TABLE #TMP(MenuID INT, Text VARCHAR(50), Description VARCHAR(50), ParentID INT, NavigateUrl VARCHAR(100))
DECLARE @VAL VARCHAR(MAX), @Pos INT, @len INT
SET @VAL=(SELECT REPLACE(REPLACE(CONVERT(VARCHAR(30), SUM(CAST(PrivilegeID AS NUMERIC(30,0)))), '2', '1'), '3', '1') FROM tblGroupPrivMst WHERE GroupCode in (SELECT GroupCode FROM tblUserGrpMap WHERE UserID=@UserID))
SET @Pos=1
SET @len=LEN(@VAL)
WHILE (@len!=0)
BEGIN
DECLARE @Value CHAR(1)
SET @Value=SUBSTRING(@VAL, @Pos, 1)
IF @Value=1
BEGIN
INSERT INTO #TMP SELECT * FROM tblMenuMst WHERE MenuID=@Pos
END
SET @Pos=@Pos+1
SET @len=@len-1
END
-- 插入顶级节点
INSERT INTO #TMP SELECT * FROM tblMenuMst WHERE MenuID IN (SELECT DISTINCT ParentID FROM #TMP WHERE ParentID NOT IN (SELECT MenuID FROM #TMP))
-- 插入第二级节点
INSERT INTO #TMP SELECT * FROM tblMenuMst WHERE MenuID IN (SELECT DISTINCT ParentID FROM #TMP WHERE ParentID NOT IN (SELECT MenuID FROM #TMP))
-- 插入第三级节点
INSERT INTO #TMP SELECT * FROM tblMenuMst WHERE MenuID IN (SELECT DISTINCT ParentID FROM #TMP WHERE ParentID NOT IN (SELECT MenuID FROM #TMP))
SELECT * FROM #TMP ORDER BY MenuID ASC
DROP TABLE #TMP
END
这个SP将生成最多三级的菜单项。如果有更多的级别,需要重复这个插入命令:
INSERT INTO #TMP SELECT * FROM tblMenuMst WHERE MenuID IN(SELECT DISTINCT ParentID FROM #TMP WHERE ParentID NOT IN(SELECT MenuID FROM #TMP))
执行程序后,将得到类似于这样的菜单:
知道,在设计上可能有点无聊。