今天在使用Apifox的时候看到数据模型那一块能根据数据模型生成SQL但是不能添加约束,于是想着自己写一个SQL生成器,想到大多数情况下我们都是先设计模型然后才去写sql,我个人比较偏向于使用md的表格设计,于是写了这段根据md文档生成sql的代码,先看效果
【使用演示】 www.bilibili.com/video/BV1e7…
假如我们有以下表格
md语法是这样的
特征很明显,经过处理可以很容易构造出sql,于是有了下面代码(使用maven工程结构),向外暴露了一个静态方法convertToSQL调用这个方法传入一个md路径就会根据路径生成sql,将md文件的文件名作为数据库名
package com.neuedu.elm.utils;
import lombok.Data;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
public class SQLBuilder {
public static void main(String[] args) {
SQLBuilder.convertToSQL("src/main/resources/test.md");
}
/**
* 转换为SQL语句
* @param path 文件路径
* @return SQL语句
*/
public static String convertToSQL(String path) {
// 示例: src/main/resources/test.md
File file = new File(path);
List<SQLField> list = new ArrayList<>();
System.out.println("文件名:" + file.getName());
// 表名
String tableName = file.getName().substring(0, file.getName().indexOf("."));
try {
Scanner sc = new Scanner(file);
String line;
// 先读两行跳过
sc.nextLine();
sc.nextLine();
while (sc.hasNextLine()) {
line = sc.nextLine();
String[] arr = line.split("\|");
// System.out.println(Arrays.toString(arr));
// 如果数组长度为1,说明到了最后一行,跳出循环
if (arr.length == 1 || arr.length == 0) {
break;
}
list.add(handler1(arr));
}
String sql = generateSQL(tableName, list);
System.out.println(sql);
return sql;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
// 根据字段生成对象
private static SQLField handler1(String[] arr) {
// 如果数组为空或者长度为0,返回null (有空行)
for (int i = 0; i < arr.length; i++) {
arr[i] = arr[i].trim();
}
SQLField sqlField = new SQLField();
try {
// 从数组第二项开始,因为第一列是序号
sqlField.setFieldName(arr[2]);
sqlField.setType(arr[3]);
sqlField.setSize(arr[4]);
sqlField.setDefaultValue(arr[5]);
sqlField.setConstraints(arr[6]);
sqlField.setExplain(arr[7]);
} catch (IndexOutOfBoundsException e) {
System.out.println("数组越界异常");
}
return sqlField;
}
/**
* 生成SQL语句
* @param tableName 表名
* @param list 字段列表
* @return SQL语句
*/
private static String generateSQL(String tableName, List<SQLField> list) {
StringBuilder sb = new StringBuilder();
sb.append("CREATE TABLE `" + tableName + "` (\n");
for (int i = 0; i < list.size(); i++) {
SQLField field = list.get(i);
if (field == null) continue;
sb.append("\t`" + field.getFieldName() + "` " + field.getType());
if (field.getSize() != null && !"".equals(field.getSize())) {
// 如果有括号就不加
if (field.getSize().startsWith("(") && field.getSize().endsWith(")")) {
sb.append(field.getSize());
} else {
sb.append("(" + field.getSize() + ")");
}
}
// 约束处理外键约束不处理
if (field.getConstraints() != null && !"".equals(field.getConstraints())) {
if (field.getConstraints().contains("PK")) {
sb.append(" PRIMARY KEY");
}
if (field.getConstraints().contains("UN")) {
sb.append(" UNIQUE");
}
if (field.getConstraints().contains("NN")) {
sb.append(" NOT NULL");
}
if (field.getConstraints().contains("AI")) {
sb.append(" AUTO_INCREMENT");
}
}
// 默认值处理
if (field.getDefaultValue() != null && !"".equals(field.getDefaultValue())) {
if (field.getDefaultValue().contains("CURRENT_TIMESTAMP") || field.getDefaultValue().equals("now()")) {
sb.append(" DEFAULT CURRENT_TIMESTAMP");
} else if (field.getType().contains("varchar") || field.getType().contains("char") || field.getType().contains("mediumtext")) {
sb.append(" DEFAULT '" + field.getDefaultValue() + "'");
} else if (field.getType().contains("int") || field.getType().contains("decimal")) {
sb.append(" DEFAULT " + field.getDefaultValue());
} else if (field.getType().contains("date")) {
sb.append(" DEFAULT '" + field.getDefaultValue() + "'");
}
}
// 添加描述
if (field.getExplain()!= null &&!"".equals(field.getExplain())) {
sb.append(" COMMENT '" + field.getExplain() + "'");
}
// 生成语句结尾的分号
if (i != list.size() - 1) {
sb.append(",\n");
} else {
sb.append("\n");
}
}
sb.append(");");
return sb.toString();
}
}
// 字段所有内容的对象
@Data
class SQLField {
private String fieldName;
private String type;
private String size;
private String defaultValue;
private String constraints;
private String explain;
}
测试结果
运行结果