diff --git a/README.md b/README.md
index 2bcb6859..283bc6ea 100644
--- a/README.md
+++ b/README.md
@@ -38,6 +38,7 @@
* [状态枚举生成插件(EnumTypeStatusPlugin)](#21-状态枚举生成插件)
* [增量插件(IncrementPlugin)](#22-增量插件)
* [Mapper注解插件(MapperAnnotationPlugin)](#23-Mapper注解插件)
+* [修改目标包名插件](#24-修改目标包名插件)
---------------------------------------
Maven引用:
@@ -1654,4 +1655,23 @@ public class Test {
-```
\ No newline at end of file
+```
+
+### 24. 修改目标包名插件
+有的项目组要求按照业务逻辑划分子包,在业务子包中进一步分controller、service, entity、mapper...., ModelClass需要生成在entity包中,ClientClass需要生成在mapper包中,而SQLMAP文件需要在/src/map/xxx/文件夹下,`targetPackage`属性和`domainObjectName`无法实现
+TargetPackagePlugin可用为一个表的ModelClass、ClientClass、SQLMap分别设置不同的targetPackage
+
+插件:
+```xml
+
+
+
+
+
+```
+
+生成的三类文件的包名分别为``、``、``标签中配置的`targetPackage`属性与``标签中配置的`xxxTargetPackage`属性的拼接结果
diff --git a/src/main/java/com/itfsw/mybatis/generator/plugins/TargetPackagePlugin.java b/src/main/java/com/itfsw/mybatis/generator/plugins/TargetPackagePlugin.java
new file mode 100644
index 00000000..97609764
--- /dev/null
+++ b/src/main/java/com/itfsw/mybatis/generator/plugins/TargetPackagePlugin.java
@@ -0,0 +1,125 @@
+package com.itfsw.mybatis.generator.plugins;
+
+import com.itfsw.mybatis.generator.plugins.utils.BasePlugin;
+import org.mybatis.generator.api.IntrospectedTable;
+import org.mybatis.generator.config.JavaClientGeneratorConfiguration;
+import org.mybatis.generator.config.JavaModelGeneratorConfiguration;
+import org.mybatis.generator.config.SqlMapGeneratorConfiguration;
+import org.mybatis.generator.config.TableConfiguration;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/***
+ *
+ * TargetPackagePlugin可用为一个表的ModelClass、ClientClass、SQLMap分别设置不同的targetPackage
+ *
+ **/
+
+public class TargetPackagePlugin extends BasePlugin {
+ /**
+ * 模型类目标子包
+ */
+ public static final String PRO_CLIENT_TARGET_PACKAGE = "clientTargetPackage";
+ /**
+ * mapper接口目标子包
+ */
+ public static final String PRO_MODEL_TARGET_PACKAGE = "modelTargetPackage";
+ /**
+ * mapper文件目标子包
+ */
+ public static final String PRO_SQL_MAP_TARGET_PACKAGE = "sqlMapTargetPackage";
+
+ private static Pattern regex = Pattern.compile("[a-zA-Z]+[0-9a-zA-Z_]*(\\.[a-zA-Z]+[0-9a-zA-Z_]*)*");
+
+ @Override
+ public boolean validate(List warnings) {
+ // 如果table配置了domainObjectName或者mapperName就不要再启动该插件了
+ for (TableConfiguration tableConfiguration : context.getTableConfigurations()) {
+ if (tableConfiguration.getDomainObjectName() != null || tableConfiguration.getMapperName() != null) {
+ warnings.add("itfsw:插件" + this.getClass().getTypeName() + "插件请不要配合table的domainObjectName或者mapperName一起使用!");
+ return false;
+ }
+ }
+ return super.validate(warnings);
+ }
+
+ @Override
+ public void initialized(IntrospectedTable introspectedTable) {
+ super.initialized(introspectedTable);
+ // 1.设置 Client 的子包
+ String clientTargetPackage = getValidTargetPackage(introspectedTable, PRO_CLIENT_TARGET_PACKAGE);
+ if (null == clientTargetPackage) {
+ logger.warn("itfsw:插件" + this.getClass().getTypeName() + " 设置的clientTargetPackage属性不是有效包名");
+ } else {
+ JavaClientGeneratorConfiguration javaClientGeneratorConfiguration = context.getJavaClientGeneratorConfiguration();
+ String targetPackage = javaClientGeneratorConfiguration.getTargetPackage() + "." + clientTargetPackage;
+ javaClientGeneratorConfiguration.setTargetPackage(targetPackage);
+
+ try {
+ Method calculateJavaClientAttributes = IntrospectedTable.class.getDeclaredMethod("calculateJavaClientAttributes");
+ calculateJavaClientAttributes.setAccessible(true);
+ calculateJavaClientAttributes.invoke(introspectedTable);
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+ e.printStackTrace();
+ logger.error("itfsw:插件" + this.getClass().getTypeName() + "设置clientTargetPackage时异常");
+ }
+ }
+
+ // 2.设置 Model 的子包
+ String modelTargetPackage = getValidTargetPackage(introspectedTable, PRO_MODEL_TARGET_PACKAGE);
+ if (null == modelTargetPackage) {
+ logger.warn("itfsw:插件" + this.getClass().getTypeName() + " 设置的modelTargetPackage属性不是有效包名");
+ } else {
+ JavaModelGeneratorConfiguration javaModelGeneratorConfiguration = context.getJavaModelGeneratorConfiguration();
+ String targetPackage = javaModelGeneratorConfiguration.getTargetPackage() + "." + modelTargetPackage;
+ logger.info("targetPackage:" + targetPackage);
+ javaModelGeneratorConfiguration.setTargetPackage(targetPackage);
+
+ try {
+ Method calculateModelAttributes = IntrospectedTable.class.getDeclaredMethod("calculateModelAttributes");
+ calculateModelAttributes.setAccessible(true);
+ calculateModelAttributes.invoke(introspectedTable);
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+ e.printStackTrace();
+ logger.error("itfsw:插件" + this.getClass().getTypeName() + "设置modelTargetPackage时异常");
+ }
+ }
+
+ // 3.设置 sqlMap 的子包
+ String sqlMapTargetPackage = getValidTargetPackage(introspectedTable, PRO_SQL_MAP_TARGET_PACKAGE);
+ if (null == sqlMapTargetPackage) {
+ logger.warn("itfsw:插件" + this.getClass().getTypeName() + " 设置的sqlMapTargetPackage属性不是有效包名");
+ } else {
+ SqlMapGeneratorConfiguration sqlMapGeneratorConfiguration = context.getSqlMapGeneratorConfiguration();
+ String targetPackage = sqlMapGeneratorConfiguration.getTargetPackage() + "." + sqlMapTargetPackage;
+ sqlMapGeneratorConfiguration.setTargetPackage(targetPackage);
+
+ try {
+ Method calculateXmlAttributes = IntrospectedTable.class.getDeclaredMethod("calculateXmlAttributes");
+ calculateXmlAttributes.setAccessible(true);
+ calculateXmlAttributes.invoke(introspectedTable);
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+ e.printStackTrace();
+ logger.error("itfsw:插件" + this.getClass().getTypeName() + "设置sqlMapTargetPackage时异常");
+ }
+ }
+ }
+
+ /**
+ * 检查包名格式是否正确
+ */
+ private String getValidTargetPackage(IntrospectedTable introspectedTable, final String PROPERTY_NAME) {
+ String targetPacakge = introspectedTable.getTableConfigurationProperty(PROPERTY_NAME);
+ if (null == targetPacakge || "".equals(targetPacakge.trim())) {
+ return null;
+ }
+
+ targetPacakge = targetPacakge.trim();
+ Matcher matcher = regex.matcher(targetPacakge);
+ return matcher.matches() ? targetPacakge : null;
+ }
+}