PasteForm最佳CRUD实践,实际案例PasteTemplate详解之3000问(三)

简介: PasteForm最佳CRUD实践,实际案例PasteTemplate详解之3000问(三)

作为“贴代码”力推的一个CRUD实践项目PasteTemplate,在对现有的3个项目进行实战后效果非常舒服!下面就针对PasteForm为啥我愿称为最佳CRUD做一些回答:
image
哪里可以下载这个PasteForm的项目案例

目前“贴代码”对外使用PasteForm的项目有"贴Builder(PasteSpider)"和案例项目(PasteTemplate),其中案例项目你可以在
https://gitee.com/pastecode/paste-template 获得
PasteForm的CRUD模式有什么特色?

搞这个的起初是因为我有一个项目要在小程序上行实现大量的表单,思考了下,一大堆相似的代码,不是可以使用那个组件的方式实现么,那就需要传入模型,换位思考下,那么我们经常使用的CRUD是否也可以这么搞?
于是就有了这个利用多数据模型Dto和反射的原理实现的PasteForm,主要优点如下

1.PasteForm输出的是一个思想,就是管理端的页面由后端控制,无论是安全性还是数据的表现

2.前端编写一次后,后续都不用编写,如果你使用的是我的案例项目,那么你前端都可以不用编写,包括后端要新增表,修改字段等,前端都不再需要修改代码

3.前端页面的超简洁性,无论你的后端是30个表还是100个表,对于前端来说都差不多大概4个页面搞定!当然了一些特殊的需求,还是需要编写下的!

4.无语言限制,上面说得输出的是一个思想,本文的案例使用的是.netcore+html的形式实现的,你也可以使用比如java+vue的模式

5.统一性,比如你30个表的图片上传,在表单中他们的样式都是一样的,因为他们其实使用的是同一个管理端页面

6.后端统筹所有,比如字段的显示顺序,字段是否显示,字段的默认值等等等,都由后端对应的Dto来限制和控制,比如同样的新增,由于当前登陆用户的角色不同,你可以限制某一个字段张三必填,而李四可以是选填!

image
看到管理端的代码,感觉像JSP的?

整个PasteForm的原理就是后端把数据模型的属性,字段等返回给前端,前端基于后端返回的数据再渲染到UI上,为了便于编写所以采用了template的模式,其实不是JSP,是长得像而已!
我的项目拥有120个数据表,那是不是要编写很多的后端文件?

PasteForm原则上只有3个页面pasteform/index.html,pasteform/view.html,pasteform/detail.html,只是有一些特殊情况下,会添加一些页面,这个要看你项目的实际需求,其实无论多少个表,PasteForm的页面都只是那么几个,比如说权限的页面为pasteform/index.html?path=roleInfo而用户的表为pasteform/index.html?path=userInfo,你会发觉其实他们是同一个页面,只是参数path不一样而已,这个path就是WebApi的Service!
其实你完全可以一个页面都不写,直接使用我提供的案例项目PasteTemplate中的pasteform的文件!
image
我看案例PasteTemplate项目是使用html,js,css编写的,可以使用vue编写管理端么?

上面提到的,PasteForm主要输出的是一个思想,也就是由后端的Dto控制前端的页面呈现和交互等,所以从WebApi中请求得到模板得属性字段等信息后,你可以使用其他语言实现管理端得页面得,不限原生,vue,angular等
pasteform/index.html是干嘛用?

作为对应数据表得数据展示用,一般为表格table呈现,对应模型为XXXListDto,也包括了搜索区域,搜索区域由对应得InputQueryXXX的数据模型决定,一般只有page,size,word三个字段!当然了这个页面也包含了新增数据,编辑,详情,删除等的操作交互!
pasteform/view.html是做什么用得?
[box.hfrsyky.com)
[box.szzdcl.com)
[box.webinsz.com)
[box.xgxsdly.com)
[box.ljzrsy.com)
[box.hy-leather.com)
新增数据,或者编辑数据的时候使用的都是这个页面,不过他们读取的数据模型不一样,比如权限这个表roleInfo,则有新增的时候为pasteform/view.html?path=roleInfo,对应的数据模型为roleInfoAddDto,而在编辑的时候为pasteform/view.html?path=roleInfo&id=3,对应的数据模型为roleInfoUpdateDto。页面的整体逻辑就是从WebApi中获得对应模型后,基于规则渲染到UI中,包括默认值,当前值等,提交的时候再从页面中的form读取到值提交给后端,所以说主要的控制还是在后端中!
pasteform/detail.html是做什么用得?

有些时候我们的数据没办法在pasteform/index.html页面中显示完成,比如文章列表,主要是一些字段过长的,这个时候我们希望有一个页面显示详细内容,所以detail就是干这个用的,对应的数据模型为XXXDto!
我不会.netcore可以用其他语言写pasteform么

PasteForm输出的是一个思想,所以使用其他语言也是可以的,不过你得对着写一整套的就是了,比如你可以使用vue+java的模式搞一套!后端核心代码案例

    /// <summary>
    /// 读取AddDto的数据模型
    /// </summary>
    /// <returns></returns>
    [HttpGet]
    [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "root", "root" })]
    public PasteBuilderHelper.VoloModelInfo ReadAddModel()
    {
        var _model = PasteBuilderHelper.ReadModelProperty<RoleInfoAddDto>(new RoleInfoAddDto());
        return _model;
    }

    /// <summary>
    /// 读取UpdateDto的数据模型
    /// </summary>
    /// <returns></returns>
    [HttpGet]
    [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "root", "root" })]
    public async Task<PasteBuilderHelper.VoloModelInfo> 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("查询的信息不存在,无法执行编辑操作!");
        }
        var _dataModel = PasteBuilderHelper.ReadModelProperty<RoleInfoUpdateDto>(_info);
        return _dataModel;
    }

    /// <summary>
    /// 读取UpdateDto的数据模型
    /// </summary>
    /// <returns></returns>
    [HttpGet]
    [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "root", "root" })]
    public async Task<PasteBuilderHelper.VoloModelInfo> 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("查询的信息不存在,无法执行编辑操作!");
        }
        var _dataModel = PasteBuilderHelper.ReadModelProperty<RoleInfoDto>(_info);
        return _dataModel;
    }

    /// <summary>
    /// 读取ListDto的数据模型
    /// </summary>
    /// <returns></returns>
    [HttpGet]
    [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "root", "root" })]
    public PasteBuilderHelper.VoloModelInfo ReadListModel()
    {
        var _model = PasteBuilderHelper.ReadModelProperty<RoleInfoListDto>(new RoleInfoListDto());
        var _query_model = PasteBuilderHelper.ReadModelProperty(new InputQueryRoleInfo());
        if (_query_model != null)
        {
            _model.QueryProperties = _query_model.Properties;
        }
        return _model;
    }

PasteForm使用到的各个模型是干嘛用的,Dto

我最早接触Dto的时候是ABPvNext,说到这个Dto不得不说ObjectMapper,比如说权限表RoleInfo,则对应的有RoleInfoAddDto,RoleInfoUpdateDto,RoleInfoDto和RoleInfoListDto,当前实际开发中你可能还会引申出更多的Dto,比如我常用的RoleMenuDto,RoleAuthDto等,PasteForm中主要用到前面的4个,一般还会附带一个InputQueryRoleInfo!比如说新增的时候,用户提交的数据模型是RoleInfoAddDto,提交给API后,API处数据校验合法后再使用AutoMapper把RoleInfoAddDto转化成RoleInfo,然后写入到数据库!
XXXAddDto:用于新增的时候的数据模型,对应的是pasteform/view.html页面使用
XXXUpdateDto:用于数据编辑修改的数据模型,对应的是pasteform/view.html页面使用
XXXDto:这里我一般用于显示详情的时候的数据模型,也就是pasteform/detail.html的页面使用
XXXListDto:这里一般使用于数据表格展示的时候的数据模型,也就是pasteform/index.html的页面使用
InputQueryXXX:这里一般用于表格上方的搜索项的数据模型,也就是pasteform/index.html的搜索区域使用
如何上传图片?

图片分新增编辑和展示,展示的话这里就是pasteform/index.html和pasteform/detail.html页面中了,其实在编辑的时候pasteform/view.html页面上也有展示,只要给对应字段添加属性[ColumnDataTypeAttribute("image","1","image","60*60")]即可

    /// <summary>
    /// 多图 回传的值是多个的,使用,隔开
    /// </summary>
    [ColumnDataType("image", "3", "img", "60*60")]
    public string Img2 { get; set; }

    /// <summary>
    /// 图片 回传的使用string[]的模式
    /// </summary>
    [ColumnDataType("image", "3", "img", "60*60")]
    public string[] Img3 { get; set; }

表格中如何让数据左靠

    ///<summary>
    ///文本区域 模拟文本区域的输入
    ///</summary>
    [ColumnDataType("class","fleft")]
    public string Desc { get; set; }

表格中如何自定义显示

    ///<summary>
    ///单选 一般表示状态,内定的,有点像Enum,关于Enum后续会支持
    ///</summary>
    [ColumnDataType("html", "<div>{
  {:=item.dateType}}-{
  {:=item.gradeId}}</div>")]
    public int DateType { get; set; }

表格中如何显示按钮

    /// <summary>
    /// 普通菜单
    /// </summary>
    [ColumnDataType("menu", "菜单一", "open_window('查阅用户带参','./index.html?path=userInfo&xxid={
  {:=item.id}}');", "Hui-iconfont-menu")]
    public string Menu2 { get; set; }

表格中如何显示条件按钮

有些时候我们需要基于当前行数据进行判断,是否显示某一个按钮,则有

    /// <summary>
    /// 普通条件菜单
    /// </summary>
    [ColumnDataType("ifmenu", "item.age==7", "<a href=\"javascript:;\" onclick=\"open_window(`111`,`./index.html?path=userInfo&goid={
  {:=item.id}}`)\">条件1</a>", "")]
    public string Menu3 { get; set; }

按钮太多,如何使用按钮盒子

    /// <summary>
    /// 菜单盒子菜单
    /// </summary>
    [ColumnDataType("menu", "菜单二", "open_window('查阅用户带参','./index.html?path=userInfo&xxid={
  {:=item.id}}');", "Hui-iconfont-menu", "box")]
    public string Menu5 { get; set; }

    /// <summary>
    /// 菜单盒子中的条件菜单
    /// </summary>
    [ColumnDataType("ifmenu", "item.age==8", "<a href=\"javascript:;\" onclick=\"open_window(`222`,`./index.html?path=userInfo&goid={
  {:=item.id}}`)\">条件2</a>", "box")]
    public string Menu4 { get; set; }

按照排序查下,某些字段支持升序降序

前端只是基于这个属性,在查下的时候会回传orderby字段给后端,后续需要基于回传的这个字段进行orderby查询

    ///<summary>
    ///排序
    ///</summary>
    [ColumnDataType("orderby", "Sort","Sort desc")]
    public int Sort { get; set; }

--- 未完待续,下期继续 ---

相关文章
|
24天前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
16天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
20天前
|
机器学习/深度学习 算法 大数据
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
2024“华为杯”数学建模竞赛,对ABCDEF每个题进行详细的分析,涵盖风电场功率优化、WLAN网络吞吐量、磁性元件损耗建模、地理环境问题、高速公路应急车道启用和X射线脉冲星建模等多领域问题,解析了问题类型、专业和技能的需要。
2577 22
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
|
18天前
|
人工智能 IDE 程序员
期盼已久!通义灵码 AI 程序员开启邀测,全流程开发仅用几分钟
在云栖大会上,阿里云云原生应用平台负责人丁宇宣布,「通义灵码」完成全面升级,并正式发布 AI 程序员。
|
3天前
|
JSON 自然语言处理 数据管理
阿里云百炼产品月刊【2024年9月】
阿里云百炼产品月刊【2024年9月】,涵盖本月产品和功能发布、活动,应用实践等内容,帮助您快速了解阿里云百炼产品的最新动态。
阿里云百炼产品月刊【2024年9月】
|
2天前
|
存储 人工智能 搜索推荐
数据治理,是时候打破刻板印象了
瓴羊智能数据建设与治理产品Datapin全面升级,可演进扩展的数据架构体系为企业数据治理预留发展空间,推出敏捷版用以解决企业数据量不大但需构建数据的场景问题,基于大模型打造的DataAgent更是为企业用好数据资产提供了便利。
164 2
|
20天前
|
机器学习/深度学习 算法 数据可视化
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
2024年中国研究生数学建模竞赛C题聚焦磁性元件磁芯损耗建模。题目背景介绍了电能变换技术的发展与应用,强调磁性元件在功率变换器中的重要性。磁芯损耗受多种因素影响,现有模型难以精确预测。题目要求通过数据分析建立高精度磁芯损耗模型。具体任务包括励磁波形分类、修正斯坦麦茨方程、分析影响因素、构建预测模型及优化设计条件。涉及数据预处理、特征提取、机器学习及优化算法等技术。适合电气、材料、计算机等多个专业学生参与。
1576 16
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
|
22天前
|
编解码 JSON 自然语言处理
通义千问重磅开源Qwen2.5,性能超越Llama
击败Meta,阿里Qwen2.5再登全球开源大模型王座
979 14
|
4天前
|
Linux 虚拟化 开发者
一键将CentOs的yum源更换为国内阿里yum源
一键将CentOs的yum源更换为国内阿里yum源
221 2
|
17天前
|
人工智能 开发框架 Java
重磅发布!AI 驱动的 Java 开发框架:Spring AI Alibaba
随着生成式 AI 的快速发展,基于 AI 开发框架构建 AI 应用的诉求迅速增长,涌现出了包括 LangChain、LlamaIndex 等开发框架,但大部分框架只提供了 Python 语言的实现。但这些开发框架对于国内习惯了 Spring 开发范式的 Java 开发者而言,并非十分友好和丝滑。因此,我们基于 Spring AI 发布并快速演进 Spring AI Alibaba,通过提供一种方便的 API 抽象,帮助 Java 开发者简化 AI 应用的开发。同时,提供了完整的开源配套,包括可观测、网关、消息队列、配置中心等。
735 9