1. 背景

要画ER图,一个个打费时费力,StarUML文件打开是json。那么就有可能自动生成。

2. 效果

把表结构生成好,自己只要维护关系即可。

3. 代码

import lombok.Data;

import java.io.FileWriter;
import java.io.IOException;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; /**
* @author liwei
* @version 1.0
* @className MySqlToStarUML
* @date 2022/9/21 22:47
*/
public class MySqlToStarUML { /**
* 自动生成代码入口
*
* @author liwei
* @date 2022-09-25 00:58:45
* @param args
* @return void
*/
public static void main(String[] args) {
localTest();
} public static void localTest() {
String driver = "com.mysql.cj.jdbc.Driver";
String url = "jdbc:mysql://localhost:3306/test_nacos?useUnicode=true&characterEncoding=UTF-8";
String userName = "root";
String password = "密码";
String filePath = "D:\\test_nacos.mdj"; List<Table> tableList = getTableList(driver, url, userName, password);
saveAsFileWriter(filePath, getProject(url, tableList));
System.out.println("===============生成成功================");
} /**
* 获取项目字符串
*
* @author liwei
* @date 2023-03-16 18:37:01
* @param url
* 地址
* @param tableList
* 表集合
* @return {@link String}
*/
public static String getProject(String url, List<Table> tableList) {
String database = getDBByUrl(url); Project project = new Project();
// 不能使用中文
project.setName(database);
project.set_id("AAAAAA_Project");
List<OwnedElement> erddatamodels = new ArrayList<>();
List<OwnedElement> ownedElements = new ArrayList<>();
ERDDataModel erdDataModel = new ERDDataModel();
erdDataModel.setName("Data Model1");
erdDataModel.set_id("AAAAAA_DataModel1");
erdDataModel.set_parent(project.get_id());
erddatamodels.add(erdDataModel);
ERDDiagram erdDiagram = new ERDDiagram();
erdDiagram.setName("ERDDiagram1");
erdDiagram.set_id("AAAAAA_ERDDiagram1");
erdDiagram.set_parent(erdDataModel.get_id());
ownedElements.add(erdDiagram);
for (Table table : tableList) {
table.set_parent(erdDataModel.get_id());
}
ownedElements.addAll(tableList);
erdDataModel.setOwnedElements(ownedElements);
project.setOwnedElements(erddatamodels);
return project.toString();
} /**
* 通过url获取数据库
*
* @author liwei
* @date 2022-09-23 09:21:09
* @param url
* 地址
* @return {@link String}
*/
public static String getDBByUrl(String url) {
if (null == url || url.isEmpty()) {
throw new RuntimeException("地址为空");
}
if (url.indexOf(":") == 0 && url.length() <= 1) {
throw new RuntimeException("地址有误");
}
while (url.indexOf(":") > 0) {
url = url.substring(url.indexOf(":") + 1);
}
if (url.indexOf("?") > 0) {
url = url.substring(0, url.indexOf("?"));
}
if (url.indexOf("/") > 0) {
url = url.substring(url.indexOf("/") + 1);
}
return url;
} /**
* 保存内容到文件
*
* @author liwei
* @date 2022-11-22 14:19:47
* @param filePath
* 文件路径
* @param content
* 内容
* @return void
*/
private static void saveAsFileWriter(String filePath, String content) {
FileWriter fwriter = null;
try {
fwriter = new FileWriter(filePath);
fwriter.write(content);
} catch (IOException ex) {
ex.printStackTrace();
} finally {
try {
if (null != fwriter) {
fwriter.flush();
fwriter.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
} /**
* 获取表集合
*
* @author liwei
* @date 2022-11-22 14:20:24
* @param driver
* 驱动
* @param url
* 连接
* @param userName
* 账号
* @param password
* 密码
* @return {@link List< Table>}
*/
private static List<Table> getTableList(String driver, String url, String userName, String password) {
Connection connection;
try {
Class.forName(driver);
connection = DriverManager.getConnection(url, userName, password);
} catch (ClassNotFoundException e) {
throw new RuntimeException("加载驱动失败,找不到:" + driver);
} catch (SQLException e) {
throw new RuntimeException("获取数据库连接失败,请检查配置和日志", e);
} String database = getDBByUrl(url);
String sqlTable = String.format("select * from information_schema.tables where TABLE_SCHEMA='%s'", database); List<Map<String, String>> mapList = runSql(connection, sqlTable); List<Table> tableList = new ArrayList<>();
for (int i = 0; i < mapList.size(); i++) {
Map<String, String> map = mapList.get(i);
Table table = new Table();
String tableId = String.valueOf(i + 1);
table.set_id(tableId);
table.setName(map.get("TABLE_NAME"));
table.setDocumentation(map.get("TABLE_COMMENT"));
String sqlColumn = String.format("select * from information_schema.columns where TABLE_SCHEMA='%s' and TABLE_NAME = '%s'", database, table.getName());
List<Map<String, String>> mapList2 = runSql(connection, sqlColumn);
List<Column> columnList = new ArrayList<>();
for (Map<String, String> stringMap : mapList2) {
Column column = new Column();
column.setTableId(tableId);
column.setName(stringMap.get("COLUMN_NAME"));
column.setType(stringMap.get("DATA_TYPE"));
String columnType = stringMap.get("COLUMN_TYPE");
if (columnType.indexOf("(") > 0) {
column.setLength(columnType.substring(columnType.indexOf("(") + 1, columnType.indexOf(")")));
} else {
column.setLength(stringMap.get("CHARACTER_MAXIMUM_LENGTH"));
}
column.setOrdinalPosition(Integer.parseInt(stringMap.get("ORDINAL_POSITION")));
column.setNullable("YES".equals(stringMap.get("IS_NULLABLE")));
column.setPrimaryKey("PRI".equals(stringMap.get("COLUMN_KEY")));
column.setUnique("UNI".equals(stringMap.get("COLUMN_KEY")));
columnList.add(column);
}
columnList.sort((c1, c2) -> c1.ordinalPosition - c2.getOrdinalPosition());
table.setColumns(columnList);
tableList.add(table);
} close(null, connection, null);
return tableList;
} /**
* 关闭连接
*
* @author liwei
* @date 2022-09-23 09:21:53
* @param pstmt
* 预编译
* @param conn
* 连接
* @param rs
* 结果集
* @return void
*/
public static void close(PreparedStatement pstmt, Connection conn, ResultSet rs) {
try {
if(null != rs) {
rs.close();
rs = null;
}
if(null != pstmt) {
pstmt.close();
pstmt = null;
}
if(null != conn) {
conn.close();
conn = null;
}
} catch (SQLException e) {
throw new RuntimeException("关闭数据库连接异常", e);
}
} /**
* 运行sql
*
* @author liwei
* @date 2022-11-22 14:21:40
* @param conn
* 连接
* @param sql
* 执行的sql
* @return {@link List< Map< String, String>>}
*/
public static List<Map<String, String>> runSql(Connection conn, String sql) {
if (null == sql || sql.isEmpty()) {
throw new RuntimeException("执行的sql不可为空");
}
List<Map<String, String>> list = new ArrayList<>();
if(null == conn) {
throw new RuntimeException("获取数据库连接失败");
} PreparedStatement pstmt = null;
ResultSet rs = null;
try {
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
while (rs.next()) {
Map<String, String> map = new HashMap<>();
ResultSetMetaData metaData = rs.getMetaData();
int columnCount = metaData.getColumnCount();
for (int i = 1; i <= columnCount; i++) {
map.put(metaData.getColumnName(i), rs.getString(i));
}
list.add(map);
}
} catch (SQLException e) {
throw new RuntimeException("执行sql异常", e);
} finally {
close(pstmt, null, rs);
}
return list;
} @Data
static class Table extends OwnedElement {
private String _type = "ERDEntity";
private String documentation;
private List<Column> columns; @Override
public String toString() {
return "{" +
"\"_type\":\"" + _type + '\"' +
", \"_id\":\"" + super._id + '\"' +
", \"_parent\":{\"$ref\":\"" + super._parent + "\"}" +
", \"name\":\"" + super.name + " " + documentation + '\"' +
", \"documentation\":\"" + documentation + '\"' +
", \"columns\":" + columns +
'}';
}
} @Data
static class Column {
private String _type = "ERDColumn";
private String name;
private String tableId;
private String type;
private String length;
// UNI、PRI
private String columnKey;
private int ordinalPosition;
private Boolean primaryKey;
private Boolean unique;
private Boolean nullable; @Override
public String toString() {
return "{" +
"\"_type\":\"ERDColumn\"" +
", \"_parent\":{\"$ref\":\"" + tableId + "\"}" +
", \"name\":\"" + name + '\"' +
", \"type\":\"" + type + '\"' +
(null != length ? ", \"length\":\"" + length + '\"' : "") +
(primaryKey ? ", \"primaryKey\":\"" + primaryKey + "\"" : "") +
(unique ? ", \"unique\":\"" + unique + "\"" : "") +
(nullable ? ", \"nullable\":\"" + nullable + "\"" : "") +
'}';
}
} @Data
static class Project extends OwnedElement {
private String _type = "Project"; @Override
public String toString() {
return "{" +
"\"_type\":\"Project\"" +
", \"_id\":\"" + super._id + '\"' +
", \"name\":\"" + super.name + '\"' +
", \"ownedElements\":" + super.ownedElements +
"}";
}
} @Data
static class OwnedElement {
private String _type;
private String _id;
private String _parent;
private String name;
private List<OwnedElement> ownedElements;
} @Data
static class ERDDataModel extends OwnedElement {
private String _type = "ERDDataModel"; @Override
public String toString() {
return "{" +
"\"_type\":\"ERDDataModel\"" +
", \"_id\":\"" + super._id + '\"' +
", \"_parent\":{\"$ref\":\"" + super._parent + "\"}" +
", \"name\":\"" + super.name + '\"' +
", \"ownedElements\":" + super.ownedElements +
"}";
}
} @Data
static class ERDDiagram extends OwnedElement {
private String _type = "ERDDiagram"; @Override
public String toString() {
return "{" +
"\"_type\":\"ERDDiagram\"" +
", \"_id\":\"" + super._id + '\"' +
", \"_parent\":{\"$ref\":\"" + super._parent + "\"}" +
", \"name\":\"" + super.name + '\"' +
(null != super.ownedElements ? ", \"ownedViews\":" + super.ownedElements : "") +
"}";
}
} @Data
static class ERDEntityView extends OwnedElement {
private String _type = "ERDEntityView";
private String tableId; @Override
public String toString() {
return "{" +
"\"_type\":\"ERDEntityView\"" +
", \"model\":{\"" + tableId + "\"}" +
(null != super.ownedElements ? ", \"subViews\":" + super.ownedElements : "") +
"}";
}
}
}

MySql生成ER【StarUML】文件的更多相关文章

  1. PowerDesigner连接 MySQL 生成 ER图

    powerdesigner 16.5 http://www.pcsoft.com.cn/soft/27495.html jdk 1.8 32位 https://mirrors.huaweicloud. ...

  2. MySQL数据表生成ER图

    遇到没有说明文档的数据库的时候,一张一张表去分析,需要花费很长时间和精力. 幸好有一些工具,可以帮助我们生成ER图,这样看起来就一目了然: 下面我将自己的一次实践记录于下,供参考: 1.下载并安装工具 ...

  3. EA逆向生成数据库E-R图(mysql数据库-->ER图)

    [1]选择 工具-->ODBC-Data-Sources [2]ODBC数据源管理器  ,点击添加 [3]选择一个mysql驱动  ,点击MySQL ODBC 5.1 Driver(其它同理), ...

  4. 利用powerdesigner反向数据库结构,生成ER图

    参考月下狼~图腾~:<利用powerdesigner反向数据库结构,生成ER图> https://www.zybuluo.com/Jpz/note/123582 首先新建一个"P ...

  5. 【PowerDesigner】【4】连接数据库并生成ER图

    文字版: 1,File→Reverse Engineer→Database...., 2,新窗口database reverse engineering打开后,填写名称(Model name),选择数 ...

  6. MySQL命令执行sql文件的两种方法

    MySQL命令执行sql文件的两种方法 摘要:和其他数据库一样,MySQL也提供了命令执行sql脚本文件,方便地进行数据库.表以及数据等各种操作.下面笔者讲解MySQL执行sql文件命令的两种方法,希 ...

  7. myBatis自动生成相关代码文件配置(Maven)

    pom.xml文件添加配置 <build> <finalName>generator</finalName> <plugins> <!-- mav ...

  8. MySQL服务读取参数文件my.cnf的规律研究探索

    在MySQL中,它是按什么顺序或规律去读取my.cnf配置文件的呢?其实只要你花一点功夫,实验测试一下就能弄清楚,下面的实验环境为5.7.21 MySQL Community Server.其它版本如 ...

  9. 利用TPC-H为MYSQL生成数据

    ## 利用TPC-H为MYSQL生成数据 导言 这篇文章是看了joyee写的TPC-H数据导入MySQL教程以及另一篇网上的MySQL TPCH测试工具简要手册 后写的,有些内容是完全转载自以上两篇文 ...

  10. MySQL体系结构之物理文件

    一.MySQL日志文件 mysql日志文件及功能: 日志文件 功能 错误日志 记录启动.停止.运行过程中mysqld时出现的问题 通用日志 记录建立客户端连接和执行的语句 二进制日志 记录更改数据的所 ...

随机推荐

  1. 华硕推出无风扇迷你电脑 PL64-明显是奔着软路由去的

    看这个配置,做客厅软路由再合适不过了.要是针对客厅的影音需求,CPU性能以及对大容量存储的刚需,这个还是有些欠缺. IT之家 12 月 17 日消息,华硕 PL 系列迷你电脑现已迎来最新一代机型,其中 ...

  2. 「DIARY」PKUSC 2021 游记

    冬令营没了但是还有夏令营 (完蛋,前两天忘写游记了,完全没想起来--最后一天补一补) 试题分析在另外一篇博客上 # Day 0 早上去机场的时候把手机落在出租车上了 (还好之后找回来了),导致我前两天 ...

  3. 半成品 java 身份证校验

    public static Boolean is18Card(String idCard18) { //证件省份 HashMap<String, String> aCity = new H ...

  4. DAST精简代码

    先训练G:先不计算D的梯度: 判别器输入类型为(源域,0)或者(目标域,1),输出图片为真实图片(源域)的概率值for param in model_D.parameters(): # model_D ...

  5. c++ dll 传递string参数

    用c++编写了一个dll,需要传递一个路径的变量参数,刚开始想着使用string变量,但是在实践过程中string变量会成为乱码,尽量避免使用string变量传递参数,可以使用const char* ...

  6. UI自动化之【报错记录-selenium】

    1.找不到元素 写脚本的过程中时不时就会报这种错,一般路径定位不到直接复制xpath基本就能找到了,也有时候是因为有iframe或是句柄不对 原因: ①没有加等待时间,脚本运行到那步时,页面还没加载完 ...

  7. Shell脚本结构化-控制流

    脚本结构化命令 上一章给出的那些 shell 脚本里,shell 按照命令在脚本中出现的顺序依次进行处理.对顺序操作来说,这已经足够了,因为在这种操作环境下,你想要的就是所有的命令按照正确的顺序执行. ...

  8. win10 wampserver升级 php7.0至 php7.2

    1.去官网下载php7.2 下载地址: https://windows.php.net/download#php-7.0 2.下载安装 visual c++ 2017 或  visual c++ 20 ...

  9. matlab函数学习笔记

    数值精度 显示精度由format函数控制,不影响原始数据,只控制显示精度 命令 说明 long   short   rat 分数 digits   vpa   pi的输出 命令 显示结果结果 form ...

  10. cmake 实现交叉编译注意事项

    (1)确保安装交叉编译工具安装成功 在终端输入arm-linux-gnueabihf-g++ -v 或 arm-linux-gnueabihf-gcc -v ,能看到相应交叉C编译器和C++编译器的版 ...