天天看點

業務系統設計之一:系統菜單設計

      首先看看上面的資料庫設計結構,其中ID為自動編号的主鍵字段,Code為菜單編碼(也稱業務編碼),Name為菜單名稱, Url為單擊菜單所導航的路徑,ImageUrl為菜單上顯示的圖檔位址,ShortCut為快捷鍵,Order為菜單項顯示順序,Grade為菜單級限,EndGrade為是否為末級菜單(既最後一菜單項),SupMenuCode為目前菜單項的父級菜單編碼(對應于Code字段),完整的還應該包括是否受權限控制等字段,這裡不一一列出。

      上面的資料庫設計其實很簡單,需要主要的字段有Code菜單編碼(也稱業務編碼),在業務系統裡通常設計為每一菜單項都可以認為是一個業務操作,這裡的Code非常重要,業務系統的後續工作都是從這裡開始,通常與權限設計結合使用得最多。

      系統菜單應該是多層次結構的,比如常見的Windows菜單,業務系統裡的菜單設計同樣如此,通過SupMenuCode字段來标記該菜單項屬于那一項菜單的子菜單,如果沒有父級菜單(系統頂層菜單)則标記為0。

      既然菜單有層次結構,那就一定有層次辨別,通過Grade來标記;EndGrade則表示目前菜單項在該層次級别上的菜單項上是否為末級。

      分析清楚了需求和菜單設計方案,下面我們着手代碼開發,下圖為項目解決方案截圖:

      如上圖,Menu.cs裡封裝了資料庫查詢功能,App_Data下存放的Access資料庫,RadControls為RadMenu控件所需要的相關檔案,Default.aspx則為菜單UI界面。

      首先需要配置資料庫連串,如下:

1 private static string connectionString = "Provider=Microsoft.jet.OLEDB.4.0;data Source=" 

2     + HttpContext.Current.Server.MapPath(@"App_Data\MenuDB.mdb");

      接着我們需要一個執行SQL的方法,如下代碼塊:

 1 private  DataTable ExecuteQuery(string cmdText)

 2 {

 3     using (OleDbConnection conn = new OleDbConnection(connectionString))

 4     {

 5         using (OleDbDataAdapter oda = new OleDbDataAdapter(cmdText, conn))

 6         {

 7             DataSet ds = new DataSet();

 8             oda.Fill(ds);

 9             return ds.Tables[0];

10         }

11     }

12 }

      最後我們還需要寫兩個方法,一個是查詢頂層菜單的方法,一個則是實作查詢菜單下的子菜單方法(做法有很多種,我個人建議把所有的資料查詢出然後在操作記憶體資料,這裡為了友善了解我故采用多次查詢資料庫的方式來實作)。

 1 public DataTable GetMenu()

 3     string sql = "select * from menu where grade=0";

 4     return ExecuteQuery(sql);

 5 }

 6 

 7 public DataTable GetMenuBySupCode(string supMenuCode)

 8 {

 9     string sql = "select * from menu where supmenucode='" + supMenuCode + "'";

10     return ExecuteQuery(sql);

11 }

      OK,準備工作做好後,現在就是需要到UI層上去做菜單的展現工作了。菜單的展現我通過RadContrls的RadMenu控件來實作,此控件相對ASP.NET的标準Menu控件功能強大。要使用RadMenu則需要注冊控件的引用,如果你是通過RadContrls控件庫安裝包安裝的則會自動注冊到VS工具箱,和标準控件使用方法一樣。

1 <%@ Register Assembly="RadMenu.Net2" Namespace="Telerik.WebControls" TagPrefix="rad" %>

1     <%--菜單開始--%>

2     <rad:RadMenu ID="SystemMenu" runat="server" Skin="Vista">

3     </rad:RadMenu>

4     <%--菜單結束--%>

      上面準備好了頂層菜單的查詢方法,直接通過該方法查詢出頂層菜單項對菜單進行初始化:

 1 protected void Page_Load(object sender, EventArgs e)

 3     if (!IsPostBack)

 5         InitMenu();

 6     }

 7 }

 8 

 9 Menu menu = new Menu();

10 private void InitMenu()

11 {

12     //查詢出菜單配置資訊

13     DataTable dtMenu = menu.GetMenu();

14 

15     for (int i = 0; i < dtMenu.Rows.Count; i++)

16     {

17         //Rad菜單項

18         RadMenuItem item = new RadMenuItem();

19 

20         item.ID = dtMenu.Rows[i]["Code"].ToString();

21         item.Text = dtMenu.Rows[i]["Name"].ToString();

22         item.Value = dtMenu.Rows[i]["Url"].ToString();

23         item.AccessKey = dtMenu.Rows[i]["ShortCut"].ToString();

24 

25         this.SystemMenu.Items.Add(item);

26 

27         //菜建子菜單

28         InitSubMenu(item, dtMenu.Rows[i]["Code"].ToString());

29     }

30 }

      我們設計為多層次菜單結構,那麼在初始化頂層菜單的時候就應該判斷該菜單項是否有子菜單,如果有則也初始化子菜單,如果是多級層次的結構,通過遞歸算法來完成多層次的初始化。如下代碼塊:

 1 

 2 private void InitSubMenu(RadMenuItem item, string supMenuCode)

 3 {

 4     //根據父菜單編碼查詢出子菜單配置項

 5     DataTable dtMenu = menu.GetMenuBySupCode(supMenuCode);

 7     if (dtMenu != null)

 8     {

 9         foreach (DataRow dataRow in dtMenu.Rows)

10         {

11             RadMenuItem subItem = new RadMenuItem();

12 

13             subItem.ID = dataRow["ID"].ToString();

14             subItem.Text = dataRow["Name"].ToString();

15             subItem.Value = dataRow["Url"].ToString();

16             subItem.AccessKey = dataRow["ShortCut"].ToString();

17 

18             item.Items.Add(subItem);

20             if (Convert.ToInt32(dataRow["EndGrade"]) != 1)

21             {

22                 InitSubMenu(subItem, Convert.ToString(dataRow["Code"]));

23             }

24         }

25     }

26 }

      如上就完成了系統的菜單設計,實際項目開發中的設計與這樣的設計幾乎都大同小異。主要是了解設計思想,或許看完了本文你還是沒有明白為什麼要這樣設計,如果是這樣那請你關注下一篇文章,下一篇文章中就用到了菜單中的業務編碼,應該可以給一個滿意的答案。

本文轉自 beniao 51CTO部落格,原文連結:http://blog.51cto.com/beniao/202205,如需轉載請自行聯系原作者