MyBatisリバースエンジニアリングと日本語アノテーション

日本語コメントフィールドが取得できない場合は、以下の方法を試してみてください。

以下の設定はすべて、MyBatis Generatorの設定ファイル(通常はgeneratorConfig.xmlと呼ばれます)に関するものです。

MySQL

方法1:

<jdbcConnection driverClass="${driver}"
    connectionURL="{url}" userId="${username}" password="${password}">
    <!-- MySQLデータベース向け -->
    <property name="useInformationSchema" value="true"></property>
</jdbcConnection>

方法2

connectionURL="jdbc:mysql://127.0.0.1:3306/test?characterEncoding=UTF-8&useInformationSchema=true"

Oracle

<jdbcConnection driverClass="${driver}"
    connectionURL="{url}" userId="${username}" password="${password}">
    <!-- Oracleデータベース向け -->
    <property name="remarksReporting" value="true"></property>
</jdbcConnection>

詳細解説

MBG(MyBatis Generator)はデータベースへのアクセスもJDBCを介して行いますが、OracleやMySQL(その他のデータベースについては未確認)にJDBC接続して、テーブルやフィールドのコメントを取得するには、追加の接続プロパティ設定が必要です。一般的には、以下のようなコードになります(Oracleを例に):

まず、MBGのデータベース接続コードを見てみましょう。org.mybatis.generator.internal.JDBCConnectionFactoryにあります:

    public JDBCConnectionFactory(JDBCConnectionConfiguration config) {
        super();
        userId = config.getUserId();
        password = config.getPassword();
        connectionURL = config.getConnectionURL();
        driverClass = config.getDriverClass();
        otherProperties = config.getProperties(); // この行に注意
    }
    
    public Connection getConnection()
            throws SQLException {
        Driver driver = getDriver();

        Properties props = new Properties();

        if (stringHasValue(userId)) {
            props.setProperty("user", userId); //$NON-NLS-1$
        }

        if (stringHasValue(password)) {
            props.setProperty("password", password); //$NON-NLS-1$
        }

        props.putAll(otherProperties); // この行に注意

        Connection conn = driver.connect(connectionURL, props);

        if (conn == null) {
            throw new SQLException(getString("RuntimeError.7")); //$NON-NLS-1$
        }

        return conn;
    }

上記のコード(特に「注意」とコメントした2行)からわかるように、MBGは接続を確立する際に、JDBCConnectionConfigurationのすべてのプロパティを設定しています。では、これらのプロパティをどこで設定すればよいかを見つけましょう。JDBCConnectionConfigurationはXML設定のjdbcConnectionノードに対応します。

公式の使用ドキュメントを見てみましょう。公式ドキュメントのjdbcConnection(クリックして確認)セクションの<property>サブ要素の説明:

  • <property> (0..N) 注記: ここで指定されたプロパティは、JDBCドライバのプロパティに追加されます。

したがって、設定ファイルを以下のように変更できます:

<jdbcConnection driverClass="${driver}"
    connectionURL="{url}" userId="${username}" password="${password}">
    <!-- Oracleデータベース向け -->
    <property name="remarksReporting" value="true"></property>
</jdbcConnection>

MyBatis Generatorにはコメント生成機能が組み込まれていますが、英語であり、生成されたコメントは理解するのが困難です。そのため、ソースコードを変更して日本語のコメントを生成することができます。具体的な方法は以下の通りです:

  1. カスタムCommentGeneratorの作成
  2. ソースコードの変更
  3. PluginAdapterプラグインの形式

この例では、カスタムCommentGeneratorを使用して実装します。

  1. Mavenプロジェクトを作成し、pom.xmlを変更します:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <groupId>com.example.platform</groupId>
    <version>0.0.1</version>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>example-generator</artifactId>

    <properties>
        <!-- 依存バージョン -->
        <mapper.version>3.3.9</mapper.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.25</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper</artifactId>
            <version>${mapper.version}</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.4.0</version>
        </dependency>
    </dependencies>

    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
        </resources>

        <plugins>
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.4.0</version>
                <configuration>
                    <configurationFile>${basedir}/src/main/resources/generatorConfig.xml</configurationFile>
                    <overwrite>true</overwrite>
                    <verbose>true</verbose>
                </configuration>
                <executions>
                    <execution>
                        <id>Generate MyBatis Artifacts</id>
                        <!-- パッケージ段階では実行しない。設定しないとpackageライフサイクルで実行される -->
                        <phase>deploy</phase>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
                <dependencies>
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>8.0.25</version>
                    </dependency>
                    <dependency>
                        <groupId>org.mybatis.generator</groupId>
                        <artifactId>mybatis-generator-core</artifactId>
                        <version>1.4.0</version>
                    </dependency>
                    <dependency>
                        <groupId>tk.mybatis</groupId>
                        <artifactId>mapper</artifactId>
                        <version>${mapper.version}</version>
                    </dependency>
                    <dependency>
                        <groupId>com.example.platform</groupId>
                        <artifactId>example-generator</artifactId>
                        <version>0.0.1</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>
</project>

javaディレクトリにカスタムアノテーションクラスAnnotations.javaを追加します:

public enum Annotations {

    DATA("data", "@Data", "lombok.Data"),
    BUILDER("builder", "@Builder", "lombok.Builder"),
    ALL_ARGS_CONSTRUCTOR("allArgsConstructor", "@AllArgsConstructor", "lombok.AllArgsConstructor"),
    NO_ARGS_CONSTRUCTOR("noArgsConstructor", "@NoArgsConstructor", "lombok.NoArgsConstructor"),
    ACCESSORS("accessors", "@Accessors", "lombok.experimental.Accessors"),
    TO_STRING("toString", "@ToString", "lombok.ToString");


    private final String paramName;
    private final String name;
    public final FullyQualifiedJavaType javaType;
    private final List<String> options;


    Annotations(String paramName, String name, String className) {
        this.paramName = paramName;
        this.name = name;
        this.javaType = new FullyQualifiedJavaType(className);
        this.options = new ArrayList<String>();
    }

    public static Annotations getValueOf(String paramName) {
        for (Annotations annotation : Annotations.values()) {
            if (String.CASE_INSENSITIVE_ORDER.compare(paramName, annotation.paramName) == 0) {
                return annotation;
            }
        }
        return null;
    }

    public static Collection<Annotations> getDependencies(Annotations annotation) {
        if (annotation == ALL_ARGS_CONSTRUCTOR) {
            return Collections.singleton(NO_ARGS_CONSTRUCTOR);
        } else {
            return Collections.emptyList();
        }
    }

    private static String quote(String value) {
        if (Boolean.TRUE.toString().equals(value) || Boolean.FALSE.toString().equals(value)) {
            // ブール値の場合、配列として渡されない
            return value;
        }
        return value.replaceAll("[\\w]+", "\"$0\"");
    }

    public void appendOptions(String key, String value) {
        String keyPart = key.substring(key.indexOf(".") + 1);
        String valuePart = value.contains(",") ? String.format("{%s}", value) : value;
        this.options.add(String.format("%s=%s", keyPart, quote(valuePart)));
    }

    public String asAnnotation() {
        if (options.isEmpty()) {
            return name;
        }
        StringBuilder sb = new StringBuilder();
        sb.append(name);
        sb.append("(");
        boolean first = true;
        for (String option : options) {
            if (first) {
                first = false;
            } else {
                sb.append(", ");
            }
            sb.append(option);
        }
        sb.append(")");
        return sb.toString();
    }
}

実装クラスEmptyCommentGenerator.java:

public class EmptyCommentGenerator implements CommentGenerator {
    @Override
    public void addConfigurationProperties(Properties properties) {

    }

    @Override
    public void addFieldComment(Field field, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) {

    }

    @Override
    public void addFieldComment(Field field, IntrospectedTable introspectedTable) {

    }

    @Override
    public void addModelClassComment(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {

    }

    @Override
    public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable) {

    }

    @Override
    public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable, boolean b) {

    }

    @Override
    public void addEnumComment(InnerEnum innerEnum, IntrospectedTable introspectedTable) {

    }

    @Override
    public void addGetterComment(Method method, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) {

    }

    @Override
    public void addSetterComment(Method method, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) {

    }

    @Override
    public void addGeneralMethodComment(Method method, IntrospectedTable introspectedTable) {

    }

    @Override
    public void addJavaFileComment(CompilationUnit compilationUnit) {

    }

    @Override
    public void addComment(XmlElement xmlElement) {

    }

    @Override
    public void addRootComment(XmlElement xmlElement) {

    }

    @Override
    public void addGeneralMethodAnnotation(Method method, IntrospectedTable introspectedTable, Set<FullyQualifiedJavaType> set) {

    }

    @Override
    public void addGeneralMethodAnnotation(Method method, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn,
                                           Set<FullyQualifiedJavaType> set) {

    }

    @Override
    public void addFieldAnnotation(Field field, IntrospectedTable introspectedTable, Set<FullyQualifiedJavaType> set) {

    }

    @Override
    public void addFieldAnnotation(Field field, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn,
                                   Set<FullyQualifiedJavaType> set) {

    }

    @Override
    public void addClassAnnotation(InnerClass innerClass, IntrospectedTable introspectedTable, Set<FullyQualifiedJavaType> set) {

    }
}

クラスMyCommentGenerator.java:

public class MyCommentGenerator extends EmptyCommentGenerator {
    private final Collection<Annotations> annotations;
    private String author;
    /**
     * 現在日時
     */
    private String currentDateStr;


    public MyCommentGenerator() {
        currentDateStr = (new SimpleDateFormat("yyyy-MM-dd")).format(new Date());
        annotations = new LinkedHashSet<>(Annotations.values().length);
    }


    @Override
    public void addConfigurationProperties(Properties properties) {
//        annotations.add(Annotations.DATA);
        for (String stringPropertyName : properties.stringPropertyNames()) {
            if (stringPropertyName.contains(".")) {
                continue;
            }
            if (!Boolean.parseBoolean(properties.getProperty(stringPropertyName))) {
                continue;
            }
            Annotations annotation = Annotations.getValueOf(stringPropertyName);
            if (annotation == null) {
                continue;
            }

            String optionsPrefix = stringPropertyName + ".";
            for (String propertyName : properties.stringPropertyNames()) {
                if (!propertyName.startsWith(optionsPrefix)) {
                    continue;
                }
                String propertyValue = properties.getProperty(propertyName);
                annotation.appendOptions(propertyName, propertyValue);
                annotations.add(annotation);
                annotations.addAll(Annotations.getDependencies(annotation));
            }
            annotations.add(annotation);
        }
        author = properties.getProperty("author");
    }

    @Override
    public void addModelClassComment(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
        String remarks = introspectedTable.getRemarks();
        topLevelClass.addJavaDocLine("/**");
        topLevelClass.addJavaDocLine(" * " + remarks);
        topLevelClass.addJavaDocLine(" * ");
        topLevelClass.addJavaDocLine(" * @author " + author);
        topLevelClass.addJavaDocLine(" * @date " + currentDateStr);
        topLevelClass.addJavaDocLine(" */");
        addClassAnnotation(topLevelClass);
    }


    private void addClassAnnotation(TopLevelClass topLevelClass) {
        for (Annotations annotation : annotations) {
            topLevelClass.addImportedType(annotation.javaType);
            topLevelClass.addAnnotation(annotation.asAnnotation());
        }
    }

    @Override
    public void addFieldComment(Field field, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) {
        String remarks = introspectedColumn.getRemarks();
        field.addJavaDocLine("/**");
        field.addJavaDocLine(" * " + remarks);
        field.addJavaDocLine(" */");
    }
}

resourcesディレクトリにconfig.propertiesファイルとgeneratorConfig.xmlファイルを追加します。

config.propertiesの内容:

jdbc.driverClass=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://192.168.110.110:3306/wmsoft?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
jdbc.user=root
jdbc.password=123456

mapper.plugin=tk.mybatis.mapper.generator.MapperPlugin
mapper.Mapper=tk.mybatis.mapper.common.Mapper
mapper.forceAnnotation=true

targetModelPackage=com.example.system.core.domain
targetXMLPackage=com.example.system.core.mapper.xml
targetMapperPackage=com.example.system.core.mapper
targetJavaProject=E:/code/example-generator/src/main/java
targetResourcesProject=E:/code/example-generator/src/main/java

generatorConfig.xmlの内容:

<?xml version="1.0" encoding="UTF-8"?>
<generatorConfiguration>
    <properties resource="config.properties"/>

    <context id="Mysql" targetRuntime="MyBatis3" defaultModelType="flat">
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/>

        <!-- シリアライズのサポート -->
        <plugin type="org.mybatis.generator.plugins.SerializablePlugin"></plugin>
        <!-- XMLの重複生成を防止 -->
        <plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin" />
        <!--        <commentGenerator>-->
        <!--            &lt;!&ndash; 自動生成されたコメントを削除するか true:削除する false:削除しない &ndash;&gt;-->
        <!--            <property name="suppressAllComments" value="false"/>-->
        <!--            <property name="addRemarkComments" value="true"/>-->
        <!--        </commentGenerator>-->

        <commentGenerator type="com.MyCommentGenerator">
            <property name="author" value="mx"/>
            <property name="allArgsConstructor" value="false"/>
            <property name="noArgsConstructor" value="false"/>
            <property name="toString" value="false"/>
            <property name="builder.toBuilder" value="false"/>
            <property name="data" value="false"/>
            <property name="builder" value="false"/>
        </commentGenerator>

        <jdbcConnection driverClass="${jdbc.driverClass}"
                        connectionURL="${jdbc.url}"
                        userId="${jdbc.user}"
                        password="${jdbc.password}">
            <!-- テーブルコメントを取得するにはuseInformationSchemaプロパティをtrueに設定 -->
            <property name="useInformationSchema" value="true"/>
            <!-- 同じ名前のテーブルが存在する場合の判定 -->
            <property name="nullCatalogMeansCurrent" value="true"/>
        </jdbcConnection>

        <javaTypeResolver type="org.mybatis.generator.internal.types.JavaTypeResolverDefaultImpl">
            <property name="useJSR310Types" value="true"/>
        </javaTypeResolver>

        <javaModelGenerator targetPackage="${targetModelPackage}" targetProject="${targetJavaProject}">
            <!-- enableSubPackages: schemaをパッケージの接尾辞にするか -->
            <property name="enableSubPackages" value="false"/>
            <!-- データベースから返された値の前後の空白を削除 -->
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>

        <sqlMapGenerator targetPackage="${targetXMLPackage}" targetProject="${targetResourcesProject}">
            <!-- enableSubPackages: schemaをパッケージの接尾辞にするか -->
            <property name="enableSubPackages" value="false"/>
        </sqlMapGenerator>

        <javaClientGenerator targetPackage="${targetMapperPackage}" targetProject="${targetResourcesProject}"
                             type="XMLMAPPER">
            <!-- enableSubPackages: schemaをパッケージの接尾辞にするか -->
            <property name="enableSubPackages" value="false"/>
        </javaClientGenerator>

        <!-- すべてのテーブルをリバースエンジニアリング対象に -->
        <!-- 以下のexampleはfalseに設定するとexampleクラスが生成されず、trueの場合は自動生成されます -->
        <!--        -->
        

        <!-- 特定のテーブルのみリバースエンジニアリング対象に -->
        <!---->
    </context>
</generatorConfiguration>

関連ファイルの作成後のディレクトリ構成:

生成方法1

生成ファイル用のクラスStartUp.javaを作成します:

public class StartUp {
    /**
     * 公式ドキュメント: http://mybatis.org/generator/index.html
     */
    public static void main(String[] args) {
        try {
            List<String> warnings = new ArrayList<>();
            ClassLoader classloader = Thread.currentThread().getContextClassLoader();
            InputStream is = classloader.getResourceAsStream("generatorConfig.xml");
            ConfigurationParser cp = new ConfigurationParser(warnings);
            Configuration config = cp.parseConfiguration(is);
            DefaultShellCallback callback = new DefaultShellCallback(true);
            MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
            myBatisGenerator.generate(null);
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (InvalidConfigurationException e) {
            e.printStackTrace();
        } catch (XMLParserException e) {
            e.printStackTrace();
        }
    }
}

mainメソッドを実行すればファイルが生成されます。

生成されたエンティティやマッパーが他のオブジェクトやインターフェースを継承するように設定するには:

        <javaModelGenerator targetPackage="${targetModelPackage}" targetProject="${targetJavaProject}">
            <!-- enableSubPackages: schemaをパッケージの接尾辞にするか -->
            <property name="enableSubPackages" value="false"/>
            <!-- データベースから返された値の前後の空白を削除 -->
            <property name="trimStrings" value="true"/>
            <property name="rootClass" value="com.XXX.BaseEntity"/>
        </javaModelGenerator>

        <javaClientGenerator targetPackage="${targetMapperPackage}" targetProject="${targetJavaProject}"
                             type="XMLMAPPER">
            <!-- enableSubPackages: schemaをパッケージの接尾辞にするか -->
            <property name="enableSubPackages" value="true"/>
            <property name="rootInterface" value="com.XXX.BaseMapper"/>
        </javaClientGenerator>

さらに、生成されたエンティティやマッパーの内容をカスタマイズしたい場合は、MyBatis Generatorが生成するMapperをより簡潔にするを参考にしてください。

生成方法2

まずMavenプロジェクトをインストールし、設定ファイルを通じてMavenプラグインを実行してファイルを生成します。

生成後のディレクトリパス:

生成されたエンティティファイルに日本語コメントが含まれています:

生成方法3

IDEAのプラグインMyBatisCodeHelperなどを使用して生成することもできます。

タグ: MyBatis リバースエンジニアリング Java アノテーション

5月30日 18:38 投稿