低代码编辑平台后台实现

背景

之前做过一个前端低代码编辑平台,可以实现简单的移动端页面组件拖拽编辑:
https://github.com/li-car-fei/react-visual-design

最近基于C++的oatpp框架实现了一下后台。使用oatpp框架做web后台开发时,发现按照官方的示例使用的话,很难在多表多控制视图模式下进行开发,因此修改了一些它的使用方法,以面向对象的方式对各个部分管理,高效开发。

github链接:https://github.com/li-car-fei/oatpp-low-code
求求 star~~

其中,对于低代码平台中核心功能,实现思路如下所述。

主要思路

  • 运用 oatpp++ 搭建后端服务程序

  • Restful API 接口 (Swagger 提供接口示例文档)

  • 将低代码的逻辑通过四个表实现

    • user 表:用户信息,一个用户对应多个project
    • project 表:某个低代码编辑图的基础信息;一个project对应多个component
    • component 表:组件表,储存组件类别、属性、序号等;一个component对应0个或多个childComponnet;
    • childComponent 表:子组件表,存储子组件属性、序号等;
  • 对 oatpp++ CRUD 的改写:

    • 数据 DTO 有共用字段的采用类的继承方式定义
   /**
* 组件记录的 DTO
*/
class ComponentRecordDto : public oatpp::DTO {DTO_INIT(ComponentRecordDto, DTO)DTO_FIELD(Int32, record_id);DTO_FIELD(Int32, project_id, "project_id");DTO_FIELD(Enum<ComponentType>::AsString, component_type);DTO_FIELD(Int32, components_index);DTO_FIELD(String, currentDate);DTO_FIELD(String, header, "header");DTO_FIELD(String, title, "title");DTO_FIELD(String, content, "content");DTO_FIELD(String, mode, "mode");DTO_FIELD(String, src, "src");DTO_FIELD(String, link, "link");DTO_FIELD(String, label1, "label1");DTO_FIELD(String, label2, "label2");DTO_FIELD(String, backgroundColor, "backgroundColor");
};/**
* 组件记录 包括了子组件数组 数据 的 DTO
*/
class ComponentTransferDto : public ComponentRecordDto {DTO_INIT(ComponentTransferDto, ComponentRecordDto)DTO_FIELD(Vector<oatpp::Object<ChildComponentTranserDto>>, childs, "childs");
};
  • Db 部分,每个表的SQL操作分别定义为一个类,随后挂载到一个总的 Db 类中,使用共享的数据库连接池和语句执行器excuator
/*** 总的 DB 类,管理所有的 数据相关操作类
*/
class Db {
public:Db(const std::shared_ptr<oatpp::orm::Executor>& executor): userDb(std::make_shared<UserDb>(executor)),projectDb(std::make_shared<ProjectDb>(executor)),componentDb(std::make_shared<ComponentDb>(executor)),childComponentDb(std::make_shared<ChildComponentDb>(executor)){std::cout << "Db start creating" << std::endl;oatpp::orm::SchemaMigration migration(executor);migration.addFile(1 /* start from version 1 */, DATABASE_MIGRATIONS "/001_init.sql");// TODO - Add more migrations here.migration.migrate(); // <-- run migrations. This guy will throw on error.auto version = executor->getSchemaVersion();OATPP_LOGD("Db", "Migration - OK. Version=%lld.", version);};std::shared_ptr<UserDb> userDb;std::shared_ptr<ProjectDb> projectDb;std::shared_ptr<ComponentDb> componentDb;std::shared_ptr<ChildComponentDb> childComponentDb;
};
  • service 方面;

    • 定义一个基础服务类,存储 Db 与所有服务共用的成员

    • 每个表的服务定义一个service,虚继承基础服务类(保证后续派生类只有一个Db连接);提供每个表自己独立的服务

    • 所有的 service,都继承自基础服务类;即共用一个数据库连接池,共用一套集成好的 SQL 语句接口;

    • 两个表相关的服务,且有层次关系的,如组件和子组件,则采用继承方式实现;使得组件服务可以调用子组件服务;

    • 多个表相关的服务,如整个 project 相关的服务,另外新建一个 service 类,继承所需的服务对应的类实现;

    • 只需直接继承 BaseService 的类是虚继承即可,就可保证所有类中只有一份 Db;

/*** BaseService* 声明 Status 后续子类都用于HTTP状态的码的设定* 保存 std::shared_ptr<Db> m_database,用于数据库相关操作* 直接继承BaseService的类需要是 virtual 继承,则可保证所有相关Service类中都只有一份Db
*/
class BaseService {/* protected ,子类可以访问到,外界不可以访问 */protected:typedef oatpp::web::protocol::http::Status Status;std::shared_ptr<Db> m_database;public:BaseService(std::shared_ptr<Db> database) : m_database(database) {};
};/* 子组件相关服务 */
class ChildComponentService : virtual public BaseService {public:ChildComponentService(std::shared_ptr<Db> database) : BaseService(database) {};/* others... */
};/* 组件相关服务 */
class ComponentService : public ChildComponentService {public:/*** 虚继承中,需要由最上层派生类调用基类的构造函数* (普通继承则不用,调用直接继承的基类的构造即可)*/ComponentService(std::shared_ptr<Db> database) : BaseService(database), ChildComponentService(database) {};/* others... */
};
  • controller 方面,与 service 提供的服务对应起来,定义HTTP接口的信息;

    • 每个 controller 都接收指向 Db 的共享指针,以传给对应的 service 成员;

    • controller 继承自 oatpp++ 提供的对象,需要从环境中找到序列化/反序列化器objectMapper用于其初始化

    • 定义一个将所有controller进行统一管理的 MyController,将所有实例(只需一个)挂载到里面,并对外提供统一的controller相关操作接口,如router配置;

/*** 通过一个 MyController 将所有的 数据库相关的 Controller 包含起来,* 统一完成 原本在App.cpp 中的 路由的配置
*/class MyController {public:/* 构造函数 : 一个database对象构建所有 Controller */MyController(std::shared_ptr<Db> database) : userController(UserController::createShared(database)),projectController(ProjectController::createShared(database)),componentController(ComponentController::createShared(database)),childComponentController(ChildComponentController::createShared(database)),uploadController(UploadController::createShared()){};/* 静态函数,MyController 只需要一个实例即可 */static std::shared_ptr<MyController> createShared(std::shared_ptr<Db> database){return std::make_shared<MyController>(database);}/* 通过 MyController 完成 所有 子Controller 的路由配置 */void setRouter(oatpp::web::server::api::Endpoints& docEndpoints,std::shared_ptr<oatpp::web::server::HttpRouter> router){docEndpoints.append(router->addController(userController)->getEndpoints());docEndpoints.append(router->addController(projectController)->getEndpoints());docEndpoints.append(router->addController(componentController)->getEndpoints());docEndpoints.append(router->addController(childComponentController)->getEndpoints());docEndpoints.append(router->addController(uploadController)->getEndpoints());};/* 所有的 Controller */std::shared_ptr<UserController> userController;std::shared_ptr<ProjectController> projectController;std::shared_ptr<ComponentController> componentController;std::shared_ptr<ChildComponentController> childComponentController;std::shared_ptr<UploadController> uploadController;
};
  • 另外运用oatpp++的文件上传接口提供图片上传,用于AI模型识别;识别后调用projectComplete的服务存储完整低代码视图信息;
ENDPOINT_INFO(upload) {info->summary = "upload image to parse";}
ENDPOINT("POST", "/upload", upload, REQUEST(std::shared_ptr<IncomingRequest>, request)) {oatpp::data::stream::FileOutputStream fileOutputStream(UPLOADFILEPATH);request->transferBodyToStream(&fileOutputStream); // transfer body chunk by chunkreturn createResponse(Status::CODE_200, "OK");
}

Interceptor Auth 鉴权

JWT 模式,对 header 中的 json web token (userId_ )进行加解密确认;

AuthController 中配置哪些接口不需要鉴权,其余的接口都要增加 JWT 的 Header 参数设置;

请求接口接收后需要 Interceptor 模式进行加解密确认;

接口示例

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI Navigation导航系统_unity基础开发教程

AI Navigation导航系统 安装插件烘焙导航系统障碍物创建人物的AI导航动态障碍物 在unity编辑器中&#xff0c;有一个灰常好用的插件&#xff1a;Navigation。有了它1&#xff0c;你就可以实现人物自动走到你鼠标点击的位置&#xff0c;而且还会自动避开障碍物&#xff0c;下面就…

CronExpression

CronTrigger配置格式: 格式: [秒] [分] [小时] [日] [月] [周] [年]序号 说明 是否必填 允许填写的值 允许的通配符 1 秒 是 0-59 , - * / 2 分 是 0-59 , - * / 3 小时 是 0-23 , - * / 4 日 是 1-31 , - * ? / L W 5 月 是 1-12 or JA…

服务容错之限流之 Tomcat 限流 Tomcat 线程池的拒绝策略

在文章开头&#xff0c;先和大家抛出两个问题&#xff1a; 每次提到服务限流为什么都不考虑基于 Tomcat 来做呢&#xff1f;大家有遇到过 Tomcat 线程池触发了拒绝策略吗&#xff1f; JUC 线程池 在谈 Tomcat 的线程池前&#xff0c;先看一下 JUC 中线程池的执行流程&#x…

安全框架springSecurity+Jwt+Vue-1(vue环境搭建、动态路由、动态标签页)

一、安装vue环境&#xff0c;并新建Vue项目 ①&#xff1a;安装node.js 官网(https://nodejs.org/zh-cn/) 2.安装完成之后检查下版本信息&#xff1a; ②&#xff1a;创建vue项目 1.接下来&#xff0c;我们安装vue的环境 # 安装淘宝npm npm install -g cnpm --registryhttps:/…

如何零基础自学AI人工智能

随着人工智能&#xff08;AI&#xff09;的快速发展&#xff0c;越来越多的有志之士被其强大的潜力所吸引&#xff0c;希望投身其中。然而&#xff0c;对于许多零基础的人来说&#xff0c;如何入门AI成了一个难题。本文将为你提供一份详尽的自学AI人工智能的攻略&#xff0c;帮…

SpringCloud微服务:Ribbon负载均衡

目录 负载均衡策略&#xff1a; 负载均衡的两种方式&#xff1a; 饥饿加载 1. Ribbon负载均衡规则 规则接口是IRule 默认实现是ZoneAvoidanceRule&#xff0c;根据zone选择服务列表&#xff0c;然后轮询 2&#xff0e;负载均衡自定义方式 代码方式:配置灵活&#xff0c;但修…

OpenCV C++ 图像 批处理 (批量调整尺寸、批量重命名)

文章目录 图像 批处理(调整尺寸、重命名)图像 批处理(调整尺寸、重命名) 拿着棋盘格,对着相机变换不同的方角度,采集十张以上(以10~20张为宜);或者棋盘格放到桌上,拿着相机从不同角度一通拍摄。 以棋盘格,第一个内焦点为坐标原点,便于计算世界坐标系下三维坐标; …

Pycharm之配置python虚拟环境

最近给身边的人写了脚本&#xff0c;在自己电脑可以正常运行。分享给我身边的人&#xff0c;却运行不起来&#xff0c;然后把报错的截图给我看了&#xff0c;所以难道不会利用pycharm搭建虚拟的环境&#xff1f;记录一下配置的过程。 第一步&#xff1a;右键要打开的python的代…

利用jquery对HTML中的名字进行替代

想法&#xff1a;将网页中经常要修改的名字放在一个以jquery编写的js文件中&#xff0c;如果需要修改名字&#xff0c;直接修改js文件中的名字即可。 新建name_07.html文件&#xff0c;写入下面的代码&#xff1a; <!DOCTYPE html> <html> <head><meta …

mp4视频批量截取!!!

mp4视频批量截取&#xff01;&#xff01;&#xff01; 问题&#xff1a;如果我们想截取一个mp4视频中的多个片段&#xff0c;一个一个截会很麻烦&#xff01; 可以将想要截取的开始时间和结束时间保存到 excel表 中&#xff0c;进行批量截取。 1、对一个视频&#xff0c;记…

给openlab搭建web网站

1.作业的要求 2.访问www.openlab.com网站 2.1先准备好相关的包和关闭防火墙等操作 mount /dev/sr0 /mnt/ //先挂载 yum install httpd -y //下载htppd systemctl stop firewalld //关闭防火墙 setenforce 02.2然后开始配置文件和仓库 这一步比较关键,之前改了接口…

【原创】java+swing+mysql鲜花购物商城设计与实现

前言&#xff1a; 本文主要介绍了鲜花购物商城的设计与实现。首先&#xff0c;通过市场需求&#xff0c;我们确定了鲜花商场的功能&#xff0c;通常的商城一般都是B/S架构&#xff0c;然而我们今天要用javaswing去开发一个C/S架构的鲜花商城&#xff0c;利用开发技术和工具&am…

C#WPF用户控件及自定义控件实例

本文演示C#WPF自定义控件实例 用户控件(UserControl)和自定义控件(CustomControl)都是对UI控件的一种封装方式,目的都是实现封装后控件的重用。 只不过各自封装的实现方式和使用的场景上存在差异。 1 基于UserControl 创建 创建控件最简单一个方法就是基于UserControl …

【观察】OpenHarmony:技术先进“创新局”,持续创新“谋新篇”

毫无疑问&#xff0c;开源作为今天整个软件产业的创新“原动力”&#xff0c;目前在软件产业发展中的重要性愈加凸显。根据Linux基金会的统计&#xff0c;现在全球软件产业中有70%以上的代码来源于开源软件。 从这个角度来看&#xff0c;开源技术已逐渐成为推动企业数字化转型和…

MATLAB中zticks函数用法

目录 语法 说明 示例 指定 z 轴刻度值和标签 指定非均匀 z 轴刻度值 以 2 为增量递增 z 轴刻度值 将 z 轴刻度值设置回默认值 指定特定坐标区的 z 轴刻度值 删除 z 轴刻度线 zticks函数的功能是设置或查询 z 轴刻度值。 语法 zticks(ticks) zt zticks zticks(auto)…

土地利用强度(LUI)综合指数

土地利用强度的概念可以解释为某一时间特定区域内人类活动对土地利用强度的干扰程度[1]&#xff0c;其不仅反映不同土地利用类型本身的自然属性&#xff0c;也体现了人类利用土地的深度和广度&#xff0c;进而揭示在人类社会系统干扰下土地资源自然综合体自然平衡的保持状态[2]…

jbase打印导出实现

上一篇实现了虚拟M层&#xff0c;这篇基于虚拟M实现打印导出。 首先对接打印层 using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using System.Xml;namesp…

为什么Transformer模型中使用Layer Normalization(Layer Norm)而不是Batch Normalization(BN)

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

通过 Canal 将 MySQL 数据实时同步到 Easysearch

Canal 是阿里巴巴集团提供的一个开源产品&#xff0c;能够通过解析数据库的增量日志&#xff0c;提供增量数据的订阅和消费功能。使用 Canal 模拟成 MySQL 的 Slave&#xff0c;实时接收 MySQL 的增量数据 binlog&#xff0c;然后通过 RESTful API 将数据写入到 Easysearch 中。…

Diagrams——制作短小精悍的流程图

今天为大家分享的是一款轻量级的流程图绘制软件——Diagrams。 以特定的图形符号加上说明&#xff0c;表示算法的图&#xff0c;称为流程图或框图。流程图是流经一个系统的信息流、观点流或部件流的图形代表。我们常用流程图来说明某一过程。 流程图使用一些标准符号代表某些类…