ShenNiu.MVC管理系統

神牛003發表於2016-12-12

本篇將要和大家分享的是一個簡單的後臺管理系統,這裡先發個地址http://www.lovexins.com:8081/(登陸賬號:youke,密碼:123123;高階使用者賬號:gaoji,密碼:123123)有興趣的各位可以先簡單看下效果,此係統採用:Ace的h5樣式+Mvc5.0 + redis+sqlserver+shenniu.pager.js構建完成,構建此專案初衷為了有一套自己現成的h5後臺系統,為了以後能快速開發搭建一些系統;專案原始碼暫時不開源(完善後開源),如果您的確認可或者想研究下,可以掃部落格下方二維碼支援一下獲取原始碼(哪怕1分錢都可),當然此文章主要目的不是為了廣告,而是為了分享一些重要或者常用的程式碼處理方式,希望大家喜歡,多多支援:

 

. Controller中使用自帶生成的Dispose(bool)好與壞

. List集合生成許可權樹

. 對比集合,載入checkboxlist

. 為啥使用redis來儲存session

 

下面一步一個腳印的來分享:

. Controller中使用自帶生成的Dispose(bool)好與壞

首先,咋們先來看下mvc模板自動生成的Dispose重寫方法:

1        protected override void Dispose(bool disposing)
2         {
3             if (disposing)
4             {
5                 db.Dispose();
6             }
7             base.Dispose(disposing);
8         }

因為Controller實現了介面IDisposable,所以裡面可以使用Dispose方法,再看db.dispose()這是用來釋放連線資料庫物件的,如果細心的朋友可以在除錯的時候發現,我們在執行某個連線資料庫操作後,退出action的時候會進入這個重新的Dispose方法中去,主要目的用來釋放在Controller最上面生成的連線資料庫物件,我這裡是:

看到這裡個人覺吧這個物件放在這使用起來挺方便的,不過帶來一個問題就是,如果在業務邏輯複雜的地方,直接使用這個db,直到最後執行完整個action退出Controller的時候才dispose釋放連線會不會有問題,心中存疑,再加上前幾天看了一篇博文,分享的內容大概有如此的字樣:ef不需要使用using(原理也就是dispose)自己就能在操作完資料庫後釋放,原因底層已經實現了這個dispose;如此更讓人感覺直接在Controller類下面申明資料庫連結方便的很,但試為什麼微軟mvc模板Controller中會再自帶一個dispose方法呢,這兩種情況存在不排除的說法,當然今天的主要目的不是為了驗證這兩種到底哪個是對的,此文章暫時以自動生成的dispose為合理說法來分享內容(注:朋友們請勿摳字眼);

一起來看,假如自動模板生成的全部靠Controller重寫的這個dispose來釋放資料連線,那麼在多業務邏輯下,比如我在登陸的時候我們除了匹配唯一使用者外,還需要記錄獲取許可權樹,加入redis的session儲存其中等操作,不可能等這些操作完了再來釋放資料連線,這樣登陸使用者多了一定會有問題吧,如果是這種情況的問題,或許只能通過在某處運算元據庫後即時釋放連線了;以上是格式觀點和看法,或許有不妥之處,請聯絡指正,謝謝,特別是using真的不需要嗎這個問題;

 

. List集合生成許可權樹

首先,我這裡定義了一個固定的實體:

 /// <summary>
        /// 選單類
        /// </summary>
        public class MoMenu
        {

            /// <summary>
            /// 選單Id (必填)
            /// </summary>
            public int Id { get; set; }

            /// <summary>
            /// 名稱
            /// </summary>
            public string Name { get; set; }

            /// <summary>
            /// 連結地址 (建議填寫,每個需要登入訪問的Action需要使用這個對比是否有許可權)
            /// </summary>
            public string Link { get; set; }

            /// <summary>
            /// 描述
            /// </summary>
            public string Des { get; set; }

            /// <summary>
            /// 圖示樣式,對應StageClass.MoIcon
            /// </summary>
            public string Icon { get; set; }

            /// <summary>
            /// 排序(升序)
            /// </summary>
            public int Sort { get; set; }

            /// <summary>
            /// 父級選單Id,最頂層父級預設0
            /// </summary>
            public int ParentId { get; set; }

            /// <summary>
            /// 是否導航欄
            /// </summary>
            public bool IsMenu { get; set; }

            /// <summary>
            /// 選單子級集合
            /// </summary>
            public List<MoMenu> ListMenu { get; set; }
        }
View Code

主要用來裝系統中所有選單的資料,並且區分層級關係,然後通過如下方法:

 1 /// <summary>
 2         /// List集合生成選單樹
 3         /// </summary>
 4         /// <typeparam name="T">對比選中選單的物件</typeparam>
 5         /// <param name="html"></param>
 6         /// <param name="list">系統全部選單(需要有層級關係)</param>
 7         /// <param name="name">生成的checkboxlist的name</param>
 8         /// <param name="checkList">選中選單的集合</param>
 9         /// <param name="defValFiled">選中匹配的預設值</param>
10         /// <param name="isEnable">是否啟用(檢視狀態不需要啟用)</param>
11         /// <param name="nLoop">迴圈層次(可能多餘的吧)</param>
12         /// <returns></returns>
13         public static MvcHtmlString CheckBoxMenuByList<T>(
14             this HtmlHelper html,
15             List<StageModel.MoMenu> list,
16             string name = "RadStatus",
17             IEnumerable<T> checkList = null,
18             string defValFiled = "Id",
19 
20             bool isEnable = true,
21             int nLoop = 0)
22             where T : class ,new()
23         {
24             var sbHtml = new StringBuilder(string.Empty);
25             sbHtml.AppendFormat("<ul class='divmenu' style=\"list-style:none;{0}\">", nLoop <= 0 ? "display:block" : "display:none");
26             foreach (var item in list)
27             {
28                 var isCheck = false;
29                 if (checkList != null)
30                 {
31                     foreach (var checkItem in checkList)
32                     {
33                         var ty = checkItem.GetType();
34                         var val = ty.GetProperty(defValFiled).GetValue(checkItem, null);
35                         isCheck = val.ToString().Equals(item.Id.ToString());
36                         if (isCheck) { break; }
37                     }
38                 }
39 
40                 sbHtml.Append("<li>");
41                 sbHtml.AppendFormat("<input id=\"{0}{1}\" name=\"{0}\" type=\"checkbox\" value=\"{1}\" {3} {4}/><label>{2}<b>{5}</b></label>",   // class=\"arrow fa fa-angle-down\"
42                     name,
43                     item.Id,
44                     item.Name,
45                     isCheck ? "checked=\"checked\"" : "",
46                     isEnable ? "" : "disabled=\"disabled\"",
47 
48                     item.ListMenu == null ? "" : (item.ListMenu.Count > 0 ? string.Format("[{0}]", item.ListMenu.Count) : "")
49                     );
50                 if (item.ListMenu == null) { sbHtml.Append("</li>"); continue; }
51                 if (item.ListMenu.Count > 0)
52                 {
53                     sbHtml.Append(CheckBoxMenuByList(html, item.ListMenu, name, checkList, defValFiled, isEnable, isCheck ? 0 : nLoop++));
54                 }
55                 sbHtml.Append("</li>");
56             }
57             sbHtml.Append("</ul>");
58             return MvcHtmlString.Create(sbHtml.ToString());
59         }

遍歷生成選單樹,功能有:1.在檢視狀態即可使其禁用選擇,2.編輯狀態匹配物件選中選單;然後需要在試圖中增加如js程式碼:

1 $("ul[class='divmenu'] li input[type='checkbox']").on("click", function () {
2 
3             var isCheck = $(this).is(":checked");
4             //子級
5             $(this).nextAll("ul").find("li input[type='checkbox']").prop("checked", isCheck);
6         });
7         $("ul[class='divmenu'] li label").on("click", function () {
8             $(this).next("ul[class='divmenu']").toggle("normal");
9         });

最後,只需要在需要用到該選單樹的地方新增程式碼如: @Html.CheckBoxMenuByList(Stage.Com.Extend.StageClass.GetAllMenus(), "MenuIds", Model.MoRoleAndMenus, "MenuId") 即可,看到的效果圖:

具體大家可以登陸ShenNiu.MVC試試效果

 

. 對比集合,載入checkboxlist

首先,直接貼程式碼如:

 1 /// <summary>
 2         /// 對比集合,載入checkboxlist
 3         /// </summary>
 4         /// <typeparam name="T">目標物件</typeparam>
 5         /// <param name="html"></param>
 6         /// <param name="orgList">目標集合</param>
 7         /// <param name="orgFiledVal">目標對應checkbox的value值的屬性名稱</param>
 8         /// <param name="orgFiledText">對應的checkbox文字的text值的屬性名稱</param>
 9         /// <param name="destList">匹配集合</param>
10         /// <param name="destFiled">匹配列的屬性名稱</param>
11         /// <param name="sClass">樣式</param>
12         /// <param name="name">checkboxlist的Name</param>
13         /// <returns></returns>
14         public static MvcHtmlString CheckBoxRoleByList<T, TT>(
15             this HtmlHelper html,
16             IEnumerable<T> orgList,
17             string orgFiledVal,
18             string orgFiledText,
19 
20             IEnumerable<TT> destList = null,
21             string destFiled = "",
22 
23             string sClass = "",
24             string name = "cbAll")
25             where T : class ,new()
26             where TT : class,new()
27         {
28             var sbHtml = new StringBuilder(string.Empty);
29             if (orgList.Count() <= 0) { return MvcHtmlString.Create(string.Empty); }
30 
31             sbHtml.AppendFormat("<div class=\"{0}\">", sClass);
32             foreach (var item in orgList)
33             {
34                 var ty = item.GetType();
35                 var val = ty.GetProperty(orgFiledVal).GetValue(item, null);
36                 var text = ty.GetProperty(orgFiledText).GetValue(item, null);
37 
38                 var isMatch = false;
39                 if (destList != null)
40                 {
41                     foreach (var destItem in destList)
42                     {
43                         var destty = destItem.GetType();
44                         var destval = destty.GetProperty(destFiled).GetValue(destItem, null);
45 
46                         if (val.ToString().ToUpper().Equals(destval.ToString().ToUpper()))
47                         {
48                             isMatch = true;
49                             break;
50                         }
51                     }
52                 }
53                 sbHtml.AppendFormat("<label><input type='checkbox' name='{0}' value='{1}' {3} />{2}</label>", name, val, text, isMatch ? "checked='checked'" : "");
54             }
55             sbHtml.Append("</div>");
56             return MvcHtmlString.Create(sbHtml.ToString());
57         }

使用編輯頁面的效果圖如:

看到效果是預設繫結了該使用者對應的許可權“高階使用者”,程式碼需要重點是:

1  var ty = item.GetType();
2  var val = ty.GetProperty(orgFiledVal).GetValue(item, null);
3  var text = ty.GetProperty(orgFiledText).GetValue(item, null);

主要作用就是指定特定的屬性,獲取特定屬性的value值;item是List集合中的某個物件,具體引數說明可以看下程式碼備註;

 

. 為啥使用redis來儲存session

這個小標題不好定義,我個人的見解,大家可以看看罷了;1:redis儲存資料可以設定失效時間,這就類似於session失效的效果一樣,所以redis能很好的來當做session容器;2:用上面一點我們可以再增加nginx等分散式服務,以此來打架一個分散式架構,這樣在更新子系統的時候不會造成所以的業務癱瘓,可以不對使用者的操作造成阻礙,彷彿沒有更細過一樣;3:基於redis搭建session伺服器後session伺服器這個時候可以單獨分到另外一臺伺服器上,這樣減少了記憶體佔有率,應用程式和session分佈多個伺服器,大大提高承載率,不至於說什麼千萬級別就把您系統cpu爆滿了,session還各種丟失的情況;4.使用redis打架服務後可以利用剩餘空間儲存一些不長變動的資料和訊息,列如:系統中的選單欄,一些訊息提醒,郵件傳送等資料,都可以使用其儲存;

以上是個人的觀點和總結,希望能對大家有幫助;由於本人經驗有限,如有不合理的地方請多多指正,謝謝。

相關文章