若依源码解析:代码生成ruoyi-generator

news/2024/4/18 18:48:25

文章目录

  • 摘要
  • 代码生成器的使用
    • 数据库连接配置
    • 数据库表设计
    • 代码生成器配置
      • 修改mybatis别名配置,增加对com.cyl包名的识别
      • 修改mybatis的mapper扫描包路径
    • 代码生成
    • 代码输出
    • 模板配置
  • 代码生成器原理
    • 模板引擎:Velocity
      • 使用Velocity模板引擎的一般流程
      • 模板语法
      • 上下文数据
    • information_schema
  • 源码解析
    • 导入表结构(com.ruoyi.generator.controller.GenController#importTableSave接口)
    • 生成代码(com.ruoyi.generator.controller.GenController#batchGenCode接口)
    • generatorCoded方法

摘要

若依的代码生成器模块(ruoyi-generator)可以根据数据库表的设计信息和配置的模板,自动生成相应的Java代码文件。代码生成器使用Velocity作为模板引擎,根据模板文件中的占位符和变量替换规则,将元数据信息嵌入到生成的代码中,生成具体的代码文件。通过导入表结构和生成代码两个后端接口,实现了快速导入数据库表结构和生成代码的功能。导入表结构会从information_schema数据库的tables和columns表中查询表和列的信息,并插入到ruoyi数据库的gen_table和gen_table_column表中。生成代码时,会根据查询到的表和列信息,初始化Velocity模板引擎,并准备上下文信息,包括变量值信息。然后,读取模板文件,渲染模板,并将渲染后的内容添加到压缩流中生成zip压缩文件,供前端下载使用。ruoyi-vue代码生成器大大提高了开发效率,使得开发人员能够快速生成符合规范的代码文件。

代码生成器的使用

通过以下步骤,若依可以根据数据库表的设计信息自动生成相应的代码文件,极大地提高了开发效率。开发人员可以根据生成的代码文件进行进一步的开发和定制。

以下是若依实现代码自动生成的一般流程:

数据库连接配置

首先,若依需要配置数据库连接信息,包括数据库类型、地址、用户名和密码等。
在这里插入图片描述

数据库表设计

在数据库中设计和定义表结构,包括表名、字段名、数据类型、约束等。
若依建表有个要求:表字段 和 表,都需要加注释,注释就是生成页面的显示内容

CREATE TABLE `goods` (`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',`GOODS_NAME` varchar(255) DEFAULT NULL COMMENT '商品名字',`put_way_flag` tinyint(1) DEFAULT NULL COMMENT '商品是否上架,0:下架,1:上架',`create_time` datetime DEFAULT NULL COMMENT '创建时间',`create_by` varchar(64) DEFAULT NULL COMMENT '创建人',`update_time` datetime DEFAULT NULL COMMENT '更新时间',`update_by` varchar(64) DEFAULT NULL COMMENT '更新人',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='商品表'

代码生成器配置

若依提供了一个代码生成器,通过application.yml配置文件可以设置生成器的参数,如生成路径、包名、作者等。

# 代码生成
gen: # 作者author: zcc# 默认生成包路径 system 需改成自己的模块名称 如 system monitor toolpackageName: com.cyl.pms# 自动去除表前缀,默认是falseautoRemovePre: false# 表前缀(生成类名不会包含表前缀,多个用逗号分隔)tablePrefix: pms_

另外,这里要使用自定义包名com.cyl.pms,所以若依系统中mybatis也要做相应的修改

修改mybatis别名配置,增加对com.cyl包名的识别

# MyBatis配置
mybatis:# 搜索指定包别名typeAliasesPackage: com.ruoyi.**.domain,com.cyl.**.domain

修改mybatis的mapper扫描包路径

修改com.ruoyi.framework.config.ApplicationConfig类的MapperScan注解,增加对com.cyl包的扫描

@MapperScan({"com.ruoyi.**.mapper","com.cyl.**.mapper"})
public class ApplicationConfig{...
}

代码生成

若依根据配置和模板,通过解析数据库表的元数据信息,自动生成对应的Java类、Mapper接口、Service类、Controller类等代码文件。
进入系统工具-代码生成页面,点击导入按钮,找到goods表并导入,如下图所示
在这里插入图片描述
点击编辑按钮之后,跳转修改生成配置页面。
在这里插入图片描述
在这里插入图片描述
点击生成代码按钮
在这里插入图片描述

代码输出

生成的代码文件可以输出到指定的目录中,可以选择直接写入磁盘文件或者打包成压缩文件。
生成的代码目录结构如下所示

├── goodsMenu.sql
├── main
│   ├── java
│   │   └── com
│   │       └── kdyzm
│   │           └── business
│   │               ├── controller
│   │               │   └── GoodsController.java
│   │               ├── domain
│   │               │   └── Goods.java
│   │               ├── mapper
│   │               │   └── GoodsMapper.java
│   │               └── service
│   │                   ├── IGoodsService.java
│   │                   └── impl
│   │                       └── GoodsServiceImpl.java
│   └── resources
│       └── mapper
│           └── business
│               └── GoodsMapper.xml
└── vue├── api│   └── business│       └── goods.js└── views└── business└── goods└── index.vue

模板配置

若依代码生成器支持三种数据格式模板的代码生成:单表、树表、主子表,一般默认使用的是单表模板,也是最常使用的模板。
在这里插入图片描述

代码生成器原理

模板引擎:Velocity

在若依(Ruoyi)项目的代码生成中,使用了Apache Velocity作为模板引擎来生成具体的代码。

使用Velocity模板引擎的一般流程

Velocity是一个Java模板引擎,它使用简单的模板语法和变量替换规则来生成文本输出。以下是若依项目中使用Velocity模板引擎的一般流程:

  1. 引入Velocity依赖:
    首先,在项目的构建文件中(如pom.xml)添加Velocity的依赖项,以便在代码中使用Velocity的相关类和方法。

  2. 获取模板:
    在代码生成过程中,若依会根据配置的模板文件路径,使用Velocity模板引擎获取指定的模板。通常,模板文件以.vm为后缀,如xxx.java.vm表示Java类的模板。

  3. 创建Velocity模板引擎对象:
    若依通过Velocity.getTemplate(template, charset)方法创建Velocity模板引擎对象。template参数是模板文件的路径,charset参数是模板文件的字符编码。

  4. 准备上下文数据:
    在代码生成过程中,若依会准备一些上下文数据,以便在模板中使用。这些数据通常包括表信息、字段信息和其他生成参数等。上下文数据被封装在一个context对象中,可以通过context.put(key, value)方法添加到上下文中。

  5. 渲染模板:
    使用Template.merge(context, writer)方法,将上下文数据应用于模板,并将渲染后的结果写入指定的输出writer中。在若依中,通常使用StringWriter作为输出的writer,以便将渲染后的代码保存为字符串。

  6. 获取渲染结果:
    通过StringWriter.toString()方法获取渲染后的代码字符串,即生成的具体代码。

  7. 输出代码:
    生成的代码可以输出到指定的路径或文件中。若依中使用FileUtils.writeStringToFile(file, content, charset)方法将代码字符串写入文件中。

模板语法

Velocity模板引擎使用简洁而强大的模板语法。在若依项目中,模板文件通常采用.java.vm的后缀,表示Java类的模板。在模板文件中,可以使用Velocity的标签、变量和指令来定义动态内容和控制流程。

一些常用的Velocity模板语法包括:

  • 变量替换:使用${variable}来引用变量。
  • 条件语句:使用#if#elseif#else来控制条件判断。
  • 循环语句:使用#foreach来进行循环迭代。
  • 宏定义:使用#macro来定义可重用的宏。
  • 注释:使用##进行单行注释。

上下文数据

在代码生成过程中,若依会准备上下文数据,用于传递给Velocity模板引擎。上下文数据通常包括表信息、字段信息和其他生成参数等。这些数据被封装在一个context对象中,可以使用context.put(key, value)方法将数据添加到上下文中。

在模板中,可以通过${key}的形式引用上下文中的数据。例如,${table.name}表示引用上下文中表名的值。

information_schema

MySQL数据库中的information_schema数据库是MySQL的系统数据库之一,它包含了关于数据库、表、列等元数据信息的表。在代码生成器中,正是利用了information_schema数据库中的TABLES表和COLUMNS表来获取数据库表的信息,从而实现代码的生成。

  1. TABLES表:
    TABLES表存储了数据库中所有表的信息,包括表名、表所属的数据库、表的引擎类型、创建时间、更新时间等。通过查询TABLES表,代码生成器可以获取到需要生成代码的表的相关信息,如表名、表所在的数据库等。

  2. COLUMNS表:
    COLUMNS表存储了数据库中所有表的列信息,包括列名、数据类型、列的默认值、是否允许为空、字符集等。通过查询COLUMNS表,代码生成器可以获取到需要生成代码的表的列信息,如列名、数据类型等。

通过查询TABLES表和COLUMNS表,代码生成器可以获得数据库表的设计信息,包括表名、列名、数据类型等。这些信息可以用于生成代码文件,例如生成实体类的属性、Mapper接口的方法等。通过结合模板引擎,将这些数据库表的设计信息嵌入到模板中,就可以自动生成具体的Java代码文件。

代码生成器利用information_schema数据库中的TABLES表和COLUMNS表,提供了一种便捷的方式来获取数据库表的结构信息,使得生成的代码与数据库表的设计保持一致,减少了手动编写代码的工作量,并提高了代码的一致性和可维护性。

源码解析

在ruoyi-vue项目的ruoyi-generator模块中,代码生成器相关的代码实现了以下步骤。
通过以下步骤,ruoyi-vue代码生成器可以根据数据库表的结构信息和模板文件,生成具体的代码文件。导入表结构步骤将表和列信息存储到数据库中,生成代码步骤则利用这些信息和模板进行代码的生成和打包。这样可以实现代码的快速生成和下载,提高开发效率。

导入表结构(com.ruoyi.generator.controller.GenController#importTableSave接口)

@PreAuthorize("@ss.hasPermi('tool:gen:import')")@Log(title = "代码生成", businessType = BusinessType.IMPORT)@PostMapping("/importTable")public AjaxResult importTableSave(String tables){String[] tableNames = Convert.toStrArray(tables);// 查询表信息List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames);genTableService.importGenTable(tableList, SecurityUtils.getUserId());return AjaxResult.success();}
  • 通过查询information_schema数据库的tables表,获取目标表的表名、表注释、创建时间和更新时间。这里忽略了定时任务的表和已经生成过的表。
  • 初始化表数据,并将数据插入ruoyi数据库的gen_table表中。
  • 通过查询information_schema数据库的columns表,获取目标表的列信息,包括字段名、字段注释、字段类型、是否允许为null等详细信息。
  • 初始化列信息,并将数据插入ruoyi数据库的gen_table_column表中。

生成代码(com.ruoyi.generator.controller.GenController#batchGenCode接口)

@PreAuthorize("@ss.hasPermi('tool:gen:code')")@Log(title = "代码生成", businessType = BusinessType.GENCODE)@GetMapping("/batchGenCode")public void batchGenCode(HttpServletResponse response, String tables) throws IOException{String[] tableNames = Convert.toStrArray(tables);byte[] data = genTableService.downloadCode(tableNames);genCode(response, data);}
  • 从ruoyi数据库的gen_table表和gen_table_column表中查询出生成代码所需的表和列信息。
  • 初始化Velocity模板引擎。
  • 准备Velocity上下文信息,包括变量值信息。上下文中存储了从数据库查询到的表和列信息,以及其他生成参数。
  • 读取模板文件,渲染模板,并将渲染后的模板内容添加到压缩流中,最后生成zip压缩文件供前端下载。

generatorCoded方法

/*** 生成代码(自定义路径)** @param tableName 表名称*/@Overridepublic void generatorCode(String tableName) {// 查询表信息GenTable table = genTableMapper.selectGenTableByName(tableName);Result result = getResult(table);for (String template : result.templates) {if (template.endsWith(".java.vm")) {result.context.put("fullPackage", getFullPackage(template));}// 渲染模板StringWriter sw = new StringWriter();Template tpl = Velocity.getTemplate(template, Constants.UTF8);tpl.merge(result.context, sw);String path = null;try {path = generatePath(template, table);File file = new File(path);FileUtils.writeStringToFile(file, sw.toString(), CharsetKit.UTF_8);log.info("{}", file.getAbsoluteFile());} catch (IOException e) {throw new ServiceException("渲染模板失败,表名:" + table.getTableName() + ", path: " + path);}}}

这段代码是在若依(Ruoyi)项目的代码生成器中的一个方法,用于生成代码并写入文件。

具体解释如下:

  1. 方法签名:
    public void generatorCode(String tableName)

    该方法接受一个参数 tableName,表示要生成代码的表名。

  2. 查询表信息:
    GenTable table = genTableMapper.selectGenTableByName(tableName);

    通过 genTableMapper(数据访问层)根据表名查询数据库中的表信息,并将结果保存在 GenTable 对象 table 中。

  3. 获取模板结果:
    Result result = getResult(table);

    通过调用 getResult 方法,根据查询到的表信息 table,获取生成代码所需的模板文件和上下文数据,结果保存在 Result 对象 result 中。

  4. 遍历模板文件:
    for (String template : result.templates)

    遍历 result 中的模板文件列表。

  5. 处理 Java 模板:

    if (template.endsWith(".java.vm")) {result.context.put("fullPackage", getFullPackage(template));
    }
    

    如果模板文件以 .java.vm 结尾,表示为 Java 类的模板文件。将生成的代码所属的包名(通过 getFullPackage 方法获取)放入上下文数据 result.context 中。

  6. 渲染模板:

    StringWriter sw = new StringWriter();
    Template tpl = Velocity.getTemplate(template, Constants.UTF8);
    tpl.merge(result.context, sw);
    

    使用 Velocity 模板引擎,根据模板文件和上下文数据,将模板渲染为具体的代码,结果保存在 StringWriter 对象 sw 中。

  7. 生成文件:

    String path = generatePath(template, table);
    File file = new File(path);
    FileUtils.writeStringToFile(file, sw.toString(), CharsetKit.UTF_8);
    

    根据模板文件和表信息,生成代码文件的路径。然后创建文件对象 file,将渲染后的代码内容写入文件中。

  8. 日志输出:
    log.info("{}", file.getAbsoluteFile());

    输出生成的代码文件的绝对路径。

  9. 异常处理:

    } catch (IOException e) {throw new ServiceException("渲染模板失败,表名:" + table.getTableName() + ", path: " + path);
    }
    

    如果在渲染模板和生成文件的过程中发生了异常,抛出自定义的 ServiceException 异常,并提供失败的表名和路径信息。

通过以上步骤,这段代码会根据表名查询表信息,获取模板文件和上下文数据,然后遍历模板文件,将模板渲染为具体的代码,最后生成代码文件并写入磁盘。


http://www.ppmy.cn/news/101262.html

相关文章

Java设计模式-解释器模式

简介 设计模式是软件开发中重要的概念之一&#xff0c;它们为我们提供了可重用、灵活和可扩展的解决方案。在Java领域中&#xff0c;解释器模式是一种强大的设计模式&#xff0c;它能够将复杂的问题拆分成简单的表达式&#xff0c;并提供一种灵活的方式来解释和执行这些表达式…

律师使用ChatGPT 进行法律文献检索提交了错误信息;李开复表示,威力强大的大模型将彻底变革人工智能

&#x1f680; 一名律师使用ChatGPT 进行法律文献检索提交了错误信息 近日&#xff0c;一名律师在法庭案件中使用聊天机器人 ChatGPT 进行法律文献检索&#xff0c;结果提交了错误信息&#xff0c; 揭示了人工智能在法律领域的潜在风险&#xff0c;包括误传错误信息。 该事件…

数字化时代,企业面临哪些共同的挑战?

在这种全新的社会、商业环境下&#xff0c;各行各业的企业都开始寻求探索新的商业模式&#xff0c;通过转型适应当前时代的转变&#xff0c;促进业务健康持续的发展。所以数字化成为了企业进行转型的工具&#xff0c;也成为了众多领域内企业对未来的共识。 一、管理挑战 ●经…

Logisim 头歌 偶校验编码设计图解及代码(计算机组成原理)

努力是为了不平庸~ 学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。 急的同学请直接点击目录跳到下方解答处&#xff01;&#xff01; 目录 图解&#xff1a; 代码题解&#xff08;免费&#xff09;&#xff1a; 实…

做外贸算运费的时候需不需要多算一些

看到一个网友在一篇文章下留言说&#xff1a;客户算运费的时候需不需要多算一些 听公司老员工说给客户算运费要多加20% 这样合适吗 我个人感觉有点离谱。 那我们就这个话题&#xff0c;谈一谈运费是否要多加一些呢&#xff1f;为什么要多加一些&#xff1f; 首先&#xff0c;要…

swagger页面 doc.html出不来,swagger-ui/index.html能出来

swagger页面 doc.html出不来&#xff0c;swagger-ui/index.html能出来。前前后后折腾了很久&#xff0c;jar包冲突&#xff0c;jar包版本&#xff0c;添加路径啥的都弄了&#xff0c;就是出不来。 后来全局搜索“doc.html”页面发现能出来的项目能搜到这个页面&#xff1a; 定…

springboot+vue+java旅行旅游景点酒店预订出行订票系统eaog5

线上旅行信息管理系统要求实现以下功能&#xff1a; a.景点管理&#xff0c;展示景点的基础信息&#xff0c;介绍等信息。 b.酒店管理,展示酒店的基础信息&#xff0c;介绍等信息。 c.评价管理&#xff0c;可以查看景点或酒店的相关评价信息&#xff0c;客户消费完&#xff0c;…

实时频谱-3.1实时频谱分析仪测量

RSA 测量类型 泰克RSA 可以在频域、时域、调制域和统计域中工作。 频域测量 基本频域测量是实时 RF 数字荧光显示(DPX)频谱显示测量、频谱显示测量和频谱图显示测量功能。 DPX 频谱 DPX 频谱测量对 RSA 发现其它分析仪漏掉的难检信号的能力至关重要。在所有泰克 RSA 中&am…

《面向对象程序设计》实践任务书

《面向对象程序设计》实践任务书 一、基本要求 &#xff08;1&#xff09;要求利用面向对象的方法以及c编程语言来完成系统的设计&#xff1b; &#xff08;2&#xff09;要求在设计的过程中&#xff0c;建立清晰的类层次&#xff1b; &#xff08;3&#xff09;自行设计文件保…

electron-vue 运行报错 Object.fromEntries is not a function

文章目录 1. 背景2. 解决方案2.1 第一步&#xff1a;安装依赖2.2 第二步&#xff1a;项目中引入 3. 组件详解 1. 背景 最近研究一款桌面端应用的开发框架electron-vue&#xff0c;在按照 electron-vue官方文档 操作之后操作如下&#xff0c;Object.fromEntries is not a funct…

C语言编程 7-12 日期格式化

世界上不同国家有不同的写日期的习惯。比如美国人习惯写成“月-日-年”&#xff0c;而中国人习惯写成“年-月-日”。下面请你写个程序&#xff0c;自动把读入的美国格式的日期改写成中国习惯的日期。 输入格式&#xff1a; 输入在一行中按照“mm-dd-yyyy”的格式给出月、日、年…

从0到整写一个Mini-Spring/Web框架实现基础的功能

文章持续更新中… 1. 针对于Spring/Web的执行流程 配置阶段 1.1 配置Web.xml —> 我们自己写的DispatcherServlet 1.2 设定init-param —> contextConfigLocation classpath:application.properties 1.3 设定url-pattern —> /* 1.4 配置Annotation —> XXCOntro…

汽车和地铁的无人驾驶了解

01汽车无人驾驶技术 汽车相对地铁列车&#xff0c;控制设备的安装空间较为有限&#xff0c;不同车辆的个体差异较大&#xff0c;其无人驾驶技术的实现方案需要更简约&#xff0c;主流的方案通常是通过多种车载传感器&#xff08;如摄像头、激光雷达、毫米波雷达、北斗/GPS、惯性…

基于springboot注解的shiro 授权及角色认证

目录 授权 后端接口服务注解 授权验证-没有角色无法访问 授权验证-获取角色进行验证 授权验证-获取权限进行验证 授权验证-异常处理 授权 用户登录后&#xff0c;需要验证是否具有指定角色指定权限。Shiro也提供了方便的工具进行判 断。 这个工具就是Realm的doGetAuthor…

C++ 异步编程

1. 异步编程含义及作用 相对于同步编程方式时&#xff0c;由于每个线程同时只能发起一个请求并同步等待返回&#xff0c;所以为了提高系统性能&#xff0c;此时我们就需要引入更多的线程来实现并行化处理。但是 多线程下对共享资源进行访问时&#xff0c;不可避免会引入资源争用…

Spring Boot启动流程

1 Springboot 启动流程 创建一个StopWatch实例&#xff0c;用来记录SpringBoot的启动时间。 通过SpringFactoriesLoader加载listeners&#xff1a;比如EventPublishingRunListener。 发布SprintBoot开始启动事件&#xff08;EventPublishingRunListener#starting()&#xff0…

使用 Elastic Learned Sparse Encoder 和混合评分的卓越相关性

作者&#xff1a;The Elastic Platform team 2023 年 5 月 25 今天&#xff0c;我们很高兴地宣布 Elasticsearch 8.8 正式发布。 此版本为矢量搜索带来了多项关键增强功能&#xff0c;让开发人员无需付出通常的努力和专业知识即可在搜索应用程序中利用一流的 AI 驱动技术。 使…

Qt文件系统源码分析—第七篇QFileSelector

深度 本文主要分析Windows平台&#xff0c;Mac、Linux暂不涉及 本文只分析到Win32 API/Windows Com组件/STL库函数层次&#xff0c;再下层代码不做探究 本文QT版本5.15.2 类关系图 QTemporaryFile继承QFile QFile、QSaveFile继承QFileDevice QFileDevice继承QIODevice Q…

NoSQL Redis之配置与优化

Redis 数据类型 ---------------------- String数据类型 ---------------------------------------- 概述&#xff1a;String是redis最基本的类型&#xff0c;最大能存储512MB的数据&#xff0c;String类型是二进制安全的&#xff0c;即可以存储任何数据、比如数字、图片、序列…

06- AOP(实现案例:记录日志操作)

目录 1. 通知类型 2. 通知顺序 3. 切入点表达式 execution() annotation() 4. 连接点&#xff08;JoinPoint&#xff09; 5. 案例&#xff1a;将CRUD接口的相关操作记录到数据库中 AOP: Aspect Oriented Programming (面向切面编程、面向方面编程)&#xff0c;其实就是…