低代码编辑平台后台实现

news2024/10/7 14:26:28

背景

之前做过一个前端低代码编辑平台,可以实现简单的移动端页面组件拖拽编辑:
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 chunk
    return createResponse(Status::CODE_200, "OK");
}

Interceptor Auth 鉴权

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

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

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

接口示例

在这里插入图片描述

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

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

相关文章

SSH远程登录协议

目录 什么是ssh服务器 概念 优点 原理 SSH登录 方法一 无需验证 方法二 格式&#xff1a; ssh -l 用户名 IP 地址 -p port -l &#xff1a;指定登录名称 -p&#xff1a;选项&#xff0c;指定登录端口&#xff08;当服务端的端口非默认时&#xff0c;需要使用-p…

拿到信创天翼云电脑账号后,我又傻眼了...

在《面向国产系统的 App 发布&#xff0c;含泪总结》中&#xff0c;我就吐槽过信创产品的不靠谱。用户购买一台终端&#xff0c;都没法用&#xff0c;得经历复杂的账号申请。 紧催慢催&#xff0c;等待了半个月之后&#xff0c;今天终于拿到了账号。然而&#xff0c;满怀期待登…

OpenAI与微软合作,构建 ChatGPT 5 模型;10天准确天气预报

&#x1f989; AI新闻 &#x1f680; OpenAI与微软合作&#xff0c;构建 ChatGPT 5 模型&#xff0c;下一代人工智能或拥有超级智能 摘要&#xff1a;OpenAI首席执行官 Sam Altman 在接受采访时表示&#xff0c;OpenAI正在与微软合作构建下一代人工智能模型 ChatGPT 5&#x…

Django——模板层、模型层

模板层 一. 模版语法 {{ }}: 变量相关 {% %}: 逻辑相关 1. 注释是代码的母亲 {# ... #} 2. 基本数据类型传值 int1 123 float1 11.11 str1 我也想奔现 bool1 True list1 [小红, 姗姗, 花花, 茹茹] tuple1 (111, 222, 333, 444) dict1 {username: jason, age: 18, i…

rpmbuild 包名 version 操作系统信息部分来源 /etc/rpm/macros.dist

/etc/rpm/macros.dist openeuler bclinux src.rpm openssl-1.1.1f-13.oe1.src.rpm 打包名称结果 openeuler openssl-1.1.1f-13.aarch64.rpm bclinux openssl-1.1.1f-13.oe1.bclinux.aarch64.rpm 验证 修改openeuler配置文件macros.dist 重新在openeuler上执行rpmbuild…

第三章 栈和队列【24王道数据结构笔记】

1.栈 1.1 栈的基本概念 只允许在一端(栈顶top)进行插入或删除操作的受限的线性表。后进先出&#xff08;Last In First Out&#xff09;LIFO。或者说先进后出FILO。 进栈顺序&#xff1a;a1 > a2 > a3 > a4 > a5出栈顺序&#xff1a;a5 > a4 > a3 > a2 …

数据结构—LinkedList与链表

目录 一、链表 1. 链表的概念及结构 1. 单向或者双向 2. 带头或者不带头 3. 循环或者非循环 二.LinkedList的使用 1.LinkedList概念及结构 2. LinkedList的构造 3. LinkedList的方法 三. ArrayList和LinkedList的区别 一、链表 1. 链表的概念及结构 链表是一种 物理…

Postman实现接口的文件上传

近期在复习Postman的基础知识&#xff0c;在小破站上跟着百里老师系统复习了一遍&#xff0c;也做了一些笔记&#xff0c;希望可以给大家一点点启发。 接口的文件上传&#xff0c;与其他接口的传参差不多&#xff0c;只要点击form-data&#xff0c;选择要上传的文件即可。 实际…

Java第十九章

一.绘制图形 Java 可以分别使用 Graphics类和Graphics2D 类绘制图形&#xff0c;Graphics 类使用不同的方法实现不同图形的绘制。例如&#xff0c;drawLine()方法可以绘制直线&#xff0c;drawRect()方法用于绘制矩形&#xff0c;drawOval()方法用于绘制椭圆形等。 例1. 例2. …

物联网项目:充电桩项目实战~

你好&#xff0c;我是田哥 最近除了忙于面试辅导、模拟面试以外&#xff0c;还在搞一件大事&#xff1a;充电桩项目。 分布式微服务项目实战&#xff1a;充电桩项目 充电桩项目肯定是和物联网相关的&#xff0c;聊到物联网又不得不聊的是MQTT协议。 什么是MQTT MQTT&#xff0c…

数据结构前言(空间复杂度)

1.空间复杂度 空间复杂度也是一个数学表达式&#xff0c;是对一个算法在运行过程中临时占用存储空间大小的量度 。 空间复杂度不是程序占用了多少bytes的空间&#xff0c;因为这个也没太大意义&#xff0c;所以空间复杂度算的是变量的个数。 空间复杂度计算规则基本跟实践复杂…

解决Github上的README无法显示图片

首先感谢博主的思路&#xff1a;思路 最近写了点东西提交到git 发现本地能查看md里的图片用的相对路径&#xff0c;提交到github就看不见&#xff0c;并且发现不只是我自己的仓库看不见&#xff0c;其他人的我也看不见。那就有问题了 解决&#xff1a;正常使用相对路径&…

C#中.NET Framework4.8 Windows窗体应用通过EF访问新建数据库

目录 一、 操作步骤 二、编写EF模型和数据库上下文 三、 移植&#xff08;Migrations&#xff09;数据库 四、编写应用程序 五、生成效果 前文已经说过.NET Framework4.8 控制台应用通过EF访问已经建立的和新建的数据库。 本文想说的是&#xff0c;.NET Framework4.8 Win…

黑豹程序员-SpringCloudAlibaba聚合工程打包和运行

文章目录 1、SpringCloudAlibaba项目结构2、打包配置3、打包4、运行 1、SpringCloudAlibaba项目结构 2、打包配置 3、打包 4、运行 java -jar rms-parent.jar

解决:java: 错误: 不支持发行版本 5 最有效方法

报错信息如图&#xff1a; 直接上终极方法&#xff1a; 修改配置文件 如图找到settings.xml文件 在标签中间插入如下代码&#xff08;jdk更改为自己电脑上的版本&#xff09; <profile><id>development</id><activation><jdk>11</jdk><…

SQL练习---619.出现一次的最大数字

题目 分析 首先确定表的来源只有一个表数字表&#xff0c;再者判断他是不是单一数字&#xff0c;&#xff08;想到的是直接按数字分组&#xff0c;通过count函数来判断是否为单一数子&#xff09;&#xff0c;然后求最大值。 题解 select Max(num) as num from MyNumbers wh…

EMNLP 2023 | DeepMind提出大模型In-Context Learning的可解释理论框架

论文题目&#xff1a;In-Context Learning Creates Task Vectors 论文链接&#xff1a;https://arxiv.org/abs/2310.15916 01. 引言 此外&#xff0c;作者也提到本文的方法与软提示&#xff08;soft-prompt&#xff09;[1]方法类似&#xff0c;soft-prompt也是通过调整大模型内…

C语言查看main函数的参数

这里写自定义目录标题 argc 代表参数的个数argv 代表参数的具体值&#xff0c;其中argv[0]代表的是可执行文件的名字&#xff0c;参考上图

[工业自动化-22]:西门子S7-15xxx编程 - 软件编程 - 如何PLC建立用户界面: SIMATIC 面板式HMI 或工控机PC HMI

目录 前言&#xff1a; 一、PLC&#xff08;可编程逻辑控制器&#xff09;的用户界面支持方式 1.1 概述 1.2 西门子&#xff08;Siemens&#xff09;的人机界面&#xff08;HMI&#xff09;支持多种类型 1.3 PC HMI VS SIMATIC HMI 二、PC—HMI—PLC连接架构的实现 三、…

百度曹海涛:生成式AI正从“探索能力边界”向“推动应用落地”过渡

11月9日&#xff0c;以“星云棋布&#xff0c;步步为‘赢’”为主题的2023 IDC中国生态峰会在北京举办。会上&#xff0c;IDC中国区总裁霍锦洁女士的发表致辞。同时&#xff0c;IDC生态伙伴和行业领袖从多重维度分析了AI技术应用的发展&#xff0c;以及对于整体IT生态所产生的影…