diff --git a/pom.xml b/pom.xml index 690b6a5..dc4cd5d 100644 --- a/pom.xml +++ b/pom.xml @@ -43,6 +43,13 @@ ${querydsl.version} + + org.hibernate.orm + hibernate-ant + 6.6.15.Final + provided + + org.mapstruct mapstruct diff --git a/src/main/java/com/lanyuanxiaoyao/service/template/util/DDLGenerator.java b/src/main/java/com/lanyuanxiaoyao/service/template/util/DDLGenerator.java new file mode 100644 index 0000000..a430142 --- /dev/null +++ b/src/main/java/com/lanyuanxiaoyao/service/template/util/DDLGenerator.java @@ -0,0 +1,116 @@ +package com.lanyuanxiaoyao.service.template.util; + +import jakarta.persistence.Entity; +import java.util.EnumSet; +import java.util.List; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.model.naming.CamelCaseToUnderscoresNamingStrategy; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.tool.hbm2ddl.SchemaExport; +import org.hibernate.tool.schema.TargetType; +import org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy; +import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; +import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.util.ClassUtils; + +/** + * 构造DDL建表语句 + *

+ * 该工具类用于生成数据库表结构的DDL语句,通过扫描指定包下的实体类, + * 利用Hibernate的SchemaExport工具生成建表SQL脚本。 + *

+ * + *

+ * 使用示例: + *

+ * DDLGenerator.generateDDL(
+ *     List.of("com.example.entity", "com.another.package"),
+ *     "./sql",
+ *     MySQL8Dialect.class,
+ *     "jdbc:mysql://localhost:3306/test",
+ *     "username",
+ *     "password",
+ *     com.mysql.cj.jdbc.Driver.class
+ * );
+ * 
+ *

+ * + * @author lanyuanxiaoyao + */ +public class DDLGenerator { + public static void generateDDL( + List entityPackages, + String ddlFilePath, + Class dialect, + String jdbc, + String username, + String password, + Class driver + ) { + var metadataSources = new MetadataSources( + new StandardServiceRegistryBuilder() + .applySetting("hibernate.dialect", dialect.getName()) + .applySetting("hibernate.physical_naming_strategy", CamelCaseToUnderscoresNamingStrategy.class.getName()) + .applySetting("hibernate.implicit_naming_strategy", SpringImplicitNamingStrategy.class.getName()) + .applySetting("hibernate.connection.url", jdbc) + .applySetting("hibernate.connection.username", username) + .applySetting("hibernate.connection.password", password) + .applySetting("hibernate.connection.driver_class", driver.getName()) + .build() + ); + + // 使用Spring类路径扫描方式查找所有@Entity注解的类 + var scanner = new ClassPathScanningCandidateComponentProvider(false); + scanner.addIncludeFilter(new AnnotationTypeFilter(Entity.class)); + + // 遍历所有包路径,扫描@Entity注解的类 + for (String entityPackage : entityPackages) { + var candidates = scanner.findCandidateComponents(entityPackage); + + // 将找到的实体类添加到metadataSources中 + for (var candidate : candidates) { + // 处理candidate或getBeanClassName可能为null的情况 + if (candidate == null || candidate.getBeanClassName() == null) { + continue; + } + + try { + var entityClass = ClassUtils.forName(candidate.getBeanClassName(), DDLGenerator.class.getClassLoader()); + metadataSources.addAnnotatedClass(entityClass); + } catch (ClassNotFoundException e) { + throw new RuntimeException("Failed to load entity class: " + candidate.getBeanClassName(), e); + } + } + } + + var export = new SchemaExport(); + export.setFormat(true); + export.setDelimiter(";"); + export.setOutputFile(ddlFilePath + "/" + dialect.getSimpleName() + ".sql"); + export.setOverrideOutputFileContent(); + export.execute(EnumSet.of(TargetType.SCRIPT), SchemaExport.Action.CREATE, metadataSources.buildMetadata()); + } + + /** + * 兼容旧版本的方法签名 + * + * @param entityPackage 实体类包路径 + * @param ddlFilePath DDL文件输出路径 + * @param dialect 方言类 + * @param jdbc JDBC连接URL + * @param username 数据库用户名 + * @param password 数据库密码 + * @param driver JDBC驱动类 + */ + public static void generateDDL( + String entityPackage, + String ddlFilePath, + Class dialect, + String jdbc, + String username, + String password, + Class driver + ) { + generateDDL(List.of(entityPackage), ddlFilePath, dialect, jdbc, username, password, driver); + } +} \ No newline at end of file