連着兩天更新敘述性的文章你們可別覺得我轉行了!哈哈!今天就繼續講講咱們的.NET Core實戰項目之CMS系統的教程吧!這個系列教程拖得過久了,因此今天我就以菜單部分的增刪改查爲例來說述下個人項目分層之間的協同工做吧!若是你以爲文中有任何不妥的地方還請留言或者加入DotNetCore實戰千人交流羣637326624跟大夥進行交流討論吧!javascript
本文已收錄至《.NET Core實戰項目之CMS 第一章 入門篇-開篇及整體規劃》html
做者:依樂祝java
原文地址:https://www.cnblogs.com/yilezhu/p/10263714.htmlajax
前面的章節中咱們基本的增刪改查都有了,甚至後臺模板咱們也找到並集成到了咱們的CMS系統中了!那麼剩下的就是對功能的開發了。對於功能的開發部分,我不會所有都拿出來說,只會以一個菜單的例子來進行講解!話很少說,開是吧!數據庫
先來說講個人分層協做的設計思路。雖然藉助了DDDLite的部分思想,可是又與其不通,由於小項目嚴格按照DDD的思想來進行開發徹底是找虐。若是有須要我後期會對結構進行調整來向DDD層次遷移。先上一張圖吧:c#
這裏全部的底層方法都是在Repository層進行的,加入倉儲接口層的緣由是爲了解耦,一路跟着教程走來的朋友必定知道我目前個人倉儲層是按照SQLServer數據庫進行開發的,後期我會對MySQL,甚至PgSql的支持!這樣的話對應用層絲絕不會有影響。app
爲何這裏用了應用層的服務?由於若是不實用應用層的話,設計到一些邏輯判斷等等的話會把控制器搞的很龐大,代碼量太多!爲了使控制器簡潔因此我加入了服務層的概念,這樣服務層處理業務邏輯,把結果返回給控制器便可!固然若是涉及到多個事件的處理的話可能還須要藉助MediatR來進行實現!什麼你不知道MediatR是什麼?那你能夠看看個人這篇《ASP.NET Core中使用MediatR實現命令和中介者模式》文章的講述。異步
實體層充當數據庫實體映射以及DTO及ViewModel的角色!對於實體對象模型我更喜歡貧血模式的整潔乾淨的實體對象!不喜歡充斥各類代碼的充血對象。因此裏面都是POCO的簡單生成。而ViewModel這個層可能我對這個層的概念設計有點模糊,因此DTO跟ViewModel的都混在一塊兒了!這裏你不用太過驚訝,由於你徹底能夠按照本身的理解來進行整理!自由發揮吧!ui
這一節咱們就開始寫菜單的增刪改查的代碼實現吧!設計
首選在咱們的Czar.Cms.Admin
項目的Controllers
控制器下創建MenuController
控制器!如圖所示:
裏面的代碼以下:
public class MenuController : BaseController { private readonly IMenuService _service; public MenuController(IMenuService service) { _service = service; } public IActionResult Index() { return View(); } }
咱們這裏先列出首頁(也就是列表頁的代碼)而後建立對應的Index.cshtml
視圖
Index.cshtml視圖的代碼以下:
@{ ViewData["Title"] = "後臺菜單管理"; } <blockquote class="layui-elem-quote quoteBox"> <form class="layui-form"> @Html.AntiForgeryToken() <div class="layui-inline"> <div class="layui-input-inline"> <input type="text" class="layui-input searchVal" placeholder="請輸入菜單名稱" /> </div> <a class="layui-btn search_btn" data-type="reload">搜索</a> </div> <div class="layui-inline"> <a class="layui-btn layui-btn-normal addMenu_btn"><i class="layui-icon"></i>添加菜單</a> </div> <div class="layui-inline"> <a class="layui-btn layui-btn-danger layui-btn-normal delAll_btn"><i class="layui-icon layui-icon-delete"></i>批量刪除</a> </div> </form> </blockquote> <table id="menuList" lay-filter="menuList"></table> <!--操做--> <script type="text/html" id="menuListBar"> <a class="layui-btn layui-btn-xs" lay-event="edit">編輯</a> <a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="del">刪除</a> </script> <script type="text/html" id="IsDisplay"> {{# if(d.IsDisplay ===true){ }} <input type="checkbox" name="IsDisplay" value="{{d.Id}}" lay-filter="IsDisplay" lay-skin="switch" lay-text="是|否" checked> {{# } else{ }} <input type="checkbox" name="IsDisplay" value="{{d.Id}}" lay-filter="IsDisplay" lay-skin="switch" lay-text="是|否"> {{# }}} </script> @section Scripts{ <script type="text/javascript" src="~/layui/layui.js"></script> <script type="text/javascript" src="~/js/menu/menuList.js?_=@DateTime.Now.ToString("yyyyMMddHHmmss")"></script> }
可能對於大多數人來講看到這個視圖很懵逼,怎麼沒有列表的信息啊,語法什麼的也都看不懂啊?別急,這裏用到的是Layui的一些語法!咱們拆分下來看:
<form class="layui-form">
這個部分就是搜索功能部分
<table id="menuList" lay-filter="menuList"></table>
就是表格
<script type="text/html" id="IsDisplay">
這個是layui模板部分
在wwwroot\js\menu\
下面建立一個menuList.js
的js文件,來對頁面的列表進行下初始化。並對一些操做進行控制。因爲代碼太長,因此只粘貼加載表格的部分代碼以下所示:
對應的LoadData裏面的代碼以下:
是否是很簡潔,那是由於全部的業務代碼都在服務層實現了,不信?我把代碼粘貼出來給你看:
這時候體會到服務層的好處了吧!
運行起來看下效果吧:
首先仍是要寫控制器方法來顯示視圖,代碼以下:
因爲修改編輯頁面菜單有層級關係,因此咱們須要加載頂層的菜單(畫外音:只支持兩級菜單)因此咱們加載編輯頁面的時候須要把頂層的菜單給加載出來,方法以下:
列表頁彈出編輯或者新增的功能是在menu.js
中實現的,代碼以下:
新增或者編輯的時候須要判斷菜單的別名是否重複,這裏是經過layui的驗證模塊而後使用ajax實現的,視圖代碼以下:
js代碼以下:
先判斷是否符合規則,而後判斷是否存在,這個須要對新增或者編輯分別進行處理!新增的時候須要判斷是否存在便可,編輯的時候須要判斷除本身外有沒有重複的,代碼以下:
可能你更喜歡看服務層及倉儲層的代碼,固然我也會絕不吝嗇的貼出來,只是可能會消耗你些許流量來查看圖片。
服務層:
倉儲層代碼(因爲本人比較懶,因此只實現同步方法,異步獲取的方法後期再補上吧,相信參照其餘的寫法你有何能自行實現):
這裏須要注意,我在抽象接口裏面都加了註釋,因此實現裏面就沒加了,相信你也能看懂。換句話說,我懶~~~~
結果提交,這裏須要注意只要涉及到結果提交的我都會用到ValidateAntiForgeryToken
還有就是個人結果提交所有是經過ajax進行的,而且把防僞Token放在Token裏面的,代碼以下:
至於爲何這裏的Headers設置爲X-CSRF-TOKEN-yilezhu
這個你能夠看個人上一節課程《.NET Core實戰項目之CMS 第十四章 開發篇-防止跨站請求僞造(XSRF/CSRF)攻擊處理》
裏面有講述,因此這裏就不作過多的講述了。咱們直接上結果提交的代碼吧。
很簡潔對不對?寥寥幾行代碼,但是實現真的這麼簡單嗎?看看服務層你就知道了。
public BaseResult AddOrModify(MenuAddOrModifyModel item) { var result = new BaseResult(); Menu model; if (item.Id == 0) { //TODO ADD model = _mapper.Map<Menu>(item); model.AddManagerId = 1; model.IsDelete = false; model.AddTime = DateTime.Now; if (_repository.Insert(model) > 0) { result.ResultCode = ResultCodeAddMsgKeys.CommonObjectSuccessCode; result.ResultMsg = ResultCodeAddMsgKeys.CommonObjectSuccessMsg; } else { result.ResultCode = ResultCodeAddMsgKeys.CommonExceptionCode; result.ResultMsg = ResultCodeAddMsgKeys.CommonExceptionMsg; } } else { //TODO Modify model = _repository.Get(item.Id); if (model != null) { _mapper.Map(item, model); model.ModifyManagerId = 1; model.ModifyTime = DateTime.Now; if (_repository.Update(model) > 0) { result.ResultCode = ResultCodeAddMsgKeys.CommonObjectSuccessCode; result.ResultMsg = ResultCodeAddMsgKeys.CommonObjectSuccessMsg; } else { result.ResultCode = ResultCodeAddMsgKeys.CommonExceptionCode; result.ResultMsg = ResultCodeAddMsgKeys.CommonExceptionMsg; } } else { result.ResultCode = ResultCodeAddMsgKeys.CommonFailNoDataCode; result.ResultMsg = ResultCodeAddMsgKeys.CommonFailNoDataMsg; } } return result; }
是否是業務還蠻複雜的,若是都放在控制器處理想一想控制器是否是很恐怖,因此說引入服務層頗有必要,把一些邏輯移到服務層讓控制器只用來顯示數據多好!
你覺得刪除功能很簡單嗎?沒錯,是很簡單,但是咱們在設計數據庫的時候加入了IsDeleted
,看到這個相信你已經猜到了,咱們全部的刪除操做都是軟刪除哦!至於爲何這樣作?緣由就是不想刪錯了後悔!我只能說這麼多了,只有經歷慘痛的經歷可能纔會這樣作!還有就是刪除以前我會進行js的彈窗提醒,以下圖所示,提醒您是否真的要刪除!
好了,按照慣例咱們第一步是否是要上js的代碼啊?那還等什麼?立馬奉上
注意這裏刪除的時候也是須要進行防僞驗證的,防止別人進行接口惡意刪除,下面看下控制器中的代碼,哇真乾淨就一行代碼啊,有木有!
其實我想說服務層的代碼有超過二十行,不信?我截圖給你看吧!好好數數,加上換行是否是有二十行。
今天講的內容比較簡單就是咱們這個CMS系統設計的各層以前如何聯動工做來實現增刪改查業務的,望對你們瞭解這個系統有所幫助!至於其餘的業務功能你們均可以參照這個進行開發!好比角色管理,用戶管理等等!下節咱們就來實現用戶登陸模塊的功能。