12

私は、Mybatis (Java をデータベースに永続化するため) とMybatis Generator (データベース スキーマからマッパー xml ファイルと Java インターフェイスを自動的に生成するため) の両方を使用するプロジェクトに参加しています。

Mybatis ジェネレーターは、基本的な crud 操作に必要なファイルを適切に生成します。

環境

一部のテーブル/クラスでは、MyBatis ジェネレーター ツールによって生成された "crud stuff" よりも多くの "stuff" (コード クエリなど) が必要になります。

「両方の長所」を持つ方法はありますか。つまり、自動生成と「カスタム コード」を使用します。「手動で編集されたファイル」と「自動生成されたファイル」をどのように分離して構造化しますか。

提案

私は次のことを考えていました。つまり、テーブル「Foo」について

自動生成

  • FooCrudMapper.xml
  • インターフェイス FooCrud.java

(「Crud」は「Create Read Update Delete」の略です)

手編集

  • FooMapper.xml
  • インターフェイス Foo は FooCrud を拡張します

概念: スキーマが変更された場合、カスタム変更を消去することなく、「Crud」xml および .java ファイルを常に安全に自動生成できます。

質問

  • mybatis はこのシナリオを正しく処理しますか?つまり、このマッパーは自動生成された「crud コード」を正しく実行しますか?

    FooMapper fooMapper = sqlSession.getMapper(FooMapper.class);

  • どのようなアプローチをお勧めしますか?

編集 1: * 私たちのデータベース設計は、「コア テーブル」(「要素」) を他のテーブルと共に使用し、そのテーブルを「拡張」し、追加の属性 (共有キー) を追加します。私はドキュメントを見て、手動で編集せずに Mybatis Generator をそのような「拡張機能」と組み合わせて使用​​することはできないと結論付けました。

つまり、これは機能しません。-ElementMapper は「ElementCrudMapper」を拡張します -FooMapper.xml は「ElementCrudMapper」と「FooCrudMapper」の両方を拡張します

皆さんありがとう!

4

4 に答える 4

20

生成されたファイルと手動で編集されたファイルを分離できます。

mybatis-spring と spring を使用して dao インターフェースを管理しています。このライブラリは、MyBatis が Spring トランザクションに参加できるようにし、MyBatis マッパーと SqlSessions を作成して他の Bean に注入し、MyBatis 例外を Spring DataAccessExceptions に変換し、最後に、MyBatis、Spring、またはMyBatis-Spring .

DAO Interfaces については、汎用の MybatisBaseDao を作成して、mybatis ジェネレーターによって生成された基本インターフェイスを表します。

    public interface MybatisBaseDao<T, PK extends Serializable, E> {
    int countByExample(E example);

    int deleteByExample(E example);

    int deleteByPrimaryKey(PK id);

    int insert(T record);

    int insertSelective(T record);

    List<T> selectByExample(E example);

    T selectByPrimaryKey(PK id);

    int updateByExampleSelective(@Param("record") T record, @Param("example") E example);

    int updateByExample(@Param("record") T record, @Param("example") E example);

    int updateByPrimaryKeySelective(T record);

    int updateByPrimaryKey(T record);
    }

もちろん、お客様BaseDaoのご要望に応じてカスタマイズすることもできます。たとえば、 がありUserDaoます。次に、次のように定義できます。

public interface UserDao extends MybatisBaseDao<User, Integer, UserExample>{
    List<User> selectUserByAddress(String address); // hand edited query method
}

マッパー xml ファイルの場合、マッパー (.xml) ベース フォルダーに 2 つのパッケージを作成して、生成されたファイルと手動で編集されたファイルを分離します。上記UserDaoの場合、generator で生成された UserMapper.xml を「 generated 」という名前のパッケージに入れました。という名前のパッケージ内の別の UserMapper.xml ファイルに、すべて手書きのマッパー SQL を入れましたmanual。2 つのマッパー ファイルは同じヘッダーで始まります<mapper namespace="com.xxx.dao.UserDao" >。Mybatis は xml マッパー ファイルをスキャンして、SQL と対応するインターフェイス メソッドを自動的にマップできます。

生成されたエンティティとサンプル オブジェクトについては、直接上書きします。

上記の方法がお役に立てば幸いです!

于 2013-11-08T04:53:23.080 に答える
2

Larry.Z ソリューションは、同じ問題を解決して、手動で編集されたファイルから自動生成されたファイルを分離するのに役立ちます。私は自分のプロジェクトにカスタムフォルダー構造を持っていて、自分のプロジェクトで動作するように Larry ソリューションを適応させ、Larry ソリューションを適応させることで他の人を助けるためにこの回答を追加しました。

最良の解決策は、Mybatis ジェネレーター ( MBG ) に機能を追加して、手動で変更された xml マッパーを統合することです。対応するハンド ノード メソッドをクライアント マッパー インターフェイスに追加するには、MBG に解析機能を追加する必要がありましたが、現在この機能は存在しないため、Larry.Z ソリューションを使用して適応させました。

私のプロジェクトでは、次を使用します。

<properties>  
...  
<java.version>1.7</java.version>  
<spring.version>3.2.2.RELEASE</spring.version>  
<mybatis.version>3.2.2</mybatis.version>  
<mybatis-spring.version>1.2.0</mybatis-spring.version>  
<mybatis-generator-core.version>1.3.2</mybatis-generator-core.version>  
...  
</properties>  

私のフォルダ構造は次のとおりです。

<base>/dao/: MBG 生成された dao クラス

<base>/dao/extended/: 拡張生成クラス ( <DaoGeneratedName>Extended)

<base>/sqlmap/: MBG によって生成されたクライアント インターフェイスと対応する xml マッパー

<base>/sqlmap/extended/:
xml マッパーをハンドリングし、クライアント インターフェイスをハンドリングします
( <InterfaceGenerated>Extended extends InterfaceGenerated {...)

<base>/sqlmap/generated/: MBG によって生成されたマッパー名前空間のコピーが変更されました

Mybatis - 春を設定しました

<bean id="mapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer"  
        p:basePackage="<base>.sqlmap"  
        p:sqlSessionTemplate-ref="sqlSessionTemplate"  
        p:nameGenerator-ref="myBeanNameGenerator"  
    />  

myBeanNameGenerator は、私のようなカスタム名が必要な場合にのみ実装してください。この例では、行を削除できますp:nameGenerator-ref="myBeanNameGenerator"

すべてのクライアント インターフェイスが拡張された場合は、上記で代用できます
p:basePackage="<base>.sqlmap.extended"

(私のプロジェクト構成は巨大なので、最も重要なビットを抽出しました)

これは、私のクライアント インターフェイスとマッパーのハンド コーディングの例です。

import <base>.dao.Countries;
import <base>.sqlmap.CountriesMapper;
import org.apache.ibatis.annotations.Param;

public interface CountriesMapperExtended extends CountriesMapper {

/**
 *
 * @param code
 * @return
 */
Countries selectByCountryCode(@Param("code") String code);

}

ここで、CountriesMapper は MBG が生成したクライアント インターフェイスです

手作業でコーディングされた相関 xml マッパーは次のとおりです。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="<base>.sqlmap.extended.CountriesMapperExtended">

  <select id="selectByCountryCode" parameterType="java.lang.String" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from countries co
    where co.countrycode = #{code,jdbcType=VARCHAR}
  </select>

</mapper>

すべての作業を行うには、MBG が生成したすべてのインターフェイス メソッドを xml マッパーに統合する必要があります。これを行うには、MBG で生成された xml マッパーをコピーし<base>/sqlmap/generated/て名前空間を変更します。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="<base>.sqlmap.extended.CountriesMapperExtended">
... unchanged ...
</mapper>  

データベースが変更されたときに問題が発生し、新しいデータベース構造を反映するために MBG を使用する必要があります。

<base>/sqlmap/extended/そこで、手動でコーディングされた xml マッパーがあるかどうかを監視してチェックする bash スクリプトをすばやく作成しました。手動でコーディングされた xml マッパーがある場合は、名前空間を変更して生成された対応する MBG をコピーします。

このコードはすべて適切な解決策ではありませんが、機能します。

bash スクリプトはファイルを上書きする<base>/sqlmap/generated/ので、このフォルダーにコードを入れません。

プロジェクトのバックアップ コピーを作成し、bash スクリプトを変更してカスタマイズし、自分の責任で使用します。

#!/bin/bash
CURDIR="$(pwd)"
SCRIPT_DIR=`dirname $0`
usage()
{
cat << EOF
usage: $0 options

This script is usefull to generate xml map to extend mybatis 
generator client interfaces. It suppose this structure:
<base>/sqlmap/           : generated xml mapper and interfaces
<base>/sqlmap/extended/  : extended xml mapper and interfaces
<base>/sqlmap/generated/ : copy of generated xml mapper changing
                           its namespace

If exist a mapper xml in <base>/sqlmap/extend identify by a name 
ending in Extended this script generate a copy of original generated
xml map of extended interface changing then namespace to reflect the 
extended Interface in <base>/sqlmap/generated.

This script require a list of base path:
$0 path1 path2 ...

Required parameters are marked by an *

OPTIONS:
  -h, --help          Show this message

EOF
}

declare -a BASES
let INDEX=0
TEMP=`getopt -o "hb:" --long "help,base:" -n "$0" -- "$@"`
eval set -- "$TEMP"
while true ; do
    case "$1" in
        -h|--help) 
            usage
            exit 1 ;;
        --) 
            shift ;
            break ;;
        *) 
            echo "Too mutch parametes!!! abort." ;
            exit 1 ;;
    esac
done
#process all paths
let INDEX=0
BASE="$1"
while [ "${BASE:0:1}" == "/" ]
do
    shift ;
    BASES[$INDEX]="$BASE"
    let INDEX+=1
    BASE="$1"
done
if [ "$INDEX" -le "0" ]
then
    echo "--bases options cannot be emplty"
    usage
    exit 1
fi

for BASE in ${BASES[@]}
do
    if [ ! -d "$BASE" ]
    then
        echo "Error: every base parameter must be a folder!!"
        echo "Base=$BASE is not a folder"
        usage
        exit 1
    fi
    SQLMAP="$BASE/sqlmap"
    if [ ! -d "$SQLMAP" ]
    then
        echo "Error: every base parameter must have a sqlmap folder!!"
        echo "$SQLMAP is not a folder"
        usage
        exit 1
    fi
    EXTENDED="$BASE/sqlmap/extended"
    if [ ! -d "$EXTENDED" ]
    then
        echo "Error: every base parameter must have a sqlmap/extended folder!!"
        echo "$EXTENDED is not a folder"
        usage
        exit 1
    fi
    GENERATED="$BASE/sqlmap/generated"
    if [ ! -d "$GENERATED" ]
    then
        mkdir -p "$GENERATED"
    fi
    while IFS= read -r -d '' file
    do
        name="${file##*/}" 
        #path="${file%/*}"
        ext=".${name##*.}"
        nameNoSuffix="${name%$ext}"
        nameBase="${nameNoSuffix%Extended}"
        sed -r 's/<mapper namespace="(.+)\.([^."]+)"\s*>\s*$/<mapper namespace="\1.extended.\2Extended">/' "$SQLMAP/$nameBase.xml" > "$GENERATED/$nameNoSuffix.xml"
    done < <(eval "find $EXTENDED/ -type f -name \*Extended\.xml -print0")

done
exit 0

スクリプトの使用

$ ./post-generator.sh "/home/...<base>"/パスに最後のものを置かないでください

このパスは、sqlmap、sqlmap/extended、sqlmap/generated を含むフォルダーへのパスです。

私のように複数のパスがある場合は、パスのリストを使用できます

Maven で使用するには、プロジェクト pom.xml でこのプラグインを使用します。

            <plugin>
                <artifactId>exec-maven-plugin</artifactId>
                <groupId>org.codehaus.mojo</groupId>
                <version>1.2.1</version>
                <executions>
                    <execution>
                        <id>build client extended xml</id>
                        <goals>
                            <goal>exec</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <executable>${basedir}/scripts/post-generator.sh</executable>
                    <workingDirectory>${basedir}/scripts</workingDirectory>
                    <arguments>
                        <argument>${basedir}/<basepath1></argument>
                        <argument>${basedir}/<basepath2></argument>
                    </arguments>
                </configuration>
            </plugin>

$ mvn exec:exec プロジェクトフォルダーで、または使用できます$ mvn mybatis-generator:generate exec:exec

Netbeans を使用する場合は、Netbeansmybatis-generator:generate exec:execを残さずにこれらの目標を実行するようにプロジェクト アクションを構成できます。データベース構造に変更がある場合は、手動で開始できます。

これで拡張マッパーで問題なく作業でき、db 構造が変更された場合は MBG に作業を任せることができます。


Bean では、自動生成された MBG メソッドと手動でコーディングされたメソッドを持つ拡張インターフェイスを注入できます。

    <bean id="service" class="<base>.services.ServiceImpl" scope="singleton" 
        ...
        p:countriesMapper-ref="countriesMapperExtended"
        ...
        p:sqlSessionTemplate-ref="sqlSessionTemplate"
    />

ここで、countriesMapperExtended Bean は上記の mapperScanner によって生成されます。

于 2014-04-15T11:51:37.283 に答える