【C#MVC4】菜单管理和访问权限分配(四)
【C#MVC4】菜单管理和访问权限分配(四)
这一篇,介绍菜单的管理功能。
上一篇中,我们完成了过渡,明白了本例是通过读取xml文件的方式加载菜单到easyui的tree控件上的。也自己模拟了而一个菜单(手动创建),菜单最终肯定是要从数据库中加载而得,由于数据库目前是空的,暂时不做这一块的东西。等到项目最后再回头做。这里使用这个模拟的菜单做 菜单的创建工作。
按照习惯,从后往前书写,做菜单管理就是对Menu_list的正删改查:
Service层:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Arise.Model;
using Arise.Common;
namespace Arise.Service
{
public class Menu_List_Service
{
public IList<Menu_List> GetAllMenuList()
{
using(AriseEntities ariseEntities = new AriseEntities())
{
return ariseEntities.Menu_List.ToList();
}
}
public Menu_List GetMenuListById(Guid MenuListId)
{
using(AriseEntities ariseEntities = new AriseEntities())
{
return ariseEntities.Menu_List.Where(ml => ml.Menu_List_Id == MenuListId).FirstOrDefault();
}
}
public void SaveMenuList(Menu_List menuList,string saveType)
{
using(AriseEntities ariseEntities = new AriseEntities())
{
try
{
if(saveType.ToUpper() == "ADD")
{
ariseEntities.Menu_List.Add(menuList);
}
else
{
ariseEntities.Entry(menuList).State = System.Data.Entity.EntityState.Modified;
}
ariseEntities.SaveChanges();
}
catch(Exception ex)
{
throw ex;
}
}
}
public void DeleteMenuList(Guid menuListId)
{
using(AriseEntities ariseEntities = new AriseEntities())
{
//这里最好加上当前删除的链接是否有用户在使用的业务
//....
Menu_List menuList = ariseEntities.Menu_List.Where(ml => ml.Menu_List_Id == menuListId).FirstOrDefault();
ariseEntities.Entry(menuList).State = System.Data.Entity.EntityState.Deleted;
ariseEntities.SaveChanges();
}
}
}
}
上面的方法很明显了, GetMenuListById():通过Id获取Menu对象。 DeleteMenuList():删除Menu,这里做的不是很完善,当期按钮若存在用户使用时,不应该删除成功的,但是这里没做这个业务,有兴趣的可以自己判断一下,就是去关联查询Menu_List_Access,若存在则不允许删除即可。
Manager层:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Arise.Model;
using Arise.Service;
namespace Arise.Manager
{
public class Menu_List_Manager
{
private Menu_List_Service menuListService = new Menu_List_Service();
public IList<Menu_List> GetAllMenuList()
{
return menuListService.GetAllMenuList();
}
public Menu_List GetMenuListById(string MenuListId)
{
if (MenuListId == "")
{
return null;
}
return menuListService.GetMenuListById(Guid.Parse(MenuListId));
}
public void SaveMenuList(Menu_List menuList, string saveType)
{
try
{
menuListService.SaveMenuList(menuList,saveType);
}
catch(Exception ex)
{
throw ex;
}
}
public void DeleteMenuList(string menuListId)
{
if (menuListId != "")
{
menuListService.DeleteMenuList(Guid.Parse(menuListId));
}
}
}
}
这里什么赘述的,就是简单的调用,值得一提的是,因为数据库Id字段为uniqueidentifier,这里需要使用Guid。
重点来了,一大波代码正在前进:
我先将Controller的代码和View的发出来,两相结合,讲解:
Controller层:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Arise.Common;
using Arise.Model;
using Arise.Manager;
namespace Arise.Web.Controllers
{
public class AdminController : BaseController
{
//
// GET: /Admin/
public ActionResult Home()
{
User_Master userMaster = (User_Master)Session["UserMaster"];
ViewBag.User = userMaster.User_Name;
ViewBag.Date = DateTime.Now;
string userMasterId = userMaster.User_Master_Id.ToString();
string userMenuPath = System.Configuration.ConfigurationManager.AppSettings["UserMenuPath"].ToString().Trim();
string xmlPath = userMenuPath + userMasterId + ".xml";
ViewBag.MenuTreeList = MenuXMLHelper.LoadMenuXML(xmlPath);
return View();
}
public ActionResult Index()
{
return View();
}
#region Menu List Page
public ActionResult MenuList()
{
return View();
}
/*
*获取菜单信息,并将菜单信息拼接成tree能够识别的字符串
* */
public string GeneratePermission()
{
string type = Request.Params["Type"].ToString().Trim();
Menu_List_Manager menuListManager = new Menu_List_Manager();
List<Menu_List> listMenu = menuListManager.GetAllMenuList().ToList();
string permissionList = "[";
//若menu_Level为空则表示为菜单父分类
var parentlist = listMenu.Where(p => p.Menu_Level.ToString() == "").OrderBy(p => p.Serial).ToList();
for (int i = 0; i < parentlist.Count; i++)
{
if (type != "")//表示为菜单管理页面
{
permissionList += "{\"id\":\"" + parentlist[i].Menu_List_Id.ToString().Trim() + "\",\"text\":\"" + parentlist[i].Menu_Name.ToString().Trim() + " /Serial:" + parentlist[i].Serial.ToString().Trim() + "\",\"iconCls\":\"" + parentlist[i].Icon_Name.ToString().Trim() + "\",\"attributes\":{\"level\":\"1\"}";
}
else//表示为菜单权限分配页面
{
permissionList += "{\"id\":\"" + parentlist[i].Menu_List_Id.ToString().Trim() + "\",\"text\":\"" + parentlist[i].Menu_Name.ToString().Trim() + "\",\"iconCls\":\"" + parentlist[i].Icon_Name.ToString().Trim() + "\",\"attributes\":{\"level\":\"1\"}";
}
//若menu_list不为空,则为父分类的ID,
var childlist = listMenu.Where(p => p.Menu_Level == parentlist[i].Menu_List_Id.ToString()).OrderBy(p => p.Serial).ToList();
if (childlist.Count != 0)
{
permissionList += ",\"children\":[";
}
for (int j = 0; j < childlist.Count; j++)
{
if (type != "")
{
permissionList += "{\"id\":\"" + childlist[j].Menu_List_Id.ToString().Trim() + "\",\"text\":\"" + childlist[j].Menu_Name.ToString().Trim() + " /Serial:" + childlist[j].Serial.ToString().Trim() + "\",\"iconCls\":\"" + parentlist[i].Icon_Name.ToString().Trim() + "\",\"attributes\":{\"level\":\"2\"}},";
}
else
{
permissionList += "{\"id\":\"" + childlist[j].Menu_List_Id.ToString().Trim() + "\",\"text\":\"" + childlist[j].Menu_Name.ToString().Trim() + "\",\"iconCls\":\"" + parentlist[i].Icon_Name.ToString().Trim() + "\",\"attributes\":{\"level\":\"2\"}},";
}
if (childlist.Count != 0 && j == childlist.Count - 1)
{
permissionList = permissionList.Substring(0, permissionList.Length - 1);
permissionList += "]";
}
}
permissionList += "},";
}
permissionList = permissionList.Substring(0, permissionList.Length - 1);
permissionList += "]";
return permissionList;
}
public JsonResult SaveMenuList()
{
try
{
string saveType = Request.Params["SaveType"].ToString().Trim();
string menuListId = Request.Params["MenuListId"].ToString().Trim();
string requestURL = Request.Params["RequestURL"].ToString().Trim();
string menuName = Request.Params["MenuName"].ToString().Trim();
int serial = Utility.ConvertToInt32(Request.Params["Serial"].ToString().Trim());
string menuLevel = Request.Params["MenuLevel"].ToString().Trim();
string iconName = "icon-system";
Menu_List_Manager menuListManager = new Menu_List_Manager();
Menu_List menuList = null;
if (menuListId != null)
{
menuList = menuListManager.GetMenuListById(menuListId);
}
if (saveType.ToUpper() == "ADD")
{
if (menuList != null)
{
Utility.ReturnJsonResult("0", UserMessageShow.Invaild);
}
menuList = new Menu_List();
menuList.Menu_List_Id = Guid.NewGuid();
menuList.Request_URL = requestURL;
menuList.Menu_Name = menuName;
menuList.Menu_Level = menuLevel;
menuList.Serial = serial;
menuList.Icon_Name = iconName;
}
else
{
if (menuList == null)
{
Utility.ReturnJsonResult("0", UserMessageShow.Invaild);
}
menuList.Request_URL = requestURL;
menuList.Menu_Name = menuName;
menuList.Menu_Level = menuLevel;
menuList.Serial = serial;
menuList.Icon_Name = iconName;
}
menuListManager.SaveMenuList(menuList, saveType);
return Utility.ReturnJsonResult("1", UserMessageShow.SaveSuccess);
}
catch(Exception ex)
{
return Utility.ReturnJsonResult("0",ex.Message);
}
}
public JsonResult GetMenuByMenuId()
{
try
{
string menuListId = Request.Params["MenuListId"].ToString().Trim();
Menu_List_Manager menuListManager = new Menu_List_Manager();
Menu_List menuList = menuListManager.GetMenuListById(menuListId);
return Utility.ReturnJsonResult<Menu_List>(menuList);
}
catch(Exception ex)
{
return Utility.ReturnJsonResult("0",ex.Message);
}
}
public JsonResult DeleteMenuByMenuId()
{
string menuListId = Request.Params["MenuListId"].ToString().Trim();
Menu_List_Manager menuListManager = new Menu_List_Manager();
menuListManager.DeleteMenuList(menuListId);
return Utility.ReturnJsonResult("0", UserMessageShow.DeleteSuccess);
}
#endregion
}
}
在代码段#region Menu List Page下为MenuList页面对应的action。
View层:
@{
ViewBag.Title = "Menu List";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<script type="text/javascript">
function AddParentMenu()
{<!-- -->
$("#AddMenuInformation").dialog({
title: 'Add Menu Information',
width: 500,
height: 250
});
$('#trParentName').css("display", "none");
$('#trRequestURL').css("display", "none");
$('#hfSaveType').val("ADD");
$('#hfParentId').val("");
$("#txtMenuName").focus();
$('#txtParentMenuName').val("");
$('#hfMenuId').val("");
$('#txtMenuName').val('');
$('#txtMenuRequestURL').val('');
$('#txtSerialNumber').val('');
$("#AddMenuInformation").dialog('open');
}
function AddMenu() {<!-- -->
var node = $('#tt').tree('getSelected');
if (node == null) {
alert("Please select a menu Item!");
}
if (node.attributes.level == "2") {
alert("This menu can not be added child menu!");
return;
}
$('#hfParentId').val(node.id);
$("#AddMenuInformation").dialog({
title: 'Add Menu Information',
width: 500,
height: 250
});
$('#trParentName').css("display", "");
$('#trRequestURL').css("display", "");
$('#hfSaveType').val("ADD");
$("#txtMenuName").focus();
$('#txtParentMenuName').val(node.text.substring(0, node.text.indexOf("/")));
$('#hfMenuId').val("");
$('#txtMenuName').val('');
$('#txtMenuRequestURL').val('');
$('#txtSerialNumber').val('');
$("#AddMenuInformation").dialog('open');
}
function SaveMenuInfo() {<!-- -->
var type = $('#hfSaveType').val();
var menuId = $('#hfMenuId').val();
var parentMenuId = $('#hfParentId').val();
var menuName = $('#txtMenuName').val();
var menuRequestURL = $('#txtMenuRequestURL').val();
var serialNumber = $('#txtSerialNumber').val();
$.ajax({
url: '/Admin/SaveMenuList',
data: {
SaveType: type, MenuListId: menuId, MenuLevel: parentMenuId, MenuName: menuName, RequestURL: menuRequestURL, Serial: serialNumber
},
type: 'post',
dataType: 'json',
success: function (data) {<!-- -->
if (data.result == "0") {
alert(data.message);
} else {
$("#AddMenuInformation").dialog('close');
alert(data.message);
$('#tt').tree('reload');
}
}
});
}
function DeleteMenu() {<!-- -->
var node = $('#tt').tree('getSelected');
if (node.attributes.level == "1") {
alert("This menu can not be deleted!");
return;
}
if (confirm("Are you sure delete this menu?")) {
$.ajax({
url: '/Admin/DeleteMenuByMenuId',
data: {
MenuListId: node.id
},
type: 'post',
dataType: 'json',
success: function (data) {<!-- -->
if (data.result == "0") {
alert(data.message);
$('#tt').tree('reload');
} else {
alert(data.message);
}
}
});
}
}
function EditMenu() {<!-- -->
var node = $('#tt').tree('getSelected');
if (node == null) {
alert("Please select a menu Item!");
}
if (node.attributes.level == "1") {
return;
}
var nodeParent = $('tt').tree('getParent', node.target)
$('#hfMenuId').val(node.id);
$('#hfParentId').val(nodeParent.id);
$.ajax({
url: '/Admin/GetMenuByMenuId',
data: {
MenuListId: node.id
},
type: 'post',
dataType: 'json',
success: function (data) {<!-- -->
if (data.result == "1") {
alert(data.message);
} else {
$("#AddMenuInformation").dialog({
title: 'Edit Menu Information',
width: 500,
height: 250
});
$('#trParentName').css("display", "");
$('#trRequestURL').css("display", "");
$('#hfSaveType').val("Update");
$('#txtParentMenuName').val(nodeParent.text.substring(0, nodeParent.text.indexOf("/")));
$('#txtMenuName').val(data.Menu_Name);
$('#txtMenuRequestURL').val(data.Request_URL);
$('#txtSerialNumber').val(data.Serial);
$("#AddMenuInformation").dialog('open');
}
}
});
}
</script>
<div style="padding-top: 2px; padding-left: 2px;font-size:8px;">
<div id="dQueryPermissionList" class="easyui-panel" style="float: left; width: 360px; height: 'auto';
padding: 10px; background-color: #FFFFFF;" title="Menu List">
<div style="width: 330px; height: 450px; overflow: auto;">
<ul id="tt" class="easyui-tree" data-options="url:'/Admin/GeneratePermission?Type=S',method:'get',animate:true"></ul>
</div>
</div>
<div style="margin-top:15px;">
<a href="#" class="easyui-linkbutton" data-options="iconCls:'icon-add'" onclick="AddMenu();" style="margin-right: 18px;">Add</a>
<a href="#" class="easyui-linkbutton" data-options="iconCls:'icon-edit'" onclick="EditMenu();" style="margin-right: 18px;">Edit</a>
<a href="#" class="easyui-linkbutton" data-options="iconCls:'icon-cancel'" onclick="DeleteMenu();" style="margin-right: 18px;">Delete</a>
<a href="#" class="easyui-linkbutton" data-options="iconCls:'icon-cancel'" onclick="AddParentMenu();" style="margin-right: 18px;">AddParentMenu</a>
</div>
<div id="AddMenuInformation" class="easyui-dialog" closed="true" buttons="#AddMenuInformation-Buttons"
style="padding: 10px 20px">
<table>
<tr id="trParentName">
<td>
Parent Menu Name:
</td>
<td>
<input type="text" id="txtParentMenuName" name="txtParentMenuName" class="easyui-textbox" style="width: 238px" readonly="readonly" />
<input type="hidden" id="hfParentId" name="hfParentId" />
<input type="hidden" id="hfMenuId" name="hfMenuId" />
<input type="hidden" id="hfSaveType" name="hfSaveType" />
</td>
</tr>
<tr>
<td>
Menu Name:
</td>
<td>
<input type="text" id="txtMenuName" name="txtMenuName" class="easyui-textbox" style="width: 238px" />
</td>
</tr>
<tr id="trRequestURL">
<td>
Menu Request URL:
</td>
<td>
<input type="text" id="txtMenuRequestURL" name="txtMenuRequestURL" class="easyui-textbox" style="width: 238px" />
</td>
</tr>
<tr>
<td>
Serial Number:
</td>
<td>
<input type="text" id="txtSerialNumber" name="txtSerialNumber" class="easyui-textbox" style="width: 238px" onkeyup="onlyNumber(this)" onafterpaste="onlyNumber(this)" />
</td>
</tr>
</table>
</div>
<div id="AddMenuInformation-Buttons">
<a href="#" class="easyui-linkbutton" iconcls="icon-ok" onclick="SaveMenuInfo();">
Save
</a> <a href="#" class="easyui-linkbutton" iconcls="icon-cancel" onclick="javascript: $('#AddMenuInformation').dialog('close');">
Close
</a>
</div>
</div>
页面显示:
好了,代码贴完了,讲解开始,
在页面我们看到tree是通过下面这个代码加载的:
<div style="width: 330px; height: 400px; overflow: auto;">
<ul id="tt" class="easyui-tree" data-options="url:'/Admin/GeneratePermission?Type=S',method:'get',animate:true"></ul>
</div>
在页面easyui通过tree控价访问url获取菜单信息,最终展示,这个返回的数据easyui是有规范的,他给提供一些可选参数,大致类似这种:
[{
"id":"5686e272-cc26-4039-8519-705baa2ab88d",
"text":"Setting /Serial:1",
"iconCls":"icon-system",
"children":[{
"id":"9c40bb25-92cb-40c8-a7cf-59f2e11c89ba",
"text":"Test /Serial:1",
"iconCls":"icon-system",
"attributes":{"level":"2"}},
{"id":"dc686259-11dc-4dbf-997f-c823c55387fd",
"text":"Test2 /Serial:2",
"iconCls":"icon-system",
"attributes":{"level":"2"}}]
}]
一串json,这个参数标准是easyui提供的,不是我们随意定义的,这个具体还有那些参数可选呢?
每个节点可以包括下列属性:(这个是easyui官网提供的可选参数)
id:节点的 id,它对于加载远程数据很重要。 state:节点状态,’open’ 或 ‘closed’,默认是 ‘open’。当设置为 ‘closed’ 时,该节点有子节点,并且将从远程站点加载它们。 attributes:给一个节点添加的自定义属性。
children:定义了一些子节点的节点数组
官网提供的一个Demo:
[{
"id":1,
"text":"Folder1",
"iconCls":"icon-save",
"children":[{
"text":"File1",
"checked":true
},{
"text":"Books",
"state":"open",
"attributes":{
"url":"/demo/book/abc",
"price":100
},
"children":[{
"text":"PhotoShop",
"checked":true
},{
"id": 8,
"text":"Sub Bookds",
"state":"closed"
}]
}]
},{
"text":"Languages",
"state":"closed",
"children":[{
"text":"Java"
},{
"text":"C#"
}]
}]
根据你项目的需要你可以选择性的添加或是删除某些不重要的属性。所以这里你应该知道了,服务器端有两种实现方式,一种是你建立对应的Model,然后使用Utility里面的Object直接转成json;一种是自己拼接字符串。
第二种看似很傻,但是对于这种复用不是很强的业务,是没必要建立Model的,所以这里直接拼接字符串。
获取所有列表,并将列表信息,转换成easyui的tree等够识别的json字符:
public string GeneratePermission()
{
string type = Request.Params["Type"].ToString().Trim();
Menu_List_Manager menuListManager = new Menu_List_Manager();
List<Menu_List> listMenu = menuListManager.GetAllMenuList().ToList();
string permissionList = "[";
//若menu_Level为空则表示为菜单父分类
var parentlist = listMenu.Where(p => p.Menu_Level.ToString() == "").OrderBy(p => p.Serial).ToList();
for (int i = 0; i < parentlist.Count; i++)
{
if (type != "")//表示为菜单管理页面
{
permissionList += "{\"id\":\"" + parentlist[i].Menu_List_Id.ToString().Trim() + "\",\"text\":\"" + parentlist[i].Menu_Name.ToString().Trim() + " /Serial:" + parentlist[i].Serial.ToString().Trim() + "\",\"iconCls\":\"" + parentlist[i].Icon_Name.ToString().Trim() + "\",\"attributes\":{\"level\":\"1\"}";
}
else//表示为菜单权限分配页面
{
permissionList += "{\"id\":\"" + parentlist[i].Menu_List_Id.ToString().Trim() + "\",\"text\":\"" + parentlist[i].Menu_Name.ToString().Trim() + "\",\"iconCls\":\"" + parentlist[i].Icon_Name.ToString().Trim() + "\",\"attributes\":{\"level\":\"1\"}";
}
//若menu_list不为空,则为父分类的ID,
var childlist = listMenu.Where(p => p.Menu_Level == parentlist[i].Menu_List_Id.ToString()).OrderBy(p => p.Serial).ToList();
if (childlist.Count != 0)
{
permissionList += ",\"children\":[";
}
for (int j = 0; j < childlist.Count; j++)
{
if (type != "")
{
permissionList += "{\"id\":\"" + childlist[j].Menu_List_Id.ToString().Trim() + "\",\"text\":\"" + childlist[j].Menu_Name.ToString().Trim() + " /Serial:" + childlist[j].Serial.ToString().Trim() + "\",\"iconCls\":\"" + parentlist[i].Icon_Name.ToString().Trim() + "\",\"attributes\":{\"level\":\"2\"}},";
}
else
{
permissionList += "{\"id\":\"" + childlist[j].Menu_List_Id.ToString().Trim() + "\",\"text\":\"" + childlist[j].Menu_Name.ToString().Trim() + "\",\"iconCls\":\"" + parentlist[i].Icon_Name.ToString().Trim() + "\",\"attributes\":{\"level\":\"2\"}},";
}
if (childlist.Count != 0 && j == childlist.Count - 1)
{
permissionList = permissionList.Substring(0, permissionList.Length - 1);
permissionList += "]";
}
}
permissionList += "},";
}
permissionList = permissionList.Substring(0, permissionList.Length - 1);
permissionList += "]";
return permissionList;
}
这里有两个关键的点,需要略作解释:
var parentlist = listMenu.Where(p => p.Menu_Level.ToString() == "").OrderBy(p => p.Serial).ToList();
取出所有父节点,并根据Serial排序。
这里是使用linq将集合中符合条件的对象筛选出来,所以以后不要别人问你linq,你就只知道linq to ef。这是不全面的。linq不止有跟EF连用哦,功能强大着呢。
var childlist = listMenu.Where(p => p.Menu_Level == parentlist[i].Menu_List_Id.ToString()).OrderBy(p => p.Serial).ToList();
这里是将当前父节点的所有子节点取出来。
这列的type参数你可能会有点迷惑,这个是添加用来区分做权限分配时候显示的那个tree的。因为做权限分配的时候也需要显示一个tree结构,重写一个方法又太麻烦了,所以都在这个方法里写了,这样可能会对你现在造成一些麻烦,这样,你看着太乱,就现将判断type的那部分删了,这样就清晰了。
显示讲完之后,好像就没什么好讲的了,添加和修改公用的同一个方法,添加父节点,跟添加子节点不太一下,所以就专门开了一个按钮,这里你可能遇到的问题就是easyui的dialg控件了。这个是easyui固定的写法格式,自己多看两遍熟悉一下就好了,基本用法都在代码中了,这里不过多解释,希望可以自己钻研一番。谢谢大家