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

工具(十二):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方法运行即可。

三、结果截图:

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

END


http://www.kler.cn/a/583870.html

相关文章:

  • 5G/6G通信技术
  • 便利店商品推荐数字大屏:基于python和streamlit
  • js下载blob二进制文件流 预览
  • 瑞芯微RK3588安卓使用fastboot分区烧录
  • 江科大51单片机笔记【12】AT24C02(I2C总线)
  • 浙江大学第四讲:DeepSeek模型优势:算力、成本角度解读(含PPT及直播回放)(文末附链接下载)
  • 前端面试:px 如何转为 rem
  • DrBioRight2.0:用于癌症蛋白组分析的生物学聊天机器人
  • 【Linux篇】进程状态(僵尸进程,孤儿进程),优先级与调度机制
  • 内检实验室lims系统在电子设备制造行业的应用
  • 中小型企业如何利用远程控制方案来降低40%运维成本的
  • 麒麟v10 ARM64架构系统升级mysql数据库从mysql-5.7.27到mysql-8.4.4图文教程
  • Django系列教程(7)——路由配置URLConf
  • 使用AI一步一步实现若依前端(12)
  • 快读模板(Java)
  • 【后端开发面试题】每日 3 题(十二)
  • 【从零开始学习计算机科学】数据库系统(九)DBMS的体系结构
  • 复变函数摘记1
  • 在微信小程序或前端开发中,picker 和 select 都是用户交互中用于选择的组件,但它们在功能、设计和使用场景上有一定的区别
  • 桂云OSG:什么是桂链?