今天由于业务要求,写了一个自动生成数据库,其实网上一大堆,但有些不适用,cv多了自己也能写点东西了,仔细琢磨了一下,我打算从sql语句入手,也就是通过拼接sql语句然后执行sql语句就可以实现,这里我并没考虑不到sql注入的问题,毕竟是简易版,但为了满足需求后续会继续更新这部分代码,废话不多说了,步入正题。
直接上代码,写了一部分注解
public class GenSqlUtil {
static Connection con = null;
static String url = "jdbc:mysql://localhost:3306/auto_system?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC";
static String user = "root";
static String word = "123456";
static String driver = "com.mysql.cj.jdbc.Driver";
static PreparedStatement stmt;
public static void genSql(String tableName, Map<String, Object> map) {
StringBuilder sql = new StringBuilder();
//取出键
Set set = map.keySet();
int flag = 0;
int addFlag = 0;
//判断数据库是否存在表 如果存在
if (validateTableNameExist(tableName)) {
for (Iterator iter = set.iterator(); iter.hasNext(); ) {
String key = (String) iter.next();
if (key == "id") {
Integer id = (Integer) map.get(key);
String selSql = "select * from " + tableName + " where id = " + id;
try {
Class.forName(driver);
con = DriverManager.getConnection(url, user, word);
stmt = con.prepareStatement(selSql);
ResultSet rsColumn = stmt.executeQuery(selSql);
ResultSetMetaData data = rsColumn.getMetaData();
if (rsColumn.next()) {
//组成update更新语句
sql.append("update " + tableName + " set ");
for (Iterator iters = set.iterator(); iters.hasNext(); ) {
String keys = (String) iters.next();
if (keys != "id") {
String value = (String) map.get(keys);
sql.append(keys + " = " + "'" + value + "'" + " ");
flag++;
if (flag < set.size() - 1)
sql.append(",");
}
}
sql.append(" where id = " + map.get("id"));
con = DriverManager.getConnection(url, user, word);
stmt = con.prepareStatement(sql.toString());
stmt.execute(sql.toString());
System.out.println(sql);
} else {
//组成insert更新语句
sql.append("insert into " + tableName + "(");
for (Iterator iterss = set.iterator(); iterss.hasNext(); ) {
String keyss = (String) iterss.next();
if (keyss != "id") {
flag++;
sql.append(keyss);
if (flag < set.size() - 1) {
sql.append(", ");
} else {
sql.append(")");
}
}
}
sql.append(" values(");
for (Iterator itersss = set.iterator(); itersss.hasNext(); ) {
String keysss = (String) itersss.next();
if (keysss != "id") {
String valuesss = (String) map.get(keysss);
sql.append("'" + valuesss +"'");
addFlag++;
if (addFlag < set.size() - 1)
sql.append(", ");
else
sql.append(")");
}
}
System.out.println(sql);
con = DriverManager.getConnection(url, user, word);
stmt = con.prepareStatement(sql.toString());
stmt.execute(sql.toString());
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
}
} else {
//如果不存在就建表 组成create语句
sql.append("create table " + tableName + " (");
for (Iterator idIter = set.iterator(); idIter.hasNext(); ) {
String key = (String) idIter.next();
if (key == "id")
{
Integer id = (Integer) map.get("id");
sql.append(key + " int NOT NULL AUTO_INCREMENT, ");
}
}
for (Iterator iter = set.iterator(); iter.hasNext(); ) {
String key = (String) iter.next();
if (key != "id") {
sql.append(key + " varchar(255) DEFAULT NULL,");
}
}
sql.append("PRIMARY KEY(id))");
System.out.println(sql);
try {
//执行sql语句三要素
con = DriverManager.getConnection(url, user, word);
stmt = con.prepareStatement(sql.toString());
stmt.execute(sql.toString());
genSql(tableName,map);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
public static boolean validateTableNameExist(String tableName) {
// 数据源配置
try {
String sql = "select * from " + tableName;
PreparedStatement stmt;
Class.forName(driver);
con = DriverManager.getConnection(url, user, word);
ResultSet rs = con.getMetaData().getTables(null, null, tableName, null);
if (rs.next()) {
stmt = con.prepareStatement(sql);
ResultSet rsColumn = stmt.executeQuery(sql);
ResultSetMetaData data = rsColumn.getMetaData();
Map<String, Object> columns = new HashMap<>();
for (int i = 1; i <= data.getColumnCount(); i++) {
// 获得所有列的数目及实际列数
int columnCount = data.getColumnCount();
// 获得指定列的列名
String columnName = data.getColumnName(i);
// 获得指定列的列值
columns.put(columnName, columnName);
int columnType = data.getColumnType(i);
// 获得指定列的数据类型名
String columnTypeName = data.getColumnTypeName(i);
// 所在的Catalog名字
String catalogName = data.getCatalogName(i);
// 对应数据类型的类
String columnClassName = data.getColumnClassName(i);
// 在数据库中类型的最大字符个数
int columnDisplaySize = data.getColumnDisplaySize(i);
// 默认的列的标题
String columnLabel = data.getColumnLabel(i);
// 获得列的模式
String schemaName = data.getSchemaName(i);
// 某列类型的精确度(类型的长度)
int precision = data.getPrecision(i);
// 小数点后的位数
int scale = data.getScale(i);
// 获取某列对应的表名
String tablesName = data.getTableName(i);
// 是否自动递增
boolean isAutoInctement = data.isAutoIncrement(i);
// 在数据库中是否为货币型
boolean isCurrency = data.isCurrency(i);
// 是否为空
int isNullable = data.isNullable(i);
// 是否为只读
boolean isReadOnly = data.isReadOnly(i);
// 能否出现在where中
boolean isSearchable = data.isSearchable(i);
}
return true;
} else {
return false;
}
} catch (SQLException | ClassNotFoundException troubles) {
troubles.printStackTrace();
return false;
}
}
public static void genSqlFace(String tableName,Map<String,Object> map) {
// String tableName = "acd";
// Map<String, Object> map = new HashMap<>();
// map.put("id", 1);
// map.put("name", "ysy");
// map.put("sex", "man");
// map.put("age", "18");
// map.put("score", "100");
genSql(tableName, map);
}
}
由于我的业务需求是需要传值进入调用这个类方法,所以才多此一举写了一个face方法来接参数,代码中有些逻辑比较复杂,所以一时半会我也没有转过来,可能就会出现一些多余的代码段,考虑到后期可能会用到一些获取数据信息的代码,可供参考。
调用这个方法
public DataResponse genAuto(Map<String,Object> params){
String tableName = (String) params.get("tableName");
params.remove("tableName");
GenSqlUtil.genSqlFace(tableName,params);
GenMainUtil.genMainFace(tableName);
return new DataResponse().defaultOperationResponse(BizSuccessEnum.BUSINESS_OPERATE_SUCCESS.getMessage());
}
这个是我在service层写的方法,将数据在一个封装进入hashmap,返回值类型是我自定义的一个类,是一个前辈传授与我,我还没吃透,等吃透了会专门写一篇解析的博客
接下来是我的controller层了
@PostMapping("/test")
public DataResponse generators (@RequestBody Map<String,Object> params){
DataResponse dataResponse = acdService.genAuto(params);
return dataResponse;
}
打开邮递男孩postman,测试一波
封装json的数据传入接口,此时数据库内并没有testTable这张表,于是根据代码逻辑,需要执行create和insert方法
执行的语句会在控制台输出
语句执行完毕,打开navicat看一波
表在
数据在
邮递男孩postman返回
我的DataResponse类返回的数据就是这些
这段代码可以用来学习sql语句、执行sql,可以直接cv下来用,传入的参数在face中注释掉了,对简单单表可直接使用,由于字段使用hashmap存储的,目前只能确保id是在第一列,其他的就得看hashcode值了,后续我会继续更新这一块的内容,让代码更加完善。有问题可以留言交流哦。
我是飞扬,专注于写bug的程序猿