連着兩天更新叙述性的文章大家可别以為我轉行了!哈哈!今天就繼續講講我們的.NET Core實戰項目之CMS系統的教程吧!這個系列教程拖得太久了,是以今天我就以菜單部分的增删改查為例來講述下我的項目分層之間的協同工作吧!如果你覺得文中有任何不妥的地方還請留言或者加入DotNetCore實戰千人交流群637326624跟大夥進行交流讨論吧!
本文已收錄至《 .NET Core實戰項目之CMS 第一章 入門篇-開篇及總體規劃》
作者:依樂祝
原文位址:
https://www.cnblogs.com/yilezhu/p/10263714.html
寫在前面
前面的章節中我們基本的增删改查都有了,甚至背景模闆我們也找到并內建到了我們的CMS系統中了!那麼剩下的就是對功能的開發了。對于功能的開發部分,我不會全部都拿出來講,隻會以一個菜單的例子來進行講解!話不多說,開是吧!
各層之間的協作
先來講講我的分層協作的設計思路。雖然借助了DDDLite的部分思想,但是又與其不通,因為小項目嚴格按照DDD的思想來進行開發完全是找虐。如果有需要我後期會對結構進行調整來向DDD層次遷移。先上一張圖吧:

這裡所有的底層方法都是在Repository層進行的,加入倉儲接口層的原因是為了解耦,一路跟着教程走來的朋友一定知道我目前我的倉儲層是按照SQLServer資料庫進行開發的,後期我會對MySQL,甚至PgSql的支援!這樣的話對應用層絲毫不會有影響。
為什麼這裡用了應用層的服務?因為如果不實用應用層的話,設計到一些邏輯判斷等等的話會把控制器搞的很龐大,代碼量太多!為了使控制器簡潔是以我加入了服務層的概念,這樣服務層處理業務邏輯,把結果傳回給控制器即可!當然如果涉及到多個事件的處理的話可能還需要借助MediatR來進行實作!什麼你不知道MediatR是什麼?那你可以看看我的這篇《
ASP.NET Core中使用MediatR實作指令和中介者模式》文章的講述。
實體層充當資料庫實體映射以及DTO及ViewModel的角色!對于實體對象模型我更喜歡貧血模式的整潔幹淨的實體對象!不喜歡充斥各種代碼的充血對象。是以裡面都是POCO的簡單生成。而ViewModel這個層可能我對這個層的概念設計有點模糊,是以DTO跟ViewModel的都混在一起了!這裡你不用太過驚訝,因為你完全可以按照自己的了解來進行整理!自由發揮吧!
菜單的增删改查實作
這一節我們就開始寫菜單的增删改查的代碼實作吧!
菜單的清單頁面功能實作
- 首選在我們的
項目的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/[email protected]("yyyyMMddHHmmss")"></script> }
可能對于大多數人來說看到這個視圖很懵逼,怎麼沒有清單的資訊啊,文法什麼的也都看不懂啊?别急,這裡用到的是Layui的一些文法!我們拆分下來看:
<form class="layui-form">
這個部分就是搜尋功能部分
<table id="menuList" lay-filter="menuList"></table>
就是表格
<script type="text/html" id="IsDisplay">
這個是layui模闆部分
- 在
下面建立一個wwwroot\js\menu\
的js檔案,來對頁面的清單進行下初始化。并對一些操作進行控制。由于代碼太長,是以隻粘貼加載表格的部分代碼如下所示:menuList.js
對應的LoadData裡面的代碼如下:
是不是很簡潔,那是因為所有的業務代碼都在服務層實作了,不信?我把代碼粘貼出來給你看:
這時候體會到服務層的好處了吧!
- 運作起來看下效果吧:
菜單增加修改功能實作
- 首先還是要寫控制器方法來顯示視圖,代碼如下:
- 由于修改編輯頁面菜單有層級關系,是以我們需要加載頂層的菜單(畫外音:隻支援兩級菜單)是以我們加載編輯頁面的時候需要把頂層的菜單給加載出來,方法如下:
- 清單頁彈出編輯或者新增的功能是在
中實作的,代碼如下:menu.js
- 新增或者編輯的時候需要判斷菜單的别名是否重複,這裡是通過layui的驗證子產品然後使用ajax實作的,視圖代碼如下:
js代碼如下:
先判斷是否符合規則,然後判斷是否存在,這個需要對新增或者編輯分别進行處理!新增的時候需要判斷是否存在即可,編輯的時候需要判斷除自己外有沒有重複的,代碼如下:
可能你更喜歡看服務層及倉儲層的代碼,當然我也會毫不吝啬的貼出來,隻是可能會消耗你些許流量來檢視圖檔。
服務層:
倉儲層代碼(由于本人比較懶,是以隻實作同步方法,異步擷取的方法後期再補上吧,相信參照其他的寫法你有何能自行實作):
這裡需要注意,我在抽象接口裡面都加了注釋,是以實作裡面就沒加了,相信你也能看懂。換句話說,我懶~~~~
- 結果送出,這裡需要注意隻要涉及到結果送出的我都會用到
還有就是我的結果送出全部是通過ajax進行的,并且把防僞Token放在Token裡面的,代碼如下:ValidateAntiForgeryToken
至于為什麼這裡的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系統設計的各層之前如何關聯工作來實作增删改查業務的,望對大家了解這個系統有所幫助!至于其他的業務功能大家都可以參照這個進行開發!比如角色管理,使用者管理等等!下節我們就來實作使用者登入子產品的功能。