前言:好久没更新博客了,每天被该死的业务缠身,今天正好一个模块完成了,继续来完善我们的代码。之前的六篇完成了领域层、应用层、以及基础结构层的部分代码,这篇打算搭建下UI层的代码。
一、UI层介绍
在DDD里面,UI层的设计也分为BS和CS,本篇还是以Web为例来说明。我们的Web采用的是MVC+bootstrap的架构。Table组件使用的是bootstrap table,之所以用它是因为它的API比较全,并且博主觉得它的风格适用于各种类型的设备,无论是PC端还是手机端都都能很好的兼容各种浏览器。
这里还是贴出bootstrap API的相关地址。
Bootstrap中文网:http://www.bootcss.com/
Bootstrap Table Demo:http://issues.wenzhixin.net.cn/bootstrap-table/index.html
Bootstrap Table API:http://bootstrap-table.wenzhixin.net.cn/zh-cn/documentation/
Bootstrap Table源码:https://github.com/wenzhixin/bootstrap-table
Bootstrap DataPicker:http://www.bootcss.com/p/bootstrap-datetimepicker/
Bootstrap离线API
二、代码示例
上篇完成了WCF的设计代码,但是具体的业务逻辑的代码还没有,我们先来实现具体业务的CURD代码。
1、WCF代码
1.1 WCF服务业务接口代码
/// /// 权限管理模块接口契约 /// [ServiceContract] [ServiceInterface] public interface IPowerManageWCFService { #region 用户管理 [OperationContract] List 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 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 GetRoles(ExpressionNode expressionNode); [OperationContract] DTO_TB_ROLE AddRole(DTO_TB_ROLE oRole); #endregion #region 菜单管理 [OperationContract] List GetMenus(ExpressionNode expressionNode); [OperationContract] DTO_TB_MENU AddMenu(DTO_TB_MENU oMenu); #endregion }
1.2 WCF接口实现代码:
[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>这种类型,是因为Expression不支持序列化,无法用于WCF数据的传递 public List GetUsers(ExpressionNode expressionNode) { Expressionbool>> selector = null; if (expressionNode != null) { selector = expressionNode.ToExpressionbool>>(); } var lstRes = base.GetDtoByLamada(userRepository, selector); return lstRes; } public DTO_TB_USERS AddUser(DTO_TB_USERS oUser) { return base.AddDto(userRepository, oUser); } public bool DeleteUser(DTO_TB_USERS oUser) { var bRes = false; try { base.DeleteDto(userRepository, oUser); bRes = true; } catch { } return bRes; } public bool DeleteUserByLamada(ExpressionNode expressionNode) { Expressionbool>> selector = null; if (expressionNode != null) { selector = expressionNode.ToExpressionbool>>(); } var bRes = false; try { base.DeleteDto(userRepository, selector); bRes = true; } catch { } return bRes; } public bool UpdateUser(DTO_TB_USERS oUser) { var bRes = false; try { base.UpdateDto(userRepository, oUser); bRes = true; } catch { } return bRes; } #endregion #region 部门管理 public List GetDepartments(ExpressionNode expressionNode) { Expressionbool>> selector = null; if (expressionNode != null) { selector = expressionNode.ToExpressionbool>>(); } return base.GetDtoByLamada(departmentRepository, selector); } public DTO_TB_DEPARTMENT AddDepartment(DTO_TB_DEPARTMENT oDept) { return base.AddDto(departmentRepository, oDept); } public bool DeleteDepartment(DTO_TB_DEPARTMENT oDept) { var bRes = false; try { base.DeleteDto(departmentRepository, oDept); bRes = true; } catch { } return bRes; } public bool DeleteDeptByLamada(ExpressionNode expressionNode) { Expressionbool>> selector = null; if (expressionNode != null) { selector = expressionNode.ToExpressionbool>>(); } var bRes = false; try { base.DeleteDto(departmentRepository, selector); bRes = true; } catch { } return bRes; } public bool UpdateDepartment(DTO_TB_DEPARTMENT oDept) { var bRes = false; try { base.UpdateDto(departmentRepository, oDept); bRes = true; } catch { } return bRes; } #endregion #region 角色管理 public List GetRoles(ExpressionNode expressionNode) { Expressionbool>> selector = null; if (expressionNode != null) { selector = expressionNode.ToExpressionbool>>(); } return base.GetDtoByLamada(roleRepository, selector); } public DTO_TB_ROLE AddRole(DTO_TB_ROLE oRole) { return base.AddDto(roleRepository, oRole); } #endregion #region 菜单管理 public List GetMenus(ExpressionNode expressionNode) { Expressionbool>> selector = null; if (expressionNode != null) { selector = expressionNode.ToExpressionbool>>(); } return base.GetDtoByLamada(menuRepository, selector); } public DTO_TB_MENU AddMenu(DTO_TB_MENU oMenu) { return base.AddDto(menuRepository, oMenu); } #endregion #endregion }
这里要说明一点,在通过lamada表达式查询的方法里面为什么不直接用Expression>这种类型,而要使用ExpressionNode这种类型的变量呢?
这是因为Expression不支持序列化,无法用于WCF数据的传递。ExpressionNode这个对象的使用需要添加Serialize.Linq这个dll的引用,还好有我们神奇的NuGet,让我们再也不用去网上找一大堆的dll了。
我们公用的增删改查封装到了BaseService这个父类里面。
1.3 BaseService代码
public class BaseService { #region Fields private bool bInitAutoMapper = false; #endregion #region Construct public BaseService() { //注册MEF Regisgter.regisgter().ComposeParts(this); } #endregion #region 查询 /// /// 通用单表查询方法 /// /// DTOmodel /// 领域模型 /// 需要传过来的仓储接口对象 /// 前端传过来的lamada表达式 /// public List GetDtoByLamada(IRepository oRepository, Expressionbool>> selector = null) where DomainModel : AggregateRoot where DtoModel : Dto_BaseModel { InitAutoMapper(); if (selector == null) { var lstDomainModel = oRepository.Entities.ToList(); return Mapper.Map, List>(lstDomainModel); } //得到从Web传过来和DTOModel相关的lamaba表达式的委托 Funcbool> match = selector.Compile(); //创建映射Expression的委托 Func mapper = AutoMapper.QueryableExtensions.Extensions.CreateMapExpression(Mapper.Engine).Compile(); //得到领域Model相关的lamada Expressionbool>> lamada = ef_t => match(mapper(ef_t)); List list = oRepository.Find(lamada).ToList(); return Mapper.Map, List>(list); } #endregion #region 新增 public DtoModel AddDto(IRepository oRepository, DtoModel oDtoModel) where DomainModel : AggregateRoot where DtoModel : Dto_BaseModel { InitAutoMapper(); var oDomain = Mapper.Map(oDtoModel); oRepository.Insert(oDomain); return Mapper.Map(oDomain); } #endregion #region 删除 public int DeleteDto(IRepository oRepository, DtoModel oDtoModel) where DomainModel : AggregateRoot where DtoModel : Dto_BaseModel { InitAutoMapper(); var oDomain = Mapper.Map(oDtoModel); return oRepository.Delete(oDomain); } public int DeleteDto(IRepository oRepository, Expressionbool>> selector = null) where DomainModel : AggregateRoot where DtoModel : Dto_BaseModel { InitAutoMapper(); if (selector == null) { return 0; } //得到从Web传过来和DTOModel相关的lamaba表达式的委托 Funcbool> match = selector.Compile(); //创建映射Expression的委托 Func mapper = AutoMapper.QueryableExtensions.Extensions.CreateMapExpression(Mapper.Engine).Compile(); //得到领域Model相关的lamada Expressionbool>> lamada = ef_t => match(mapper(ef_t)); return oRepository.Delete(lamada); } #endregion #region 更新 public void UpdateDto(IRepository oRepository, DtoModel oDtoModel) where DomainModel : AggregateRoot where DtoModel : Dto_BaseModel { InitAutoMapper(); var oDomain = Mapper.Map(oDtoModel); oRepository.Update(oDomain); } #endregion #region Private private void InitAutoMapper() { var oType = Mapper.FindTypeMapFor(); if (oType==null) { Mapper.CreateMap(); Mapper.CreateMap(); } } #endregion }
这个父类主要做了两件事:一是MEF的初始化;二是通用增删改查的实现。所有dto对象和领域model的映射都在这里统一管理。
2、UI层代码
UI层里面,为了更好分离代码,我们引入了接口编程的机制,引入了ESTM.Web.IBLL和ESTM.Web.BLL两个项目,如图:
为什么要有这么一个接口层?之前 MEF实现设计上的“松耦合”(终结篇:面向接口编程)这篇已经做过介绍,对面向接口编程不了解的朋友可以看看。
2.1 ESTM.Web.IBLL代码
这个dll主要定义接口规则。
public interface IPowerManager { List GetUsers(Expressionbool>> selector = null); DTO_TB_USERS AddUser(DTO_TB_USERS oUser); bool DeleteUser(DTO_TB_USERS oUser); bool UpdateUser(DTO_TB_USERS oUser); bool DeleteUser(Expressionbool>> selector = null); List GetDepartments(Expressionbool>> selector = null); DTO_TB_DEPARTMENT AddDepartment(DTO_TB_DEPARTMENT oDept); bool DeleteDepartment(DTO_TB_DEPARTMENT oDept); bool DeleteDepartment(Expressionbool>> selector = null); bool UpdateDepartment(DTO_TB_DEPARTMENT oDept); List GetRoles(Expressionbool>> selector = null); List GetMenus(Expressionbool>> selector = null); }
2.2 ESTM.Web.BLL代码
这个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 GetUsers(Expressionbool>> selector = null) { return oService.GetUsers(GetExpressionNode(selector)); } public List GetDepartments(Expressionbool>> selector = null) { return oService.GetDepartments(GetExpressionNode(selector)); } public List GetRoles(Expressionbool>> selector = null) { return oService.GetRoles(GetExpressionNode(selector)); } public List GetMenus(Expressionbool>> selector = null) { return oService.GetMenus(GetExpressionNode(selector)); } #endregion #region Privates //将lamada表达式转换为可用于WCF传递的ExpressionNode类型 private ExpressionNode GetExpressionNode(Expressionbool>> 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(Expressionbool>> 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(Expressionbool>> 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的内容,那么我们就需要更新下服务引用。还好,微软给我们选择的机制,我们来看图
这样就能解决上面的问题了。
2.3 ESTM.Web代码
按照面向接口的机制,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(); 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(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(); 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(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(); 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(); 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(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 id="新增">新增</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 Entities { get { return UnitOfWork.context.Set(); } }
改成
public virtual IQueryable Entities{ get { return UnitOfWork.context.Set().AsNoTracking() as IQueryable; }}
就可以了。
至此,从领域模型到Web前端的代码基本完成,可能很多代码并未完善,比如异常处理、数据验证等。
DDD领域驱动设计初探系列文章:
- 《DDD领域驱动设计初探(1):聚合》
- 《DDD领域驱动设计初探(2):仓储Repository(上)》
- 《DDD领域驱动设计初探(3):仓储Repository(下)》
- 《DDD领域驱动设计初探(4):WCF搭建》
- 《DDD领域驱动设计初探(5):AutoMapper使用》
- 《DDD领域驱动设计初探(6):领域服务》

HTML, CSS 및 JavaScript는 최신 웹 페이지를 구축하기위한 핵심 기술입니다. 1. HTML 웹 페이지 구조를 정의합니다. 2. CSS는 웹 페이지의 모양을 담당합니다.

HTML의 기능은 웹 페이지의 구조와 내용을 정의하는 것이며, 그 목적은 정보를 표시하는 표준화 된 방법을 제공하는 것입니다. 1) HTML은 타이틀 및 단락과 같은 태그 및 속성을 통해 웹 페이지의 다양한 부분을 구성합니다. 2) 콘텐츠 및 성능 분리를 지원하고 유지 보수 효율성을 향상시킵니다. 3) HTML은 확장 가능하므로 사용자 정의 태그가 SEO를 향상시킬 수 있습니다.

HTML의 미래 트렌드는 의미론 및 웹 구성 요소이며 CSS의 미래 트렌드는 CSS-In-JS 및 CSShoudini이며, JavaScript의 미래 트렌드는 WebAssembly 및 서버리스입니다. 1. HTML 시맨틱은 접근성과 SEO 효과를 향상시키고 웹 구성 요소는 개발 효율성을 향상 시키지만 브라우저 호환성에주의를 기울여야합니다. 2. CSS-in-JS는 스타일 관리 유연성을 향상 시키지만 파일 크기를 증가시킬 수 있습니다. CSShoudini는 CSS 렌더링의 직접 작동을 허용합니다. 3. Webosembly는 브라우저 애플리케이션 성능을 최적화하지만 가파른 학습 곡선을 가지고 있으며 서버리스는 개발을 단순화하지만 콜드 스타트 문제의 최적화가 필요합니다.

웹 개발에서 HTML, CSS 및 JavaScript의 역할은 다음과 같습니다. 1. HTML은 웹 페이지 구조를 정의하고, 2. CSS는 웹 페이지 스타일을 제어하고 3. JavaScript는 동적 동작을 추가합니다. 그들은 함께 현대 웹 사이트의 프레임 워크, 미학 및 상호 작용을 구축합니다.

HTML의 미래는 무한한 가능성으로 가득합니다. 1) 새로운 기능과 표준에는 더 많은 의미 론적 태그와 WebComponents의 인기가 포함됩니다. 2) 웹 디자인 트렌드는 반응적이고 접근 가능한 디자인을 향해 계속 발전 할 것입니다. 3) 성능 최적화는 반응 형 이미지 로딩 및 게으른로드 기술을 통해 사용자 경험을 향상시킬 것입니다.

웹 개발에서 HTML, CSS 및 JavaScript의 역할은 다음과 같습니다. HTML은 컨텐츠 구조를 담당하고 CSS는 스타일을 담당하며 JavaScript는 동적 동작을 담당합니다. 1. HTML은 태그를 통해 웹 페이지 구조와 컨텐츠를 정의하여 의미를 보장합니다. 2. CSS는 선택기와 속성을 통해 웹 페이지 스타일을 제어하여 아름답고 읽기 쉽게 만듭니다. 3. JavaScript는 스크립트를 통해 웹 페이지 동작을 제어하여 동적 및 대화식 기능을 달성합니다.

Htmlisnotaprogramminglanguage; itisamarkuplanguage.1) htmlstructuresandformatswebcontentusingtags.2) itworksporstylingandjavaScriptOfforIncincivity, WebDevelopment 향상.

HTML은 웹 페이지 구조를 구축하는 초석입니다. 1. HTML은 컨텐츠 구조와 의미론 및 사용 등을 정의합니다. 태그. 2. SEO 효과를 향상시키기 위해 시맨틱 마커 등을 제공합니다. 3. 태그를 통한 사용자 상호 작용을 실현하려면 형식 검증에주의를 기울이십시오. 4. 자바 스크립트와 결합하여 동적 효과를 달성하기 위해 고급 요소를 사용하십시오. 5. 일반적인 오류에는 탈수 된 레이블과 인용되지 않은 속성 값이 포함되며 검증 도구가 필요합니다. 6. 최적화 전략에는 HTTP 요청 감소, HTML 압축, 시맨틱 태그 사용 등이 포함됩니다.


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

DVWA
DVWA(Damn Vulnerable Web App)는 매우 취약한 PHP/MySQL 웹 애플리케이션입니다. 주요 목표는 보안 전문가가 법적 환경에서 자신의 기술과 도구를 테스트하고, 웹 개발자가 웹 응용 프로그램 보안 프로세스를 더 잘 이해할 수 있도록 돕고, 교사/학생이 교실 환경 웹 응용 프로그램에서 가르치고 배울 수 있도록 돕는 것입니다. 보안. DVWA의 목표는 다양한 난이도의 간단하고 간단한 인터페이스를 통해 가장 일반적인 웹 취약점 중 일부를 연습하는 것입니다. 이 소프트웨어는

맨티스BT
Mantis는 제품 결함 추적을 돕기 위해 설계된 배포하기 쉬운 웹 기반 결함 추적 도구입니다. PHP, MySQL 및 웹 서버가 필요합니다. 데모 및 호스팅 서비스를 확인해 보세요.

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

mPDF
mPDF는 UTF-8로 인코딩된 HTML에서 PDF 파일을 생성할 수 있는 PHP 라이브러리입니다. 원저자인 Ian Back은 자신의 웹 사이트에서 "즉시" PDF 파일을 출력하고 다양한 언어를 처리하기 위해 mPDF를 작성했습니다. HTML2FPDF와 같은 원본 스크립트보다 유니코드 글꼴을 사용할 때 속도가 느리고 더 큰 파일을 생성하지만 CSS 스타일 등을 지원하고 많은 개선 사항이 있습니다. RTL(아랍어, 히브리어), CJK(중국어, 일본어, 한국어)를 포함한 거의 모든 언어를 지원합니다. 중첩된 블록 수준 요소(예: P, DIV)를 지원합니다.
