是近項目中應用到了動態菜單,覺的做的還是不錯的,這里總結出來,也許有一些做的不對的地方,仁者見仁吧。
菜單需求:
1:支持多語言。
2:只支持兩級菜單,不需要考慮無限級菜單這種需求。
3:二級菜單與一級菜單可以動態調整。
比如我們有一個給用戶授權的功能,網站共有兩個一級菜單:系統管理員以及二級管理員,之前用戶授權的二級菜單出現在系統管理員下來,但后來有人認為應該出現在級 別低點的二級管理員菜單下,這種情況要非常容易的進行調整,這里的容易調整是指不修改任何程序任何配置文件的基礎上完成,完成在網頁上就能完成。
4: 菜單的顯示需要和登錄用戶權限結合
比如系統管理員總共有六個二級菜單,每個二次菜單對應一個功能,只要用戶的授權中有其中一項,當用戶登錄系統后就會出現系統管理員的一級菜單,點擊一級菜單,能看到一個自己被授權的二級菜單。
我們采用的是比較傳統的用戶授權模式,這種方式並不一定是最好的,但適用於我們自己的項目。
1:User,用戶信息。
2:Role,角色信息。
3:Function,功能信息,比如數據字典表維護就是一個Function, ControllerName是指mvc程序中Controller路由信息,即去掉Controller后綴的部分,比如HomeController,數據庫中就存Home。Name,是一個程序員能認認識的名稱,不用於菜單顯示,因為我們的菜單需要多語言。
4:Action,子功能信息,比如數據字典表的查詢就是一個Action,刪除也屬於一個Action。ActionName是指mvc程序中的Action名稱,比如HomeController下面有一個類型為ViewResult的Index方法,此時ActionName就存這個Index。Name,也是一個供 程序員參考的名稱。
5:RoleAction,角色與子功能的關系,所有權到每一個子功能Action而不是更高一級的Function。
6:UserRole,用戶與角色的關系。
如何實現二級菜單?
實現的方式有很多種,但我們選擇的是MvcSiteMap,它允許我們對於展示的樣式進行自定義的控制,而且支持多語言以及動態菜單。
如何實現菜單多語言?
MvcSiteMap自身就提供了多語言機制,比如我們可以在配置文件中指定如下菜單,通過資源文件的方式來實現。
<mvcSiteMapNode title="$resources:SiteMapResources,Page" controller="PageName" action="Index" roles="Regional Admin"/>
但這是靜態菜單(要想修改菜單就需要修改這個配置文件),不符合要求,不能寫在配置文件中,因為功能與角色的關系是動態的而非靜態固定的,我們需要采用MvcSiteMap提供的動態菜單,但解決的思想還是采用資源文件。
在Function以及Action表中,增加了ResourceKey字段,MvcSiteMap讀取到Function信息時,顯示的名稱根據ResourceKey從指定的資源文件中獲取,而不是取數據庫中的Name字段,從而實現菜單的多語言。
修改后的sitemap配置文件,配置文件沒有具體指明菜單信息,而只是指定了兩個動態菜單配置節。
<mvcSiteMapNode title="LevelOne" dynamicNodeProvider="My.Web.Utility.LevelOneDynamicNodeProvider, My.Web"> <mvcSiteMapNode title="LevelTwo" dynamicNodeProvider="My.Web.Utility.LevelTwoDynamicNodeProvider, My.Web"> </mvcSiteMapNode> </mvcSiteMapNode>
需要分別完成上圖中的兩個菜單Provider,這里就不貼全部的了,MvcSiteMap源碼中包含了示例,菜單的Provider變成:
DynamicNode node = new DynamicNode(); var resouceObject = HttpContext.GetGlobalResourceObject("ResourcesMap", menuGroup[j].ResourceKey); if (null == resouceObject) continue; node.Title = resouceObject.ToString(); node.Key = menuGroup[j].ResourceKey+"_"+HttpContext.Current.User.Identity.Name; result.Add(node);
如何實現二級菜單與一級菜單動態調整?
1:定義二級菜單:
我們提到的Function,它對應的是一個大的功能,比如一個表的增刪改查,它有四個功能,但都屬於某某表維護的功能,我這里認為一個Function就是一個二級菜單。
2:定義一級菜單?
一級菜單是一大堆二級菜單的匯聚,可以按功能類別來分,比如可以將所有的報表頁面放在一個一級菜單下面,也可以按其它標准。這里我定義了一個MenuGroup的表,任何Function都可以屬於一個MenuGroup,也可以不屬於任何一個MenuGrop,因為有些功能,是不能直接放在菜單上的,它往往需要有前置條件才能導航到這些頁面。既然Function和MenuGroup之間的關系建立起來了,那么一級二級菜單的關系也就解決了。
例如一個系統包含100個功能,A地區的客戶需要用到其中的50個功能,B地區的客戶需要用到其中的80個功能,通過上面的兩級菜單定義,可以方便的為不同地區的客戶選擇對應的功能,也可以自由的組織一級菜單的分組。
下面是數據庫表關系圖: