基于ry-vue-plus的代码生成工具整合自定义模版

前言

         鉴于自己最近参加一个比赛,整区块链应用,因此部分核心数据需要往区块链网络的数据库中存储。用的区块链框架为FISCO-BCOS。FISCO-BCOS官方提供一一个预编译合约,名叫Table.sol (CRUD合约),能让我们通过CRUD合约像使用一般关系型数据库中的增删改查操作,从而对数据进行增删改查。

        但,问题是,这个合约虽然提供了数据库一样的操作,并没有像Java一样的映射框架,就算用Table.sol来操作数据上链,这个代码量也非常大。

        所以啊,我就想到之前我研究到的一个项目ry-vue-plus,有个代码生成工具,通过数据库连接->进而生成一般的crud代码、以及vue文件、domain、service、mapper之类的。在此基础上,对合约也设置一个模版,对数据库表 —— 合约的映射。

ry-vue-plus采用的模版引擎为velocity。

以下,只是记录如何整合自定义模版配置。以及设计对模版引擎的介绍。

1.什么是模版引擎?

 模板引擎是构建动态内容的重要工具,特别适用于生成HTML、邮件内容、报告和其他文本文档。

简单来讲,能够让我们通过定义模板来生成动态内容。模板通常包含静态内容以及特殊语法或占位符,这些占位符可以在运行时被动态数据替换

2.Velocity 简介 

Velocity是一个强大的模板引擎,它具有简单易用的语法和灵活性。 
Velocity是一个用于生成文本输出的模板引擎。它是一种轻量级的、开源的工具,最初由Apache开发。

Velocity的主要特点包括:

简单的语法: Velocity使用简单的模板语法,易于学习和使用。

  • 灵活性: Velocity允许在模板中嵌套、迭代和使用条件语句,以便生成复杂的输出。
  • 模板重用: 模板可以被多次重用,从而减少了重复代码。
  • 可扩展性: Velocity可以与Java代码集成,允许在模板中调用Java方法。
  • 广泛支持: Velocity可以用于生成HTML、XML、JSON等多种文本格式。

 开发

吆西,知道他是个啥东西了,直接在ry-vue-plus原有的配置上进行代码开发。

找到代码生成核心

废话少说,他的代码生成在GenTableServiceImpl.java类中。核心代码在这里。

  ......

 /**
     * 查询表信息并生成代码
     */
    private void generatorCode(Long tableId, ZipOutputStream zip) {
        // 查询表信息
        GenTable table = baseMapper.selectGenTableById(tableId);
        List<Long> menuIds = new ArrayList<>();
        for (int i = 0; i < 6; i++) {
            menuIds.add(identifierGenerator.nextId(null).longValue());
        }
        table.setMenuIds(menuIds);
        // 设置主键列信息
        setPkColumn(table);
        VelocityInitializer.initVelocity();

        VelocityContext context = VelocityUtils.prepareContext(table);

        // 获取模板列表
        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
        for (String template : templates) {
            // 渲染模板
            StringWriter sw = new StringWriter();
            Template tpl = Velocity.getTemplate(template, Constants.UTF8);
            tpl.merge(context, sw);
            // TODO 将模版的内容替换成实际渲染的内容
            try {
                // 添加到zip
                zip.putNextEntry(new ZipEntry(VelocityUtils.getFileName(template, table)));
                IoUtil.write(zip, StandardCharsets.UTF_8, false, sw.toString());
                IoUtil.close(sw);
                zip.flush();
                zip.closeEntry();
            } catch (IOException e) {
                log.error("渲染模板失败,表名:" + table.getTableName(), e);
            }
        }
    }

......

第二个框中定义代码,将变量和那个模版渲染成那个实际的文件。

我们在模版文件中占位符使用的变量,就是在VelocityContext context = VelocityUtils.prepareContext(table);这行代码得出来的。

我们调试context变量里面的数据,发现就是这些字段吧,可以在模版文件中通过占位符的形式访问。

现在,我们知道这个模版中的占位符的数据是如何来的,然就是把我们自定义的模版添加到他的代码里面。

添加我们自己的模版

如下图位置。

在VelocityUtils.java 文件中,修改如下代码。定义如下,我们获取模版列表才能获取到。

在这个VelocityUtils.java的getFileName方法内。定义文件打包的路径。

定制我们自己的模版

仿写​

在GenTableServiceImpl.java的generatorCode方法内。

我们在上述知道context存储定义模版要使用的变量,调试到这里。以及参考项目已经定义好的模版使用,写在我们自己的模版中。

使用自定义方法

嗯,怎么讲,它里面有些样式可以用他的语法做出来,但是嫌麻烦,因此直接在模版文件调用java自定义方法,来处理数据得出我们想要的。

 还是在GenTableServiceImpl.java 文件的generatorCode方法内,如下位置,可以添加我们自定义类。从而在模版文件就可以调用这个类中的方法了。

 对应的静态类方法:

模版文件中的使用:


 

storage.sol.vm

pragma solidity ^0.4.25;
pragma experimental ABIEncoderV2;
import "./TableTools.sol";

#set($primayKey = $velocityUtil.getPrimaryKey($columns))
/// @title ${functionName}Storage
/// @author ${author}
/// @notice 操作${functionName}
contract  ${ClassName}Storage is TableTools{

    string constant ${ClassName}_Table = "${businessName}_table";
    string constant ${ClassName}_Fields = "$velocityUtil.generateFiledList($columns)";


    Bean tb_${businessName};

    event InsertResult(int8);

    constructor() public {
        // 初始化表结构
        initTableStruct(tb_${businessName}, ${ClassName}_Table,NOMINAL_PRIMARYKEY,${ClassName}_Fields);
    }

    /*
    * 查询全部${functionName}列表
    *
    * @return  ${functionName}列表
    */
    function queryList() public view returns(string memory) {
        int _code;
        string memory _res;
        string[] memory _strs = new string[](0);
        (_code,_res) = selectOneRecordByCondToJson(tb_${businessName}, COMMON_VALUE, _strs);
        require(_code == 1,"query failed!");
        return _res;
    }


    /*
    * 根据主键查询${functionName}
    *
    * @return  ${functionName}列表
    */
    function queryById(string memory _id) public view returns (string memory) {
        int8 _code;
        string memory _res;
        string[] memory _conditionPair = new string[](2);
        _conditionPair[0] = "${primayKey}"; 
        _conditionPair[1] = _id;
        (_code,_res) = selectOneRecordByCondToJson(tb_${businessName}, COMMON_VALUE,_conditionPair); // : 自定义字段查询
        require(_code == 1,"query failed!");
        return _res;
    }

    /*
    * 根据查询条件、分页查询${functionName}列表
    *
    * @param _conditionPair  查询条件
    * @param _pageNum  起始页数
    * @param _pageSize  起始页数
    * @return  ${functionName}列表
    */
    function queryList(string[] _conditionPair,int _pageNum,int _pageSize) public view returns(string memory) {
        string memory _res;int8 _code;
        Page memory _page = Page(_pageNum, _pageSize);
        (_code,_res) = selectOneRecordByCondToJson(tb_${businessName}, COMMON_VALUE,_conditionPair,_page);
        require(_code == 1,"query failed!");
        return _res;
    }

    /*
    *  新增${functionName}
    *
    * @param fieldsStr  字段列表字符串
    * @return  新增结果
    */
    function insert(string fieldsStr) public returns(bool) {
        string[] memory fields = getFieldsArray(fieldsStr);
        require(fields.length == $velocityUtil.getColumnsLength($columns),"The list length is wrong!");
        require(!_isIDExist(fields[0]),"insert info primaryKey exist!");
        int8 _code = insertOneRecord(tb_${businessName},COMMON_VALUE,fieldsStr, true);
        emit InsertResult(_code);
        bool end = _code == 1;
        require(end,"insert failed!");
        return end;
    }


    /*
    *  根据主键值更新${functionName}信息
    *
    * @param fieldsStr  字段列表字符串
    * @return  新增结果
    */
    function updateById(string memory _fieldsStr) public returns(bool) {
        string[] memory fields = getFieldsArray(_fieldsStr);
        string[] memory _conditionPair = new string[](2);
        _conditionPair[0] = "${primayKey}"; 
        _conditionPair[1] = fields[0];
        return update(_fieldsStr,_conditionPair);
    }

    /*
    *  根据条件更新${functionName}信息
    *
    * @param _fieldsStr 新字段列表字符串
    * @param _conditionPair 条件
    * @return  修改结果
    */
    function update(string memory _fieldsStr,string[] memory _conditionPair) public returns(bool) {
        int8 _code =  updateOneRecordByCond(tb_${businessName}, COMMON_VALUE,_fieldsStr,_conditionPair);
        bool end = _code == 1;
        require(end,"update failed!");
        return end;
    }

    /*
    * 根据主键值列表批量删除${functionName}信息
    *
    * @param _id  主键值
    * @param _id  主键值
    * @return  删除结果
    */
    function deleteWithValidByIds(string[] memory _ids,bool isValid) public returns(bool) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        int8 _code;
        for (uint j = 0; j < _ids.length; j++) {
            require(_isIDExist(_ids[j]),"remove failed!");
        }
        for (uint i = 0; i < _ids.length; i++) {
            string[] memory _conditionPair = new string[](2);
            _conditionPair[0] = "${primayKey}";
            _conditionPair[1] = _ids[i];
            _code =  remove(COMMON_VALUE,Test_Table,_conditionPair);
        }
        return _code == 1;
    }

    function deleteByIds(string[] memory _ids)  public returns(bool) {
        return deleteWithValidByIds(_ids,false);
    }


    /*
    * 根据主键值判断信息是否存在
    *
    * @param _id  主键值
    * @return  是否存在
    */
    function _isIDExist(string memory _id) internal view returns(bool) {
        string[] memory _conditionPair = new string[](2);
        _conditionPair[0] = "${primayKey}"; 
        _conditionPair[1] = _id;
        (int _code,) = selectOneRecordByCondToJson(tb_${businessName}, COMMON_VALUE,_conditionPair);
        return _code == 1;
    }

}

测试

导入数据表,点击生成之后。

打开解压好的文件,成功。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

本郡主是喵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值