Mybatis Generator: какой лучший способ выделить "автоматически сгенерированные" и "отредактированные вручную файлы",

Я участвую в проекте, который использует как Mybatis (для сохранения java для базы данных), так и Mybatis Generator (для автоматического создания XML файлов mapper и java-интерфейсов из схемы базы данных).

Генератор Mybatis отлично справляется с созданием файлов, необходимых для базовой операции crud.

Контекст

Для некоторых из таблиц/классов, нам потребуется больше "материал" (код запросов и т.д.), чем "сырого материала", порожденного инструментом MyBatis генератора.

Есть ли способ, чтобы "лучшее из обоих миров", то есть использовать автоматическое поколение, как и "пользовательский код". Как вы выделяете и структурируете "отредактированные вручную файлы" и "автоматически сгенерированные файлы".

Предложение

Я думал о следующем, т.е. для таблицы "Foo"

автоматически

  • FooCrudMapper.xml
  • интерфейс FooCrud.java

(где "Crud" означает "Create Read Update Delete" )

Отредактировано вручную

  • FooMapper.xml Интерфейс
  • Foo расширяет FooCrud

Понятие: если схема была изменена, вы всегда могли бы автоматически генерировать файлы "Crud" xml и .java, не удаляя любые пользовательские изменения.

Вопросы

  • Будет ли mybatis корректно обрабатывать этот сценарий, т.е. правильно ли этот картограф выполнит автоматически сгенерированный "crud code"?

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

  • Какой подход вы рекомендуете?

Изменить 1: * Наш проект db использует "основную таблицу" ( "элемент" ), а другие таблицы "расширяют" эту таблицу и добавляют дополнительные атрибуты (общий ключ). Я просмотрел документы и источник пришел к выводу, что я не могу использовать Mybatis Generator в сочетании с таким расширением без редактирования вручную:

то есть. Это не работает.  -ElementMapper расширяет "ElementCrudMapper"  -FooMapper.xml расширяет и "ElementCrudMapper" и "FooCrudMapper"

спасибо всем!

Ответ 1

Я могу отделить созданные файлы и отредактированные вручную файлы.

Я использую mybatis- spring и spring для управления интерфейсами dao. Эта библиотека позволяет MyBatis участвовать в транзакциях spring, заботится о создании MyBatis mappers и SqlSessions и вводит их в другой beans, переводит исключения MyBatis в spring DataAccessExceptions и, наконец, позволяет вам создавать код приложения без зависимостей от MyBatis, spring или MyBatis- Spring.

Для DAO-интерфейсов я пишу общий 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
}

Для файлов mapper xml я создаю два пакета в базовой папке mapper (.xml) для разделения сгенерированных файлов и отредактированных вручную файлов. Для UserDao выше я помещаю UserMapper.xml, сгенерированный генератором в пакете с именем "сгенерированный". Я помещал все ручные sql файлы в другой файл UserMapper.xml в пакете с именем manual. Два файла сопоставления начинаются с одного и того же заголовка <mapper namespace="com.xxx.dao.UserDao" >. Mybatis может сканировать файлы XML файла xml для автоматического сопоставления sql и соответствующего метода интерфейса.

Для созданных объектов и объектов объектов Я их переписываю напрямую.

Я надеюсь, что вышеописанный метод поможет вам!

Ответ 2

Решение Larry.Z поможет мне решить ту же проблему, чтобы отделить авто, созданный от отредактированных вручную файлов. У меня была собственная структура папок в моем проекте и адаптировано решение Ларри для работы в моем проекте и добавить этот ответ, чтобы помочь другим, используя решение Larry, адаптирующее его.

Лучшим решением является добавление функции в генератор Mybatis (MBG) для интеграции модифицированного вручную XML-преобразователя. MBG нужно было добавить функции парсинга, чтобы добавить соответствующий метод стороны node к интерфейсу клиентского интерфейса, но сейчас эти функции не существуют, поэтому я использую и адаптирую решение 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 class

<base>/dao/extended/: расширенный сгенерированный класс (<DaoGeneratedName>Extended)

<base>/sqlmap/: Клиентский интерфейс, созданный MBG, и соответствующий сопоставление xml

<base>/sqlmap/extended/:
hand xml mapper и интерфейс клиентского интерфейса

(<InterfaceGenerated>Extended extends InterfaceGenerated {...)

<base>/sqlmap/generated/: скопирована копия пространства имен созданного транслятора MBG

Я настроил Mybatis - spring

<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"

(моя конфигурация проекта огромна, поэтому я извлекаю самый важный бит)

Это пример моего клиентского интерфейса и ручной команды handler:

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);

}

Где СтраныMapper - это клиентский интерфейс, созданный 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>

Чтобы выполнить всю работу, мне нужно интегрировать в xml mapper весь метод метода MBG, и для этого я скопировал созданный MBG xml mapper в <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>  

Проблема возникает при изменении db, и я должен использовать MBG для отражения новой структуры db.

Итак, я быстро создал bash script, которые смотрят в <base>/sqlmap/extended/, и проверьте, есть ли обработчик XML-кодировки вручную. Если есть ручной кодировщик xml, скопируйте соответствующий MBG, сгенерированный с помощью изменения его пространства имен.

Весь этот код не является изящным решением, но работает.

bash script перезаписать файл в <base>/sqlmap/generated/, поэтому не помещайте в эту папку свой код.

Сделайте резервную копию своего проекта и измените bash script, чтобы настроить его и использовать для своей ответственности.

#!/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" -- "[email protected]"`
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

Использование script

$ ./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, вы можете настроить действие проекта для выполнения этих целей mybatis-generator:generate exec:exec без оставленных Netbeans. Вы можете запустить его вручную, когда у вас есть изменение структуры db.

Теперь вы можете работать с ограниченным картографом без проблем, и пусть MBG выполняет свою работу, если структура db изменяется.

В bean вы можете ввести расширенный интерфейс, который имеет автоматические сгенерированные методы MBG плюс ваши ручные кодированные методы:

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

Где страныMapperExtended bean создается с помощью mapperScanner выше.

Ответ 3

Я даю рабочий ответ, но он сложный и нелегкий для понимания из-за огромных конфигураций.

Теперь я нашел лучший и более краткий и простой ответ.
Я вдохновлен сообщением Emacarron: Исправить # 35

У меня есть mbg и в generatorConfig.xml я помещаю <javaClientGenerator type="XMLMAPPER" ...> для создания интерфейса java и конфигурации xml-карты в mapper файле.

поэтому в моем примере в папке mapper у меня есть:

  • AnagraficaMapper.java
  • AnafigraficaMapper.xml

в папке модели у меня есть

  • Anagrafica.java
  • AnagraficaKey.java
  • AnagraficaExample.java

Первые два являются объектной моделью и расширяют ее тривиальность. Чтобы расширить mapper, я просто копирую и пустую. AnagraficaMapper.java → AnagraficaExMapper.java
AnagraficaMapper.xml → AnagraficaExMapper.xml
в этом двух новых файлах я поставил свой новый код.
Например, я решил добавить новый sql selectByPrimaryKeyMy

public interface AnagraficaExMapper extends AnagraficaMapper {
    Anagrafica selectByPrimaryKeyMy(AnagraficaKey key);
}  

Это мой интерфейс, расширяющий интерфейс AnagraficaMapper, созданный mgb.
в AnagraficaExMapper.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="net.algoritmica.ciaomondo.mapper.AnagraficaExMapper" >
  <select id="selectByPrimaryKeyMy" parameterType="net.algoritmica.ciaomondo.model.AnagraficaKey" resultMap="net.algoritmica.ciaomondo.mapper.AnagraficaMapper.BaseResultMap">
    select 
      <include refid="net.algoritmica.ciaomondo.mapper.AnagraficaMapper.Base_Column_List" />
    from ANAGRAFICA anag
    where anag.IDANAGRAFICA = #{idanagrafica,jdbcType=INTEGER}
  </select>
</mapper>  

Как вы видите пространство имен... AnagraficaExMapper указывает на новый расширяемый интерфейс.

В решении Исправить # 35, когда MyBatis искал код в AnagraficaExMapper.java и нашел метод selectByPrimaryKeyMy, он был создан в AnagraficaExMapper. xml тоже;

но при поиске иерархического метода, такого как selectByPrimaryKey, это не было найдено в AnagraficaExMapper.xml, но благодаря Fix # 35 в результате поиска кода родительское имя тоже, привязывая весь метод расширенных interfeces в старом AnagraficaMapper.xml

Чтобы включить фрагмент, включенный в старый XML файл, вы должны использовать полный путь к старому файлу xml, например, в: <include refid="net.algoritmica.ciaomondo.mapper.AnagraficaMapper.Base_Column_List" />

Теперь вам просто нужно настроить MyBatis для автоматического сканирования карт и всех интерфейсов, где правильно ограничено xml mapper.
когда вы используете mbg для изменения db, интерфейс был регенерирован, но новый расширяемый интерфейс не переопределяется, поэтому ваш код сохраняется.

рассматривает