作為“貼代碼”力推的一個(gè)CRUD實(shí)踐項(xiàng)目PasteTemplate,在對(duì)現(xiàn)有的3個(gè)項(xiàng)目進(jìn)行實(shí)戰(zhàn)后效果非常舒服!下面就針對(duì)PasteForm為啥我愿稱為最佳CRUD做一些回答: 哪里可以下載這個(gè)PasteForm的項(xiàng)目案例 目前“貼代碼”對(duì)外使用PasteForm的項(xiàng)目有"貼Builder(
作為“貼代碼”力推的一個(gè)CRUD實(shí)踐項(xiàng)目PasteTemplate,在對(duì)現(xiàn)有的3個(gè)項(xiàng)目進(jìn)行實(shí)戰(zhàn)后效果非常舒服!下面就針對(duì)PasteForm為啥我愿稱為最佳CRUD做一些回答:
目前“貼代碼”對(duì)外使用PasteForm的項(xiàng)目有"貼Builder(PasteSpider)"和案例項(xiàng)目(PasteTemplate),其中案例項(xiàng)目你可以在
https://gitee.com/pastecode/paste-template
獲得
搞這個(gè)的起初是因?yàn)槲矣幸粋(gè)項(xiàng)目要在小程序上行實(shí)現(xiàn)大量的表單,思考了下,一大堆相似的代碼,不是可以使用那個(gè)組件的方式實(shí)現(xiàn)么,那就需要傳入模型,換位思考下,那么我們經(jīng)常使用的CRUD是否也可以這么搞?
于是就有了這個(gè)利用多數(shù)據(jù)模型Dto和反射的原理實(shí)現(xiàn)的PasteForm,主要優(yōu)點(diǎn)如下
1.PasteForm輸出的是一個(gè)思想,就是管理端的頁(yè)面由后端控制,無(wú)論是安全性還是數(shù)據(jù)的表現(xiàn)
2.前端編寫(xiě)一次后,后續(xù)都不用編寫(xiě),如果你使用的是我的案例項(xiàng)目,那么你前端都可以不用編寫(xiě),包括后端要新增表,修改字段等,前端都不再需要修改代碼
3.前端頁(yè)面的超簡(jiǎn)潔性,無(wú)論你的后端是30個(gè)表還是100個(gè)表,對(duì)于前端來(lái)說(shuō)都差不多大概4個(gè)頁(yè)面搞定!當(dāng)然了一些特殊的需求,還是需要編寫(xiě)下的!
4.無(wú)語(yǔ)言限制,上面說(shuō)得輸出的是一個(gè)思想,本文的案例使用的是.netcore+html的形式實(shí)現(xiàn)的,你也可以使用比如java+vue的模式
5.統(tǒng)一性,比如你30個(gè)表的圖片上傳,在表單中他們的樣式都是一樣的,因?yàn)樗麄兤鋵?shí)使用的是同一個(gè)管理端頁(yè)面
6.后端統(tǒng)籌所有,比如字段的顯示順序,字段是否顯示,字段的默認(rèn)值等等等,都由后端對(duì)應(yīng)的Dto來(lái)限制和控制,比如同樣的新增,由于當(dāng)前登陸用戶的角色不同,你可以限制某一個(gè)字段張三必填,而李四可以是選填!
整個(gè)PasteForm的原理就是后端把數(shù)據(jù)模型的屬性,字段等返回給前端,前端基于后端返回的數(shù)據(jù)再渲染到UI上,為了便于編寫(xiě)所以采用了template的模式,其實(shí)不是JSP,是長(zhǎng)得像而已!
PasteForm原則上只有3個(gè)頁(yè)面pasteform/index.html,pasteform/view.html,pasteform/detail.html,只是有一些特殊情況下,會(huì)添加一些頁(yè)面,這個(gè)要看你項(xiàng)目的實(shí)際需求,其實(shí)無(wú)論多少個(gè)表,PasteForm的頁(yè)面都只是那么幾個(gè),比如說(shuō)權(quán)限的頁(yè)面為pasteform/index.html?path=roleInfo而用戶的表為pasteform/index.html?path=userInfo,你會(huì)發(fā)覺(jué)其實(shí)他們是同一個(gè)頁(yè)面,只是參數(shù)path不一樣而已,這個(gè)path就是WebApi的Service!
其實(shí)你完全可以一個(gè)頁(yè)面都不寫(xiě),直接使用我提供的案例項(xiàng)目PasteTemplate中的pasteform的文件!
上面提到的,PasteForm主要輸出的是一個(gè)思想,也就是由后端的Dto控制前端的頁(yè)面呈現(xiàn)和交互等,所以從WebApi中請(qǐng)求得到模板得屬性字段等信息后,你可以使用其他語(yǔ)言實(shí)現(xiàn)管理端得頁(yè)面得,不限原生,vue,angular等
作為對(duì)應(yīng)數(shù)據(jù)表得數(shù)據(jù)展示用,一般為表格table呈現(xiàn),對(duì)應(yīng)模型為XXXListDto,也包括了搜索區(qū)域,搜索區(qū)域由對(duì)應(yīng)得InputQueryXXX的數(shù)據(jù)模型決定,一般只有page,size,word三個(gè)字段!當(dāng)然了這個(gè)頁(yè)面也包含了新增數(shù)據(jù),編輯,詳情,刪除等的操作交互!
新增數(shù)據(jù),或者編輯數(shù)據(jù)的時(shí)候使用的都是這個(gè)頁(yè)面,不過(guò)他們讀取的數(shù)據(jù)模型不一樣,比如權(quán)限這個(gè)表roleInfo,則有新增的時(shí)候?yàn)閜asteform/view.html?path=roleInfo,對(duì)應(yīng)的數(shù)據(jù)模型為roleInfoAddDto,而在編輯的時(shí)候?yàn)閜asteform/view.html?path=roleInfo&id=3,對(duì)應(yīng)的數(shù)據(jù)模型為roleInfoUpdateDto。頁(yè)面的整體邏輯就是從WebApi中獲得對(duì)應(yīng)模型后,基于規(guī)則渲染到UI中,包括默認(rèn)值,當(dāng)前值等,提交的時(shí)候再?gòu)捻?yè)面中的form讀取到值提交給后端,所以說(shuō)主要的控制還是在后端中!
有些時(shí)候我們的數(shù)據(jù)沒(méi)辦法在pasteform/index.html頁(yè)面中顯示完成,比如文章列表,主要是一些字段過(guò)長(zhǎng)的,這個(gè)時(shí)候我們希望有一個(gè)頁(yè)面顯示詳細(xì)內(nèi)容,所以detail就是干這個(gè)用的,對(duì)應(yīng)的數(shù)據(jù)模型為XXXDto!
PasteForm輸出的是一個(gè)思想,所以使用其他語(yǔ)言也是可以的,不過(guò)你得對(duì)著寫(xiě)一整套的就是了,比如你可以使用vue+java的模式搞一套!后端核心代碼案例
///
/// 讀取AddDto的數(shù)據(jù)模型
///
///
[HttpGet]
[TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "root", "root" })]
public PasteBuilderHelper.VoloModelInfo ReadAddModel()
{
var _model = PasteBuilderHelper.ReadModelProperty(new RoleInfoAddDto());
return _model;
}
///
/// 讀取UpdateDto的數(shù)據(jù)模型
///
///
[HttpGet]
[TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "root", "root" })]
public async Task ReadUpdateModel(int id)
{
var _query = from a in _dbContext.RoleInfo
join b in _dbContext.RoleInfo on a.FatherId equals b.Id into c
from rol in c.DefaultIfEmpty()
select new RoleInfoUpdateDto
{
Id = a.Id,
Desc = a.Desc,
FatherId = a.FatherId,
Icon = a.Icon,
IsEnable = a.IsEnable,
Model = a.Model,
Name = a.Name,
Path = a.Path,
Role = a.Role,
RoleType = a.RoleType,
Sort = a.Sort,
ExtendRole = rol != null ? new RoleShortModel
{
Id = rol.Id,
Model = rol.Model,
Name = rol.Name,
Path = rol.Path,
Role = rol.Role,
RoleType = rol.RoleType
} : null
};
var _info = await _query.Where(x => x.Id == id).AsNoTracking().FirstOrDefaultAsync();
if (_info == null || _info == default)
{
throw new PasteCodeException("查詢的信息不存在,無(wú)法執(zhí)行編輯操作!");
}
var _dataModel = PasteBuilderHelper.ReadModelProperty(_info);
return _dataModel;
}
///
/// 讀取UpdateDto的數(shù)據(jù)模型
///
///
[HttpGet]
[TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "root", "root" })]
public async Task ReadDetailModel(int id)
{
var _query = from a in _dbContext.RoleInfo
join b in _dbContext.RoleInfo on a.FatherId equals b.Id into c
from rol in c.DefaultIfEmpty()
select new RoleInfoDto
{
Id = a.Id,
Desc = a.Desc,
FatherId = a.FatherId,
Icon = a.Icon,
IsEnable = a.IsEnable,
Model = a.Model,
Name = a.Name,
Path = a.Path,
Role = a.Role,
RoleType = a.RoleType,
SortStr = a.SortStr,
FatherStr = a.FatherStr,
Level = a.Level,
RootId = a.RootId,
Sort = a.Sort,
ExtendRole = rol != null ? new RoleShortModel
{
Id = rol.Id,
Model = rol.Model,
Name = rol.Name,
Path = rol.Path,
Role = rol.Role,
RoleType = rol.RoleType
} : null
};
var _info = await _query.Where(x => x.Id == id).AsNoTracking().FirstOrDefaultAsync();
if (_info == null || _info == default)
{
throw new PasteCodeException("查詢的信息不存在,無(wú)法執(zhí)行編輯操作!");
}
var _dataModel = PasteBuilderHelper.ReadModelProperty(_info);
return _dataModel;
}
///
/// 讀取ListDto的數(shù)據(jù)模型
///
///
[HttpGet]
[TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "root", "root" })]
public PasteBuilderHelper.VoloModelInfo ReadListModel()
{
var _model = PasteBuilderHelper.ReadModelProperty(new RoleInfoListDto());
var _query_model = PasteBuilderHelper.ReadModelProperty(new InputQueryRoleInfo());
if (_query_model != null)
{
_model.QueryProperties = _query_model.Properties;
}
return _model;
}
我最早接觸Dto的時(shí)候是ABPvNext,說(shuō)到這個(gè)Dto不得不說(shuō)ObjectMapper,比如說(shuō)權(quán)限表RoleInfo,則對(duì)應(yīng)的有RoleInfoAddDto,RoleInfoUpdateDto,RoleInfoDto和RoleInfoListDto,當(dāng)前實(shí)際開(kāi)發(fā)中你可能還會(huì)引申出更多的Dto,比如我常用的RoleMenuDto,RoleAuthDto等,PasteForm中主要用到前面的4個(gè),一般還會(huì)附帶一個(gè)InputQueryRoleInfo!比如說(shuō)新增的時(shí)候,用戶提交的數(shù)據(jù)模型是RoleInfoAddDto,提交給API后,API處數(shù)據(jù)校驗(yàn)合法后再使用AutoMapper把RoleInfoAddDto轉(zhuǎn)化成RoleInfo,然后寫(xiě)入到數(shù)據(jù)庫(kù)!
XXXAddDto:用于新增的時(shí)候的數(shù)據(jù)模型,對(duì)應(yīng)的是pasteform/view.html頁(yè)面使用
XXXUpdateDto:用于數(shù)據(jù)編輯修改的數(shù)據(jù)模型,對(duì)應(yīng)的是pasteform/view.html頁(yè)面使用
XXXDto:這里我一般用于顯示詳情的時(shí)候的數(shù)據(jù)模型,也就是pasteform/detail.html的頁(yè)面使用
XXXListDto:這里一般使用于數(shù)據(jù)表格展示的時(shí)候的數(shù)據(jù)模型,也就是pasteform/index.html的頁(yè)面使用
InputQueryXXX:這里一般用于表格上方的搜索項(xiàng)的數(shù)據(jù)模型,也就是pasteform/index.html的搜索區(qū)域使用
圖片分新增編輯和展示,展示的話這里就是pasteform/index.html和pasteform/detail.html頁(yè)面中了,其實(shí)在編輯的時(shí)候pasteform/view.html頁(yè)面上也有展示,只要給對(duì)應(yīng)字段添加屬性[ColumnDataTypeAttribute("image","1","image","60*60")]即可
///
/// 多圖 回傳的值是多個(gè)的,使用,隔開(kāi)
///
[ColumnDataType("image", "3", "img", "60*60")]
public string Img2 { get; set; }
///
/// 圖片 回傳的使用string[]的模式
///
[ColumnDataType("image", "3", "img", "60*60")]
public string[] Img3 { get; set; }
///
///文本區(qū)域 模擬文本區(qū)域的輸入
///
[ColumnDataType("class","fleft")]
public string Desc { get; set; }
///
///單選 一般表示狀態(tài),內(nèi)定的,有點(diǎn)像Enum,關(guān)于Enum后續(xù)會(huì)支持
///
[ColumnDataType("html", "{{:=item.dateType}}-{{:=item.gradeId}}")]
public int DateType { get; set; }
///
/// 普通菜單
///
[ColumnDataType("menu", "菜單一", "open_window('查閱用戶帶參','./index.html?path=userInfo&xxid={{:=item.id}}');", "Hui-iconfont-menu")]
public string Menu2 { get; set; }
有些時(shí)候我們需要基于當(dāng)前行數(shù)據(jù)進(jìn)行判斷,是否顯示某一個(gè)按鈕,則有
///
/// 普通條件菜單
///
[ColumnDataType("ifmenu", "item.age==7", "條件1", "")]
public string Menu3 { get; set; }
///
/// 菜單盒子菜單
///
[ColumnDataType("menu", "菜單二", "open_window('查閱用戶帶參','./index.html?path=userInfo&xxid={{:=item.id}}');", "Hui-iconfont-menu", "box")]
public string Menu5 { get; set; }
///
/// 菜單盒子中的條件菜單
///
[ColumnDataType("ifmenu", "item.age==8", "條件2", "box")]
public string Menu4 { get; set; }
前端只是基于這個(gè)屬性,在查下的時(shí)候會(huì)回傳orderby字段給后端,后續(xù)需要基于回傳的這個(gè)字段進(jìn)行orderby查詢
///
///排序
///
[ColumnDataType("orderby", "Sort","Sort desc")]
public int Sort { get; set; }
--- 未完待續(xù),下期繼續(xù) ---
機(jī)器學(xué)習(xí):神經(jīng)網(wǎng)絡(luò)構(gòu)建(下)
閱讀華為Mate品牌盛典:HarmonyOS NEXT加持下游戲性能得到充分釋放
閱讀實(shí)現(xiàn)對(duì)象集合與DataTable的相互轉(zhuǎn)換
閱讀鴻蒙NEXT元服務(wù):論如何免費(fèi)快速上架作品
閱讀算法與數(shù)據(jù)結(jié)構(gòu) 1 - 模擬
閱讀基于鴻蒙NEXT的血型遺傳計(jì)算器開(kāi)發(fā)案例
閱讀5. Spring Cloud OpenFeign 聲明式 WebService 客戶端的超詳細(xì)使用
閱讀Java代理模式:靜態(tài)代理和動(dòng)態(tài)代理的對(duì)比分析
閱讀Win11筆記本“自動(dòng)管理應(yīng)用的顏色”顯示規(guī)則
閱讀本站所有軟件,都由網(wǎng)友上傳,如有侵犯你的版權(quán),請(qǐng)發(fā)郵件[email protected]
湘ICP備2022002427號(hào)-10 湘公網(wǎng)安備:43070202000427號(hào)© 2013~2025 haote.com 好特網(wǎng)