mirror of
https://github.com/moshowgame/SpringBootCodeGenerator.git
synced 2026-10-21 09:30:45 +08:00
古法编程·非遗传承
This commit is contained in:
20
README.md
20
README.md
@@ -6,6 +6,7 @@
|
||||

|
||||

|
||||

|
||||
[](#description)
|
||||
[](https://github.com/moshowgame/SpringBootCodeGenerator/actions/workflows/maven.yml)
|
||||
|
||||
# Author
|
||||
@@ -34,11 +35,20 @@
|
||||
> 📦 **One-click ZIP download** — package all generated code into a structured ZIP in one click\
|
||||
> 📦 **一键 ZIP 打包下载** — 按模板分组自动归档,告别逐个文件复制
|
||||
|
||||
> 🙏 Thanks for your continued support! BeJSON once peaked at 1.5K daily PV 👀, and now maintains a steady flow of around 600 visits — plus 2K+ GitHub Stars ✨. Your feedback remains our greatest motivation to keep improving!
|
||||
> ❤️ 感谢大家一直以来的支持!BeJSON 曾创下日均访问量 1.5K 👀 的高峰,目前稳定在约 600 左右,GitHub Star 数也已突破 2K ✨。你们的反馈始终是我们不断前进的最大动力!
|
||||
> 🏺 In the age of AI vibe coding, every line of these templates is still handcrafted — traditional code craft, certified intangible cultural heritage\
|
||||
> 🏺 AI vibe coding 时代,本项目的模板依然坚持手搓:开启「🏺 古法印章」,生成的每份代码都会带上一枚非遗传承手作印章,ZIP 包内附《手工代码认证书》——致敬每一位古法编程非遗传承者!
|
||||
|
||||
> 🌈 Wishing everyone balance, health, and success — may your code be bug-free and your coffee strong ☕\
|
||||
> 💬 祝大家工作顺利,生活平衡,身体健康,步步高升,代码无 bug,咖啡够劲!
|
||||
> ### 🐺 写在 AI 时代
|
||||
>
|
||||
> 大狼狗代码生成器诞生于 2018 年,彼时 AI 写代码还是科幻。数万开发者使用过它,数千颗 Star 见证了它的成长。
|
||||
>
|
||||
> 如今 AI 浪潮滚滚而来,我们选择不追逐风口,而是回归本质:
|
||||
>
|
||||
> - **工具的价值**,在于服务人,而非替代人;
|
||||
> - **代码的价值**,在于解决问题,而非堆砌行数;
|
||||
> - **开发者的价值**,在于思考与判断,而非手速与复制。
|
||||
>
|
||||
> 感谢每一位使用过大狼狗的朋友。愿你在 AI 时代,既有工具的效率,也有匠人的定力。🙏
|
||||
|
||||
> 📬 Feel free to submit issues, share useful templates, or contribute your brilliant ideas via PR\
|
||||
> 🤝 欢迎提交问题、分享常用模板,或将你的灵感通过 PR 实现!
|
||||
@@ -309,7 +319,7 @@ ResultVo.error(message);
|
||||
|
||||
| 更新日期 | 更新内容 |
|
||||
| :--------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| 2026.09.09 | 🎨 前端全面重构为 jQuery3 + Bootstrap 5.3 + CodeMirror 5:全新 `newui3` 现代化界面,`data-bs-theme` 原生深/浅色模式(CodeMirror 双主题跟随),输出区按模板类型动态切换语法高亮(Java/XML/SQL/JSON/JS);新增 `app.js` 独立命名空间 `CodeGenApp`(与旧版 main.js 零冲突),补齐本地 mode 文件(sql/clike/xml/javascript);新增🏺古法印章开关(isHeritage,致敬古法编程非遗传承者);模板选择区改为组内联布局,`template.json` 支持 `tier` 字段分级(main 常驻 / legacy 折叠),折叠与选中状态 localStorage 记忆;修复 JDK23+ 下 Lombok 注解处理不生效的编译问题; |
|
||||
| 2026.09.09 | 🎨 前端全面重构为 jQuery3 + Bootstrap 5.3 + CodeMirror 5:全新 `newui3` 现代化界面,`data-bs-theme` 原生深/浅色模式(CodeMirror 双主题跟随),输出区按模板类型动态切换语法高亮(Java/XML/SQL/JSON/JS);新增 `app.js` 独立命名空间 `CodeGenApp`(与旧版 main.js 零冲突),补齐本地 mode 文件(sql/clike/xml/javascript);新增🏺古法印章开关(isHeritage,致敬古法编程非遗传承者);模板选择区改为组内联布局,`template.json` 支持 `tier` 字段分级(main 常驻 / legacy 折叠),折叠与选中状态 localStorage 记忆;修复 JDK23+ 下 Lombok 注解处理不生效的编译问题;🏺非遗传承后端落地:`HeritageUtil` 按内容嗅探+后缀适配注释语法盖章(Java/JS/QVS 用 `//`,SQL 用 `--`,YAML 用 `#`,XML/Vue/HTML 在声明后插 `<!-- -->`,JSON 不盖章),ZIP 首条目附《手工代码认证书》;修正 `template.json` 中 `swagger-ui`/`beanutil`/`qliksense` 三个模板 fileName 后缀与实际内容类型不符的问题,并修复 ZIP 包误将 `tableName` 字段打成伪文件的 bug; |
|
||||
| 2026.06.02 | 📦 新增"一键 ZIP 打包下载"功能:在生成按钮旁新增独立下载按钮,按模板 group 自动分目录打包成 ZIP;<br>支持 `template.json` 中 `fileName` 字段(含 `${className}` 占位符),智能推断文件后缀; |
|
||||
| 2025.12.09 | 优化Mybatis和Mybatis-Plus模板 |
|
||||
| 2025.12.08 | 引入单元测试和JaCoCo测试覆盖率,优化代码覆盖率 [UNIT\_TEST\_DOCUMENT.md](UNIT_TEST_DOCUMENT.md) |
|
||||
|
||||
@@ -6,6 +6,8 @@ import com.softdev.system.generator.entity.dto.ParamInfo;
|
||||
import com.softdev.system.generator.entity.vo.ResultVo;
|
||||
import com.softdev.system.generator.service.CodeGenService;
|
||||
import com.softdev.system.generator.service.ZipService;
|
||||
import com.softdev.system.generator.util.HeritageUtil;
|
||||
import com.softdev.system.generator.util.MapUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
@@ -66,7 +68,7 @@ public class CodeGenController {
|
||||
result.getFileNameTemplates(),
|
||||
result.getGroupByTemplate(),
|
||||
zipName,
|
||||
buildContext(result)
|
||||
buildContext(result, paramInfo.getOptions())
|
||||
);
|
||||
|
||||
String encoded = URLEncoder.encode(zipName + ".zip", StandardCharsets.UTF_8)
|
||||
@@ -95,12 +97,14 @@ public class CodeGenController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造 ZIP 解析占位符所需的上下文
|
||||
* 构造 ZIP 解析占位符所需的上下文(含非遗传承印章开关与作者)
|
||||
*/
|
||||
private Map<String, Object> buildContext(CodeGenResult result) {
|
||||
private Map<String, Object> buildContext(CodeGenResult result, Map<String, Object> options) {
|
||||
Map<String, Object> ctx = new HashMap<>();
|
||||
ctx.put("className", result.getClassName() == null ? "" : result.getClassName());
|
||||
ctx.put("tableName", result.getTableName() == null ? "" : result.getTableName());
|
||||
ctx.put("isHeritage", HeritageUtil.isEnabled(options));
|
||||
ctx.put("author", MapUtil.getString(options, "authorName"));
|
||||
return ctx;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import com.softdev.system.generator.service.TemplateService;
|
||||
import com.softdev.system.generator.service.parser.JsonParserService;
|
||||
import com.softdev.system.generator.service.parser.SqlParserService;
|
||||
import com.softdev.system.generator.util.FreemarkerUtil;
|
||||
import com.softdev.system.generator.util.HeritageUtil;
|
||||
import com.softdev.system.generator.util.MapUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -70,6 +71,7 @@ public class CodeGenServiceImpl implements CodeGenService {
|
||||
|
||||
generatedCode.put("tableName", MapUtil.getString(params, "tableName"));
|
||||
|
||||
boolean heritage = HeritageUtil.isEnabled(params);
|
||||
JSONArray parentTemplates = templateService.getAllTemplates();
|
||||
for (int i = 0; i < parentTemplates.size(); i++) {
|
||||
JSONObject parentTemplateObj = parentTemplates.getJSONObject(i);
|
||||
@@ -81,6 +83,9 @@ public class CodeGenServiceImpl implements CodeGenService {
|
||||
String templateName = childTemplate.getString("name");
|
||||
String templatePath = group + "/" + templateName + ".ftl";
|
||||
String generatedText = FreemarkerUtil.processString(templatePath, params);
|
||||
if (heritage) {
|
||||
generatedText = HeritageUtil.stamp(childTemplate.getString("fileName"), generatedText);
|
||||
}
|
||||
generatedCode.put(templateName, generatedText);
|
||||
fileNameTemplates.put(templateName, childTemplate.getString("fileName"));
|
||||
groupByTemplate.put(templateName, group);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.softdev.system.generator.service.impl;
|
||||
|
||||
import com.softdev.system.generator.service.ZipService;
|
||||
import com.softdev.system.generator.util.HeritageUtil;
|
||||
import com.softdev.system.generator.util.ZipFileNameResolver;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -9,8 +10,10 @@ import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
@@ -40,10 +43,21 @@ public class ZipServiceImpl implements ZipService {
|
||||
Set<String> usedPaths = new HashSet<>();
|
||||
try (ZipOutputStream zos = new ZipOutputStream(baos)) {
|
||||
zos.setLevel(java.util.zip.Deflater.BEST_SPEED);
|
||||
// 🏺 非遗传承:手工代码认证书作为 ZIP 首个条目
|
||||
if (HeritageUtil.isEnabled(context)) {
|
||||
List<String> templateNames = generatedCode.keySet().stream()
|
||||
.filter(name -> !"tableName".equals(name))
|
||||
.collect(Collectors.toList());
|
||||
String certificate = HeritageUtil.buildCertificate(
|
||||
stringOf(context, "className"), stringOf(context, "tableName"),
|
||||
stringOf(context, "author"), templateNames);
|
||||
writeEntry(zos, "手工代码认证书.txt", certificate);
|
||||
}
|
||||
for (Map.Entry<String, String> entry : generatedCode.entrySet()) {
|
||||
String templateName = entry.getKey();
|
||||
String content = entry.getValue();
|
||||
if (content == null) {
|
||||
// tableName 是返回给前端的结构化字段,不是代码文件
|
||||
if (content == null || "tableName".equals(templateName)) {
|
||||
continue;
|
||||
}
|
||||
String fileNameTpl = fileNameTemplates == null ? null : fileNameTemplates.get(templateName);
|
||||
@@ -67,6 +81,14 @@ public class ZipServiceImpl implements ZipService {
|
||||
zos.closeEntry();
|
||||
}
|
||||
|
||||
private String stringOf(Map<String, Object> context, String key) {
|
||||
if (context == null || key == null) {
|
||||
return "";
|
||||
}
|
||||
Object value = context.get(key);
|
||||
return value == null ? "" : value.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造 entry 路径;遇到重名时加 _1 / _2 ...
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
package com.softdev.system.generator.util;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 🏺 非遗传承工具:为生成的代码加盖手作印章,并生成手工代码认证书
|
||||
* <p>
|
||||
* 在 AI vibe coding 的时代,每一行模板都坚持手搓,致敬古法编程非遗传承者。
|
||||
*
|
||||
* @author zhengkai.blog.csdn.net
|
||||
*/
|
||||
public final class HeritageUtil {
|
||||
|
||||
private static final String LINE_1 = "🏺 古法编程·非遗传承 | Traditional Code Craft since 2018";
|
||||
private static final String LINE_2 = "本代码由手作模板工艺生成,非 AI vibe coding 之作 | Handcrafted, not AI-generated.";
|
||||
|
||||
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
private HeritageUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* isHeritage 是否启用;未显式关闭(false)时默认开启
|
||||
*/
|
||||
public static boolean isEnabled(Map<String, Object> params) {
|
||||
Object flag = params == null ? null : params.get("isHeritage");
|
||||
return flag == null || Boolean.TRUE.equals(flag) || "true".equalsIgnoreCase(String.valueOf(flag));
|
||||
}
|
||||
|
||||
/**
|
||||
* 在文件头部盖手作印章;JSON 等不支持注释的文件类型原样返回
|
||||
*
|
||||
* @param fileName 模板配置中的目标文件名(用于推断注释语法,可能不准,仅作兜底)
|
||||
* @param content 生成的代码文本
|
||||
*/
|
||||
public static String stamp(String fileName, String content) {
|
||||
if (content == null || content.isEmpty()) {
|
||||
return content;
|
||||
}
|
||||
// 内容嗅探优先:模板配置的 fileName 可能与实际内容类型不符(如 mapper 标为 .java 实为 XML)
|
||||
String trimmed = content.trim();
|
||||
if (trimmed.startsWith("<")) {
|
||||
return stampAsXmlComment(content);
|
||||
}
|
||||
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
||||
return content;
|
||||
}
|
||||
switch (extensionOf(fileName)) {
|
||||
case "java":
|
||||
case "jjs":
|
||||
case "js":
|
||||
case "qvs":
|
||||
return "// " + LINE_1 + "\n// " + LINE_2 + "\n" + content;
|
||||
case "sql":
|
||||
return "-- " + LINE_1 + "\n-- " + LINE_2 + "\n" + content;
|
||||
case "yml":
|
||||
case "yaml":
|
||||
case "properties":
|
||||
case "txt":
|
||||
return "# " + LINE_1 + "\n# " + LINE_2 + "\n" + content;
|
||||
case "xml":
|
||||
case "html":
|
||||
case "vue":
|
||||
case "md":
|
||||
return stampAsXmlComment(content);
|
||||
default:
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 手工代码认证书(ZIP 彩蛋)
|
||||
*/
|
||||
public static String buildCertificate(String className, String tableName, String author, List<String> templateNames) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("🏺 手工代码认证书\n");
|
||||
sb.append("CERTIFICATE OF HANDCRAFTED CODE\n");
|
||||
sb.append("================================================================\n\n");
|
||||
sb.append("兹证明\n\n");
|
||||
sb.append(" ").append(safe(className)).append("(表 ").append(safe(tableName)).append(")的 ")
|
||||
.append(templateNames == null ? 0 : templateNames.size()).append(" 份代码\n");
|
||||
sb.append(" 均由「古法编程·非遗传承」工艺生成。\n\n");
|
||||
sb.append("模板清单:\n");
|
||||
if (templateNames != null) {
|
||||
for (String name : templateNames) {
|
||||
sb.append(" · ").append(name).append('\n');
|
||||
}
|
||||
}
|
||||
sb.append('\n');
|
||||
sb.append("工匠:").append(author == null || author.trim().isEmpty() ? "Anonymous" : author.trim()).append('\n');
|
||||
sb.append("时间:").append(LocalDateTime.now().format(TIME_FORMATTER)).append('\n');
|
||||
sb.append("工艺:Freemarker 手作模板 + 自研/JSqlParser 双解析引擎\n\n");
|
||||
sb.append("在 AI vibe coding 的时代,\n");
|
||||
sb.append("每一行模板都坚持手搓。\n");
|
||||
sb.append("—— 致敬所有古法编程非遗传承者 🙏\n\n");
|
||||
sb.append("Powered by SpringBootCodeGenerator (2018 - 至今)\n");
|
||||
sb.append("https://github.com/moshowgame/SpringBootCodeGenerator/\n");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* XML 声明必须位于文档最前,印章插在声明之后
|
||||
*/
|
||||
private static String stampAsXmlComment(String content) {
|
||||
if (content.startsWith("<?xml")) {
|
||||
int end = content.indexOf("?>");
|
||||
if (end > 0) {
|
||||
String prolog = content.substring(0, end + 2) + "\n";
|
||||
return prolog + "<!--\n " + LINE_1 + "\n " + LINE_2 + "\n-->\n" + content.substring(end + 2);
|
||||
}
|
||||
}
|
||||
return "<!--\n " + LINE_1 + "\n " + LINE_2 + "\n-->\n" + content;
|
||||
}
|
||||
|
||||
private static String extensionOf(String fileName) {
|
||||
if (fileName == null) {
|
||||
return "";
|
||||
}
|
||||
String lower = fileName.toLowerCase();
|
||||
int dot = lower.lastIndexOf('.');
|
||||
return dot < 0 ? "" : lower.substring(dot + 1);
|
||||
}
|
||||
|
||||
private static String safe(String value) {
|
||||
return value == null ? "" : value;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -51,11 +51,11 @@ OEM:
|
||||
header: SQL转Java JPA、MYBATIS实现类代码生成平台
|
||||
keywords: sql转实体类,sql转DAO,SQL转service,SQL转JPA实现,SQL转MYBATIS实现
|
||||
title: 大狼狗代码生成器
|
||||
slogan: 👐 Free your hands from boring CRUD—let the code write itself! ⚡
|
||||
slogan: 🏺 古法编程·非遗传承 | Free your hands from boring CRUD! ⚡
|
||||
description: <p>💻 SpringBootCodeGenerator,又名 `大狼狗代码生成器`🐺🐶,支持 SQL 一键转 JAVA/JPA/Mybatis/MybatisPlus 等多种模板,轻松搞定 CRUD,彻底解放双手 ✋!只需提供 DDL、SELECT SQL 或简单 JSON 👉 即可生成 生成JPA/JdbcTemplate/Mybatis/MybatisPlus/BeetlSQL/CommonMapper 等代码模板。</p><p>🔥🔥🔥 全新 JSqlParser 引擎上线,强力支持 DDL CREATE SQL与 SELECT SQL 解析!欢迎体验 & 反馈 💬!</p><p>👨💻 面向开发者的高效利器,已服务数万工程师,欢迎 Star ⭐、Fork 🍴、提 Issue 💬,一起打造更强大的代码生成平台!</p>
|
||||
author: zhengkai.blog.csdn.net
|
||||
packageName: com.software.system
|
||||
copyright: ✨ Powered by <a href="https://zhengkai.blog.csdn.net" target="_blank">Moshow郑锴</a> — may the holy light guide your code, your coffee, and your commits! ⚡🧙♂️💻
|
||||
copyright: 🏺 Powered by <a href="https://zhengkai.blog.csdn.net" target="_blank">Moshow郑锴</a> — 愿你在 AI 时代,既有工具的效率,也有匠人的定力 🙏
|
||||
returnUtilSuccess: ResponseUtil.success
|
||||
returnUtilFailure: ResponseUtil.error
|
||||
outputStr: http://zhengkai.blog.csdn.net
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
"tier": "main",
|
||||
"templates": [{
|
||||
"id": "10",
|
||||
"name": "swagger-ui",
|
||||
"description": "swagger-ui",
|
||||
"fileName": "swagger-ui.json"
|
||||
"name": "swagger-ui",
|
||||
"description": "swagger-ui",
|
||||
"fileName": "swagger-ui.java"
|
||||
},
|
||||
{
|
||||
"id": "11",
|
||||
@@ -183,7 +183,7 @@
|
||||
"id": "70",
|
||||
"name": "beanutil",
|
||||
"description": "beanutil",
|
||||
"fileName": "${className}BeanUtil.txt"
|
||||
"fileName": "${className}BeanUtil.java"
|
||||
},
|
||||
{
|
||||
"id": "71",
|
||||
@@ -313,7 +313,7 @@
|
||||
"id": "201",
|
||||
"name": "qliksense",
|
||||
"description": "qlik sense",
|
||||
"fileName": "qliksense.txt"
|
||||
"fileName": "qliksense.qvs"
|
||||
}]
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user