因个人爱好,最近接触ASP.NET mvc开发模式。自己做了一个简单的mvc的布局框架。仅供参考!
下图效果页面:
一开始我想到的是iframe来布局,但是又想了一下既然mvc提供了分部视图就还是用分部视图来做吧。
所以,拆分成模块来看就是以下的内容:
这部分知识在WebForm里面的概念叫母版页。先说一下各个模块的工作和实现:
Top分部:一直为页面的一部分,与其他视图无关。很简单,不介绍。
Meau分部:菜单部分,主要是几个大的分区,每一个菜单下面都有独立的几个子模块,子模块的功能构成体现在Left视图中。
CurrentUser分部:显示当前登录用户的部分,另外提供了一个注销的功能。
Left分部:大模块下的子功能部分,上层业务在Meau视图中,下层业务在Right视图中。
Footer分部:提供页脚显示内容。
从架构来看,我个人喜欢把数据访问层和封装的业务逻辑层单独抽出来。所以我的文件结构是这样的:
设计到逻辑业务的代码我都封装在ViewModel中,先看一下里面有些什么。
BaseViewModel对应的是几个必要视图数据的集合的封装(母版页的数据),所以其他的几个也很明显是各个视图(页面)数据的逻辑层。当然,你会发现有的视图没有逻辑层,是因为在这里没有涉及到逻辑业务,当然,一个更合理的做法是,不管有没有逻辑业务,都应有逻辑层的ViewModel,这里暂不讨论原因。(当然,你可能已经发现了我的Right视图是没有ViewModel的,其实Right视图的逻辑部分在PersonViewModel中,因为Right视图随时会改变,所以我并没有再封装一层,这是我的问题,一开始没有考虑周到,但是并不影响,有兴趣的朋友可以下来自己再封装一层。)
下面看一下怎么给Action传入这些值的。
// GET: Home
[Authorize]
[AllFilters]
public ActionResult Index()
{
ViewModel.ViewModel.PersonListViewModel personList = new ViewModel.ViewModel.PersonListViewModel();
PersonBusinessLayer businessLayer = new PersonBusinessLayer();
List<Person> persons = businessLayer.GetPerson();
List<PersonViewModel> listViewModel = new List<PersonViewModel>();
foreach(var per in persons)
{
PersonViewModel personViewModel = new PersonViewModel();
personViewModel.Name = per.Name;
personViewModel.Age = per.Age;
personViewModel.Salary = per.Salary.ToString("C");
//把工资在3000上下的区别开来
if (per.Salary > 3000)
{
personViewModel.SalaryColor = "green";
}
else
{
personViewModel.SalaryColor = "black";
}
listViewModel.Add(personViewModel);
}
personList.Persons = listViewModel;
return View("Home", personList);
}
以上是HomeController的Index方法,也可以说是这个方法调用的页面(可以这样认为,但是实际上是有偏差的)。上面的代码实际上并没有明确告诉前端,哪个分部视图应该给哪个值,其实这部分我把它放在过滤器里面了。关于过滤器及其我也不多介绍,可以上谷歌搜索一下。为什么要用过滤器,主要是考虑到权限的问题,如果一个没有登录的游客在访问我的主页并且还拿到了数据,这显然是不合常理的,我这里的过滤器的作用就是在return View();之前进行身份认证并给必须的分部视图给定初始值。
看一下这两个过滤器的代码:
public class AuthenticationController : Controller
{
// GET: Autnentication
public ActionResult Login()
{
return View();
}
[HttpPost]
[AllowAnonymous]
public ActionResult WhenLogin(UserDetails user)
{
if (ModelState.IsValid)
{
PersonBusinessLayer bal = new PersonBusinessLayer();
UserStatus status = bal.GetUserValidity(user);
bool IsAdmin = false;
if (status == UserStatus.AuthenticatedAdmin)
{
IsAdmin = true;
}
else if (status == UserStatus.AuthentucatedUser)
{
IsAdmin = false;
}
else
{
ModelState.AddModelError("CredentialError", "无效的用户名和密码");
return View("Login");
}
FormsAuthentication.SetAuthCookie(user.UserName, false);
Session["IsAdmin"] = IsAdmin;
return RedirectToAction("Index", "Home");
}
else
{
return View("Login");
}
}
public ActionResult Logout()
{
FormsAuthentication.SignOut();
return RedirectToAction("Login");
}
}
public class PersonBusinessLayer
{
public List<Person> GetPerson()
{
ErpDAL erp = new ErpDAL();
return erp.Persons.ToList();
}
public Person Saveperson(Person p)
{
ErpDAL erp = new ErpDAL();
erp.Persons.Add(p);
erp.SaveChanges();
return p;
}
public bool IsValidUser(UserDetails u)
{
if (u.UserName == "Admin" && u.PassWord == "Admin")
{
return true;
}
else
{
return false;
}
}
public UserStatus GetUserValidity(UserDetails u)
{
if (u.UserName == "Admin" && u.PassWord == "Admin")
{
return UserStatus.AuthenticatedAdmin;
}
else if (u.UserName == "Test" && u.PassWord == "Test")
{
return UserStatus.AuthentucatedUser;
}
else
{
return UserStatus.NonAuthenticatedUser;
}
}
}
可以看到在抛出post方法的时候,只要你引用了这个过滤器就会自动的进行WhenLogin的认证。如果当前没有身份认证就会转到Login页面,如果有身份,但是权限不够高的话.......(此处可以添加一些内容,不如给不同权限的用户开放不同的动能等等都是可以实现的,由于我仅仅只是区分了不同用户并没有对其做不一样的操作,所以这里暂不讨论,有兴趣的下来可以参考谷歌)。
public class AllFilters : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
ViewResult v = filterContext.Result as ViewResult;
if (v != null)
{
BaseViewModel bvm = v.Model as BaseViewModel;
if (bvm != null)
{
//顶部视图
TopViewModel top = new TopViewModel();
top.SystemName = "某某某公司员工考勤";
bvm.TopData = top;
//底部视图
FooterViewModel footer = new FooterViewModel();
footer.CompanyName = "某某某信息技术有限公司";
footer.CopyRight = "1573.cn. All Rights Reserved";
footer.Year = DateTime.Now.Year.ToString();
bvm.FooterData = footer;
//左部视图
LeftViewModel left = new LeftViewModel();
List<String> list_left = new List<string>();
if (v.ViewData.ModelState.Values.Count > 0)
{
#region ***************** /*/* 设置左边视图中显示的按钮 *\*\ *****************
switch (v.ViewData.ModelState.Values.First().Value.AttemptedValue)
{
case "流程申请":
list_left.Add("出差申请");
list_left.Add("聚餐申请");
list_left.Add("报销申请");
break;
case "请销假管理":
list_left.Add("请假附件");
list_left.Add("销假附件");
list_left.Add("假条补办");
break;
default:
list_left.Add("上班考勤");
list_left.Add("加班考勤");
list_left.Add("工作日报");
list_left.Add("每日任务栏");
break;
}
#endregion
}
else
{
#region ***************** /*/* 初始化左边视图中显示的按钮 *\*\ *****************
list_left.Add("上班考勤");
list_left.Add("加班考勤");
list_left.Add("工作日报");
list_left.Add("每日任务栏");
#endregion
}
left.FunctionNames = list_left;
bvm.LeftData = left;
//当前用户视图
CurrentUserViewModel currentuser = new CurrentUserViewModel();
currentuser.CurrentUser = HttpContext.Current.User.Identity.Name;
bvm.CurrentUserData = currentuser;
}
}
}
}
当然,这个就是在给必要的分部视图设置初始值啊什么的。
此外,在tabs(选项卡)插件方面,很有趣的事情是踌躇了千遍万遍,本来自己做了一个插件,但是后面的实际的效果就不提了,你懂的。索性后面就引用了jQuery的插件。效率和美观都比我的好了不知道多少倍(毕竟异步无刷新是要比局部刷新人性化的多)。
好了,就说这么多吧,其实我也不知道我在说些什么东西,但是还有很多东西因为篇幅有限我就不一一讨论了,如果有兴趣要源文件的可以私聊我。