工具(十二):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.pswp.cn/news/898199.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/898199.shtml
英文地址,請注明出處:http://en.pswp.cn/news/898199.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Postman 新手入門指南:從零開始掌握 API 測試

Postman 新手入門指南&#xff1a;從零開始掌握 API 測試 一、Postman 是什么&#xff1f; Postman 是一款功能強大的 API 開發與測試工具&#xff0c;支持 HTTP 請求調試、自動化測試、團隊協作等功能。無論是開發人員還是測試工程師&#xff0c;都可以用它快速驗證接口的正確…

運維工具推薦 -- 寶塔面板:一鍵部署服務器

標題&#xff1a;寶塔面板&#xff1a;一鍵部署服務器&#xff0c;輕松管理你的云端世界 引言 在數字化時代&#xff0c;服務器管理對于個人開發者、中小企業或站長來說既是機遇也是挑戰。手動配置服務器環境耗時費力&#xff0c;而 寶塔面板 作為一款 免費開源、功能全面 的服…

【軟件工程】03_軟件需求分析

3.1 系統分析 1. 系統分析概述 系統分析是一組統稱為計算機系統工程的活動。它著眼于所有的系統元素,而非僅僅局限于軟件。系統分析主要探索軟件項目的目標、市場預期、主要的技術指標等,其目的在于幫助決策者做出是否進行軟件項目立項的決定。 2. 可行性分析(Feasibility …

WD5202L超低成本 Buck 電源芯片的特性與應用電路解析, 將市電轉換為 5V 電壓

WD5202L&#xff1a;超低成本 Buck 電源芯片的特性與應用電路解析 在現代電子設備的小型化、低成本化趨勢下&#xff0c;對電源管理芯片的性能、成本和尺寸提出了嚴苛要求。WD5202L 作為一款超低成本的 Buck 電源芯片&#xff0c;憑借其獨特的特性&#xff0c;在眾多應用場景中…

UART轉AHB模塊ModelSim仿真

一、簡介 UART轉AHB模塊用于實現一種簡單的通過上位機控制FPGA內部寄存器的方式。上位機通過串口助手發送讀寫寄存器的指令&#xff0c;UART轉AHB模塊接收指令后解析出地址&#xff0c;命令&#xff0c;數據信息&#xff0c;然后轉成AHB總線格式輸出。這時UART轉AHB模塊相當于A…

Qt5.15.2實現Qt for WebAssembly與示例

目錄 1.什么是Qt for WebAssembly&#xff1f; 1.1 什么是 WebAssembly&#xff1f; 1.2 WebAssembly 的優勢 1.3 什么是 Qt for WebAssembly&#xff1f; 1.4 Qt for WebAssembly 的特點 1.5 編譯過程 1.6 運行時環境 注意&#xff01;&#xff01;&#xff01;注意&am…

AGI大模型(8):提示詞的安全與防護

1 前言 著名的「奶奶漏洞」&#xff0c;?套路把 AI 繞懵。 2 常?的提示詞攻擊技術 2.1 同類型?標劫持 同類?標劫持攻擊&#xff0c;特別是在同類型任務的背景下&#xff0c;涉及到攻擊者通過?法?段控制模型&#xff0c;并迫使其執行與原始任務性質相同但?標不同的操作…

使用redis客戶端中對于json數據格式的存儲和讀取

代碼背景&#xff1a; 現在有一個json格式的數據&#xff0c;但是由于redis客戶端上面沒辦法直接創建/導入json的數據格式。 故考慮現在redis客戶端上先存儲一個名為"old_order"的string類型的的源數據。 思路&#xff1a; 由于直接使用redisTemplate獲取自動導入…

專題三搜索插入位置

1.題目 題目分析&#xff1a; 給一個目標值&#xff0c;然后要在排序的整數數組中&#xff0c;找到跟目標值一樣的&#xff0c;如果沒有就把這個值插入進去&#xff0c;然后返回插入后的下標。 2.算法原理 根據題目的時間復雜度可以知道要用二分&#xff0c;開始劃分區域&…

Redis監控:從睜眼瞎到千里眼的進化史

各位在Redis迷霧中摸黑的探險家們&#xff01;今天我們要給Redis裝上"天眼系統"——從連自己內存爆了都不知道的睜眼瞎&#xff0c;進化到連每秒哪個鍵被摸了幾次都門兒清的監控狂魔&#xff01;準備好迎接《Redisの楚門世界》了嗎&#xff1f;&#x1f441;? 第一幕…

雙緩沖機制(含原理、優勢、實現方式、應用場景)

雙緩沖機制 一、雙緩沖機制的原理二、雙緩沖的典型應用場景三、雙緩沖的優勢四、雙緩沖的實現方式1. 硬件級雙緩沖2. 軟件級雙緩沖3. 性能提升對比 五、雙緩沖的挑戰與解決方案六、總結 雙緩沖機制是一種通過使用兩個緩沖區&#xff08;Buffer A 和 Buffer B&#xff09;來優化…

Linux 進程的創建、終止、等待與程序替換函數 保姆級講解

目錄 一、 進程創建 fork函數 二、進程的終止&#xff1a; 1. 想明白&#xff1a;終止是在做什么&#xff1f; 2.進程終止的3種情況&#xff1f; a.退出碼是什么&#xff1f;存在原因&#xff1f;為什么int main&#xff08;&#xff09;return 0? b.第三種進程終止的情況…

深入了解Linux —— git三板斧

版本控制器git 為了我們方便管理不同版本的文件&#xff0c;就有了版本控制器&#xff1b; 所謂的版本控制器&#xff0c;就是能夠了解到一個文件的歷史記錄&#xff08;修改記錄&#xff09;&#xff1b;簡單來說就是記錄每一次的改動和版本迭代的一個管理系統&#xff0c;同…

STM32---FreeRTOS事件標志組

一、簡介 事件標志位&#xff1a;用一個位&#xff0c;來表示事件是否發生 事件標志組&#xff1a;一組事件標志位的集合&#xff0c;可以簡單的理解時間標志組&#xff0c;就是一個整體。 事件標志租的特點&#xff1a; 它的每一個位表示一個時間&#xff08;高8位不算&…

在centOS Linux系統搭建自動化構建工具Jenkins

前言 在工作中發現公司使用Jenkins實現自動化部署項目方案&#xff0c;于是閑著自己也搗鼓一下&#xff0c;網上查閱相關部署資料&#xff0c;順便記錄操作步驟&#xff0c;所以有了下面這篇的文章。 部署完之后&#xff0c;安裝前端項目所需環境&#xff0c;比如node環境&am…

Git下載安裝(保姆教程)

目錄 1、Git下載 2、Git安裝&#xff08;windows版&#xff09; &#xff08;1&#xff09;啟動安裝程序 &#xff08;2&#xff09;閱讀許可協議 &#xff08;3&#xff09;選擇安裝路徑 &#xff08;4&#xff09;選擇組件 &#xff08;5&#xff09;選擇開始菜單文件夾…

深入理解嵌入式開發中的三個重要工具:零長度數組、container_of 和 typeof

在嵌入式開發中,內核開發者經常需要處理復雜的數據結構和動態內存分配。零長度數組、container_of 宏和 typeof 是內核開發中三個非常重要的工具,它們在結構體管理、內存操作和類型處理中發揮著關鍵作用。本文將詳細探討這三個工具的功能、應用場景及其在內核開發中的重要性。…

【react】react中的<></>和React Fragment的用法及區別詳解

目錄 1、<>是什么 2、為什么要使用<>&#xff1f; 3、如何使用<>&#xff1f; 基本用法 需要傳遞屬性時&#xff08;如key&#xff09; 使用效果 注意事項 總結 4、React Fragment 與空標簽&#xff08;<>&#xff09;詳解 1. Fragment 的用…

【人工智能】使用Python實現時間序列異常檢測:從基礎到深度學習模型的全方位探索

《Python OpenCV從菜鳥到高手》帶你進入圖像處理與計算機視覺的大門! 解鎖Python編程的無限可能:《奇妙的Python》帶你漫游代碼世界 時間序列異常檢測是數據分析領域中的重要課題,廣泛應用于金融、醫療、工業監控等多個行業。本篇文章深入探討了時間序列異常檢測的基本技術…

Keytool常見問題全解析:從環境配置到公鑰提取

引言 在Android開發、跨平臺應用構建&#xff08;如UniApp&#xff09;或服務端證書管理中&#xff0c;keytool 是一個不可或缺的工具。然而&#xff0c;許多開發者在使用 keytool 時&#xff0c;常因環境配置、路徑權限、密碼問題等導致操作失敗。本文基于真實問題場景&#…