DeepSeek评价PasteForm框架是最佳实践框架,一个让管理端开发爽到飞起的全栈解决方案

AI 时代程序员必备技能

Codex、Claude Code、Cursor、Hermes Agent、OpenClaw等工程化实战专栏 ,讲透 AI 如何接管脏活累活

我之前问了下DeepSeek,了解下PasteForm这个框架的优缺点,她给我以下几点
在这里插入图片描述
在这里插入图片描述
看到上面是不是心动了?
PasteForm到底是个啥东东?

PasteForm

PasteForm是贴代码在2024年推出的一个框架,可以说是框架ABP的一个补充!

通过反射原理,在对应的Dto的字段中标注特性,让管理端基于字段特性做响应的处理,比如显示为输入框,图片,富文本,下拉框,分组,数据转化等!

所以说,他应该是一个思想,一个通过Dto来控制管理端页面的思想!

Dto定义

其实Dto的概念我相信我们一直都在使用,只是是否有强调出来而已,我第一次接触规范的dto是在ABP框架中,举个栗子

用户表
User :对应数据库的表,字段和表的列一一对应
UserAddDto:对应新增User的数据Model,比如只需要账号和密码,其他的在入库前由User的默认值填充
UserUpdateDto:对应更新User的数据的Model,比如只能修改昵称,密码,头像,签名等,其他的保持不变(账号,ID)
UserDto:对应查看用户详细的时候的Model,这个Model一般只用于显示,展示数据用,不做提交修改用
UserListDto:对应表格显示的时候,比如不显示密码,比如可以显示创建时间,状态等 

从上面的信息可知,对应的Dto的操作应该都是经过表单的形式提交的,是不是高度重复???或者说高度复用!
而UserListDto则为表格显示!
假设你有一个系统,有100个数据表,你要写多少表单和表格???

任何开发语言都能使用

  • 通用思想,所以按照这个思想,你用其他语言也可以实现,比如java+vue,php+html,.net+html5等
  • 业务保留,业务接口和这个框架没有冲突,PasteForm处理的是管理端相关的接口,也就是管理端页面用到的接口
  • 底层不限,你可以在其他框架上实现PasteForm,只要按照规则返回特定格式的数据即可!

优点

敏捷天花板

比如你要开发一个新的模块,你只要确定数据库表的字段等,然后使用PasteBuilder生成对应的Dto,AppService文件即可,然后运行后,添加对应的模块的菜单(权限表中添加菜单配置,就是添加一行数据),即可在管理端对新增的模块进行表单管理和表格查看了!后续将推出图表查看模式!

代码量小

无论你的系统是100个表,还是10个表,管理端的页面总数都是差不多10个,样式高度统一(肯定统一的,因为他们用的就是一个页面),页面量这么小,是不是每个页面代码都很多?不存在的,目前单个页面的最高代码量不超过3000行,是那种没压缩的代码行!

易维护

可以说你几乎不需要开发和维护管理端,因为我们提供了整个管理端!具体的可以看下方的PastTemplate介绍

简单易上手

简单在于他对你现有的业务代码没有侵入式的改变,因为不相关!以User表为例,你需要添加以下接口

  • /api/app/user/readAddModel:返回的数据是UserAddDto对应的字段和特性信息
  • /api/app/user/readUpdateModel:返回的数据是UserUpdateDto对应的字段和特性信息
  • /api/app/user/readListModel:返回的数据是UserListDto和InputSearchUser对应的字段和特性信息
  • /api/app/user/readDetailModel:返回的数据是UserDto对应的字段和特性信息
        /// <summary>
        /// 读取AddDto的数据模型
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "add" })]
        public VoloModelInfo ReadAddModel()
        {
            var _model = PasteBuilderHelper.ReadModelProperty<UserAddDto>(new UserAddDto());
            return _model;
        }

        /// <summary>
        /// 读取UpdateDto的数据模型
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "edit" })]
        public async Task<VoloModelInfo> ReadUpdateModel(int id)
        {
            var _info = await _dbContext.User.Where(x => x.Id == id).AsNoTracking().FirstOrDefaultAsync();
            if (_info == null || _info == default)
            {
                throw new PasteCodeException("查询的信息不存在,无法执行编辑操作!");
            }
            var dto = ObjectMapper.Map<User, UserUpdateDto>(_info);
            var _dataModel = PasteBuilderHelper.ReadModelProperty<UserUpdateDto>(dto);
            return _dataModel;
        }


        /// <summary>
        /// 读取UpdateDto的数据模型
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [TypeFilter(typeof(RoleAttribute), Arguments = new object[] { "data", "edit" })]
        public async Task<VoloModelInfo> ReadDetailModel(int id)
        {
            var _info = await _dbContext.User.Where(x => x.Id == id).AsNoTracking().FirstOrDefaultAsync();
            if (_info == null || _info == default)
            {
                throw new PasteCodeException("查询的信息不存在,无法执行编辑操作!");
            }
            var dto = ObjectMapper.Map<User, UserDto>(_info);
            var _dataModel = PasteBuilderHelper.ReadModelProperty<UserDto>(dto);
            return _dataModel;
        }

        /// <summary>
        /// 读取ListDto的数据模型
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public VoloModelInfo ReadListModel()
        {
            var _model = PasteBuilderHelper.ReadModelProperty<UserListDto>(new UserListDto());
            var _query_model = PasteBuilderHelper.ReadModelProperty(new InputQueryUser());
            if (_query_model != null)
            {
                _model.QueryProperties = _query_model.Properties;
            }
            return _model;
        }

以上就是获得Model的信息的api接口,有没有发觉这些代码很简单!
如果你有100个表,那么就有100个这样的,所以这样的事情肯定是交给代码生成器去生成的!
那么问题来了,为啥不全部合并成一个???

平滑升级

如果有一个表要新增一个字段,你要如何操作?

一般流程
Entity
覆盖
升级部署add-migration
强刷
新增字段
Dto
重新生成CRUD的表单页面等
管理端
服务端
更新字段

以上流程主要的就是修改数据库的字段,然后修改对应的dto,然后重新发布api,更新或者修改管理端对应的页面,然后发布管理端页面,最后要强刷,否则会出现管理端版本和API版本不一致的问题!需要更新管理端页面

PasteForm流程

Entity
升级部署add-migration
刷新
新增字段
Dto
服务端
管理端

和上面的对比,会发觉少了管理端页面这一个步骤,也就是说PasteForm的新增字段等是不需要更新管理端页面的,也不需要强刷!不需要更新管理端页面

特性案例

下面举几个例子,特性和UI的表现,一把是常用的,也有高级的!

image

图片在表单中是很常见的一个组件,PasteForm为此设定了
1.当前字段允许上传几张,是否是单张还是比如N张
2.上传的文件存储在哪个文件夹(api接收到存储到对应位置)
3.上传后图片是否按照约定进行裁剪,比如120120或者19200
4.是否调用不一样的api地址进行上传
在这里插入图片描述
如果要实现上面的上传图片的,只要在Dto中做如下标记特性即可

        ///<summary>
        ///头像 模拟图片上传
        ///</summary>
        [ColumnDataType("image", "1", "head", "60*60")]
        public string Img1 { get; set; }

        /// <summary>
        /// 多图 上传的时候会转化成string[]提交给api
        /// </summary>
        [PasteImage(2,"img","1920*0")]
        public string[] Img2 { get; set; }

        /// <summary>
        /// 多图 上传的时候多图会以,隔开
        /// </summary>
        [PasteImage(2, "img", "1920*0")]
        public string Img3 { get; set; }

是不是很简单,只要一行代码即可实现图片上传!!!

lselect

我们常用的选择,一般是select,而这个lselect是一个变种,可以直观的显示,不过有一个要点要注意,项不能过多,否则会放不下!
在这里插入图片描述

        /// <summary>
        /// 权限类型 基于权限类型查询
        /// </summary>
        [PasteLselect(PasteFormString.SelectRoleTypeQuery, "", 1)]
        public int RoleType { get; set; } = -1;

以上这个也是支持Enum枚举类型的,比如这样

        /// <summary>
        /// 授权类型
        /// </summary>
        [PasteLselect]
        public EnumModel AuthType { get; set; } = EnumModel.ok;

是不是非常简单,不过EnumModel的注释也要遵循PasteForm的XML注释规范,就是标题和注释部分用空格隔开即可,连在一起会变成都是标题,可能会很长!

daterange

时间区间选择,这个很常用吧,在查询和时间相关的时候
在这里插入图片描述
要实现上面的输入也很简单

        /// <summary>
        /// 日期区间
        /// </summary>
        [ColumnDataType("daterange", "sdate", "edate")]
        [PasteMark]
        public DateTime? sdate { get; set; } = DateTime.Now.AddDays(-1);

        /// <summary>
        /// 日期区间
        /// </summary>
        [ColumnDataType("hidden")]
        public DateTime? edate { get; set; } = DateTime.Now.AddDays(1);

注意如果不设置为Nullable的类型,则会变成必填项目!
如果使用PasteDaterange则更简单

        /// <summary>
        /// 日期区间
        /// </summary>
        [PasteDaterange("start", "end")]
        public DateTime? start { get; set; } = DateTime.Now.AddDays(-1);

        /// <summary>
        /// 日期区间
        /// </summary>
        public DateTime? end { get; set; } = DateTime.Now.AddDays(1);

PasteForm目前支持的特性大概在60个左右,更多的你可以查看源码,或者是查阅文档

PasteForm文档
PasteForm专题

可能在以上信息中,你看到的特性不完整,因为我一直在用PasteForm开发新的需求,这样就会产出出新的规则(特性)

你可以查看
贴代码案例项目
下载后关注example\PasteTemplate\PasteTemplate.HttpApi.Host\wwwroot\page\pasteform\readme.md文件
一般有新的思路或者问题我都会以草稿的形式写在这里
一般一周会同步到文档或者专题中!

框架辅助

一个框架,一定要有其他的辅助工具,不让都是很累人的,代码生成器肯定是首要的,不如你要写一大堆重复的代码!
一起来看看我为PasteForm做了哪些贴心的辅助

PasteBuilder

代码生成器,VS2022的插件,有别于其他框架的代码生成器,操作流程是
写好Entity后,右键对应的这个文件,然后点击生成,会在以下地方生成对应的代码
1.EF中的xxxDbContext中添加对应的Dbset

        /// <summary>
        /// 角色信息
        /// </summary>
        public DbSet<GradeInfo> GradeInfo { get; set; }

2.EF中的XXXModelCreatingExtensions

            //**UserInfo**
            builder.Entity<UserInfo>(b =>
            {
                b.ToTable(options.TablePrefix + "UserInfo", options.Schema);
                b.ConfigureByConvention();
            });

3.XXX.Application.Contracts中添加对应的Dto,生成的规则是创建一个模板名称文件夹,然后以EntityDto为文件名,里面包含了所有对应的Dto,比如
UserDto.cs里面有UserAddDto,UserUpdateDto,UserDto,UserListDto
4.XXX.Application中创建对应的AppService文件,比如UserAppService.cs,这个文件的内容包含了RestApi的接口
5.XXX.Application中的XXXAutoMapperProfile中添加

            // *UserInfo*:
            CreateMap<UserInfo, UserInfoListDto>();
            CreateMap<UserInfo, UserInfoDto>();
            CreateMap<UserInfo, UserInfoUpdateDto>();
            CreateMap<UserInfoUpdateDto, UserInfo>();
            CreateMap<UserInfoAddDto, UserInfo>();

没啦!没了!
如果只是以上的5点,你肯定会觉得好像少了啥,比如个性化等,比如AppService的内容和你的习惯不符等,比如Dto中确实很多特性,你总不能把所有特性写Entity吧!这和我们说的规范存放不太符合!
PasteBuilder其实还有2个隐藏功能!

config.json

配置文件,主要是给Dto的特性而设计的,他应该存放于XXX.Domain项目中的/template/config.json文件内,大概如下内容

{
    "readme": "这个是后续支持的,目前处于思路阶段,表示代码生成器的一些配置,比如字段隐藏,字段的属性直接填充等",
    "version": "1.0.0",
    "ignore": { //忽略哪些字段
        "all": {
            "add": [ "CreateDate", "AdminUid", "CreateUid" ],
            "update": [ "UpdateDate", "CreateDate" ],
            "detail": [ "UpdateDate", "CreateDate" ],
            "list": [ "Body", "Content", "Context" ]
        },
        "other": {
            "UserInfo:add": [ "DelColumn" ] //表示表示这个表的这个add模式下,删除这个字段DelColumn 
        }
    },
    "fields": {
        "*:add:user_id": { //表示在adddto中,如果当前class有字段user_id,则添加如下字段(ExtendUser)
            "CnName": "创建者", //字段中文
            "PropertyDisplayStr": "", //字段说明,如果有空格用_*_替代
            "PropertyType": "UserShort", //数据类型
            "Name": "ExtendUser" //字段名
        }
    },
    "attribute": {
        "ignore": [ "Comment", "Display", "Decription", "Index", "DefaultValue", "Column", "NotMapped" ], //表示忽略哪些来自Domain的特性
        "all": {
            "UserId": "[ColumnDataType(\"outer\",\"userInfo\",\"extendUser\",\"id\",\"userName\")]" //表示这个字段UserId需要添加这个特性多个之间用::隔开 示例:[PasteLeft]::[PasteHidden]
        },
        "other": {
            "UserInfo:list:userName": "[PasteClass]", //表名称 示例:[PasteClass]::[PasteHidden]
            "*:add:mark": "[PasteClass]" //新版本支持
        }
    }
}

注意看上面的内容,也就是你可以在此配置,哪些字段不在dto中出现,比如创建时间,比如更新时间你总不能让用户在表单自己输入吧!
还有就是标记特性,上面有一个关键信息fields代码块,这个块的意思就是在dto中基于规则,动态引入新的字段信息!
这个一般用于外表
1.方式一,直接使用外表模式,也就是Include查询方式,这个直接用就行,本身支持!
2.方式二,没有走外表关系,只走了一个ID,比如GradeRole表,记录了2个字段GradeId和RoleID,问题来了,编辑的时候,你不能让用户填写数字和查看数字吧,这个时候我们希望管理员看到的是这个数字对应的名称,比如

    ///<summary>
    ///角色绑定权限
    ///</summary>
    public class GradeRoleUpdateDto : EntityDto<int>
    {
        ///<summary>
        ///角色ID 点击选择角色
        ///</summary>
        [ColumnDataType("outer", "gradeInfo", "extendGrade", "id", "name")]
        public int GradeId { get; set; }

        /// <summary>
        /// 
        /// </summary>
        [ColumnDataType("hidden")]
        public GradeShortModel ExtendGrade { get; set; }

        ///<summary>
        ///权限ID 点击选择权限
        ///</summary>
        [ColumnDataType("outer", "roleInfo", "extendRole", "id", "name")]
        public int RoleId { get; set; }

        /// <summary>
        /// 
        /// </summary>
        [ColumnDataType("hidden")]
        public RoleShortModel ExtendRole { get; set; }

    }

看上面的信息,在Entity中是只有GradeId和RoleId2个字段的,而在Dto中我们还要引入其他的字段ExtendGrade和ExtendRole,这就需要fileds这个配置块了,看了上面的信息,比如你要动态引入public RoleShortModel ExtendRole { get; set; },那他的特性hidden咋办?
attribute配置块同样生效的!

template

模板,主要是用于生成dto文件的规则,比如上面说的UserDto.cs和UserAppService.cs,模板文件放于config.json同文件夹,如果你下载PasteTemplate项目,会看到template文件夹下有以下文件
dto.html.txt,server.html.txt,如果你要修改某一个模板,需要把后缀删除,也就是dto.html,server.html等,如果你要生成表格页面和表单页面,你也可以修改index.html.txt和view.html.txt,不过PasteForm框架已经不需要这2个文件生成了!
模板文件的语法你可以点击同文件夹的readme.md文件查看,是liquid这个模板!

生成规则

如果你仔细观察的话,会发现生成的代码如果追加代码的,一般会有特别的信息,比如上面的UserInfo,这个就是用于防止重复生成的,如果即将生成的文件已经存在了,则不会生成新的,这样可以防止你好不容易修改好了的文件被覆盖了!!!

PasteTemplate

这个是我提供的案例项目,可以说我后续的升级都在这个项目上测试的,所以你下载后可能会优点乱,不过应该都可以运行的,下载后先要执行add-migration进行数据库结构升级才可以运行,默认是以本地数据库sqlite的方式运行!
下载项目后可以看到如下结构
在这里插入图片描述

  • PasteFormHelper:这个是PasteForm的核心代码,用于反射Model获得Model的字段信息的
  • PasteTemplate.Handler:我提倡的业务层,被Application或者其他引用
  • 其他的就是标准的ABP的框架层了,基础版本的,我觉得应该算是最精简的了!
项目模板

你可以参考我以前的文章,把这个项目打包成项目模板,后续创建项目就可以按照这个基数来创建项目了,直接就搭建好了用户模块等,直接在这个基础上加业务表等即可!而且使用案例项目创建的项目,项目名称等是自定义的,不会每个项目都是PasteTemplate为namespace!

PasteSpider

这个,这个,这个其实和PasteForm关系不大,真要说,PasteSpider也是PasteForm框架项目!
优点打硬性广告吧!
开发好项目后,你可以使用PasteSpider进行部署,关键点在于你在开发过程中的迭代,使用PasteSpider可以一键发布,支持平滑升级,关键点在于3分钟就可上手!!!
无论你的服务器是windows还是linux都支持,你可以把你的项目部署为容器运行,或者Linux的systemd,也可以是Windows的IIS和Service!

其他问答

访问后表单没有标题等

注意看案例项目的XXX.ApiHost项目下的xml文件,也就是项目的文档文件,读取XML注释是从这个文件读取的!
存放注意,比如Enum枚举类,需要放在XXX.Domain或者XXX.Application.Contracts项目下

文件夹命名问题

新增Entity的时候,注意命名规范,是XXX.yyy
XXX表示你的项目名称,yyy表示模块,这样后续的Dto等也是这个规范,他们就在同一个namespace下了!

AI 时代程序员必备技能

Codex、Claude Code、Cursor、Hermes Agent、OpenClaw等工程化实战专栏 ,讲透 AI 如何接管脏活累活

内容概要:本文围绕“基于改进滑模控制的永磁同步电机调速系统模型研究”展开,重点介绍在Simulink环境中构建和仿真永磁同步电机(PMSM)调速系统的方法,采用改进滑模控制策略以提升系统鲁棒性与动态性能。文中系统阐述了控制算法的设计原理、系统建模流程、关键模块搭建及仿真结果分析,旨在复现高水平科研成果(SCI/EI级别),并通过仿真实验验证所提控制策略的有效性。该研究属于电机控制与电力电子领域的前沿方向,对高精度伺服系统、新能源汽车电驱动系统等实际应用场景具有重要的理论指导和工程参考价值; 适合人群:具备自动控制理论基础和Simulink/MATLAB仿真能力,从事电气工程、自动化、电力电子等相关专业的研究生、科研人员及工程技术人员,尤其适合致力于复现高水平学术论文成果的研究者; 使用场景及目标:①深入学习永磁同步电机矢量控制与滑模变结构控制的核心原理与建模方法;②复现并理解SCI/EI期刊中先进电机控制算法的技术细节;③开展电机控制系统仿真研究,优化控制参数,提升系统抗干扰能力、稳态精度与动态响应性能; 阅读建议:建议结合文中提及的完整资源包(含Simulink模型、MATLAB代码、详细说明文档)进行实践操作,重点关注控制策略的实现逻辑与仿真调试过程,注重理论推导与仿真实验相结合,同时参考同类高水平研究以拓展技术视野。
内容概要:本文提出了一种基于数据驱动的Koopman算子与递归神经网络(RNN)相结合的模型线性化方法,旨在解决纳米定位系统中因强非线性、迟滞和蠕变效应导致的建模困难问题。该方法通过Koopman算子将非线性动态系统映射至高维线性空间,利用RNN学习系统的时间序列演化特征,从而实现对复杂动态行为的精确建模与预测,并进一步集成于模型预测控制(MPC)框架中,显著提升了纳米定位系统的控制精度、动态响应能力与运行稳定性。整个算法体系在Matlab平台上完成代码实现与仿真实验验证,展示了良好的控制性能与工程应用潜力。; 适合人群:具备控制理论、非线性系统建模、机器学习及智能控制基础,从事精密仪器控制、高端制造装备研发、自动化系统设计等领域的研究生、科研人员及工程技术开发者。; 使用场景及目标:①应对扫描探针显微镜、光刻机、超精密加工平台等纳米级定位设备中的非线性建模挑战;②提升高精度运动系统的实时预测控制性能,抑制迟滞与蠕变带来的定位误差;③为数据驱动的非线性系统线性化与先进控制策略(如MPC)的融合提供可复现、可扩展的技术范例。; 阅读建议:建议读者结合提供的Matlab代码,深入理解Koopman观测矩阵构造、RNN网络训练流程及MPC控制器设计之间的协同机制,重点关注数据预处理、特征提取、模型训练与闭环控制仿真的完整链路,以便在相似高精度控制系统中进行迁移与优化应用。
内容概要:本文系统研究了基于动态三维环境下的Q-Learning算法在无人机自主避障路径规划中的应用,旨在通过强化学习实现无人机在复杂、动态空间中的智能决策与安飞行。研究构建了完整的Q-Learning模型框架,涵盖状态空间定义、动作策略设计与奖励函数构建,重点提升了算法在存在移动障碍物场景下的路径规划能力与实时避障性能。通过Matlab仿真平台实现了算法的流程建模与验证,展示了其在路径最优性、环境适应性与运行稳定性方面的优势,并为后续多机协同、城市密集环境等高级应用场景提供了可扩展的技术基础与代码支持。; 适合人群:具备一定编程基础和控制理论知识,从事无人机导航、智能优化算法或强化学习相关研究的科研人员及研究生。; 使用场景及目标:① 掌握Q-Learning算法在三维动态路径规划中的建模与实现方法;② 学习如何将强化学习技术应用于实际工程问题如无人机自主避障;③ 为深入研究多智能体协同、复杂非结构化环境下的路径规划提供算法原型与仿真基础; 阅读建议:建议读者结合提供的Matlab代码进行仿真实验,深入理解状态表示与奖励机制的设计逻辑,尝试调整算法参数或引入新的动态障碍物模式以评估鲁棒性,并可进一步对比其他智能算法(如DQN、A*、DWA等)在相同环境下的性能差异。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贴代码科技-致力于开发更加适用的应用

要不请我喝杯咖啡!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值