低代码编辑平台后台实现

背景

之前做过一个前端低代码编辑平台,可以实现简单的移动端页面组件拖拽编辑:
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.mzph.cn/news/145348.shtml

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

相关文章

Babyk勒索病毒数据集恢复,计算机服务器中了babyk勒索病毒怎么办?

计算机网络技术的不断应用&#xff0c;为企业的生产运营提供了极大便利&#xff0c;网络技术的不断发展也带来了许多网络安全隐患&#xff0c;近期&#xff0c;云天数据恢复中心陆续接到许多企业的求助&#xff0c;企业的计算机服务器遭到了babyk勒索病毒的攻击&#xff0c;导致…

text/xml和application/xml

困惑 在http消息中&#xff0c;同样是传送xml信息&#xff0c;有的时候看到Content-Type的值是text/xml&#xff0c;有的时候值是application/xml&#xff0c;感到困惑。 例如&#xff0c;用Postman发送http消息给Tomcat中的基于JAX-WS的 web服务&#xff1a; 请求中传送了xm…

vue3基础学习(上)

##以前怎么玩的? ###MVC Model:Bean View:视图 Controller ##vue的ref reactive ref:必须是简单类型 reactive:必须不能是简单类型 ###创建一个Vue项目 npm init vuelatest ###生命周期 ###setup相关 ####Vue2的一些写法 -- options API ####Vue3的写法 组合式API Vu…

洗地机选购攻略,洗地机哪个品牌好?一篇教会你挑到好用的洗地机

随着国内生活水平的提高&#xff0c;智能清洁产品的呼声也越来越高&#xff0c;尤其是洗地机&#xff0c;可以说是国内各个品牌的洗地机铺天盖地而来&#xff0c;那么如何挑选洗地机成了很多新手的困惑&#xff0c;别着急&#xff0c;笔者今天就给大家讲讲洗地机! 一、购买洗地…

【Axure教程】滑动内容选择器

滑动内容选择器通常是一种用户界面组件&#xff0c;允许用户通过滑动手势在一组内容之间进行选择。这种组件可以在移动应用程序或网页中使用&#xff0c;以提供直观的图片选择体验。 那今天就教大家如何用中继器制作一个滑动内容选择器&#xff0c;我们会以滑动选择电影为案例…

HTML5学习系列之标题和正文、描述性信息

HTML5学习系列之标题和正文、描述性信息 标题和正文标题段落 描述性信息强调注解备选上下标术语代码预定义格式缩写词编辑提示引用引述换行显示修饰非文本注解 总结 标题和正文 标题 按语义轻重排列&#xff1a;h1\h2\h3\h4\h5\h6 <h1>诗词介绍</h1> <h2>…

外汇天眼:什么是非农?非农数据对外汇市场的重要性!

非农数据在外汇市场中扮演着何等关键的角色&#xff1f; 美国非农数据&#xff0c;简称“非农”&#xff0c;具体指排除农业部门、个体户和非盈利机构雇员后的就业相关数据&#xff0c;是反映美国经济实际就业和整体经济状况的关键指标。该数据由美国劳工部劳动统计局每月发布…

ExoPlayer架构详解与源码分析(8)——Loader

系列文章目录 ExoPlayer架构详解与源码分析&#xff08;1&#xff09;——前言 ExoPlayer架构详解与源码分析&#xff08;2&#xff09;——Player ExoPlayer架构详解与源码分析&#xff08;3&#xff09;——Timeline ExoPlayer架构详解与源码分析&#xff08;4&#xff09;—…

map和set的简易封装(纯代码)

RBTree.h #pragma once#include<iostream> #include<vector> using namespace std;enum colar { red,black };template<class T>//有效参数就一个 struct RBTreeNode {RBTreeNode(const T& data):_left(nullptr), _right(nullptr), _parent(nullptr)…

黑马点评回顾 redis实现共享session

文章目录 传统session缺点整体访问流程代码实现生成验证码登录 问题具体思路 传统session缺点 传统单体项目一般是把session存入tomcat&#xff0c;但是每个tomcat中都有一份属于自己的session,假设用户第一次访问第一台tomcat&#xff0c;并且把自己的信息存放到第一台服务器…

免费的快速手机文件解压APP,快冲

各位小伙伴们大家好&#xff0c;今天我要介绍一款手机上必备的神奇工具&#xff01;你有没有经常遇到需要解压文件情况呢&#xff1f;还在为不知道用哪个软件而烦恼吗&#xff1f;别担心&#xff0c;我给你带来了解决方案 &#xff0c;就是这一款免费的解压精灵。 解压精灵是一…

【Nginx】使用nginx进行反向代理与负载均衡

使用场景 反向代理&#xff1a;一个网站由许多服务器承载的&#xff0c;网站只暴露一个域名&#xff0c;那么这个域名指向一个代理服务器ip&#xff0c;然后由这台代理服务器转发请求到网站负载的多台服务器中的一台处理。这就需要用到Nginx的反向代理实现了 负载均衡&#xf…

怎么去掉邮件内容中的回车符

上图是Outlook 截图&#xff0c;可见1指向的总有回车符&#xff1b; 故障原因&#xff1a; 不小心误按了箭头4这个选项&#xff1b; 解决方法&#xff1a; 点击2箭头确保tab展开&#xff1b; 点击3以找到箭头4. 取消勾选或者多次点击&#xff0c;即可解决。

单区域OSPF配置

配置命令步骤&#xff1a; 1.使用router ospf 进程ID编号 启用OSPF路由 2.使用network 直连网络地址 反掩码 area 0 将其归于区域0 注意&#xff1a;1.进程ID编号可任意&#xff08;1-65535&#xff09;2.反掩码用4个255相减得到 如下图&#xff0c;根据给出要求配置OSPF单区…

HT8313 D/AB切换 音频功率放大器

HT8313具有AB类和D类的自Y切换功能&#xff0c;在受到D类功放EMI干扰困扰时&#xff0c;可随时切换至AB类音频功放模式&#xff08;此时电荷泵升压功能关闭&#xff09;。 HT8313内部固定28dB增益&#xff0c;内置的关断功能使待机电流Z小化&#xff0c;还集成了输出端过流保护…

JavaEE进阶学习:Spring核心和设计思想

Spring 是什么 我们通常所说的 Spring 指的是 Spring Framework&#xff08;Spring 框架&#xff09;&#xff0c;它是⼀个开源框架&#xff0c;有着活跃而庞大的社区&#xff0c;这就是它之所以能长久不衰的原因。Spring 支持广泛的应用场景&#xff0c;它可以让 Java 企业级…

PP-ChatOCRv2、PP-TSv2、大模型半监督学习工具...PaddleX新特性等你来pick!

小A是一名刚刚毕业的算法工程师&#xff0c;有一天&#xff0c;他被老板安排了一个活&#xff0c;要对一批合同扫描件进行自动化信息抽取&#xff0c;输出结构化的分析报表。OCR问题不大&#xff0c;但是怎么进行批量的结构化信息抽取呢&#xff1f;小A陷入了苦苦思索… 小B是…

Java获取Jar、War包路径,并生成可编辑修改的本地配置文件

前言 本地的可修改配置文件的编写理应是一个很常用的功能&#xff0c;但由于数据库的存在&#xff0c;它鲜少被提及&#xff0c;大多数我们直接存储到数据库中了。 以至于现今&#xff0c;除了没接触数据库的新手时常使用它以外&#xff0c;它没有太多的出场机会。 也因此&am…

Hive数据表操作--学习笔记

1&#xff0c;Hive数据表操作 1&#xff0c;建表语句和内外部表 ①创建内部表 create [external] table [if not exists] 表名( 字段名 字段类型 [comment 注释], 字段名 字段类型 [comment 注释], ... ) [row format delimited fields terminated by 指定分隔符];&#xff0…

后端接口性能优化分析-问题发现问题定义

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring源码、JUC源码&#x1f525;如果感觉博主的文章还不错的话&#xff0c;请&#x1f44d;三连支持&…