CRUD的最佳实践,联动前后端,包含微信小程序,API,HTML等(二)

news2024/12/25 0:07:11

CRUD老生常谈,但是我搜索了一圈,发觉几乎是着重在后端,也就是API部分!
无外乎2个思路
1.归总的接口,比如一个接口,实现不同表的CRUD
2.基于各自的表,使用代码生成器实现CRUD
个人来说是推荐2,虽然代码多了,其实结构更加清晰,而且!而且!后端对安全尤为重要!!!
啥?你说前端就不安全了???
前端!那不叫安全,那叫用户体验,体验懂否?
后端!那才是安全关口!重要的门户!!!!
如果使用1的方式,你会发觉到后续代码越来越臃肿,各种判断,到最后就像上了重庆的立交桥转个不停!
上次我们说到小程序的页面表单的动态化,先看下本次的要点
在这里插入图片描述
既然是系统,那肯定也少不了后台管理端的了,这里我使用的是原生的HTML,如果你喜欢那个VUE,其实可以按照这个思想自己实现!

##!!!VUE是前端点歪了技能树的产物!!!##

WebApi新增

距离上次的一发布后,后端接口我做了如下的调整!在WebApi中

        /// <summary>
        /// 读取AddDto的数据模型
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public PasteBuilderHelper.VoloModelInfo ReadAddModel()
        {
            var _model = PasteBuilderHelper.ReadModelProperty<WebsiteNoticeAddDto>(new WebsiteNoticeAddDto());
            return _model;
        }

        /// <summary>
        /// 读取UpdateDto的数据模型
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public async Task<PasteBuilderHelper.VoloModelInfo> ReadUpdateModel(int id)
        {
            var _info = await _dbContext.WebsiteNotice.Where(x => x.Id == id).AsNoTracking().FirstOrDefaultAsync();
            if (_info != null && _info != default)
            {
                var dto = ObjectMapper.Map<WebsiteNotice, WebsiteNoticeUpdateDto>(_info);
                var _dataModel = PasteBuilderHelper.ReadModelProperty<WebsiteNoticeUpdateDto>(dto);
                return _dataModel;
            }
            var _model = PasteBuilderHelper.ReadModelProperty<WebsiteNoticeUpdateDto>(new WebsiteNoticeUpdateDto());
            return _model;
        }

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

注意看上面的,加了ListDto和InputQueryWebsiteNotice
InputQueryWebsiteNotice是什么鬼?

        /// <summary>
        /// 按页查询对象
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpGet]
        public async Task<PagedResultDto<WebsiteNoticeListDto>> Page([FromQuery] InputQueryWebsiteNotice input)
        {
            var _query = _dbContext.WebsiteNotice.Where(t => 1 == 1);
            var _pagedto = new PagedResultDto<WebsiteNoticeListDto>();
            if (input.page == 1)
            {
                _pagedto.TotalCount = await _query.CountAsync();
            }
            var dataList = await _query
                .OrderByDescending(x => x.Id)
                .Page(input.page, input.size)
                .AsNoTracking()
                .ToListAsync();
            if (dataList == null || dataList.Count == 0)
            {
                throw new PasteSoftException("没有查询到数据", 204);
            }
            var temList = ObjectMapper.Map<List<WebsiteNotice>, List<WebsiteNoticeListDto>>(dataList);
            _pagedto.Items = temList;
            return _pagedto;
        }

看上面,知道了吧?说白点就是列表的时候的查询项!
啥玩意???咋查询搞里面去了???

查询支持

看最新的页面
在这里插入图片描述
上面是某一个表的对应的列表的页面,上面的信息中,处理下方的页码,上方的新增,查询和刷新按钮,其他的都是后端控制的!!!
对,是其他的所有的(表格的线不算哈!),比如这个表对应有几个查询项,就是上面举例子的
InputQueryWebsiteNotice控制的!
以下是页面打开后第一次获取的数据模型数据
在这里插入图片描述
通过读取对应的Dto的内容,控制前端的UI
看下我的查询的模型

    /// <summary>
    /// 站点公告查询 站点公告的查询项
    /// </summary>
    public class InputQueryWebsiteNotice: InputSearchBase
    {
        /// <summary>
        /// 标题 点击键入基于标题查询
        /// </summary>
        [MaxLength(16)]
        public string title { get; set; } = "";

        /// <summary>
        /// 状态 默认值为-1表示不查询
        /// </summary>
        public int state { get; set; } = -1;

        /// <summary>
        /// 开关 基于开关类型查询
        /// </summary>
        public bool status { get; set; } = false;

        /// <summary>
        /// 开始日期
        /// </summary>
        public DateTime? sdate { get; set; } = null;

        /// <summary>
        /// 结束日期
        /// </summary>
        public DateTime edate { get; set; }
    }

如何给定其他属性,比如必填,默认值等?
其实只要和Dto一样,把对应的Attribute标注上去即可,数据模型的规则传递给前端后,前端根据规则生成UI即可!
这里有几个规定
对于DateTime类型,如果可为null的,也就是标注了 ?的则数据类型为DateTime ,其中required为false
如果不为Null类型的,则数据类型为DateTime,其中required为true

总结优势

那是不是意味着,一个项目的管理端可以做到只有4个页面!!!
1.登陆到页面
2.菜单页面
3.对应表的列表显示页面,显示表格数据等,兼顾外表的选择!
4.表单页面,兼顾新增,编辑
4个页面即可实现项目的后台管理端,涉及的功能包括不限于,图片上传等,数据列表展示,表单的新增和编辑,日期选择等!
关键点,页面的代码不多,比如我的表格数据页面的代码行才300行不到!
表单页面的代码才500行不到
我的测试页面有些规则还没有提取出来,比如数据项的格式校验等!

需要注意点

数据类型

由于涉及不同端,在数据类型上肯定有不一样的地方,比如后端的存储类型为string,在前端的表示就很多了,
比如昵称,签名内容,文章描述,文章内容,头像的地址,甚至日期等都可以使用string表示,这就需要一个协商,也就是转化,把后端类型转化,翻译成前端类型的函数,这个需要使用方自己实现,和后端协商一致即可!
比如我的规则,如果String类型,长度没有限制,则在前端翻译成richtext,如果长度小于128限定,则为text,如果长度>128则为textarea

指定类型

有些类型,后端没有,或者是没法表示,因为我们的原则是尽量后端控制前端,比如images,比如region,这就需要我们后端在模型上动手脚了!
比如我的一个案例

    /// <summary>
    /// 用于标记字段有查询的属性
    /// </summary>
    public class DataTypeAttribute : Attribute
    {
        /// <summary>
        /// 
        /// </summary>
        private string Name { get; set; }

        /// <summary>
        /// 
        /// </summary>
        public DataTypeAttribute(string _name = "")
        {
            Name = _name;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            return Name.ToString();
        }
    }

上面这个属性是自定义的,可以自己命名,后面前端基于这个进行处理即可,比如:

        /// <summary>
        /// 头像
        /// </summary>
        [DataType("image")]
        public string Head { get; set; }

这样前端在遇到这个字段的时候,读取到他的属性DataType为image,那么前端对这个字段进行渲染的时候,就使用image的类型来处理!
同样的道理,你可以实现更多的,比如单选,选项内容,等可以通过自定义的属性来实现!

写在最后

通过以上的思路,我们可以实现
1.安全,所有的属性信息是dto模块的,我们开放给前端的,前端才能够查询到
2.对模型的字段的规则,前后端都支持,前端是为了体验,后端是为了安全!
3.我们不需要为了新增一个字段而去修改前端了!

目前的代码还在完善中,后续我们会把这个功能添加到PasteTemplate(.netCore的WebApi项目模板)和PasteBuilder右键代码生成器中!

下期,作者将提供实际项目的案例展示,和其中做的一些处理等!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

css设置input单选radio多选checkbox样式

最近接手一个古老的项目&#xff0c;要修改里边的主题颜色&#xff0c;使用css的var方法一路轻松&#xff0c;最后在input的单选radio和多选checkbox被踩了刹车&#xff0c;也是有几年没做这种原始的项目手生了&#xff0c;最后经过几番折腾后&#xff0c;通过input的伪元素将其…

FPGA开发——使用verilog实现异步FIFO

一、FIFO 介绍 1、FIFO的分类 FIFO &#xff08; First In First Out&#xff09;先进先出存储器。根据接入的时钟信号&#xff0c;可以分为同步 FIFO 和异步 FIFO 。 FIFO 底层是基于双口 RAM &#xff0c;同步 FIFO 的读写时钟一致&#xff0c;异步 FIFO 读时钟和…

一看就会的Mysql 集群技术

目录 一、Mysql介绍 1.1什么是MySQL 1.2MySQL的优势 1.3MySQL的常用语句 二、MySQL源码安装 三、实验练习 3.1MySQL部署 实验环境 实验步骤 1.创建用户&#xff0c;数据目录&#xff0c;更改权限 2.修改文件 3.初始化&#xff0c;会生成一个密码&#xff0c;将其保…

没有人会窃取你的想法,关键在于执行

没有人会窃取你的想法&#xff0c;关键在于执行 引言 当我第一次读到 Pieter Levels 的创业故事时&#xff0c;我感到无比激动和鼓舞。那种看到未来无限可能的感觉&#xff0c;让我充满了希望与奋斗的力量。他的经历不仅让我明白了创意的价值&#xff0c;更重要的是让我深刻感…

内网穿透的几种方法

内网穿透的几种方法 随着网络技术和应用的不断发展&#xff0c;越来越多的企业和个人需要实现内外网之间的数据交互和服务访问。然而&#xff0c;由于防火墙、NAT&#xff08;网络地址转换&#xff09;等安全措施的存在&#xff0c;直接从外部访问内部网络中的服务器或设备变得…

Linux基础软件-dns(一)

作者介绍&#xff1a;简历上没有一个精通的运维工程师。希望大家多多关注作者&#xff0c;下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 Linux进阶部分又分了很多小的部分,我们刚讲完了Linux日常运维。讲的那些东西都算是系统自带的&#xff0c;但是Linux作为一个…

Nvidia驱动莫名其妙不好使了?nvidia-smi报错?如何解决?已解决!!

文章目录 一、报错提示二、解决方案2.1 原因1的解决办法2.2 原因2的解决方案 一、报错提示 Ubuntu20.04出现Failed to initialize NVML: Driver/library version mismatch问题NVIDIA-SMI has failed because it couldn‘t communicate with the NVIDIA driver. 二、解决方案 …

深入探究linux文件IO

一、原子操作和竞争条件 所有系统调用都是以原子操作方式执行的。之所以这么说&#xff0c;是指内核保证了某系统调用中的所有步骤会作为独立操作而一次性加以执行&#xff0c;其间不会为其他进程或线程所中断。 以独占方式创建一个文件 结合 O_CREAT 和 O_EXCL 标志来一次性…

AI学习记录 - 怎么理解 torch 的 torch.nn.BatchNorm2d

画图不易&#xff0c;有用就点个赞 这里创建了一个随机张量&#xff0c;形状为 (4, 3, 4, 4)&#xff0c;分别对应 形状为 (batch_size, num_channels, height, width) batch_size&#xff1a;批次 num_channels&#xff1a; 通道&#xff08;什么是通道看上一章节&#xff0…

串口和RS485通信

一、 定义串口收发数据结构体 /*COM Received Data Structure*/ typedef struct {uint8_t ubr_EndFlag; //Received data end flag uint8_t ubr_buffer[300]; //Received data bufferuint8_t ubr_bufferTemp[300]; //Received data bu…

K-medoids算法原理及Python实践

一、原理 K-medoids算法是一种聚类算法&#xff0c;它的原理与K-Means算法相似&#xff0c;但关键区别在于它使用数据集中的实际点&#xff08;称为medoids&#xff09;作为簇的中心点&#xff0c;而不是像K-Means那样使用簇内所有点的平均值。以下是K-medoids算法的主要原理&…

如何在算家云搭建模型Stable-Fast-3D(3D模型生成)

一、模型介绍 Stable-Fast-3D 具有 UV 展开和照明解缠的稳定快速 3D 网格重建&#xff0c;它是一种从单个图像进行快速前馈 3D 网格重建的最先进的开源模型。 二、模型搭建流程 基础环境最低要求说明&#xff1a; 环境名称版本信息1Ubuntu22.04.4 LTSCudaV12.1.105Python3.…

【项目日记】高并发内存池 ---项目介绍及组件定长池的实现

余生还长&#xff0c;你别慌&#xff0c;也别回头&#xff0c;别念旧. --- 余华 --- 1 高并发内存池简介 高并发内存池项目是实现一个高并发的内存池&#xff0c;他的原型是google的一个开源项目tcmalloc&#xff0c;tcmalloc全称Thread-Caching Malloc&#xff0c;即线程缓存…

快速排序与其例题

一、快速排序 1、简单介绍&#xff1a;快速排序&#xff08;Quick Sort&#xff09;是一种高效的排序算法&#xff0c;由计算机科学家Tony Hoare在1960年提出。它是基于分治法的排序算法&#xff0c;其基本思想和步骤如下&#xff1a; 基本概念 快速排序的核心思想是将待排序…

一种商业模式既解决引流又解决复购 你想了解一下嘛?

欢迎各位&#xff0c;我是你们的电商策略顾问&#xff0c;吴军。今天&#xff0c;我将向大家介绍一种新颖的商业模式——循环购物模式。这种模式有何独特之处&#xff1f;商家真的在进行慷慨的赠金活动吗&#xff1f;消费者在购物的同时还能获得额外收益&#xff1f;甚至可以将…

Python控制流:条件语句(if, elif, else)①

文章目录 前言1. 基本条件语句1.1 if 语句1.2 else 语句1.3 elif 语句1.4 嵌套条件语句 2. 条件表达式3. 多条件判断4. 比较运算符和逻辑运算符5. 常见错误和最佳实践5.1 常见错误5.2 最佳实践 6. 综合详细的例子&#xff1a;学生成绩管理系统6.1 类和方法Student 类 6.2 主函数…

LD/T698.45 协议解析(新)

通信架构 客户机和服务器在开始通信前&#xff0c;通信信道必须先完成预连接。预连接建立后&#xff0c;默认具有一个最低权限的应用连接&#xff0c;客户机和服务器之间可直接进行数据交换。当客户机需要得到更高权限的服务器服务时&#xff0c;客户机必须发起建立更高权限的…

浦发银行不良堆积,新任领导的无奈

撰稿|芋圆 浦发银行在2023年进行了一波董监高人员大变动&#xff0c;董事长和行长两位掌舵人双双离职&#xff0c;在其任内&#xff0c;浦发银行自2020年起的营收、利润状况和资产质量就一直难有起色。 目前&#xff0c;距新任领导班子上任已差不多过去一年之久。在这一年里&a…

Redis(面试题【速记】)

Redis简介 Redis 是一个开源(BSD 许可)内存数据结构存储用作数据库、缓存、消息代理和流引擎。Redis 提供数据结构&#xff0c;例如 字符串、散列、列表、集合、带范围查询的排序集合、位图、超日志、地理空间索引和流。Redis 内置了复制、Lua 脚本、LRU 驱逐、事务和不同级别的…

【Linux —— 线程同步 - 条件变量】

Linux —— 线程同步 - 条件变量 条件变量的概念互斥量与条件变量的关系条件变量的操作代码示例 条件变量的概念 条件变量是一种用于线程间同步的机制&#xff0c;主要用于协调线程之间的执行顺序&#xff0c;允许线程在某个条件不满足时进入等待状态&#xff0c;直到其他线程通…