记录:278
场景:在实际开发中,开发文档中的建表信息以表格的方式提供,包括字段名称、字段类型、字段注释、是否为空等。本例就是先把表格信息转换为约定格式的txt文件,在使用Java代码生成完整的建表语句。
版本:Spring Boot 2.6.3
一、案例场景
1.开发文档中以表格方式提供建表信息。
2.手动转换为txt文件,文件名:SENSOR_DATA.txt,格式约定如下:
第一行为,表名##表名称。
第二行开始,每行:字段名称##字段类型##字段非空##字段注释##字段主键或者索引。
SENSOR_DATA##传感器数据
ID##NUMBER(16)##Y##实体唯一标识##primary
REGION##VARCHAR2(8)##N##区域##index
VALUE1##NUMBER(16,2)##N##取值1##N
VALUE2##NUMBER(16,2)##N##取值2##N
3.执行代码,自动生成sql文件,文件名:SENSOR_DATA.sql,生成结果。
create table SENSOR_DATA (
ID NUMBER(16) not null ,
REGION VARCHAR2(8),
VALUE1 NUMBER(16,2),
VALUE2 NUMBER(16,2)
);
comment on table SENSOR_DATA is '传感器数据';
comment on column SENSOR_DATA.ID is '实体唯一标识';
comment on column SENSOR_DATA.REGION is '区域';
comment on column SENSOR_DATA.VALUE1 is '取值1';
comment on column SENSOR_DATA.VALUE2 is '取值2';
alter table SENSOR_DATA add constraint PK_SENSOR_DATA_ID primary key (ID);
create index IDX_SENSOR_DATA_REGION on SENSOR_DATA (REGION);
二、使用类
1.读文件操作
java.lang.AutoCloseable,接口。
java.io.Closeable,接口,继承AutoCloseable。
java.lang.Readable,接口。
java.io.Reader,抽象类,实现Readable接口和Closeable。
java.io.BufferedReader,实现类,实现Reader抽象类。
java.io.InputStreamReader,实现类,读输入流,Reader抽象类。
java.io.FileReader,实现类,读文件,继承InputStreamReader。
new BufferedReader(new FileReader(fileName))。
2.写文件操作
java.lang.AutoCloseable,接口。
java.io.Closeable,接口,继承AutoCloseable。
java.io.Flushable,接口。
java.lang.Appendable,接口。
java.io.Writer,抽象类,实现Appendable, Closeable, Flushable。
java.io.BufferedWriter,实现类,实现Writer抽象类。
java.io.OutputStreamWriter,实现类,写输出流,Writer抽象类。
java.io.FileWriter,实现类,写文件,继承OutputStreamWriter。
new BufferedWriter(new FileWriter(fileName, true));
3.操作ArrayList
java.lang.Iterable,接口。
java.util.Collection,接口,继承Iterable。
java.util.List,接口,继承Collection。
java.util.AbstractCollection,抽象类,实现Collection。
java.util.AbstractList,抽象类,继承AbstractCollection,实现List。
java.util.ArrayList,一个Resizable-array。
4.Collections
java.util.Collections,对集合相关操作。
三、代码
1.读文件
读取文件,逐行读取,每读取一行,立即解析,根据分隔符##,分割成多个String字符串,存放在一个List<String>中。解析完成的一行数据List<String>,再放入List<List>中。
public static ArrayList<ArrayList<String>> readFromTxt(String fileName) {
ArrayList<ArrayList<String>> listAll = new ArrayList<>();
try {
//1.读txt文件,一次读一行
BufferedReader br = new BufferedReader(new FileReader(fileName));
String oneLine = null;
//2.使用readLine方法,一次读一行
while ((oneLine = br.readLine()) != null) {
ArrayList<String> oneLineList = getOneLine(oneLine, "##");
listAll.add(oneLineList);
}
br.close();
} catch (Exception e) {
System.out.println("读异常.");
e.printStackTrace();
}
return listAll;
}
public static ArrayList<String> getOneLine(String content, String split) {
String[] strArr = content.split(split);
ArrayList<String> oneLine = new ArrayList<>(strArr.length);
Collections.addAll(oneLine, strArr);
return oneLine;
}
2.写文件
逐行写文件,以追加方式写入,不覆盖已经写入的内容。
public static void writeFile(String fileName, String content) {
try {
// 设置为追加写入true
BufferedWriter bw = new BufferedWriter(
new FileWriter(fileName, true));
bw.write(content);
bw.close();
} catch (IOException e) {
System.out.println("读异常.");
e.printStackTrace();
}
}
3.生成建表语句
根据从txt读取的表字段信息,生成建表语句。
public static void createTable(String fileName, ArrayList<ArrayList<String>> content) {
List<String> firstOne = content.get(0);
String tableName = firstOne.get(0);
String part1 = "create table ";
String part2 = tableName;
String part3 = " ( ";
writeFile(fileName, part1 + part2 + part3 + "\n");
String part5 = " );";
int size = content.size();
for (int i = 0; i < size; i++) {
ArrayList<String> oneLine = content.get(i);
if (StringUtils.equals(tableName, oneLine.get(0))) continue;
String line = "";
int last = content.size() - 1;
if (StringUtils.equals("Y", oneLine.get(2))) {
line = oneLine.get(0) + " " + oneLine.get(1) + " not null " + "," + "\n";
} else if (i == last) {
line = oneLine.get(0) + " " + oneLine.get(1) + "\n";
} else {
line = oneLine.get(0) + " " + oneLine.get(1) + "," + "\n";
}
writeFile(fileName, " " + line);
}
writeFile(fileName, part5 + "\n");
}
4.生成字段注释
根据从txt读取的表字段信息,生成字段注释。
public static void createComment(String fileName, ArrayList<ArrayList<String>> content) {
List<String> firstOne = content.get(0);
String tableName = firstOne.get(0);
String tableComment = firstOne.get(1);
String part1 = "comment on table ";
String part2 = tableName;
String part3 = " is '";
String part4 = tableComment;
String part5 = "';";
String tableComments = part1 + part2 + part3 + part4 + part5;
writeFile(fileName, tableComments + "\n");
int size = content.size();
for (int i = 0; i < size; i++) {
ArrayList<String> oneLine = content.get(i);
if (StringUtils.equals(tableName, oneLine.get(0))) continue;
String part01 = "comment on column ";
String part02 = tableName + ".";
String part03 = oneLine.get(0);
String part04 = " is '";
String part05 = oneLine.get(3) + "';\n";
String part = part01 + part02 + part03 + part04 + part05;
writeFile(fileName, part);
}
}
5.生成主键约束和索引
根据从txt读取的表字段信息,生成主键约束和索引。
// 生成主键和索引
public static void createPrimaryAndIndex(String fileName, ArrayList<ArrayList<String>> content) {
List<String> firstOne = content.get(0);
String tableName = firstOne.get(0);
int size = content.size();
for (int i = 0; i < size; i++) {
ArrayList<String> oneLine = content.get(i);
if (StringUtils.equals(tableName, oneLine.get(0))) continue;
if (StringUtils.equals("primary", oneLine.get(4).toLowerCase())) {
String part1 = "alter table ";
String part2 = tableName;
String part3 = " add constraint ";
String part4 = "PK_" + tableName + "_" + oneLine.get(0);
String part5 = " primary key (" + oneLine.get(0) + ");";
part4 = getLimitString(part4);
String pk = part1 + part2 + part3 + part4 + part5;
writeFile(fileName, pk + "\n");
}
if (StringUtils.equals("index", oneLine.get(4).toLowerCase())) {
String part1 = "create index ";
String part2 = "IDX_" + tableName + "_" + oneLine.get(0);
String part3 = " on ";
String part4 = tableName;
String part5 = " (" + oneLine.get(0) + ");";
part2 = getLimitString(part2);
String index = part1 + part2 + part3 + part4 + part5;
writeFile(fileName, index + "\n");
}
}
}
// 限定主键或索引名称字符串30个字符
public static String getLimitString(String srcStr){
int length = srcStr.length();
if (length > 30) {
srcStr = srcStr.substring(0, 30);
String underline = srcStr.substring(29, 30);
if (StringUtils.equals("_", underline)) {
// 最后一个字符是字母而不是下划线
srcStr = srcStr.substring(0, 29);
}
}
return srcStr;
}
6.在main函数调用
在main函数调用测试。
public static void main(String[] args) {
System.out.println("开始...");
String baseDir = "D:\\example\\";
String fileName = "SENSOR_DATA";
String txtFileName = baseDir + fileName + ".txt";
String sqlFileName = baseDir + fileName + ".sql";
ArrayList<ArrayList<String>> read = readFromTxt(txtFileName);
// 表结构
createTable(sqlFileName, read);
// 注释
createComment(sqlFileName, read);
// 主键和索引(单个字段)
createPrimaryAndIndex(sqlFileName, read);
System.out.println("结束...");
}
以上,感谢。
2022年7月1日