Efficient programming framework - a semantic-oriented low-code data persistence layer programming framework

I. Introduction

In the actual development work, the domain model of the system is often designed to design the scalability and robustness of the system. At the same time, the basic management of data cannot be avoided, such as addition, deletion, modification and query, interface definition and implementation, etc. Some tasks are actually similar and repetitive, and have little to do with business logic. These tasks can often be automatically completed by the system, and the labor cost can be mainly concentrated on the design and implementation of the domain model.

In order to achieve this small goal, we investigated the better frameworks used in the industry, and the more widely used ones are MybatisGenerator and MyBatis-Plus BaseMapper. The core capabilities of these frameworks are to reduce the development workload of persistence layer functions. I believe that students who have used it should know that in actual use, it should be like the following.

1.1 How to use MybatisGenerator to generate code

private ProductParam buildSearchParam(ProductQueryParam productQueryParam){
    ProductParam param = new ProductParam();
    ProductParam.Criteria cr = param.createCriteria();
    if(productQueryParam.getUserId() != null){
        cr.andUserIdEqualTo(productQueryParam.getUserId());
    }
    if(productQueryParam.getUserId() != null){
        cr.andUserIdEqualTo(productQueryParam.getUserId());
    }
    if(productQueryParam.getName() != null){
        cr.andNameEqual(productQueryParam.getName());
    }
    if(productQueryParam.getUserId() != null){
        cr.andUserIdEqualTo(productQueryParam.getUserId());
    }
    if(productQueryParam.getUserId() != null){
        cr.andUserIdEqualTo(productQueryParam.getUserId());
    }
    if(productQueryParam.getUserId() != null){
        cr.andUserIdEqualTo(productQueryParam.getUserId());
    }
    if(productQueryParam.getUserId() != null){
        cr.andUserIdEqualTo(productQueryParam.getUserId());
    }
    if(productQueryParam.getUserId() != null){
        cr.andUserIdEqualTo(productQueryParam.getUserId());
    }
    if(productQueryParam.getUserId() != null){
        cr.andUserIdEqualTo(productQueryParam.getUserId());
    }
    return param;

}

1.2 How to use MyBatis-Plus BaseMapper

public Condition buildCondition(ProductQueryParam productQueryParam){
    Condition condition = new Condition(ProductDO.class);
    condition.orderBy("gmtCreate").desc();
    Criteria criteria = condition.createCriteria();
    if(productQueryParam.getUserId() != null){
        criteria.andEqualTo("userId", productQueryParam.getUserId());
    }
    if(productQueryParam.getUserName() != null){
        criteria.andEqualTo("userName", productQueryParam.getUserName());
    }
    if(productQueryParam.getUserId() != null){
        criteria.andEqualTo("userId", productQueryParam.getUserId());
    }
    if(productQueryParam.getUserId() != null){
        criteria.andEqualTo("userId", productQueryParam.getUserId());
    }
    if(productQueryParam.getUserId() != null){
        criteria.andEqualTo("userId", productQueryParam.getUserId());
    }
    if(productQueryParam.getUserId() != null){
        criteria.andEqualTo("userId", productQueryParam.getUserId());
    }
    if(productQueryParam.getUserId() != null){
        criteria.andEqualTo("userId", productQueryParam.getUserId());
    }
    
    
}

It can be seen that the two usage methods are not elegant enough, both require a lot of cumbersome code blocks for constructing Conditions, and the readability is not friendly enough. There are even many magic values ​​in the construction conditions of MyBatis-Plus BaseMapper, which is not conducive to code maintenance.

How to allow developers to construct Condition gracefully, even construct Condition as simply as constructing POJO, and interact gracefully with the persistence layer, this is the problem to be solved by this development framework.

2. Introduction to low-code data persistence layer framework

2.1 Overall Architecture Diagram

2.2 Overall Architecture Concept

1) The layer open to developers is composed of DataService, DataParam, and DataObject. Developers only need to care about the semantic conditions corresponding to the business logic, and convey the semantic conditions to DataParam. The whole process of conveying is very simple, as simple as constructing a simple POJO. Then various storage operations can be completed through DataService. Developers don't need to care about how the underlying layer uses semantic conditions.

2) No matter what kind of software the storage is based on, such as mysql, mogodb, opensearch, etc., it is transparent to user developers. Developers only need semantic-oriented programming.

3) For the explanation of system interface methods, the semantics of the code itself are stronger than code comments, and code comments are stronger than external documentation. In the past, we needed to constantly construct complex and redundant Mapper operation conditions, or even though some commonly used interfaces were encapsulated for reuse, when another person used these encapsulated interfaces, he was still confused when he saw the fields in the input parameters, because he did not know whether these fields supported equal queries, notEqual queries, or Like queries, etc. Users had to read the entire method to the specific SQL implementation before using it with confidence. It is not ruled out that someone can write the comments clearly, but as the system iterates, the reliability of the comments will continue to decrease. It is very unfriendly to users and the development efficiency is very low. With this set of frameworks, these problems are gone forever.

3. How to implement a low-code data persistence layer framework

Using this development tool, a semantic-oriented low-code data persistence layer programming framework can be implemented very quickly and easily.

3.1 Introduce related dependencies into applications that need to use this framework

<dependency>
   <artifactId>fast-frame</artifactId>
   <groupId>com.rhc</groupId>
   <version>1.0-SNAPSHOT</version>
</dependency>

3.2 Perform relevant configuration in the application.properties configuration file of the application

One-time configuration, multi-table multiplexing

#################################
## 低代码数据持久层编程框架相关配置 ##
#################################
connect.driver=com.mysql.jdbc.Driver
connect.url=jdbc:mysql://xxx:3306/aaa
connect.userId=xxx
connect.password=xxx

#需要自动生成代码的表名,多个表名用英文逗号分割
table.name=common_tenant,common_log,common_notice

# 重复执行时是否覆盖老的
sql.overwrite=true

## 配置相关文件生成的目标地址
## sqlMap的xml配置文件既可以放在resource资源目录下面,也可以放在源码目录下
## 当目录中含有'com'时,则默认放在源码目录下,否则默认放在resource资源目录下
#sql.xml.targetPackage=META-INF.sqlmap
sql.xml.targetPackage=com.rhc.exam4.sqlmap

# 配置生成的dataObject文件存放的package
data.object.package=com.rhc.exam4.data.internal.dataobject
# 配置查询条件的后缀名
criteria.suffix=Criteria
# 配置生成的Mapper文件存放的package
data.mapper.package=com.rhc.exam4.data.internal.dao

# 配置负责语义化转化的相关文件存放的package
criteria.convertor.package=com.rhc.exam4.data.internal.transfer
# 配置负责语义化转化的相关文件的后缀名
criteria.convertor.suffix=Transfer

# 配置数据层服务入参相关文件存放的package
data.param.package=com.rhc.exam4.data.param
# 配置数据层服务入参的后缀名
data.param.suffix=DataParam

# 配置数据层服务相关文件存放的package
data.service.package=com.rhc.exam4.data.service
data.service.suffix=DataService
data.service.impl.package=com.rhc.exam4.data.service.impl
data.service.impl.suffix=DataServiceImpl

3.3 Start to generate data persistence layer programming framework

public static void main(String[] args) {

     EffectiveDataBootStrap.runAuto();
}

3.4 The effect of generated code

You can find the relevant code of the automatically generated data persistence layer framework in the relevant directory of the configuration, as shown in the following figure.

3.5 Actual use

In most cases, developers and users only need to care about the interface in the red box in the above figure, and directly import data services for use, and the code is concise and easy to read. It can meet 99% of database interaction scenarios. For a small number of complex scenarios that are not supported, developers can also expand it like writing code normally.

CommonLogDbParam commonLogDbParam = new CommonLogDbParam();
commonLogDbParam.setIdIn(Arrays.asList(32L,43L));
commonLogDbParam.setOperatorLike("operator");
commonLogDbParam.setGmtModifyLessThanOrEqualTo(new Date());
commonLogDbParam.setGmtCreateGreaterThanOrEqualTo(new Date());
List<CommonLog> result = commonLogDataServ.select(commonLogDbParam);

Fourth, the realization principle of low-code development tools

4.1 Implementation schematic diagram

4.2 Implementation Description

The whole set of tools implements the low-code core using MybatisGenerator. Based on the above concept and the extension capability of the plug-in, the low-code programming capability of the whole set of data layer services is realized.

The implementation of this set of low-code development tools follows the following concepts:

1) Adaptation of dataService layer and Mapper layer

2) Adaptation of the connection between the mapper layer and the specific storage medium

3) Semantic query conditions, see the name and know the meaning

4) The overall framework code is automatically generated, the class file path is configurable, and the model suffix is ​​configurable

5) Plug-in pluggable programming mode

6) Support multiple database connection drivers 

4.3 Core class diagram

If you need the framework source code, you can get it from the address below 

Information collection address

Guess you like

Origin blog.csdn.net/qq_42672856/article/details/117843398