当前位置: 首页 > news >正文

工具(十二):Java导出MySQL数据库表结构信息到excel

在这里插入图片描述

一、背景

遇到需求:将指定数据库表设计,统一导出到一个Excel中,存档查看。
如果一个一个弄,很复杂,耗时长。

二、写一个工具导出下

废话少絮,上码:

2.1 pom导入

		<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.version}</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.4.0</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>5.4.0</version></dependency>

2.2 工具类

这里提供思路和示例

package com.eduer.books.modules.app.controller;import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;import java.io.FileOutputStream;
import java.sql.*;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;/*** Java导出mysql数据库表结构信息到excel* @author wangdy* 2025/3/13*/
public class DatabaseExporter {private static final Pattern INVALID_SHEETNAME_CHARS = Pattern.compile("[\\\\/*?\\[\\]:]");private static final int MAX_SHEETNAME_LENGTH = 31;public static void exportToExcel(String dbName, String jdbcUrl, String username, String password, String outputPath)throws Exception {Set<String> usedSheetNames = new HashSet<>();try (Workbook workbook = new XSSFWorkbook(); Connection conn = DriverManager.getConnection(jdbcUrl, username, password)) {DatabaseMetaData metaData = conn.getMetaData();ResultSet tables = metaData.getTables(dbName, null, "%", new String[]{"TABLE"});while (tables.next()) {String catalog = tables.getString("TABLE_CAT");String schema = tables.getString("TABLE_SCHEM");String tableName = tables.getString("TABLE_NAME");// 生成合法的Sheet名称String baseSheetName = generateBaseSheetName(catalog, schema, tableName);String uniqueSheetName = generateUniqueSheetName(baseSheetName, usedSheetNames);Sheet sheet = workbook.createSheet(uniqueSheetName);usedSheetNames.add(uniqueSheetName);createHeaderRow(sheet);processTableColumns(metaData, tableName, sheet);autoSizeColumns(sheet, 7);}try (FileOutputStream outputStream = new FileOutputStream(outputPath)) {workbook.write(outputStream);}}}private static String generateBaseSheetName(String catalog, String schema, String tableName) {// 优先使用schema信息,MySQL中一般用catalog表示数据库String prefix = "";if (schema != null && !schema.isEmpty()) {prefix = schema;} else if (catalog != null && !catalog.isEmpty()) {prefix = catalog;}String rawName = prefix.isEmpty()? tableName: prefix + "_" + tableName;// 替换非法字符并格式化return formatSheetName(rawName);}private static String formatSheetName(String rawName) {// 1. 替换非法字符String sanitized = INVALID_SHEETNAME_CHARS.matcher(rawName).replaceAll("_");// 2. 去除首尾特殊字符sanitized = sanitized.replaceAll("^[\\s']+", "").replaceAll("[\\s']+$", "");// 3. 压缩连续下划线sanitized = sanitized.replaceAll("_{2,}", "_");// 4. 截断长度return sanitized.length() > MAX_SHEETNAME_LENGTH? sanitized.substring(0, MAX_SHEETNAME_LENGTH): sanitized;}private static String generateUniqueSheetName(String baseName, Set<String> usedNames) {if (!usedNames.contains(baseName)) {return baseName;}int suffix = 1;String candidateName;do {String suffixStr = "_" + suffix++;int maxBaseLength = MAX_SHEETNAME_LENGTH - suffixStr.length();candidateName = (baseName.length() > maxBaseLength? baseName.substring(0, maxBaseLength): baseName) + suffixStr;} while (usedNames.contains(candidateName));return candidateName;}private static void processTableColumns(DatabaseMetaData metaData, String tableName, Sheet sheet)throws SQLException {ResultSet columns = metaData.getColumns(null, null, tableName, null);Set<String> primaryKeys = getPrimaryKeys(metaData, tableName);int rowNum = 1;while (columns.next()) {Row row = sheet.createRow(rowNum++);fillRowData(columns, primaryKeys, row);}columns.close();}// 以下方法保持不变(createHeaderRow, createHeaderStyle, getPrimaryKeys, fillRowData, autoSizeColumns)private static void createHeaderRow(Sheet sheet) {Row headerRow = sheet.createRow(0);String[] headers = {"字段名称", "字段类型", "长度", "是否主键", "允许空值", "默认值", "字段注释"};CellStyle headerStyle = createHeaderStyle(sheet.getWorkbook());for (int i = 0; i < headers.length; i++) {Cell cell = headerRow.createCell(i);cell.setCellValue(headers[i]);cell.setCellStyle(headerStyle);}}private static CellStyle createHeaderStyle(Workbook workbook) {CellStyle style = workbook.createCellStyle();Font font = workbook.createFont();font.setBold(true);style.setFont(font);style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());style.setFillPattern(FillPatternType.SOLID_FOREGROUND);return style;}private static Set<String> getPrimaryKeys(DatabaseMetaData metaData, String tableName) throws SQLException {Set<String> primaryKeys = new HashSet<>();ResultSet pkResultSet = metaData.getPrimaryKeys(null, null, tableName);while (pkResultSet.next()) {primaryKeys.add(pkResultSet.getString("COLUMN_NAME"));}pkResultSet.close();return primaryKeys;}private static void fillRowData(ResultSet columns, Set<String> primaryKeys, Row row) throws SQLException {String columnName = columns.getString("COLUMN_NAME");String typeName = columns.getString("TYPE_NAME");int columnSize = columns.getInt("COLUMN_SIZE");String isNullable = columns.getString("IS_NULLABLE");String defaultValue = columns.getString("COLUMN_DEF");String remarks = columns.getString("REMARKS");row.createCell(0).setCellValue(columnName);row.createCell(1).setCellValue(typeName);row.createCell(2).setCellValue(columnSize);row.createCell(3).setCellValue(primaryKeys.contains(columnName) ? "是" : "否");row.createCell(4).setCellValue("YES".equalsIgnoreCase(isNullable) ? "是" : "否");row.createCell(5).setCellValue(defaultValue != null ? defaultValue : "");row.createCell(6).setCellValue(remarks != null ? remarks : "");}private static void autoSizeColumns(Sheet sheet, int columnCount) {for (int i = 0; i < columnCount; i++) {sheet.autoSizeColumn(i);}}public static void main(String[] args) {try {String jdbcUrl = "jdbc:mysql://127.0.0.1:3306/books-service?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai";String username = "root";String password = "xxxxxxx";String outputPath = "数据库表结构.xlsx";exportToExcel("books-service", jdbcUrl, username, password, outputPath);System.out.println("导出成功!");} catch (Exception e) {e.printStackTrace();}}
}

main方法运行即可。

三、结果截图

在这里插入图片描述
在这里插入图片描述

四、扩展:导出到同一个sheet页

以上呢是将每个表导出到每个sheet页,有时候的需求是导出到同一个sheet页。可以用如下代码进行:

4.1 导出数据库表结构到excel中的同一个sheet页,并合并表名和表注释

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;import java.io.FileOutputStream;
import java.sql.*;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;/*** Java导出mysql数据库表结构信息到excel中的同一个sheet页,并合并表名和表注释* @author wangdy* 2025/3/14*/
public class DatabaseExporterToOneSheet {private static final Pattern INVALID_SHEETNAME_CHARS = Pattern.compile("[\\\\/*?\\[\\]:]");private static final int MAX_SHEETNAME_LENGTH = 31;public static void exportToExcel(String dbName, String jdbcUrl, String username, String password, String outputPath)throws Exception {Connection conn = null;Workbook workbook = new XSSFWorkbook();Sheet sheet = workbook.createSheet(dbName);try {conn = DriverManager.getConnection(jdbcUrl, username, password);DatabaseMetaData metaData = conn.getMetaData();ResultSet tables = metaData.getTables(dbName, null, "%", new String[]{"TABLE"});createHeaderRow(sheet);int rowNum = 1;int startRow = 1;int endRow = 1;while (tables.next()) {// String catalog = tables.getString("TABLE_CAT");// String schema = tables.getString("TABLE_SCHEM");String tableName = tables.getString("TABLE_NAME");String tableRemarks = tables.getString("REMARKS");ResultSet columns = metaData.getColumns(null, null, tableName, null);Set<String> primaryKeys = getPrimaryKeys(metaData, tableName);startRow = rowNum;while (columns.next()) {Row row = sheet.createRow(rowNum++);fillRowData(tableName, tableRemarks, columns, primaryKeys, row);}endRow = rowNum - 1;// 合并该表表名和表注释:new CellRangeAddress(0, 0, 0, 3)表示合并从第0行第0列到第0行第3列的区域。sheet.addMergedRegion(new CellRangeAddress(startRow, endRow, 0, 0));sheet.addMergedRegion(new CellRangeAddress(startRow, endRow, 1, 1));columns.close();}autoSizeColumns(sheet, 9);try (FileOutputStream outputStream = new FileOutputStream(outputPath)) {workbook.write(outputStream);}} finally {if (conn != null) {conn.close();}workbook.close();}}private static String generateBaseSheetName(String catalog, String schema, String tableName) {// 优先使用schema信息,MySQL中一般用catalog表示数据库String prefix = "";if (schema != null && !schema.isEmpty()) {prefix = schema;} else if (catalog != null && !catalog.isEmpty()) {prefix = catalog;}String rawName = prefix.isEmpty()? tableName: prefix + "_" + tableName;// 替换非法字符并格式化return formatSheetName(rawName);}private static String formatSheetName(String rawName) {// 1. 替换非法字符String sanitized = INVALID_SHEETNAME_CHARS.matcher(rawName).replaceAll("_");// 2. 去除首尾特殊字符sanitized = sanitized.replaceAll("^[\\s']+", "").replaceAll("[\\s']+$", "");// 3. 压缩连续下划线sanitized = sanitized.replaceAll("_{2,}", "_");// 4. 截断长度return sanitized.length() > MAX_SHEETNAME_LENGTH? sanitized.substring(0, MAX_SHEETNAME_LENGTH): sanitized;}private static void createHeaderRow(Sheet sheet) {Row headerRow = sheet.createRow(0);String[] headers = {"表名称", "表注释", "字段名称", "字段类型", "长度", "是否主键", "允许空值", "默认值", "字段注释"};CellStyle headerStyle = createHeaderStyle(sheet.getWorkbook());for (int i = 0; i < headers.length; i++) {Cell cell = headerRow.createCell(i);cell.setCellValue(headers[i]);cell.setCellStyle(headerStyle);}}private static CellStyle createHeaderStyle(Workbook workbook) {CellStyle style = workbook.createCellStyle();Font font = workbook.createFont();font.setBold(true);style.setFont(font);style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());style.setFillPattern(FillPatternType.SOLID_FOREGROUND);return style;}private static Set<String> getPrimaryKeys(DatabaseMetaData metaData, String tableName) throws SQLException {Set<String> primaryKeys = new HashSet<>();ResultSet pkResultSet = metaData.getPrimaryKeys(null, null, tableName);while (pkResultSet.next()) {primaryKeys.add(pkResultSet.getString("COLUMN_NAME"));}pkResultSet.close();return primaryKeys;}private static void fillRowData(String tableName, String tableRemarks, ResultSet columns, Set<String> primaryKeys, Row row) throws SQLException {String columnName = columns.getString("COLUMN_NAME");String typeName = columns.getString("TYPE_NAME");int columnSize = columns.getInt("COLUMN_SIZE");String isNullable = columns.getString("IS_NULLABLE");String defaultValue = columns.getString("COLUMN_DEF");String remarks = columns.getString("REMARKS");row.createCell(0).setCellValue(tableName);row.createCell(1).setCellValue(tableRemarks);row.createCell(2).setCellValue(columnName);row.createCell(3).setCellValue(typeName);row.createCell(4).setCellValue(columnSize);row.createCell(5).setCellValue(primaryKeys.contains(columnName) ? "是" : "否");row.createCell(6).setCellValue("YES".equalsIgnoreCase(isNullable) ? "是" : "否");row.createCell(7).setCellValue(defaultValue != null ? defaultValue : "");row.createCell(8).setCellValue(remarks != null ? remarks : "");}private static void autoSizeColumns(Sheet sheet, int columnCount) {for (int i = 0; i < columnCount; i++) {sheet.autoSizeColumn(i, true);}}public static void main(String[] args) {try {String jdbcUrl = "jdbc:mysql://127.0.0.1:3306/books-service?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai";String username = "root";String password = "xxxxxx";String outputPath = "数据库表结构.xlsx";exportToExcel("books-service", jdbcUrl, username, password, outputPath);System.out.println("导出成功!");} catch (Exception e) {e.printStackTrace();}}
}

4.2 结果

结果如下图所示,非常Nice。
在这里插入图片描述

END


http://www.mrgr.cn/news/94337.html

相关文章:

  • 小程序网络大文件缓存方案
  • 用DasViewer的时候3Dtiles 转osgb 可以直接指定目标坐标系吗?
  • 双指针算法专题之——复写零
  • 记录一个SQL自动执行的html页面
  • 求递增子序列LIS的两种方法
  • 深度学习正则化技术之权重衰减法、暂退法(通俗易懂版)
  • LangChain+InternLM2搭建知识库
  • 条款1:理解模版性别推导
  • Kubernetes教程(九)了解卷volume的emptyDir和hostPath
  • 将串口接收到的十六进制数据转为十进制
  • ⭐算法OJ⭐汉明距离【位操作】(C++ 实现)Hamming Distance
  • 【vue + JS】OCR图片识别、文字识别
  • 《基于大数据的营养果蔬推荐系统的设计与实现》开题报告
  • 在 Windows 上快速部署 OpenManus:从安装到运行
  • 计算机网络——DHCP实验
  • python -面试题--算法
  • RGV调度算法(三)--遗传算法
  • LeetCode 解题思路 15(Hot 100)
  • 独立开发记录:使用Trae和Cloudflare快速搭建了自己的个人博客
  • ES6回顾:闭包->(优点:实现工厂函数、记忆化和异步实现)、(应用场景:Promise的then与catch的回调、async/await、柯里化函数)