【然然管理系统】基于 SpringBoot+MyBatisPlus+Freemarker 实现代码生成功能(下)

然然管理系统仓库地址,欢迎移步仓库点个小星星
https://gitee.com/OceanCore/ranran.git
https://github.com/qiaoting/ranran.git

一、前言

上篇我们梳理了代码生成功能的整体架构和核心模块,本篇将深入每个核心技术点,拆解关键代码的实现逻辑,同时分析开发中的踩坑点与优化方向,让你不仅能 “用”,还能 “懂” 并 “改造”。

系统截图:

二、核心点解析

1. 数据库表 / 字段查询:精准获取元数据

代码生成的前提是精准获取数据库元数据,我们基于information_schema实现,核心逻辑如下:

  • 表查询逻辑:通过GeneratorTableMapper.xmlselectAllTable方法,支持动态指定数据库名(未指定则用当前库),使用 MyBatis 的choose-when-otherwise实现条件分支:

    xml

    <choose> <when test="dbName != null and dbName != ''"> AND table_schema = #{dbName} </when> <otherwise> AND table_schema = DATABASE() </otherwise> </choose>
  • 字段查询逻辑:重点是字段属性的映射(比如isPrimaryKey/isNullable),通过case when将数据库的字符串结果(yes/no/pri)转为布尔值,适配 Java 实体类的属性类型。

踩坑点information_schema的字段名是区分大小写的(如column_name),不同 MySQL 版本可能有字段差异。

2. 数据库类型→Java 类型:精准映射

这是代码生成的核心环节之一,错误的类型映射会导致生成的代码无法编译。我们通过GenerateConstant定义类型常量,在GeneratorTableFieldService中实现映射逻辑:

步骤 1:定义类型常量(GenerateConstant)
public static final Set<String> STRING_TYPE = Set.of("char", "varchar", "varchar2", "nvarchar"); public static final Set<String> LONG_TYPE = Set.of("bit", "bigint", "integer"); public static final Set<String> INTEGER_TYPE = Set.of("int", "tinyint", "smallint", "mediumint"); public static final Set<String> DATE_TIME_TYPE = Set.of("datetime", "time", "date", "timestamp");
步骤 2:实现映射逻辑(GeneratorTableFieldService)
public List<GeneratorTableField> fetchTableFields(String tableName) { List<GeneratorTableField> generatorTableFields = generatorTableFieldMapper.selectAllField(tableName); for (GeneratorTableField field : generatorTableFields) { if (GenerateConstant.LONG_TYPE.contains(field.getColumnType())) { field.setJavaType("Long"); } else if (GenerateConstant.INTEGER_TYPE.contains(field.getColumnType())) { field.setJavaType("Integer"); } else if (GenerateConstant.DATE_TIME_TYPE.contains(field.getColumnType())) { field.setJavaType("LocalDateTime"); } else if (GenerateConstant.STRING_TYPE.contains(field.getColumnType())) { field.setJavaType("String"); } else { // 兜底:未匹配的类型默认BigDecimal(如decimal、double) field.setJavaType("BigDecimal"); } } return generatorTableFields; }

优化点:可扩展支持 JSON 类型(映射为JSONObject)、Blob 类型(映射为byte[]),或通过配置文件实现类型映射,避免硬编码。

3. 表名→Java 类名:优雅的驼峰转换

表名通常是下划线格式(如sys_user),而 Java 类名是大驼峰格式(如SysUser),TableUtil实现了这一转换,还支持移除指定前缀:

核心代码(TableUtil.convert)
public static String convert(String tableName, String[] removePrefixes) { if (!StrUtil.hasText(tableName)) { throw new IllegalArgumentException("表名不能为空"); } String lowerTableName = tableName.toLowerCase(); // 移除指定前缀(如t_、sys_) if (ObjUtil.isNotNull(removePrefixes)) { for (String prefix : removePrefixes) { if (lowerTableName.startsWith(prefix.toLowerCase())) { lowerTableName = lowerTableName.substring(prefix.length()); break; } } } // 下划线转大驼峰 String[] words = lowerTableName.split("_"); StringBuilder className = new StringBuilder(); for (String word : words) { if (!word.isEmpty()) { className.append(Character.toUpperCase(word.charAt(0))) .append(word.substring(1).toLowerCase()); } } if (className.isEmpty()) { throw new RuntimeException("转换后的类名不能为空,表名:" + tableName); } return className.toString(); }

关键设计

  • 先统一转小写,避免大小写不一致导致前缀匹配失败;
  • 支持自定义移除前缀(比如多系统表前缀不同);
  • 严格的参数校验,避免空表名 / 转换后空类名导致的异常。

踩坑点:表名全是下划线(如_test)会导致转换后类名为空,需在业务层提前校验。

4. Freemarker:模板渲染生成代码

Freemarker 是模板引擎,核心是 “数据模型 + 模板文件→生成字符串”,我们封装了FreemarkerService实现模板渲染:

步骤 1:Freemarker 初始化(PostConstruct)
@PostConstruct public void init() { configuration = new Configuration(); try { // 模板文件放在resources/ftl目录下 configuration.setClassForTemplateLoading(this.getClass(), "/ftl"); configuration.setDefaultEncoding("UTF-8"); // 解决中文乱码 configuration.setClassicCompatible(true); // 兼容空值渲染 configuration.setNumberFormat("0.##"); // 数字格式化 } catch (Exception e) { throw new RuntimeException("初始化freemarker配置失败", e); } }

踩坑点:模板路径配置错误(比如写成/templates/ftl)会导致找不到模板,需确认setClassForTemplateLoading的路径是resources下的相对路径。

步骤 2:模板渲染核心方法
public String generateString(String templateName, ClassInfoDto classInfoDto) { try { Template template = configuration.getTemplate(templateName); Writer writer = new StringWriter(); template.process(classInfoDto, writer); // 数据模型注入模板 return writer.toString(); } catch (Exception e) { throw new RuntimeException("freemarker模板渲染失败:" + templateName, e); } }
步骤 3:多模板渲染(GeneratorService)
public Map<String, String> generateCode(ClassInfoDto classInfoDto) { // 查询表字段并映射类型 List<GeneratorTableField> fields = generatorTableFieldService.fetchTableFields(classInfoDto.getTableName()); Map<String, String> codeMap = new HashMap<>(); // 组装类信息(模块名、类名、基础包名等) GenerateUtil.buildClassInfo(classInfoDto, fields); // 渲染不同模板,生成各类代码 codeMap.put("entity.java", generateEntity(classInfoDto)); codeMap.put("mapper.java", generateMapper(classInfoDto)); codeMap.put("service.java", generateService(classInfoDto)); codeMap.put("controller.java", generateController(classInfoDto)); return codeMap; }

核心设计ClassInfoDto作为统一的数据模型,包含表名、模块名、作者、字段列表、类名等所有模板所需的信息,实现 “一份数据模型,多模板复用”。

三、扩展与优化思路

基于当前实现,可从以下维度优化,让代码生成器更通用:

  1. 模板自定义:将模板文件从 jar 包内移到配置目录,支持用户上传自定义模板(如适配不同编码规范);
  2. 批量生成:支持前端选择多个表,批量生成代码并打包为 ZIP 返回;
  3. 类型映射配置化:将类型映射关系写入 YAML 配置文件,避免硬编码,示例:

    yaml

    generator: type-mapping: char: String varchar: String bigint: Long # 扩展JSON类型 json: JSONObject
  4. 前缀移除优化:当前TableUtil中移除前缀时break只移除第一个匹配的前缀,可改为循环移除所有匹配前缀(比如表名sys_t_user,移除sys_t_);
  5. 代码格式化:生成代码后通过JavaFormatter格式化代码,保证代码风格统一;
  6. 导入包自动处理:比如生成LocalDateTime时自动导入java.time.LocalDateTime,避免手动导包。

四、踩坑与解决方案

问题场景解决方案
Freemarker 渲染中文注释乱码初始化时设置configuration.setDefaultEncoding("UTF-8"),模板文件保存为 UTF-8 编码
表名转换后类名为空增加参数校验,对特殊表名(如全下划线)抛出明确异常
数据库类型映射遗漏兜底设置为BigDecimal,并在日志中打印未匹配的类型,便于后续补充
模板路径找不到确认setClassForTemplateLoading的路径是resources/ftl,且模板文件存在
五、总结与展望

本文深入解析了然然管理系统代码生成功能的核心细节,从数据库元数据查询、类型映射、表名转换到 Freemarker 模板渲染,每个环节都体现了 “职责单一、通用可扩展” 的设计思想。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1149134.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2026年--Lc337-1372. 二叉树中的最长交错路径(树)--java版

1.题目2.思路 &#xff08;1&#xff09;思路&#xff1a; 可以用dfs&#xff0c;深度优先遍历&#xff0c;但是要符合先遍历左孩子再遍历左孩子的右孩子的规则&#xff1b;或者先遍历右孩子再遍历右孩子的左孩子。最后把路径上的节点个数-1&#xff0c;就是所得的节点个数。 但…

【然然管理系统】基于 SpringBoot+MyBatisPlus+Freemarker 实现代码生成功能(上)

然然管理系统仓库地址&#xff0c;欢迎移步仓库点个小星星 https://gitee.com/OceanCore/ranran.git https://github.com/qiaoting/ranran.git一、前言在后台管理系统开发中&#xff0c;CRUD 代码的编写占据了大量重复工作 —— 每个业务表都要写 Entity、Mapper、Service、Con…

分类模型压缩终极方案:云端量化蒸馏全流程

分类模型压缩终极方案&#xff1a;云端量化蒸馏全流程 引言 当你开发一个移动端APP时&#xff0c;是否遇到过这样的困境&#xff1a;需要集成一个图像分类功能&#xff0c;但模型体积太大&#xff0c;动辄几百MB&#xff0c;严重影响用户体验&#xff1f;或者尝试在本地训练轻…

【Java毕设源码分享】基于springboot+vue的高中学生素质评价档案系统的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

MiDaS模型性能优化:推理速度与精度平衡

MiDaS模型性能优化&#xff1a;推理速度与精度平衡 1. 引言&#xff1a;AI 单目深度估计的工程挑战 在计算机视觉领域&#xff0c;单目深度估计&#xff08;Monocular Depth Estimation&#xff09;是一项极具挑战性的任务——仅通过一张2D图像推断出场景中每个像素的相对距离…

MiDaS模型详解:轻量高效的秘密

MiDaS模型详解&#xff1a;轻量高效的秘密 1. 技术背景与问题提出 在计算机视觉领域&#xff0c;深度估计是实现3D空间感知的关键技术之一。传统方法依赖双目立体视觉或多传感器融合&#xff08;如LiDAR&#xff09;&#xff0c;但这些方案成本高、部署复杂&#xff0c;难以在…

如何让AI看懂产线缺陷?Qwen3-VL-WEBUI落地实践全解析

如何让AI看懂产线缺陷&#xff1f;Qwen3-VL-WEBUI落地实践全解析 在一条高速运转的SMT贴片生产线上&#xff0c;一块刚完成回流焊的PCB板被自动传送至视觉检测工位。摄像头瞬间抓拍高清图像——画面中某处焊点隐约泛着不规则的银光。传统算法或许只能标记“异常区域”&#xf…

支持实时语义分析的中文NER工具|Cyberpunk风格WebUI体验

支持实时语义分析的中文NER工具&#xff5c;Cyberpunk风格WebUI体验 1. 项目背景与技术价值 在信息爆炸的时代&#xff0c;非结构化文本数据如新闻、社交媒体内容、企业文档等呈指数级增长。如何从这些海量文本中快速提取关键信息&#xff0c;成为自然语言处理&#xff08;NL…

无需编码!用AI 智能实体侦测服务快速实现文本信息抽取

无需编码&#xff01;用AI 智能实体侦测服务快速实现文本信息抽取 在当今信息爆炸的时代&#xff0c;非结构化文本数据&#xff08;如新闻、报告、社交媒体内容&#xff09;占据了企业数据总量的80%以上。如何从这些杂乱无章的文字中自动提取出关键信息——比如人名、地名、机…

【Java毕设源码分享】基于springboot+vue的公司人事管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

单目深度估计进阶:MiDaS高级应用指南

单目深度估计进阶&#xff1a;MiDaS高级应用指南 1. 引言&#xff1a;从2D图像到3D空间感知的跃迁 在计算机视觉领域&#xff0c;单目深度估计&#xff08;Monocular Depth Estimation&#xff09;是一项极具挑战性但又极具实用价值的技术。传统方法依赖双目立体匹配或多帧运…

一键启动Qwen3-VL-4B-Instruct|WEBUI镜像让多模态模型开箱即用

一键启动Qwen3-VL-4B-Instruct&#xff5c;WEBUI镜像让多模态模型开箱即用 在多模态大模型快速演进的今天&#xff0c;如何将强大的视觉语言能力高效落地到实际应用中&#xff0c;已成为开发者和企业关注的核心问题。部署复杂、依赖繁多、环境配置门槛高&#xff0c;常常成为技…

基于MiDaS的深度感知:快速部署与使用

基于MiDaS的深度感知&#xff1a;快速部署与使用 1. 引言&#xff1a;AI 单目深度估计的现实意义 在计算机视觉领域&#xff0c;从单张2D图像中恢复3D空间结构一直是极具挑战性的任务。传统方法依赖多视角几何或激光雷达等硬件设备&#xff0c;成本高且部署复杂。近年来&…

基于UDS协议的Bootloader定制之旅

基于UDS协议的Bootloader定制 采用autosar架构的标准&#xff0c;DCM集成uds协议&#xff0c;可定制nxpS32K&#xff0c;tc275&#xff0c;tc1782&#xff0c;NXP5746,NXP5748系列等在汽车电子开发领域&#xff0c;基于UDS&#xff08;Unified Diagnostic Services&#xff09;…

简单理解:STM32 互补 PWM 死区时间,档位设计 + 原理 + 实操全解析

一、 死区档位 “多高 3 位值” 的设计本质DT 寄存器是 8 位&#xff08;bit0~bit7&#xff09;&#xff0c;被拆为 高 3 位&#xff08;档位位&#xff09; 低 5 位&#xff08;微调位&#xff09;&#xff0c;一个档位对应多个高 3 位值的核心目的是&#xff1a;在有限的 8 位…

Rembg模型架构深度解析:U2NET原理

Rembg模型架构深度解析&#xff1a;U2NET原理 1. 智能万能抠图 - Rembg 在图像处理与内容创作领域&#xff0c;自动去背景是一项高频且关键的需求。无论是电商商品图精修、社交媒体内容制作&#xff0c;还是AI艺术生成前的素材准备&#xff0c;精准、高效的背景移除技术都至关…

从零开始使用MiDaS:深度估计实战指南

从零开始使用MiDaS&#xff1a;深度估计实战指南 1. 引言&#xff1a;走进单目深度估计的世界 在计算机视觉领域&#xff0c;三维空间感知一直是实现智能交互、机器人导航和增强现实&#xff08;AR&#xff09;的核心能力。然而&#xff0c;传统深度感知依赖双目摄像头或多传…

单目深度估计MiDaS:安防监控场景实践案例

单目深度估计MiDaS&#xff1a;安防监控场景实践案例 1. 引言&#xff1a;AI单目深度估计在安防中的价值 随着智能安防系统的不断演进&#xff0c;传统的2D视频监控已难以满足对空间感知和行为理解的高阶需求。如何让摄像头“看懂”三维世界&#xff0c;成为提升异常检测、入…

MiDaS部署技巧:如何优化CPU环境下的推理速度

MiDaS部署技巧&#xff1a;如何优化CPU环境下的推理速度 1. 引言&#xff1a;AI 单目深度估计 - MiDaS 在计算机视觉领域&#xff0c;单目深度估计&#xff08;Monocular Depth Estimation&#xff09;是一项极具挑战性但又极具应用价值的技术。它允许AI仅通过一张2D图像推断…

从零部署Qwen2.5-7B:vLLM推理加速与Gradio界面集成

从零部署Qwen2.5-7B&#xff1a;vLLM推理加速与Gradio界面集成 1. 引言 随着大语言模型&#xff08;LLM&#xff09;在自然语言处理领域的广泛应用&#xff0c;如何高效部署并快速构建交互式应用成为开发者关注的核心问题。阿里云推出的 Qwen2.5-7B 是当前极具竞争力的开源大…