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, интерфейс был регенерирован, но новый расширяемый интерфейс не переопределяется, поэтому ваш код сохраняется.
рассматривает