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是做什么用得?

新增数据,或者编辑数据的时候使用的都是这个页面,不过他们读取的数据模型不一样,比如权限这个表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; }

— 未完待续,下期继续 —

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/887749.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Android 13源码分析】Activity生命周期之onCreate,onStart,onResume-2

忽然有一天&#xff0c;我想要做一件事&#xff1a;去代码中去验证那些曾经被“灌输”的理论。                                                                                  – 服装…

微服务Sleuth解析部署使用全流程

目录 1、Sleuth链路追踪 1、添加依赖 2、修改日志配置文件 3、测试 2、zipkin可视化界面 1、docker安装 2、添加依赖 3、修改配置文件 4、查看页面 5、ribbon配置 1、Sleuth链路追踪 sleuth是链路追踪框架&#xff0c;用于在微服务架构下开发&#xff0c;各个微服务之…

[水墨:创作周年纪念] 特别篇!

本篇是特别篇&#xff01;&#xff01; 个人主页水墨不写bug // _ooOoo_ // // o8888888o // // 88" . "88 …

GO网络编程(二):客户端与服务端通信【重要】

本节是新知识&#xff0c;偏应用&#xff0c;需要反复练习才能掌握。 目录 1.C/S通信示意图2.服务端通信3.客户端通信4.通信测试5.进阶练习&#xff1a;客户端之间通信 1.C/S通信示意图 客户端与服务端通信的模式也称作C/S模式&#xff0c;流程图如下 其中P是协程调度器。可…

《CUDA编程》5.获得GPU加速的关键

从本章起&#xff0c;将关注CDUA程序的性能&#xff0c;即执行速度 1 用CUDA事件计时 在前几章中&#xff0c;使用的是C的<time.h>库进行程序运行计时&#xff0c;CUDA也提供了一种基于CUDA event的计时方式&#xff0c;用来给一段CUDA代码进行计时&#xff0c;这里只介…

系统架构设计师-下午案例题(2021年下半年)

1.试题一(共25分) 阅读以下关于软件架构设计与评估的叙述在答题纸上回答问题1和问题2。 【说明】某公司拟开发一套机器学习应用开发平台支持用户使用浏览器在线进行基于机器学习的智能应用开发活动。该平台的核心应用场景是用户通过拖拽算法组件灵活定义机器学习流程&#xf…

【含开题报告+文档+PPT+源码】基于SSM + Vue的养老院管理系统【包运行成功】

开题报告 随着社会的发展和经济的进步&#xff0c;人口老龄化问题逐渐凸显。统计数据显示&#xff0c;全球范围内的老龄人口比例正在逐年上升&#xff0c;养老需求也随之增长。养老院作为提供专业养老服务的机构&#xff0c;承担着照料老人、提供医疗保健和社交活动等责任。传…

什么是pip? -- Python 包管理工具

前言 不同的编程语言通常都有自己的包管理工具&#xff0c;这些工具旨在简化项目的依赖管理、构建过程和开发效率&#xff0c;同时促进代码的复用和共享。每个包管理工具都有其独特的特点和优势&#xff0c;开发者可以根据自己的编程语言和项目需求选择合适的包管理工具。 pip是…

车辆重识别(2021ICML改进的去噪扩散概率模型)论文阅读2024/9/29

所谓改进的去噪扩散概率模型主要改进在哪些方面&#xff1a; ①对数似然值的改进 通过对噪声的那个方差和T进行调参&#xff0c;来实现改进。 ②学习 这个参数也就是后验概率的方差。通过数据分析&#xff0c;发现在T非常大的情况下对样本质量几乎没有影响&#xff0c;也就是说…

TIM的PWM模式

定时器的工作流程: 定时器对时钟传来的脉冲次数计数&#xff0c;并且在次数到达范围值时触发中断。如向下计数模式时为0&#xff0c;向上计数为达到自动重装载计时器的值时触发中断。 四个输出比较单元 更改占空比的函数 STM32里面的定时器有多个定时器。 如TIM1、TIM2…

k8s 之安装metrics-server

作者&#xff1a;程序那点事儿 日期&#xff1a;2024/01/29 18:25 metrics-server可帮助我们查看pod的cpu和内存占用情况 kubectl top po nginx-deploy-56696fbb5-mzsgg # 报错&#xff0c;需要Metrics API 下载 Metrics 解决 wget https://github.com/kubernetes-sigs/metri…

nginx 负载均衡1

遇到的问题 大型网站都要面对庞大的用户量&#xff0c;高并发&#xff0c;海量数据等挑战。为了提升系统整体的性能&#xff0c;可以采用垂直扩展和水平扩展两种方式。 垂直扩展&#xff1a;在网站发展早期&#xff0c;可以从单机的角度通过增加硬件处理能力&#xff0c;比如 C…

LeetCode讲解篇之239. 滑动窗口最大值

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 我们维护一个长度为k的窗口&#xff0c;然后窗口从数组最左边一直移动到最右边&#xff0c;记录过程中窗口中的最大值&#xff0c;就是答案 我们每次查询长度为k的窗口最大值是什么时间复杂度是O(k)的&#xff0…

黑神话:仙童,数据库自动反射魔法棒

黑神话&#xff1a;仙童&#xff0c;数据库自动反射魔法棒 Golang 通用代码生成器仙童发布了最新版本电音仙女尝鲜版十一及其介绍视频&#xff0c;视频请见&#xff1a;https://www.bilibili.com/video/BV1ET4wecEBk/ 此视频介绍了使用最新版的仙童代码生成器&#xff0c;将 …

使用 Python 遍历文件夹

要解决这个问题&#xff0c;使用 Python 的标准库可以很好地完成。我们要做的是遍历目录树&#xff0c;找到所有的 text 文件&#xff0c;读取内容&#xff0c;处理空行和空格&#xff0c;并将处理后的内容合并到一个新的文件中。 整体思路&#xff1a; 遍历子目录&#xff1…

计算机毕业设计 基于Hadoop的智慧校园数据共享平台的设计与实现 Python 数据分析 可视化大屏 附源码 文档

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…

国外电商系统开发-运维系统拓扑布局

点击列表中设备字段&#xff0c;然后定位到【拓扑布局】中&#xff0c;可以看到拓扑发生了变化 再回头&#xff0c;您再次添加一个服务器到系统中&#xff0c;并且选择该服务器的连接节点为您刚才创建的“SDN路由器”&#xff0c;保存后&#xff0c;您可以看到这个服务器连接着…

RabbbitMQ篇(环境搭建 - 下载 安装)(持续更新迭代)

目录 一、Windows 1. 下载安装程序 2. 安装配置erlang 3. 安装rabbitMQ 4. 验证 二、Linux 1. 下载rpm包 1.1. 下载Erlang的rpm包 1.2. 下载socat的rpm包 1.3. 下载RabbitMQ的rpm包 2. 安装 2.1. 安装Erlang 2.2. 安装socat 2.3. 安装RabbitMQ 3. 启动RabbitMQ服…

小程序原生-利用setData()对不同类型的数据进行增删改

1. 声明和绑定数据 wxml文件 <view> {{school}} </view> <view>{{obj.name}}</view> <view id"{{id}}" > 绑定属性值 </view> <checkbox checked"{{isChecked}}"/> <!--算数运算--> <view>{{ id …