OneCode open source low-code engine white paper

1. Background

With the popularity of the low-code concept, related technologies and products are also emerging in an endless stream. Whether it is an established industry software manufacturer or an open platform manufacturer, whether it is a new trend of SAAS software in an Internet industry enterprise or an emerging low-code innovative product service, it is the first time. Played the low-code card. Although each platform has its own advantages, most of them are self-contained systems, and it is difficult to make a real choice when it comes to enterprises. The functional evaluation of low-code platforms and the interconnection and interoperability between various platform components have become an urgent demand in the market.

In the past 2022, in terms of platform interconnection, Ali launched the open source engine "LowCodeEngin" in the second quarter, and the National Institute of Information and Communication Technology also launched the "General Technical Requirements for Low-Code Development Platforms" in the fourth quarter in response to market demand. For low-code related concepts and new function points, further specification and sorting out.

In the context of full openness, the CodeBee team launched a low-code engine (LowCodeEngine) based on the open source LGPL protocol.

Open source address: wenzhang

Online demo address: http://demo.raddev.cn:9080/RAD/DSMdsm/projectManager http://demo.raddev.cn:9080/RAD/DSMdsm/projectManager

Two, product composition

The low-code engine is composed of the interface designer, the OneCode general code framework, and the DSM domain modeling tool. The three-part supporting system supports each other, and completes mutual inheritance and support through open standard component protocols.

(1) View Designer Engine

The designer uses a drag-and-drop engine + plug-in construction model, and users can write plug-ins through an open low-code protocol. Support JS and JAVA two extension languages. Style building provides a standard CSS3 editor, supports event actions and dynamic expansion of functions. Support custom function library expansion, support resource libraries such as Ali fonts and pictures.

(2) OneCode general code editor:

OneCode is a unified grammar system customized for low-code languages. It uses Java language as the native language and runs in the JVM environment. Users can interact with low-code applications through Java language, and can also complete engine plug-ins and call The code engine compiles and deploys the application.

(3) DSMEngine domain modeling:

DSMEngine is a OneCode modeling tool independent of the designer. The platform adopts a domain modeling model, supports warehouse management, aggregated applications, and CodeFactory output is OneCode code compilation output.

The DSM model supports three modeling modes:

(1) CodeFrist code first mode

Compose natively through Java language OneCode mode.

(2) ViewFrist view priority

The interactive model in the early stage is completed by dragging and dropping the view engine, and the DSM model is completed in reverse.

(3) ModuleFrist model priority

Build a basic model through database, microservice interface and other modes.

DSM reverse conversion

DSM models completed in different ways can be freely switched between View, Code, and Module through OneCode, and use related tools to complete simulation debugging and deployment.

DSM third-party language conversion

The DSM code output module adopts an independent template architecture. In addition to existing in the form of OneCode, it can also support independent code output modules to customize independent third-party language model output.

3. Introduction of the designer engine

(1) Function overview

(2) Designer layout

The designer engine is the front-end SDK of the low-code engine. It is oriented to developers. It is not a low-code platform that can adapt to everyone. Instead, technical developers can complete their own business customization and achieve collaboration by extending plug-ins and peripheral ecology. Office, CRM customer management, Internet of Things platform, etc. empower business systems through low-code capabilities

(3) Material library

"Material": One of the core purposes of the low-code engine is to build a cross-industry low-code framework. Since each industry has different application fields, different personnel and methods, there will be improvements in some underlying components. big gap. For example: irregular form elements that are widely used in government business, icon systems of various industries in enterprise applications, a large number of device icon pictures and real-time networking diagrams in the Internet of Things industry.

(4) Component library

Component definition : Components that can be used on low-code platforms, including configurations to enhance the building experience, can be dragged and configured in the designer. There are two classification methods: according to the scene, it can be divided into basic components, business components, chart components, layout components and composite components. Usually, users can complete related settings independently, and expand them in the view engine according to business characteristics (actual registration examples will be demonstrated in subsequent chapters)

Components are usually a group of interactive components that perform specific functions. According to different engine modes, the rendering configuration is loaded in the engine.

Configuration example

Code conversion

Component debugging import

(5) Support management

public resource import

(6) Style system

DOM tree perspective style box

DOM tree perspective

Picture sample code

  {
        "alias":"BuildTreeTreeView",
        "key":"xui.UI.TreeView",
        "host":this,
        "properties":{
            "name":"BuildTreeTreeGrid",
            "items":[
                {
                    "borderType":"none",
                    "caption":"JAVA树",
                    "dynDestory":false,
                    "hidden":false,
                    "id":"getBuildTree",
                    "imageClass":"bpmfont bpmgongzuoliuxitongpeizhi",
                    "tagVar":{ }
                }
            ],
            "iniFold":false,
            "dynDestory":true
        },
      
        "CS":{
            "KEY":{
                "color":"#000000",
                "font-weight":"lighter",
                "border-radius":"0px 2px 0px 0px"
            },
            "BAR":{
                "font-family":"tahoma,geneva,sans-serif"
            }
        }
    }

dynamic style box

Code configuration example

 {
        "alias":"xui_ui_cssbox1",
        "key":"xui.UI.CSSBox",
        "host":this,
        "properties":{
            "className":"xui-css-ame",
            "normalStatus":{
                "color":"#eeeeee",
                "border-radius":"6px",
                "box-shadow":"inset 0px 1px 0px #87C1DD",
                "text-shadow":"0 1px 0 #297192",
                "$gradient":{
                    "stops":[
                        {
                            "pos":"0%",
                            "clr":"#4BA3CC"
                        },
                        {
                            "pos":"70%",
                            "clr":"#3289B2"
                        }
                    ],
                    "type":"linear",
                    "orient":"T"
                },
                "cursor":"pointer",
                "border-top":"solid #3899C6  1px",
                "border-right":"solid #3899C6  1px",
                "border-bottom":"solid #3899C6  1px",
                "border-left":"solid #3899C6  1px"
            },
            "hoverStatus":{
                "border-radius":"0px 3px 0px 0px"
            }
        }
    }

(7) Event frame

Configuration code example:

  {
        "alias":"BuildTreeTreeView",
        "key":"xui.UI.TreeView",
        "host":this,
        "properties":{
            "name":"BuildTreeTreeGrid",
            "items":[
                {
                    "borderType":"none",
                    "caption":"JAVA树",
                    "dynDestory":false,
                    "hidden":false,
                    "id":"getBuildTree",
                    "imageClass":"bpmfont bpmgongzuoliuxitongpeizhi",
                    "tagVar":{ }
                }
            ],
            "iniFold":false,
            "dynDestory":true
        },
        "events":{
    //获取数据
            "onGetContent":{
                "actions":[
                    {
                        "args":[
                            "{page.ReloadChild.setQueryData()}",
                            null,
                            null,
                            "{args[1].tagVar}",
                            ""
                        ],
                        "desc":"设置扩展参数",
                        "method":"setQueryData",
                        "redirection":"other:callback:call",
                        "target":"ReloadChild",
                        "type":"control"
                    }
                ]
            },
//数据项选择
            "onItemSelected":{
                "actions":[
                    {
                        "args":[
                            "{args[1].id}"
                        ],
                        "conditions":[
                            {
                                "symbol":"non-empty",
                                "right":"",
                                "conditionId":"_nonempty_{args[1].className}",
                                "left":"{args[1].className}"
                            }
                        ],
                        "desc":"删除存在页",
                        "method":"removeItems",
                        "target":"BuildTreeTab",
                        "type":"control"
                    }
                ]
            }
        }
    }

(8) Action call

Function overview

Configuration example code:

 {
                            "args":[
                                "{page.ReloadChild.setQueryData()}",
                                null,
                                null,
                                "{args[1].tagVar}",
                                ""
                            ],
                            "desc":"设置扩展参数",
                            "method":"setQueryData",
                            "redirection":"other:callback:call",
                            "target":"ReloadChild",
                            "type":"control"
                        },
                        {
                            "args":[
                                "{page.ReloadChild.invoke()}",
                                "temp",
                                null,
                                "{args[2]}"
                            ],
                            "desc":"子节点装载",
                            "method":"invoke",
                            "redirection":"other:callback:call",
                            "return":false,
                            "target":"ReloadChild",
                            "type":"control"
                        }
                    ]
                }

(9) Plug-in system

A plug-in is a built-in management function embedded in the designer. Different from a business component, a plug-in is more of an extended function of the system. It is also common in practical applications. For example, during system operation, we need to display different content data according to different users. This requires permission plug-ins to complete, and business users will also involve a large number of business and data transfer functions during use. These The function needs to dynamically manage the properties of the page, and even dynamically generate the injection page. This requires process plug-ins to assist in completion. In the actual development process, especially in the engineering development of real projects, we often need to perform a lot of macro operations for engineering, such as modifying specific component styles in batches, retrieving and copying component characteristics according to specific conditions, automatically adding actions, and so on. All of these require similar macro plug-ins to complete. OneCode also regulates the plug-in system in terms of integrating back-end operations and service deployment. Respectively, DSM modeling provides DSM plug-ins, release management and operation provides OPS plug-ins, and  API integration provides proxy server plug-ins. The system plug-ins are all open source and shared by users who need to modify them to facilitate users to refer to the plug-in system later Modify your own plug-in system.

Four, OneCode middle and background

OneCode itself is based on the JAVA language system, which is a set of extended subsets based on Java Spring annotations. You can add annotations in ordinary Java programs to realize the interactive processing between the front and back and the low-code engine.

(1) Rendering principle

(2) Example display

(3) Complete module OneCode

@Controller
@RequestMapping("/admin/org/person/")
@MethodChinaName(cname = "人员管理", imageClass = "spafont spa-icon-login")
@Aggregation(sourceClass = PersonService.class)
public class PersonAPI {
    @RequestMapping(method = RequestMethod.POST, value = "Persons")
    @GridViewAnnotation()
    @ModuleAnnotation( caption = "人员列表")
    @APIEventAnnotation(autoRun = true, bindMenu = {CustomMenuItem.reload})
    @ResponseBody
    public ListResultModel<List<PersonGridView>> getPersons(String orgId) {
        ListResultModel<List<PersonGridView>> resultModel = new ListResultModel<List<PersonGridView>>();
        List<Person> personList = new ArrayList<>();
        try {
            personList = getService().getPersons(orgId);
            resultModel = PageUtil.getDefaultPageList(personList, PersonGridView.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultModel;
    }

    @MethodChinaName(cname = "人员信息")
    @RequestMapping(method = RequestMethod.POST, value = "PersonInfo")
    @NavGroupViewAnnotation()
    @APIEventAnnotation(callback = {CustomCallBack.ReloadParent, CustomCallBack.Close}, bindMenu = {CustomMenuItem.editor})
    @DialogAnnotation
    @ModuleAnnotation(caption = "编辑人员信息", width = "800", height = "550")
    @ResponseBody
    public ResultModel<PersonNav> getPersonInfo(String personId) {
        ResultModel<PersonNav> resultModel = new ResultModel<PersonNav>();
        return resultModel;
    }

    @MethodChinaName(cname = "添加人员")
    @RequestMapping(method = RequestMethod.POST, value = "AddPersonView")
    @FormViewAnnotation
    @APIEventAnnotation(bindMenu = {CustomMenuItem.add}, autoRun = true)
    @Disabled
    @ModuleAnnotation( caption = "添加人员信息", width = "370", height = "260")
    @ResponseBody
    public ResultModel<AddPerson> AddPerson(String orgId) {
        ResultModel<AddPerson> resultModel = new ResultModel<AddPerson>();
        CtPerson person = new CtPerson();
        person.setOrgId(orgId);
        resultModel.setData(new AddPerson(person));
        return resultModel;
    }

    @MethodChinaName(cname = "保存成员信息")
    @RequestMapping(value = {"savePerson"}, method = {RequestMethod.GET, RequestMethod.POST})
    @APIEventAnnotation(callback = {CustomCallBack.ReloadParent, CustomCallBack.Close}, bindMenu = CustomMenuItem.save)
    public @ResponseBody
    ResultModel<Boolean> savePerson(@RequestBody CtPerson person) {
        ResultModel<Boolean> userStatusInfo = new ResultModel<Boolean>();
        getService().savePerson(person);
        return userStatusInfo;
    }

    @MethodChinaName(cname = "删除人员")
    @RequestMapping(value = {"delPerson"}, method = {RequestMethod.GET, RequestMethod.POST})
    @APIEventAnnotation(callback = {CustomCallBack.Reload, CustomCallBack.ReloadParent}, bindMenu = CustomMenuItem.delete)
    public @ResponseBody
    ResultModel<Boolean> delPerson(String iD) {
        ResultModel<Boolean> userStatusInfo = new ResultModel<Boolean>();
        getService().delPerson(iD);
        return userStatusInfo;
    }

    PersonService getService() {
        return EsbUtil.parExpression(PersonService.class);
    }
}


@PageBar  //
@GridAnnotation(event = CustomGridEvent.editor, 
        customService = PersonService.class, 
        customMenu = {GridMenu.Add, GridMenu.Delete, GridMenu.Reload})
public class PersonGridView {
    @CustomAnnotation(pid = true, hidden = true)
    String orgId;
    @CustomAnnotation(pid = true, hidden = true)
    String roleId;
    @CustomAnnotation(uid = true, hidden = true)
    String iD;
    @CustomAnnotation(caption = "用户名称", required = true)
    String name;
    @CustomAnnotation(caption = "账户信息", required = true)
    String account;
    @CustomAnnotation(caption = "邮箱")
    String email;
    @InputAnnotation(inputType = InputType.password)
    @CustomAnnotation(caption = "密码", required = true)
    String password;
    @CustomAnnotation(caption = "手机")
    String mobile;
    @CustomAnnotation(caption = "部门名称")
    String orgName;

    public PersonGridView(Person person) {
        this.iD = person.getID();
        this.orgId = person.getOrgId();
        this.name = person.getName();
        this.account = person.getAccount();
        this.password = person.getPassword();
        this.mobile = person.getMobile();
        this.email = person.getEmail();
        Org org = null;
        try {
            org = OrgManagerFactory.getOrgManager().getOrgByID(person.getOrgId());
            this.orgName = org.getName();
        } catch (OrgNotFoundException e) {
            e.printStackTrace();
        }
    }
}


@BottomBarMenu
@FormAnnotation(bottombarMenu = {CustomFormMenu.Save, CustomFormMenu.Close}, customService = PersonService.class, col = 1)
public class AddPerson {
    @CustomAnnotation(uid = true, hidden = true)
    String iD;
    @CustomAnnotation(caption = "用户名称", required = true)
    String name;
    @CustomAnnotation(pid = true, hidden = true)
    String orgId;
    @CustomAnnotation(pid = true, hidden = true)
    String roleId;
    @CustomAnnotation(caption = "账户信息", required = true)
    String account;
    @CustomAnnotation(caption = "邮箱")
    String email;
    @InputAnnotation(inputType= InputType.password)
    @CustomAnnotation(caption = "密码",  required = true)
    String password;
    @CustomAnnotation(caption = "手机")
    String mobile;
    public AddPerson(Person person) {
        this.iD = person.getID();
        this.orgId = person.getOrgId();
        this.name = person.getName();
        this.account = person.getAccount();
        this.password = person.getPassword();
        this.mobile = person.getMobile();
        this.email = person.getEmail();

    }
}

(5) DSM modeling tool

DSM modeling, Baidu Encyclopedia defines it as follows:

Domain-specific modeling ( DSM ) is a software engineering methodology for designing and developing systems ( such as computer software) . It uses a graphical Domain Specific Language (DSL) to express every aspect of the system. The language of a DSM tends to support a higher level of abstraction than a general modeling language and thus requires less effort and less low-level detail to describe a particular system.

The application of low-code technology can improve the code efficiency of programmers by providing stronger tools. But it is essentially a software description method in a specific scenario. At this level, low-code technology and DSM ideas have similarities and similarities. At the beginning of product design, the construction of DSM modeling language and tool support are taken as the The underlying support design is designed, and the modeling applications accumulated in the application are restructured and integrated with the idea of ​​DSM at the underlying layer.

We unify existing resource tools into warehouse applications, including unified material library import and unified data source (database, external storage) management. And through the auxiliary construction of the code factory, it is unified into the current environment technology model of Contenxt (OneCode). In each specific business model, complete the integration of independent aggregated entities, as well as the corresponding service management, and provide perspective management services for related method models. On the basis of OneCode, get rid of the traditional code template and generation mechanism. Realize the reverse capability of code to model. The DSM design can run through the entire project development, implementation and management process to create a modeling language based on the real code.

(1) Warehouse modeling

(2) Aggregation application

(3) View factory

(4) Support domain

(5) Process modeling

Six, application integration


(1) Kernel minimum set integration (JS offline application)

The core of the designer is completely completed by JS script, which is an independent front-end framework. The kernel version includes: RAD page design editor, xui running and running scripts.

The minimal set contains only the page designer and plugin framework.

Design interface integration:

After downloading the open source package, run debug.html to open the editor.

When integrating into a free application, you only need to introduce two key js lib packages to integrate into your own application.

<script type="text/javascript" src="/RAD/xui.js"></script>
<script type="text/javascript" src="/RAD/index.js"></script>
<script type="text/javascript">
    var lang = (function () {
        var dft = 'zh-cn',
                map = {
                    'en-us': 'en',
                    'zh-cn': 'cn'
                },
                n = navigator,
                l = (n.language || n.browserLanguage || '').toLowerCase();
        return map[l] || map[dft];
    })();

    xui.include("xui.Locale." + lang + '.doc', "/RAD/Locale/" + lang + ".js", function () {
        xui.Module.load('RAD', function () {
            SPA = this;
        }, lang);
    });

Runtime Support Environment Integration: Open:

The designed file can be imported into the application environment with the following code

  <script type="text/javascript" src="/xui/js/xui-all.js"></script>
<script type="text/javascript" src="./xuiconf.js"></script>
<script type="text/javascript" src="/xui/Locale/cn.js"></script>

(2) Team collaboration version

The team collaboration version is an independent server deployment version. After applying for an account on the official website, it can run on an independent server. After startup, visit http://demoserver:83 through the browser   and log in with the administrator sysadmin:

The first login will enter the default project configuration interface

configuration project


Associate API

Set up team admins

Guess you like

Origin blog.csdn.net/wenzhangli/article/details/128871401