10分钟上手RuoYi代码生成器:Velocity模板引擎实战指南

10分钟上手RuoYi代码生成器:Velocity模板引擎实战指南

【免费下载链接】RuoYi 🎉 基于SpringBoot的权限管理系统 易读易懂、界面简洁美观。 核心技术采用Spring、MyBatis、Shiro没有任何其它重度依赖。直接运行即可用 【免费下载链接】RuoYi 项目地址: https://gitcode.com/yangzongzhuan/RuoYi

你还在手写CRUD代码吗?还在为重复的表单页面开发烦恼吗?RuoYi框架的代码生成器(Code Generator)让这一切成为历史!本文将带你深入了解基于Velocity模板引擎的代码生成原理,通过3个实战案例掌握自定义模板技巧,彻底解放双手,让你专注于业务逻辑而非重复劳动。

读完本文你将获得:

  • 掌握RuoYi代码生成器的核心工作流程
  • 学会自定义Velocity模板实现个性化代码生成
  • 理解表结构与代码模板的映射关系
  • 解决90%的模板开发常见问题

代码生成器核心架构

RuoYi代码生成器基于Velocity模板引擎实现,通过数据库表结构解析模板变量映射代码文件渲染的三步流程,自动生成完整的前后端代码。核心实现位于ruoyi-generator模块,主要包含模板管理、变量处理和代码生成三大功能。

核心实现类

类名职责核心方法
VelocityUtils.java模板上下文构建prepareContext()、getTemplateList()
GenUtils.java表结构解析initTable()、initColumnField()
GenController.java生成入口控制generateCode()、previewCode()

生成流程解析

代码生成的核心流程在VelocityUtils.prepareContext()方法中实现,该方法将数据库表结构信息转换为Velocity模板引擎可识别的上下文变量:

public static VelocityContext prepareContext(GenTable genTable) {
    VelocityContext velocityContext = new VelocityContext();
    velocityContext.put("tableName", genTable.getTableName());
    velocityContext.put("ClassName", genTable.getClassName());
    velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName()));
    velocityContext.put("columns", genTable.getColumns());
    // 更多变量映射...
    return velocityContext;
}

这些变量将在模板文件中被引用,最终渲染出完整的Java代码、XML配置和HTML页面。

模板文件结构

RuoYi框架内置了丰富的Velocity模板文件,位于项目的vm目录下,按照生成的代码类型分类组织:

标准模板列表

通过VelocityUtils.getTemplateList()方法可以查看系统支持的模板类型:

public static List<String> getTemplateList(String tplCategory) {
    List<String> templates = new ArrayList<String>();
    templates.add("vm/java/domain.java.vm");      // 实体类模板
    templates.add("vm/java/mapper.java.vm");     // Mapper接口模板
    templates.add("vm/java/service.java.vm");    // Service接口模板
    templates.add("vm/java/serviceImpl.java.vm");// Service实现类模板
    templates.add("vm/java/controller.java.vm"); // 控制器模板
    templates.add("vm/xml/mapper.xml.vm");       // MyBatis映射文件模板
    // HTML模板根据不同类型添加
    if (GenConstants.TPL_CRUD.equals(tplCategory)) {
        templates.add("vm/html/list.html.vm");   // 列表页模板
    }
    // ...更多模板
    return templates;
}

模板文件位置

所有模板文件遵循统一的命名规范,存放在以下路径:

vm/
├── java/              # Java代码模板
│   ├── domain.java.vm       # 实体类
│   ├── mapper.java.vm       # Mapper接口
│   ├── service.java.vm      # Service接口
│   └── ...
├── xml/               # XML配置模板
│   └── mapper.xml.vm        # MyBatis映射文件
└── html/              # HTML页面模板
    ├── list.html.vm         # 列表页
    ├── add.html.vm          # 添加页
    └── edit.html.vm         # 编辑页

实战案例:自定义业务模板

案例1:扩展实体类模板

假设我们需要为所有生成的实体类添加创建时间和更新时间字段,并使用@JsonFormat注解格式化日期。

原模板代码(domain.java.vm)
package ${packageName}.domain;

#if(${hasBigDecimal})
import java.math.BigDecimal;
#end
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.common.core.domain.BaseEntity;

/**
 * ${functionName}对象 ${tableName}
 * 
 * @author ${author}
 * @date ${datetime}
 */
public class ${ClassName} extends BaseEntity
{
    private static final long serialVersionUID = 1L;

    #foreach($column in $columns)
    #if($column.isPk)
    /** 主键 */
    @Excel(name = "${column.columnComment}", cellType = Excel.ColumnType.NUMERIC)
    private ${column.javaType} ${column.javaField};

    #end
    #end

    #foreach($column in $columns)
    #if(!$column.isPk)
    /** ${column.columnComment} */
    #if($column.isExcel)
    @Excel(name = "${column.columnComment}"
    #if($column.readConverterExp)
    , readConverterExp = "${column.readConverterExp}"
    #end
    #if($column.dictType)
    , dictType = "${column.dictType}"
    #end
    )
    #end
    private ${column.javaType} ${column.javaField};

    #end
    #end

    #foreach($column in $columns)
    #getSetMethod($column)
    #end
}
自定义模板修改
  1. 添加创建时间和更新时间字段定义:
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;

/** 更新时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
  1. 在getter/setter方法区域添加对应方法:
public Date getCreateTime() {
    return createTime;
}

public void setCreateTime(Date createTime) {
    this.createTime = createTime;
}

public Date getUpdateTime() {
    return updateTime;
}

public void setUpdateTime(Date updateTime) {
    this.updateTime = updateTime;
}

案例2:自定义查询条件模板

RuoYi默认生成的列表查询只包含简单的等值查询,我们可以扩展mapper.xml.vm模板,添加范围查询条件:

<select id="select${ClassName}List" parameterType="${ClassName}Query" resultMap="${ClassName}Result">
    select #allColumnSql() from ${tableName}
    <where>
        #foreach($column in $columns)
        #if($column.isQuery)
        <if test="${column.javaField} != null 
            #if($column.javaType == 'String')
            and ${column.javaField} != ''
            #end
        ">
            #if($column.queryType == 'LIKE')
            AND ${column.columnName} LIKE CONCAT('%', #{${column.javaField}}, '%')
            #elseif($column.queryType == 'BETWEEN')
            AND ${column.columnName} BETWEEN #{${column.javaField}Start} AND #{${column.javaField}End}
            #else
            AND ${column.columnName} = #{${column.javaField}}
            #end
        </if>
        #end
        #end
    </where>
</select>

案例3:优化前端表格模板

默认的列表页表格只显示基础字段,我们可以修改list.html.vm模板,添加状态标签和操作按钮组:

<table id="bootstrap-table" class="table table-striped table-hover">
    <thead>
        <tr>
            #foreach($column in $columns)
            #if($column.isList)
            <th data-field="${column.javaField}" 
                #if($column.columnName == 'status')
                data-formatter="statusFormatter"
                #end
                >${column.columnComment}</th>
            #end
            #end
            <th data-field="operate" data-formatter="operateFormatter" data-events="operateEvents">操作</th>
        </tr>
    </thead>
</table>

<script>
// 状态格式化函数
function statusFormatter(value, row, index) {
    var color = value === '0' ? 'success' : 'danger';
    var text = value === '0' ? '正常' : '禁用';
    return '<span class="label label-' + color + '">' + text + '</span>';
}

// 操作按钮格式化函数
function operateFormatter(value, row, index) {
    return [
        '<a class="btn btn-primary btn-xs" href="javascript:edit(\'' + row.id + '\')">编辑</a>',
        '<a class="btn btn-danger btn-xs" href="javascript:remove(\'' + row.id + '\')">删除</a>'
    ].join('');
}
</script>

高级技巧:模板变量详解

Velocity模板中可以使用的变量主要来自VelocityUtils.prepareContext()方法的设置,常用变量包括:

表级变量

变量名含义示例
${tableName}数据库表名sys_user
${ClassName}实体类名SysUser
${className}实例变量名sysUser
${moduleName}模块名system
${businessName}业务名user
${packageName}包名com.ruoyi.system

列级变量

在遍历${columns}时可使用的字段:

#foreach($column in $columns)
${column.columnName}    // 数据库列名
${column.javaField}     // Java字段名
${column.javaType}      // Java类型
${column.columnComment} // 字段注释
${column.isPk}          // 是否主键
${column.isRequired}    // 是否必填
${column.queryType}     // 查询类型
#end

自定义变量扩展

如果内置变量不足以满足需求,可以在VelocityUtils.javaprepareContext()方法中添加自定义变量:

// 添加自定义变量
velocityContext.put("basePath", GenConfig.getBasePath());
velocityContext.put("copyright", "Copyright © 2025 RuoYi Framework");

然后在模板中直接使用:

/**
 * ${functionName}对象 ${tableName}
 * ${copyright}
 */
public class ${ClassName} extends BaseEntity {
    // ...
}

常见问题解决

模板不生效问题

  1. 检查模板路径:确保自定义模板放在正确的vm子目录下
  2. 清理缓存:RuoYi会缓存模板内容,修改后需重启应用或清理target目录
  3. 检查文件名:模板文件名必须以.vm为后缀,如domain.java.vm

变量未解析问题

当模板中出现${variable}原样输出时,通常是因为:

  1. 变量名拼写错误,如将${ClassName}误写为${classname}
  2. 上下文未设置该变量,需检查VelocityUtils.prepareContext()是否添加了对应变量
  3. 数据库表结构变更后未重新同步,需在代码生成页面点击"同步数据库"

代码格式错乱问题

Velocity模板对缩进敏感,建议:

  1. 使用空格而非Tab缩进
  2. 控制语句使用#foreach#end时保持统一缩进
  3. 复杂逻辑拆分到多个模板片段

总结与进阶

通过本文的学习,你已经掌握了RuoYi代码生成器的核心原理和模板自定义技巧。合理使用代码生成器可以将开发效率提升60%以上,让你从重复的CRUD工作中解放出来。

进阶学习路径

  1. 深入Velocity语法:学习宏定义(#macro)和指令(#parse)实现复杂模板逻辑
  2. 动态模板选择:通过GenTabletplCategory字段实现不同业务类型使用不同模板集
  3. 模板版本管理:将常用模板提交到Git进行版本控制,实现团队共享

实用资源

  • 官方模板参考:ruoyi-generator/src/main/resources/vm/目录下的所有模板文件
  • 数据库设计规范:RuoYi数据库设计指南
  • 在线Velocity测试工具:可用于验证模板语法正确性

现在就动手改造你的第一个模板吧!无论是添加统一的日志打印,还是实现复杂的业务逻辑生成,RuoYi代码生成器都能成为你提高开发效率的得力助手。

本文示例代码已同步至项目仓库,可在docs/code-generator-examples目录下查看完整案例。有任何问题欢迎在项目Issues中交流讨论。

【免费下载链接】RuoYi 🎉 基于SpringBoot的权限管理系统 易读易懂、界面简洁美观。 核心技术采用Spring、MyBatis、Shiro没有任何其它重度依赖。直接运行即可用 【免费下载链接】RuoYi 项目地址: https://gitcode.com/yangzongzhuan/RuoYi

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

抵扣说明:

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

余额充值