前言:很久沒更新博客了,天天被該死的業務纏身,今天正好一個模塊完成了,繼續來完善咱們的代碼。以前的六篇完成了領域層、應用層、以及基礎結構層的部分代碼,這篇打算搭建下UI層的代碼。css
DDD領域驅動設計初探系列文章:html
在DDD裏面,UI層的設計也分爲BS和CS,本篇仍是以Web爲例來講明。咱們的Web採用的是MVC+bootstrap的架構。Table組件使用的是bootstrap table,之因此用它是由於它的API比較全,而且博主以爲它的風格適用於各類類型的設備,不管是PC端仍是手機端都都能很好的兼容各類瀏覽器。前端
這裏仍是貼出bootstrap API的相關地址。jquery
Bootstrap中文網:http://www.bootcss.com/ git
Bootstrap Table Demo:http://issues.wenzhixin.net.cn/bootstrap-table/index.htmlgithub
Bootstrap Table API:http://bootstrap-table.wenzhixin.net.cn/zh-cn/documentation/ajax
Bootstrap Table源碼:https://github.com/wenzhixin/bootstrap-tableexpress
Bootstrap DataPicker:http://www.bootcss.com/p/bootstrap-datetimepicker/編程
Bootstrap離線APIbootstrap
上篇完成了WCF的設計代碼,可是具體的業務邏輯的代碼尚未,咱們先來實現具體業務的CURD代碼。
/// <summary> /// 權限管理模塊接口契約 /// </summary> [ServiceContract] [ServiceInterface] public interface IPowerManageWCFService { #region 用戶管理 [OperationContract] List<DTO_TB_USERS> GetUsers(ExpressionNode expressionNode); [OperationContract] DTO_TB_USERS AddUser(DTO_TB_USERS oUser); [OperationContract] bool DeleteUser(DTO_TB_USERS oUser); [OperationContract] bool DeleteUserByLamada(ExpressionNode expressionNode); [OperationContract] bool UpdateUser(DTO_TB_USERS oUser); #endregion #region 部門管理 [OperationContract] List<DTO_TB_DEPARTMENT> GetDepartments(ExpressionNode expressionNode); [OperationContract] DTO_TB_DEPARTMENT AddDepartment(DTO_TB_DEPARTMENT oDept); [OperationContract] bool DeleteDepartment(DTO_TB_DEPARTMENT oDept); [OperationContract] bool DeleteDeptByLamada(ExpressionNode expressionNode); [OperationContract] bool UpdateDepartment(DTO_TB_DEPARTMENT oDept); #endregion #region 角色管理 [OperationContract] List<DTO_TB_ROLE> GetRoles(ExpressionNode expressionNode); [OperationContract] DTO_TB_ROLE AddRole(DTO_TB_ROLE oRole); #endregion #region 菜單管理 [OperationContract] List<DTO_TB_MENU> GetMenus(ExpressionNode expressionNode); [OperationContract] DTO_TB_MENU AddMenu(DTO_TB_MENU oMenu); #endregion }
[ServiceClass] public class PowerManageWCFService :BaseService, IPowerManageWCFService { #region Fields [Import] private IUserRepository userRepository { get; set; } [Import] private IDepartmentRepository departmentRepository { get; set; } [Import] private IRoleRepository roleRepository { get; set; } [Import] private IMenuRepository menuRepository { get; set; } #endregion #region Constust public PowerManageWCFService() { } #endregion #region WCF服務接口實現 #region 用戶管理 //這裏參數爲何不直接用Expression<Func<DTO_TB_USERS,bool>>這種類型,是由於Expression不支持序列化,沒法用於WCF數據的傳遞 public List<DTO_TB_USERS> GetUsers(ExpressionNode expressionNode) { Expression<Func<DTO_TB_USERS, bool>> selector = null; if (expressionNode != null) { selector = expressionNode.ToExpression<Func<DTO_TB_USERS, bool>>(); } var lstRes = base.GetDtoByLamada<DTO_TB_USERS, TB_USERS>(userRepository, selector); return lstRes; } public DTO_TB_USERS AddUser(DTO_TB_USERS oUser) { return base.AddDto<DTO_TB_USERS, TB_USERS>(userRepository, oUser); } public bool DeleteUser(DTO_TB_USERS oUser) { var bRes = false; try { base.DeleteDto<DTO_TB_USERS, TB_USERS>(userRepository, oUser); bRes = true; } catch { } return bRes; } public bool DeleteUserByLamada(ExpressionNode expressionNode) { Expression<Func<DTO_TB_USERS, bool>> selector = null; if (expressionNode != null) { selector = expressionNode.ToExpression<Func<DTO_TB_USERS, bool>>(); } var bRes = false; try { base.DeleteDto<DTO_TB_USERS, TB_USERS>(userRepository, selector); bRes = true; } catch { } return bRes; } public bool UpdateUser(DTO_TB_USERS oUser) { var bRes = false; try { base.UpdateDto<DTO_TB_USERS, TB_USERS>(userRepository, oUser); bRes = true; } catch { } return bRes; } #endregion #region 部門管理 public List<DTO_TB_DEPARTMENT> GetDepartments(ExpressionNode expressionNode) { Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null; if (expressionNode != null) { selector = expressionNode.ToExpression<Func<DTO_TB_DEPARTMENT, bool>>(); } return base.GetDtoByLamada<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, selector); } public DTO_TB_DEPARTMENT AddDepartment(DTO_TB_DEPARTMENT oDept) { return base.AddDto<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, oDept); } public bool DeleteDepartment(DTO_TB_DEPARTMENT oDept) { var bRes = false; try { base.DeleteDto<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, oDept); bRes = true; } catch { } return bRes; } public bool DeleteDeptByLamada(ExpressionNode expressionNode) { Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null; if (expressionNode != null) { selector = expressionNode.ToExpression<Func<DTO_TB_DEPARTMENT, bool>>(); } var bRes = false; try { base.DeleteDto<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, selector); bRes = true; } catch { } return bRes; } public bool UpdateDepartment(DTO_TB_DEPARTMENT oDept) { var bRes = false; try { base.UpdateDto<DTO_TB_DEPARTMENT, TB_DEPARTMENT>(departmentRepository, oDept); bRes = true; } catch { } return bRes; } #endregion #region 角色管理 public List<DTO_TB_ROLE> GetRoles(ExpressionNode expressionNode) { Expression<Func<DTO_TB_ROLE, bool>> selector = null; if (expressionNode != null) { selector = expressionNode.ToExpression<Func<DTO_TB_ROLE, bool>>(); } return base.GetDtoByLamada<DTO_TB_ROLE, TB_ROLE>(roleRepository, selector); } public DTO_TB_ROLE AddRole(DTO_TB_ROLE oRole) { return base.AddDto<DTO_TB_ROLE, TB_ROLE>(roleRepository, oRole); } #endregion #region 菜單管理 public List<DTO_TB_MENU> GetMenus(ExpressionNode expressionNode) { Expression<Func<DTO_TB_MENU, bool>> selector = null; if (expressionNode != null) { selector = expressionNode.ToExpression<Func<DTO_TB_MENU, bool>>(); } return base.GetDtoByLamada<DTO_TB_MENU, TB_MENU>(menuRepository, selector); } public DTO_TB_MENU AddMenu(DTO_TB_MENU oMenu) { return base.AddDto<DTO_TB_MENU, TB_MENU>(menuRepository, oMenu); } #endregion #endregion }
這裏要說明一點,在經過lamada表達式查詢的方法裏面爲何不直接用Expression<Func<DTO_TB_USERS,bool>>這種類型,而要使用ExpressionNode這種類型的變量呢?
這是由於Expression不支持序列化,沒法用於WCF數據的傳遞。ExpressionNode這個對象的使用須要添加Serialize.Linq這個dll的引用,還好有咱們神奇的NuGet,讓咱們不再用去網上找一大堆的dll了。
咱們公用的增刪改查封裝到了BaseService這個父類裏面。
public class BaseService { #region Fields private bool bInitAutoMapper = false; #endregion #region Construct public BaseService() { //註冊MEF Regisgter.regisgter().ComposeParts(this); } #endregion #region 查詢 /// <summary> /// 通用單表查詢方法 /// </summary> /// <typeparam name="DtoModel">DTOmodel</typeparam> /// <typeparam name="DomainModel">領域模型</typeparam> /// <param name="oRepository">須要傳過來的倉儲接口對象</param> /// <param name="selector">前端傳過來的lamada表達式</param> /// <returns></returns> public List<DtoModel> GetDtoByLamada<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, Expression<Func<DtoModel, bool>> selector = null) where DomainModel : AggregateRoot where DtoModel : Dto_BaseModel { InitAutoMapper<DtoModel, DomainModel>(); if (selector == null) { var lstDomainModel = oRepository.Entities.ToList(); return Mapper.Map<List<DomainModel>, List<DtoModel>>(lstDomainModel); } //獲得從Web傳過來和DTOModel相關的lamaba表達式的委託 Func<DtoModel, bool> match = selector.Compile(); //建立映射Expression的委託 Func<DomainModel, DtoModel> mapper = AutoMapper.QueryableExtensions.Extensions.CreateMapExpression<DomainModel, DtoModel>(Mapper.Engine).Compile(); //獲得領域Model相關的lamada Expression<Func<DomainModel, bool>> lamada = ef_t => match(mapper(ef_t)); List<DomainModel> list = oRepository.Find(lamada).ToList(); return Mapper.Map<List<DomainModel>, List<DtoModel>>(list); } #endregion #region 新增 public DtoModel AddDto<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, DtoModel oDtoModel) where DomainModel : AggregateRoot where DtoModel : Dto_BaseModel { InitAutoMapper<DtoModel, DomainModel>(); var oDomain = Mapper.Map<DtoModel, DomainModel>(oDtoModel); oRepository.Insert(oDomain); return Mapper.Map<DomainModel, DtoModel>(oDomain); } #endregion #region 刪除 public int DeleteDto<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, DtoModel oDtoModel) where DomainModel : AggregateRoot where DtoModel : Dto_BaseModel { InitAutoMapper<DtoModel, DomainModel>(); var oDomain = Mapper.Map<DtoModel, DomainModel>(oDtoModel); return oRepository.Delete(oDomain); } public int DeleteDto<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, Expression<Func<DtoModel, bool>> selector = null) where DomainModel : AggregateRoot where DtoModel : Dto_BaseModel { InitAutoMapper<DtoModel, DomainModel>(); if (selector == null) { return 0; } //獲得從Web傳過來和DTOModel相關的lamaba表達式的委託 Func<DtoModel, bool> match = selector.Compile(); //建立映射Expression的委託 Func<DomainModel, DtoModel> mapper = AutoMapper.QueryableExtensions.Extensions.CreateMapExpression<DomainModel, DtoModel>(Mapper.Engine).Compile(); //獲得領域Model相關的lamada Expression<Func<DomainModel, bool>> lamada = ef_t => match(mapper(ef_t)); return oRepository.Delete(lamada); } #endregion #region 更新 public void UpdateDto<DtoModel, DomainModel>(IRepository<DomainModel> oRepository, DtoModel oDtoModel) where DomainModel : AggregateRoot where DtoModel : Dto_BaseModel { InitAutoMapper<DtoModel, DomainModel>(); var oDomain = Mapper.Map<DtoModel, DomainModel>(oDtoModel); oRepository.Update(oDomain); } #endregion #region Private private void InitAutoMapper<DtoModel, DomainModel>() { var oType = Mapper.FindTypeMapFor<DtoModel, DomainModel>(); if (oType==null) { Mapper.CreateMap<DtoModel, DomainModel>(); Mapper.CreateMap<DomainModel, DtoModel>(); } } #endregion }
這個父類主要作了兩件事:一是MEF的初始化;二是通用增刪改查的實現。全部dto對象和領域model的映射都在這裏統一管理。
UI層裏面,爲了更好分離代碼,咱們引入了接口編程的機制,引入了ESTM.Web.IBLL和ESTM.Web.BLL兩個項目,如圖:
爲何要有這麼一個接口層?以前C#進階系列——MEF實現設計上的「鬆耦合」(終結篇:面向接口編程)這篇已經作過介紹,對面向接口編程不瞭解的朋友能夠看看。
這個dll主要定義接口規則。
public interface IPowerManager { List<DTO_TB_USERS> GetUsers(Expression<Func<DTO_TB_USERS, bool>> selector = null); DTO_TB_USERS AddUser(DTO_TB_USERS oUser); bool DeleteUser(DTO_TB_USERS oUser); bool UpdateUser(DTO_TB_USERS oUser); bool DeleteUser(Expression<Func<DTO_TB_USERS, bool>> selector = null); List<DTO_TB_DEPARTMENT> GetDepartments(Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null); DTO_TB_DEPARTMENT AddDepartment(DTO_TB_DEPARTMENT oDept); bool DeleteDepartment(DTO_TB_DEPARTMENT oDept); bool DeleteDepartment(Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null); bool UpdateDepartment(DTO_TB_DEPARTMENT oDept); List<DTO_TB_ROLE> GetRoles(Expression<Func<DTO_TB_ROLE, bool>> selector = null); List<DTO_TB_MENU> GetMenus(Expression<Func<DTO_TB_MENU, bool>> selector = null); }
這個dll用於實現ESTM.Web.IBLL裏面的接口方法
[Export(typeof(IPowerManager))] public class PowerManager : IPowerManager { #region Fields //建立WCF服務鏈接對象 private ServiceReference_PowerManager.PowerManageWCFServiceClient oService = CreatePowerManagerService.GetInstance(); #endregion #region 接口實現 public List<DTO_TB_USERS> GetUsers(Expression<Func<Common.DtoModel.DTO_TB_USERS, bool>> selector = null) { return oService.GetUsers(GetExpressionNode<DTO_TB_USERS>(selector)); } public List<Common.DtoModel.DTO_TB_DEPARTMENT> GetDepartments(Expression<Func<Common.DtoModel.DTO_TB_DEPARTMENT, bool>> selector = null) { return oService.GetDepartments(GetExpressionNode<DTO_TB_DEPARTMENT>(selector)); } public List<Common.DtoModel.DTO_TB_ROLE> GetRoles(Expression<Func<Common.DtoModel.DTO_TB_ROLE, bool>> selector = null) { return oService.GetRoles(GetExpressionNode<DTO_TB_ROLE>(selector)); } public List<Common.DtoModel.DTO_TB_MENU> GetMenus(Expression<Func<Common.DtoModel.DTO_TB_MENU, bool>> selector = null) { return oService.GetMenus(GetExpressionNode<DTO_TB_MENU>(selector)); } #endregion #region Privates //將lamada表達式轉換爲可用於WCF傳遞的ExpressionNode類型 private ExpressionNode GetExpressionNode<Dto>(Expression<Func<Dto,bool>> selector) { if (selector == null) { return null; } ExpressionConverter expressionConverter = new ExpressionConverter(); ExpressionNode expressionNode = expressionConverter.Convert(selector); return expressionNode; } #endregion public DTO_TB_USERS AddUser(DTO_TB_USERS oUser) { return oService.AddUser(oUser); } public bool DeleteUser(DTO_TB_USERS oUser) { return oService.DeleteUser(oUser); } public bool DeleteUser(Expression<Func<DTO_TB_USERS, bool>> selector = null) { if (selector == null) { return false; } ExpressionConverter expressionConverter = new ExpressionConverter(); ExpressionNode expressionNode = expressionConverter.Convert(selector); return oService.DeleteUserByLamada(expressionNode); } public bool UpdateUser(DTO_TB_USERS oUser) { return oService.UpdateUser(oUser); } public DTO_TB_DEPARTMENT AddDepartment(DTO_TB_DEPARTMENT oDept) { return oService.AddDepartment(oDept); } public bool DeleteDepartment(DTO_TB_DEPARTMENT oDept) { return oService.DeleteDepartment(oDept); } public bool UpdateDepartment(DTO_TB_DEPARTMENT oDept) { return oService.UpdateDepartment(oDept); } public bool DeleteDepartment(Expression<Func<DTO_TB_DEPARTMENT, bool>> selector = null) { if (selector == null) { return false; } ExpressionConverter expressionConverter = new ExpressionConverter(); ExpressionNode expressionNode = expressionConverter.Convert(selector); return oService.DeleteDeptByLamada(expressionNode); } }
public class CreatePowerManagerService { private static ServiceReference_PowerManager.PowerManageWCFServiceClient oPowerManagerClient = null; private static object obj = new object(); public static ServiceReference_PowerManager.PowerManageWCFServiceClient GetInstance() { lock (obj) { if (oPowerManagerClient == null) { oPowerManagerClient = new ServiceReference_PowerManager.PowerManageWCFServiceClient(); } } return oPowerManagerClient; } }
因爲是採用的添加服務引用的方式引用的WCF服務,因此在這一層須要添加WCF服務的引用。在實現這部分代碼的時候博主遇到過一個問題,在此和朋友們分享一下。因爲在WCF服務的設計裏面用到了DTO對象,而在ESTM.Web.BLL這個項目裏面也要用到DTO,可是添加WCF服務引用的時候默認的是WCF服務裏面的DTO,而不是ESTM.Common.DtoModel這個項目的DTO對象,這樣就有問題了,每次若是咱們須要改動下dto的內容,那麼咱們就須要更新下服務引用。還好,微軟給咱們選擇的機制,咱們來看圖
這樣就能解決上面的問題了。
按照面向接口的機制,ESTM.Web項目是不須要添加ESTM.Web.BLL這個實現層項目引用的,經過MEF動態導入ESTM.Web.BLL裏面的對象。咱們來看代碼:
public class PowerManagerController : BaseController { [Import] private IPowerManager PowerManager { set; get; } #region Views // GET: PowerManager public ActionResult User() { return View(); } public ActionResult Role() { return View(); } public ActionResult Menu() { return View(); } public ActionResult Department() { return View(); } #endregion #region 部門管理 public JsonResult GetDepartments(int limit, int offset, string departmentname, string statu) { //獲得lamada表達式 var oLamadaExtention = new LamadaExtention<DTO_TB_DEPARTMENT>(); if (!string.IsNullOrEmpty(departmentname)) { oLamadaExtention.GetExpression("DEPARTMENT_NAME", departmentname, ExpressionType.Contains); } if (!string.IsNullOrEmpty(statu)) { oLamadaExtention.GetExpression("STATUS", statu, ExpressionType.Contains); } var lamada = oLamadaExtention.GetLambda(); var lstRes = PowerManager.GetDepartments(lamada); return Json(new { rows = lstRes.Skip(offset).Take(limit).ToList(), total = lstRes.Count }, JsonRequestBehavior.AllowGet); } public object GetDepartmentEdit(string strPostData) { var oDepartment = Newtonsoft.Json.JsonConvert.DeserializeObject<DTO_TB_DEPARTMENT>(strPostData); if (string.IsNullOrEmpty(oDepartment.DEPARTMENT_ID)) { oDepartment.DEPARTMENT_ID = Guid.NewGuid().ToString(); oDepartment = PowerManager.AddDepartment(oDepartment); } else { PowerManager.UpdateDepartment(oDepartment); } return oDepartment; } public object DeleteDept(string strID) { PowerManager.DeleteDepartment(x=>x.DEPARTMENT_ID == strID); return new object(); } #endregion #region 菜單管理 public JsonResult GetMenus(int limit, int offset, string menuname, string menuurl) { var oLamadaExtention = new LamadaExtention<DTO_TB_MENU>(); if (!string.IsNullOrEmpty(menuname)) { oLamadaExtention.GetExpression("MENU_NAME", menuname, ExpressionType.Contains); } if (!string.IsNullOrEmpty(menuurl)) { oLamadaExtention.GetExpression("MENU_URL", menuurl, ExpressionType.Contains); } var lamada = oLamadaExtention.GetLambda(); var lstRes = PowerManager.GetMenus(lamada).ToList(); return Json(new { rows = lstRes.Skip(offset).Take(limit).ToList(), total = lstRes.Count }, JsonRequestBehavior.AllowGet); } public object GetMenuEdit(string strPostData) { var oMenu = Newtonsoft.Json.JsonConvert.DeserializeObject<DTO_TB_MENU>(strPostData); if (string.IsNullOrEmpty(oMenu.MENU_ID)) { //oMenu = MenuManager.Add(oMenu); } else { //MenuManager.Update(oMenu); } return oMenu; } public object DeleteMenu(string strID) { //MenuManager.Delete(strID); return new object(); } public object GetParentMenu() { var lstMenu = PowerManager.GetMenus(x => x.MENU_LEVEL == "1"); //var lstRes = RoleManager.Find().ToList(); //var oRes = new PageRowData(); //oRes.rows = lstRes.Skip(offset).Take(limit).ToList(); //oRes.total = lstRes.Count; return lstMenu; ; } public object GetChildrenMenu(string strParentID) { var lstMenu = PowerManager.GetMenus(x => x.MENU_LEVEL == "2" && x.PARENT_ID == strParentID).ToList(); //var lstRes = RoleManager.Find().ToList(); //var oRes = new PageRowData(); //oRes.rows = lstRes.Skip(offset).Take(limit).ToList(); //oRes.total = lstRes.Count; return lstMenu; ; } #endregion #region 權限管理 public JsonResult GetRole(int limit, int offset, string rolename, string desc) { var oLamadaExtention = new LamadaExtention<DTO_TB_ROLE>(); if (!string.IsNullOrEmpty(rolename)) { oLamadaExtention.GetExpression("ROLE_NAME", rolename, ExpressionType.Contains); } if (!string.IsNullOrEmpty(desc)) { oLamadaExtention.GetExpression("DESCRIPTION", desc, ExpressionType.Contains); } var lamada = oLamadaExtention.GetLambda(); var lstRes = PowerManager.GetRoles(lamada).ToList(); return Json(new { rows = lstRes.Skip(offset).Take(limit).ToList(), total = lstRes.Count }, JsonRequestBehavior.AllowGet); } #endregion #region 用戶管理 public JsonResult GetUsers(int limit, int offset, string username, string fullname) { var oLamadaExtention = new LamadaExtention<DTO_TB_USERS>(); if (!string.IsNullOrEmpty(username)) { oLamadaExtention.GetExpression("USER_NAME", username, ExpressionType.Contains); } if (!string.IsNullOrEmpty(fullname)) { oLamadaExtention.GetExpression("FULLNAME", fullname, ExpressionType.Contains); } var lamada = oLamadaExtention.GetLambda(); var lstRes = PowerManager.GetUsers(lamada).ToList(); return Json(new { rows = lstRes.Skip(offset).Take(limit).ToList(), total = lstRes.Count }, JsonRequestBehavior.AllowGet); } public object GetUserEdit(string strPostData) { var oUser = Newtonsoft.Json.JsonConvert.DeserializeObject<DTO_TB_USERS>(strPostData); if (string.IsNullOrEmpty(oUser.USER_ID)) { oUser.USER_ID = Guid.NewGuid().ToString(); oUser = PowerManager.AddUser(oUser); } else { PowerManager.UpdateUser(oUser); } return oUser; } public object DeleteUser(string strID) { PowerManager.DeleteUser(x => x.USER_ID == strID); return new object(); } #endregion }
View頁面
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width" /> <title>@ViewBag.Title</title> @Styles.Render("~/Content/css") @Styles.Render("~/Content/table-css") @Scripts.Render("~/bundles/jquery") @Scripts.Render("~/bundles/bootstrap") @Scripts.Render("~/bundles/bootstrap-table") @RenderSection("Scripts", false) </head> <body> @RenderBody() </body> </html>
@{ ViewBag.Title = "部門管理"; Layout = "~/Views/Shared/_Layout.cshtml"; } @Scripts.Render("~/bundles/PowerManage/DepartmentManage") <div class="panel-body" style="padding-bottom:0px;"> <div class="panel panel-default"> <div class="panel-heading">查詢條件</div> <div class="panel-body"> <div class="row"> <div class="col-md-4"> <label for="txt_search_departmentname" class="col-sm-4 control-label" style="margin-top:6px;">部門名稱</label> <span class="col-sm-8"> <input type="text" class="form-control" id="txt_search_departmentname"> </span> </div> <div class="col-md-4"> <label for="txt_search_statu" class="col-sm-3 control-label" style="margin-top:6px;">狀態</label> <span class="col-sm-8"> <input type="text" class="form-control" id="txt_search_statu"> </span> </div> <div class="col-md-4"> <button type="button" id="btn_query" class="btn btn-primary">查詢</button> </div> </div> </div> </div> </div> <div id="toolbar" class="btn-group"> <button id="btn_add" type="button" class="btn btn-default"> <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>新增 </button> <button id="btn_edit" type="button" class="btn btn-default"> <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>修改 </button> <button id="btn_delete" type="button" class="btn btn-default"> <span class="glyphicon glyphicon-remove" aria-hidden="true"></span>刪除 </button> </div> <table id="tb_departments"></table> <form> <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="myModalLabel">新增</h4> </div> <div class="modal-body"> <div class="form-group"> <label for="txt_departmentname">部門名稱</label> <input type="text" name="txt_departmentname" class="form-control" id="txt_departmentname" placeholder="部門名稱"> </div> <div class="form-group"> <label for="txt_parentdepartment">上級部門</label> <input type="text" name="txt_parentdepartment" class="form-control" id="txt_parentdepartment" placeholder="上級部門"> </div> <div class="form-group"> <label for="txt_departmentlevel">部門級別</label> <input type="text" name="txt_departmentlevel" class="form-control" id="txt_departmentlevel" placeholder="部門級別"> </div> <div class="form-group"> <label for="txt_statu">狀態</label> <input type="text" name="txt_statu" class="form-control" id="txt_statu" placeholder="狀態"> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-default" data-dismiss="modal"><span class="glyphicon glyphicon-remove" aria-hidden="true"></span>關閉</button> <button type="button" id="btn_submit" class="btn btn-primary" data-dismiss="modal"><span class="glyphicon glyphicon-floppy-disk" aria-hidden="true"></span>保存</button> </div> </div> </div> </div> </form>
JS代碼咱們來看一個頁面就行了,其餘頁面相似:
$(function () { $('#tb_departments').bootstrapTable({ url: '/PowerManager/GetDepartments', method: 'post', toolbar: '#toolbar', pagination: true, queryParams: queryParams, queryParamsType: "limit", //ajaxOptions: { departmentname: "", statu: "" }, sidePagination: "server", pageSize: 5, pageList: [5, 25, 50, 100], search: true, strictSearch: true, showColumns: true, showRefresh: true, minimumCountColumns: 2, clickToSelect: true, columns: [{ checkbox: true }, { field: 'DEPARTMENT_NAME', title: '部門名稱' }, { field: 'PARENT_ID', title: '上級部門' }, { field: 'DEPARTMENT_LEVEL', title: '部門級別' }, { field: 'STATUS', title: '狀態' }, ], onLoadSuccess: function (data) { var odata = data; } }); var oButtonInit = new ButtonInit(); oButtonInit.Init(); }); function queryParams(params) { //配置參數 var temp = { //這裏的鍵的名字和控制器的變量名必須一直,這邊改動,控制器也須要改爲同樣的 limit: params.limit, //頁面大小 offset: params.offset, //頁碼 departmentname: $("#txt_search_departmentname").val(), statu: $("#txt_search_statu").val() }; return temp; } var ButtonInit = function () { var oInit = new Object(); var postdata = {}; oInit.Init = function () { $("#btn_add").click(function () { $("#myModalLabel").text("新增"); $("#myModal").find(".form-control").val(""); $('#myModal').modal() postdata.DEPARTMENT_ID = ""; }); $("#btn_edit").click(function () { var arrselections = $("#tb_departments").bootstrapTable('getSelections'); if (arrselections.length > 1) { //alert("只能選擇一行進行編輯"); $("#btn_alert").alert(); return; } if (arrselections.length <= 0) { //alert("請先選擇須要編輯的行"); $("#btn_alert").alert() return; } $("#myModalLabel").text("編輯"); $("#txt_departmentname").val(arrselections[0].DEPARTMENT_NAME); $("#txt_parentdepartment").val(arrselections[0].PARENT_ID); $("#txt_departmentlevel").val(arrselections[0].DEPARTMENT_LEVEL); $("#txt_statu").val(arrselections[0].STATUS); postdata.DEPARTMENT_ID = arrselections[0].DEPARTMENT_ID; $('#myModal').modal(); }); $("#btn_delete").click(function () { var arrselections = $("#tb_departments").bootstrapTable('getSelections'); if (arrselections.length <= 0) { //alert("請先選擇須要編輯的行"); $("#btn_alert").alert() return; } if (!confirm("肯定要刪除選定的數據嗎?")) { return; } $.ajax({ type: "post", url: "/PowerManager/DeleteDept", data: { strID: arrselections[0].DEPARTMENT_ID }, success: function (data, status) { if (status == "success") { alert("提交數據成功"); $("#tb_departments").bootstrapTable('refresh'); } }, error: function () { alert("error"); }, complete: function () { //alert("complete"); } }); }); $("#btn_submit").click(function () { postdata.DEPARTMENT_NAME = $("#txt_departmentname").val(); postdata.PARENT_ID = $("#txt_parentdepartment").val(); postdata.DEPARTMENT_LEVEL = $("#txt_departmentlevel").val(); postdata.STATUS = $("#txt_statu").val(); $.ajax({ type: "post", url: "/PowerManager/GetDepartmentEdit", data: { strPostData: JSON.stringify(postdata) }, success: function (data, status) { if (status == "success") { alert("提交數據成功"); $("#tb_departments").bootstrapTable('refresh'); } }, error: function () { //alert("error"); }, complete: function () { //alert("complete"); } }); }); $("#btn_query").click(function () { $("#tb_departments").bootstrapTable('refresh'); }); }; return oInit; };
效果圖:
在作頁面數據更新的時候,博主又遇到一個問題:ObjectStateManager 中已存在具備同一鍵的對象。ObjectStateManager 沒法跟蹤具備相同鍵的多個對象。在此仍是記錄下解決方案:
在倉儲的公共實現類中將
public virtual IQueryable<TEntity> Entities { get { return UnitOfWork.context.Set<TEntity>(); } }
改爲
public virtual IQueryable<TEntity> Entities { get { return UnitOfWork.context.Set<TEntity>().AsNoTracking() as IQueryable<TEntity>; } }
就能夠了。
至此,從領域模型到Web前端的代碼基本完成,可能不少代碼並未完善,好比異常處理、數據驗證等。以前寫過一篇CS版本的權限系統 系統設計——權限系統,不少朋友找我要過源碼,那個時候可能代碼都在工做的項目中,沒辦法抽離出來,在此表示抱歉。如今作了一個BS的,感受BS比CS界面好看,在這裏將源碼分享出來,固然這裏的代碼確定也不太全,不少沒實現的功能還須要本身去實現,可是基本的架子搭起來了,有興趣能夠看看。源碼下載