Compare commits

...
18 Commits
Author SHA1 Message Date
hewei d645bff7c0 [maven-release-plugin] prepare release v1.0.6 2017-03-22 16:35:39 +08:00
hewei 571ba8268c fixed:[issues#2]
增加存在即更新插件
2017-03-22 16:31:00 +08:00
hewei 9d0068df0f useGeneratedKeys:使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中。抽取成一个工具方法 2017-03-22 14:38:56 +08:00
hewei 3809307502 1. 批量插入把根据字段插入和普通插入两个方法进行分开,使代码风格和Mybatis官方保持一致;
2. 批量插入老版本代码迁入com.itfsw.mybatis.generator.plugins.BatchInsertOldPlugin不影响老版本生成的代码使用;
2017-03-21 14:28:55 +08:00
hewei e4187813bd [maven-release-plugin] prepare for next development iteration 2017-01-17 18:11:03 +08:00
hewei fc71a45d7a [maven-release-plugin] prepare release v1.0.5 2017-01-17 18:10:44 +08:00
hewei cf5c29c71a 1. 增加了数据Model属性对应Column获取插件(ModelColumnPlugin);
2. 强化了example的orderBy方法;
3. 强化批量插入插件,实现按需插入指定字段;
2017-01-17 18:09:48 +08:00
何伟 9ee5ec9e20 Update README.md 2017-01-17 09:30:35 +08:00
hewei 1d2d2d1a47 README.md 修改 2017-01-16 18:34:47 +08:00
hewei 638a640996 [maven-release-plugin] prepare for next development iteration 2017-01-16 18:18:49 +08:00
hewei 4b3adacece [maven-release-plugin] prepare release v1.0.4 2017-01-16 18:18:32 +08:00
hewei 51b8abee4d 版本说明 2017-01-16 18:18:01 +08:00
hewei 5662c7f91b 版本说明 2017-01-16 18:14:48 +08:00
hewei 7e403d1dc4 统一插件调试日志格式 2017-01-16 17:47:55 +08:00
hewei 38417972a1 ExampleEnhancedPlugin 插件增加OrderBy方法 2017-01-16 17:02:01 +08:00
hewei ce099f8112 ExampleEnhancedPlugin 插件替换CriteriaBuilderPlugin插件,上个插件命名容易引起误解 2017-01-16 16:32:02 +08:00
hewei 384467ef99 Mysql分页插件增强链式调用。 2017-01-16 16:24:59 +08:00
hewei b1a61bbbf4 [maven-release-plugin] prepare for next development iteration 2017-01-13 18:22:47 +08:00
15 changed files with 1398 additions and 225 deletions
+178 -36
View File
@@ -7,10 +7,12 @@
* 查询单条数据插件(SelectOneByExamplePlugin)
* MySQL分页插件(LimitPlugin)
* 数据Model链式构建插件(ModelBuilderPlugin)
* Example Criteria 增强插件(CriteriaBuilderPlugin)
* Example Criteria 增强插件(ExampleEnhancedPlugin(CriteriaBuilderPlugin这个是老版本叫法,已经弃用))
* Example 目标包修改插件(ExampleTargetPlugin)
* 批量插入插件(BatchInsertPlugin)
* 逻辑删除插件(LogicalDeletePlugin)
* 数据Model属性对应Column获取插件(ModelColumnPlugin)
* 存在即更新插件(UpsertPlugin)
---------------------------------------
Maven引用:
@@ -18,7 +20,7 @@ Maven引用:
<dependency>
<groupId>com.itfsw</groupId>
<artifactId>mybatis-generator-plugin</artifactId>
<version>1.0.3</version>
<version>1.0.6</version>
</dependency>
```
---------------------------------------
@@ -43,7 +45,7 @@ public interface TbMapper {
}
```
### 2. MySQL分页插件
对应表Example类增加了方法
对应表Example类增加了Mysql分页方法,limit(Integer rows)、limit(Integer offset, Integer rows)和page(Integer page, Integer pageSize)
插件:
```xml
<!-- MySQL分页插件 -->
@@ -76,8 +78,9 @@ public class TbExample {
* @mbg.generated
* @author hewei
*/
public void limit(Integer rows) {
public TbExample limit(Integer rows) {
this.rows = rows;
return this;
}
/**
@@ -87,9 +90,10 @@ public class TbExample {
* @mbg.generated
* @author hewei
*/
public void limit(Integer offset, Integer rows) {
public TbExample limit(Integer offset, Integer rows) {
this.offset = offset;
this.rows = rows;
return this;
}
/**
@@ -99,9 +103,10 @@ public class TbExample {
* @mbg.generated
* @author hewei
*/
public void page(Integer page, Integer pageSize) {
public TbExample page(Integer page, Integer pageSize) {
this.offset = page * pageSize;
this.rows = pageSize;
return this;
}
// offset 和 rows 的getter&setter
@@ -121,6 +126,19 @@ public class TbExample {
offset = null;
}
}
public class Test {
public static void main(String[] args) {
this.tbMapper.selectByExample(
new TbExample()
.createCriteria()
.andField1GreaterThan(1)
.example()
.limit(10) // 查询前10条
.limit(10, 10) // 查询10~20条
.page(1, 10) // 查询第2页数据(每页10条)
);
}
}
```
### 3. 数据Model链式构建插件
这个是仿jquery的链式调用强化了表的Model的赋值操作
@@ -143,13 +161,15 @@ public class Test {
}
}
```
### 4. Example Criteria 增强插件(example,andIf)
* 表Example增加Criteria的快速返回example()方法。
* Criteria链式调用增强,以前如果有按条件增加的查询语句会打乱链式查询构建,现在有了andIf(boolean ifAdd, CriteriaAdd add)方法可一直使用链式调用下去。
### 4. Example 增强插件(example,andIf,orderBy)
* Criteria的快速返回example()方法。
* Criteria链式调用增强,以前如果有按条件增加的查询语句会打乱链式查询构建,现在有了andIf(boolean ifAdd, CriteriaAdd add)方法可一直使用链式调用下去。
* Example增强了setOrderByClause方法,新增orderBy(String orderByClause)方法直接返回example,增强链式调用,可以一路.下去了。
* 继续增强orderBy(String orderByClause)方法,增加orderBy(String ... orderByClauses)方法,配合数据Model属性对应Column获取插件(ModelColumnPlugin)使用效果更佳。
插件:
```xml
<!-- Example Criteria 增强插件 -->
<plugin type="com.itfsw.mybatis.generator.plugins.CriteriaBuilderPlugin"/>
<plugin type="com.itfsw.mybatis.generator.plugins.ExampleEnhancedPlugin"/>
```
使用:
```java
@@ -157,12 +177,13 @@ public class Test {
public static void main(String[] args) {
// -----------------------------------example-----------------------------------
// 表Example.Criteria增加了工厂方法example()支持,使用后可链式构建查询条件使用example()返回Example对象
TbExample ex = new TbExample()
.createCriteria()
.andField1EqualTo(1)
.andField2EqualTo("xxx")
.example();
this.tbMapper.selectByExample(ex);
this.tbMapper.selectByExample(
new TbExample()
.createCriteria()
.andField1EqualTo(1)
.andField2EqualTo("xxx")
.example()
);
// -----------------------------------andIf-----------------------------------
// Criteria增强了链式调用,现在一些按条件增加的查询条件不会打乱链式调用了
@@ -180,13 +201,13 @@ public class Test {
this.tbMapper.selectByExample(oldEx);
// new
TbExample newEx;
newEx = new TbExample()
this.tbMapper.selectByExample(
new TbExample()
.createCriteria()
.andField1EqualTo(1)
.andField2EqualTo("xxx")
// 如果随机数大于0.5,附加Field3查询条件
.andIf(Math.random() > 0.5, new TbExample.Criteria.CriteriaAdd() {
.andIf(Math.random() > 0.5, new TbExample.Criteria.ICriteriaAdd() {
@Override
public TbExample.Criteria add(TbExample.Criteria add) {
return add.andField3EqualTo(2)
@@ -198,8 +219,26 @@ public class Test {
.andField3EqualTo(2)
.andField4EqualTo(new Date())
)
.example();
this.tbMapper.selectByExample(newEx);
.example()
);
// -----------------------------------orderBy-----------------------------------
// old
TbExample ex = new TbExample();
ex.createCriteria().andField1GreaterThan(1);
ex.setOrderByClause("field1 DESC");
this.tbMapper.selectByExample(ex);
// new
this.tbMapper.selectByExample(
new TbExample()
.createCriteria()
.andField1GreaterThan(1)
.example()
.orderBy("field1 DESC")
// 这个配合数据Model属性对应Column获取插件(ModelColumnPlugin)使用
.orderBy(Tb.Column.field1.asc(), Tb.Column.field3.desc())
);
}
}
```
@@ -214,7 +253,10 @@ Mybatis Generator 插件默认把Model类和Example类都生成到一个包下
</plugin>
```
### 6. 批量插入插件
提供了一个批量插入batchInsert方法,因为方法使用了使用了JDBC的getGenereatedKeys方法返回插入主键,所以只能在MYSQL和SQLServer下使用。
提供了批量插入batchInsert和batchInsertSelective方法,因为方法使用了使用了JDBC的getGenereatedKeys方法返回插入主键,所以只能在MYSQL和SQLServer下使用。
需配合数据Model属性对应Column获取插件(ModelColumnPlugin)插件使用,实现类似于insertSelective插入列!
PS:为了和Mybatis官方代码风格保持一致,1.0.5+版本把批量插入方法分开了,基于老版本1.0.5-版本生成的代码请继续使用“com.itfsw.mybatis.generator.plugins.BatchInsertOldPlugin”不影响使用
PS:继续PS,本来想继续保留老版本代码,不影响老版本已经生成代码使用的,但是始终没有绕过BindingException,只能把代码移入BatchInsertOldPlugin类~~~~~
插件:
```xml
<!-- 批量插入插件 -->
@@ -226,21 +268,26 @@ public class Test {
public static void main(String[] args) {
// 构建插入数据
List<Tb> list = new ArrayList<>();
list.add(new Tb.Builder()
list.add(
new Tb.Builder()
.field1(0)
.field2("xx0")
.field3(0)
.field4(new Date())
.createTime(new Date())
.build()
);
list.add(new Tb.Builder()
list.add(
new Tb.Builder()
.field1(1)
.field2("xx1")
.field3(1)
.field4(new Date())
.createTime(new Date())
.build()
);
int inserted = this.tbMapper.batchInsert(list);
// 普通插入,插入所有列
this.tbMapper.batchInsert(list);
// !!!下面按需插入指定列(类似于insertSelective),需要数据Model属性对应Column获取插件(ModelColumnPlugin)插件
this.tbMapper.batchInsertSelective(list, Tb.Column.field1, Tb.Column.field2, Tb.Column.field3, Tb.Column.createTime);
}
}
```
@@ -270,27 +317,122 @@ public class Test {
public class Test {
public static void main(String[] args) {
// 1. 逻辑删除ByExample
TbExample ex = new TbExample()
this.tbMapper.logicalDeleteByExample(
new TbExample()
.createCriteria()
.andField1EqualTo(1)
.example();
this.tbMapper.logicalDeleteByExample(ex);
.example()
);
// 2. 逻辑删除ByPrimaryKey
this.tbMapper.logicalDeleteByPrimaryKey(1L);
// 3. 同时Example中提供了一个快捷方法来过滤逻辑删除数据
TbExample selEx = new TbExample()
this.tbMapper.selectByExample(
new TbExample()
.createCriteria()
.andField1EqualTo(1)
// 新增了一个andDeleted方法过滤逻辑删除数据
.andDeleted(true)
// 当然也可直接使用逻辑删除列的查询方法,我们数据Model中定义了一个逻辑删除常量DEL_FLAG
.andDelFlagEqualTo(Tb.DEL_FLAG)
.example();
.example()
);
}
}
```
### 8. 数据Model属性对应Column获取插件
项目中我们有时需要获取数据Model对应数据库字段的名称,一般直接根据数据Model的属性就可以猜出数据库对应column的名字,可是有的时候当column使用了columnOverride或者columnRenamingRule时就需要去看数据库设计了,所以提供了这个插件获取model对应的数据库Column。
* 配合Example Criteria 增强插件(ExampleEnhancedPlugin)使用,这个插件还提供了asc()和desc()方法配合Example的orderBy方法效果更佳。
* 配合批量插入插件(BatchInsertPlugin)使用,batchInsertSelective(@Param("list") List<XXX> list, @Param("selective") XXX.Column ... insertColumns)。
插件:
```xml
<!-- 数据Model属性对应Column获取插件 -->
<plugin type="com.itfsw.mybatis.generator.plugins.ModelColumnPlugin"/>
```
使用:
```java
public class Test {
public static void main(String[] args) {
// 1. 获取Model对应column
String column = Tb.Column.createTime.value();
// 2. 配合Example Criteria 增强插件(ExampleEnhancedPlugin)使用orderBy方法
// old
this.tbMapper.selectByExample(
new TbExample()
.createCriteria()
.andField1GreaterThan(1)
.example()
.orderBy("field1 DESC, field3 ASC")
);
// better
this.tbMapper.selectByExample(
new TbExample()
.createCriteria()
.andField1GreaterThan(1)
.example()
.orderBy(Tb.Column.field1.desc(), Tb.Column.field3.asc())
);
List<Tb> list = this.tbMapper.selectByExample(selEx);
// 3. 配合批量插入插件(BatchInsertPlugin)使用实现按需插入指定列
List<Tb> list = new ArrayList<>();
list.add(
new Tb.Builder()
.field1(0)
.field2("xx0")
.field3(0)
.field4(new Date())
.build()
);
list.add(
new Tb.Builder()
.field1(1)
.field2("xx1")
.field3(1)
.field4(new Date())
.build()
);
// 这个会插入表所有列
this.tbMapper.batchInsert(list);
// 下面按需插入指定列(类似于insertSelective)
this.tbMapper.batchInsertSelective(list, Tb.Column.field1, Tb.Column.field2, Tb.Column.field3, Tb.Column.createTime);
}
}
```
### 9. 存在即更新插件
使用MySQL的[“insert ... on duplicate key update”](https://dev.mysql.com/doc/refman/5.7/en/insert-on-duplicate.html)实现存在即更新操作,简化数据入库操作([[issues#2]](https://github.com/itfsw/mybatis-generator-plugin/issues/2))。
插件:
```xml
<!-- 存在即更新插件 -->
<plugin type="com.itfsw.mybatis.generator.plugins.UpsertPlugin"/>
```
使用:
```java
public class Test {
public static void main(String[] args) {
// 1. 未入库数据入库,执行insert
Tb tb = new Tb.Builder()
.field1(1)
.field2("xx0")
.delFlag((short)0)
.build();
int k0 = this.tbMapper.upsert(tb);
// 2. 已入库数据再次入库,执行update(!!需要注意如触发update其返回的受影响行数为2)
tb.setField2("xx1");
int k1 = this.tbMapper.upsert(tb);
// 3. 类似insertSelective实现选择入库
Tb tb1 = new Tb.Builder()
.field1(1)
.field2("xx0")
.build();
int k2 = this.tbMapper.upsertSelective(tb1);
tb1.setField2("xx1");
int k3 = this.tbMapper.upsertSelective(tb1);
}
}
```
+2 -2
View File
@@ -3,7 +3,7 @@
<groupId>com.itfsw</groupId>
<artifactId>mybatis-generator-plugin</artifactId>
<version>1.0.3</version>
<version>1.0.6</version>
<packaging>jar</packaging>
<name>${project.groupId}:${project.artifactId}</name>
@@ -175,7 +175,7 @@
<connection>scm:git:https://github.com/itfsw/mybatis-generator-plugin.git</connection>
<developerConnection>scm:git:https://github.com/itfsw/mybatis-generator-plugin.git</developerConnection>
<url>https://github.com/itfsw/mybatis-generator-plugin</url>
<tag>v1.0.3</tag>
<tag>v1.0.6</tag>
</scm>
<!-- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++distribution++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -0,0 +1,313 @@
/*
* Copyright (c) 2017.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.itfsw.mybatis.generator.plugins;
import com.itfsw.mybatis.generator.plugins.utils.CommTools;
import com.itfsw.mybatis.generator.plugins.utils.CommentTools;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.Document;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.codegen.mybatis3.ListUtilities;
import org.mybatis.generator.codegen.mybatis3.MyBatis3FormattingUtilities;
import org.mybatis.generator.config.Context;
import org.mybatis.generator.config.PluginConfiguration;
import org.mybatis.generator.internal.util.StringUtility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
/**
* ---------------------------------------------------------------------------
* 批量插入插件
* ---------------------------------------------------------------------------
* @author: hewei
* @time:2017/1/13 9:33
* ---------------------------------------------------------------------------
*/
@Deprecated
public class BatchInsertOldPlugin extends PluginAdapter {
private static final Logger logger = LoggerFactory.getLogger(BatchInsertOldPlugin.class);
public static final String METHOD_BATCH_INSERT = "batchInsert"; // 方法名
private boolean hasModelBuilderPlugin; // 是否配置了ModelBuilderPlugin插件
/**
* {@inheritDoc}
*/
@Override
public boolean validate(List<String> warnings) {
// 插件使用前提是targetRuntime为MyBatis3
if (StringUtility.stringHasValue(getContext().getTargetRuntime()) && "MyBatis3".equalsIgnoreCase(getContext().getTargetRuntime()) == false) {
logger.warn("itfsw:插件" + this.getClass().getTypeName() + "要求运行targetRuntime必须为MyBatis3!");
return false;
}
// 插件使用前提是数据库为MySQL或者SQLserver,因为返回主键使用了JDBC的getGenereatedKeys方法获取主键
if ("com.mysql.jdbc.Driver".equalsIgnoreCase(this.getContext().getJdbcConnectionConfiguration().getDriverClass()) == false
&& "com.microsoft.jdbc.sqlserver.SQLServer".equalsIgnoreCase(this.getContext().getJdbcConnectionConfiguration().getDriverClass()) == false
&& "com.microsoft.sqlserver.jdbc.SQLServerDriver".equalsIgnoreCase(this.getContext().getJdbcConnectionConfiguration().getDriverClass()) == false){
logger.warn("itfsw:插件" + this.getClass().getTypeName() + "插件使用前提是数据库为MySQL或者SQLserver,因为返回主键使用了JDBC的getGenereatedKeys方法获取主键!");
return false;
}
logger.warn("itfsw:插件" + this.getClass().getTypeName() + "插件已过期,不再维护请使用com.itfsw.mybatis.generator.plugins.BatchInsertPlugin区分batchInsert和batchInsertSelective!");
return true;
}
/**
* 初始化
* 具体执行顺序 http://www.mybatis.org/generator/reference/pluggingIn.html
*
* @param introspectedTable
* @return
*/
@Override
public void initialized(IntrospectedTable introspectedTable) {
// 插件使用前提是使用了ModelColumnPlugin插件
Context ctx = getContext();
// 利用反射获取pluginConfigurations属性
try {
java.lang.reflect.Field field = Context.class.getDeclaredField("pluginConfigurations");
field.setAccessible(true);
List<PluginConfiguration> list = (List<PluginConfiguration>) field.get(ctx);
// 检查是否配置了ModelColumnPlugin插件
for (PluginConfiguration config: list) {
if (ModelColumnPlugin.class.getName().equals(config.getConfigurationType())){
this.hasModelBuilderPlugin = true;
}
}
} catch (Exception e) {
logger.error(e.getLocalizedMessage());
}
}
/**
* Java Client Methods 生成
* 具体执行顺序 http://www.mybatis.org/generator/reference/pluggingIn.html
*
* @param interfaze
* @param topLevelClass
* @param introspectedTable
* @return
*/
@Override
public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
if (hasModelBuilderPlugin){
// 方法生成
Method method = new Method(METHOD_BATCH_INSERT);
// 返回值类型
method.setReturnType(FullyQualifiedJavaType.getIntInstance());
// 添加参数
FullyQualifiedJavaType type = FullyQualifiedJavaType.getNewListInstance();
type.addTypeArgument(introspectedTable.getRules().calculateAllFieldsClass());
method.addParameter(new Parameter(type, "list", "@Param(\"list\")"));
FullyQualifiedJavaType type1 = new FullyQualifiedJavaType(introspectedTable.getRules().calculateAllFieldsClass().getShortName()+"."+ModelColumnPlugin.ENUM_NAME);
method.addParameter(new Parameter(type1, "insertColumns", "@Param(\"insertColumns\")", true));
// 添加方法说明
CommentTools.addGeneralMethodComment(method, introspectedTable);
// interface 增加方法
interfaze.addMethod(method);
logger.debug("itfsw(批量插入插件):" + interfaze.getType().getShortName() + "增加batchInsert方法。");
} else {
// 方法生成
Method method = new Method(METHOD_BATCH_INSERT);
// 方法可见性 interface会忽略
// method.setVisibility(JavaVisibility.PUBLIC);
// 返回值类型
method.setReturnType(FullyQualifiedJavaType.getIntInstance());
// 添加参数
FullyQualifiedJavaType type = FullyQualifiedJavaType.getNewListInstance();
type.addTypeArgument(introspectedTable.getRules().calculateAllFieldsClass());
method.addParameter(new Parameter(type, "list", "@Param(\"list\")"));
// 添加方法说明
CommentTools.addGeneralMethodComment(method, introspectedTable);
// interface 增加方法
interfaze.addMethod(method);
logger.debug("itfsw(批量插入插件):" + interfaze.getType().getShortName() + "增加batchInsert方法。");
}
return true;
}
/**
* SQL Map Methods 生成
* 具体执行顺序 http://www.mybatis.org/generator/reference/pluggingIn.html
*
* @param document
* @param introspectedTable
* @return
*/
@Override
public boolean sqlMapDocumentGenerated(Document document, IntrospectedTable introspectedTable) {
if (hasModelBuilderPlugin){
XmlElement element = new XmlElement("insert");
element.addAttribute(new Attribute("id", METHOD_BATCH_INSERT));
// 参数类型
element.addAttribute(new Attribute("parameterType", "map"));
// 添加注释(!!!必须添加注释,overwrite覆盖生成时,@see XmlFileMergerJaxp.isGeneratedNode会去判断注释中是否存在OLD_ELEMENT_TAGS中的一点,例子:@mbg.generated)
CommentTools.addComment(element);
// 使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中。所以只支持MYSQL和SQLServer
CommTools.useGeneratedKeys(element, introspectedTable);
// choose 节点
XmlElement choose = new XmlElement("choose");
// when 节点
XmlElement when = new XmlElement("when");
when.addAttribute(new Attribute("test", "insertColumns.length != 0"));
when.addElement(new TextElement("insert into "+introspectedTable.getFullyQualifiedTableNameAtRuntime()+" ("));
XmlElement foreachInsertColumns = new XmlElement("foreach");
foreachInsertColumns.addAttribute(new Attribute("collection", "insertColumns"));
foreachInsertColumns.addAttribute(new Attribute("item", "column"));
foreachInsertColumns.addAttribute(new Attribute("separator", ","));
foreachInsertColumns.addElement(new TextElement("${column.value}"));
when.addElement(foreachInsertColumns);
when.addElement(new TextElement(")"));
// values
when.addElement(new TextElement("values"));
// foreach values
XmlElement foreachValues = new XmlElement("foreach");
foreachValues.addAttribute(new Attribute("collection", "list"));
foreachValues.addAttribute(new Attribute("item", "item"));
foreachValues.addAttribute(new Attribute("separator", ","));
foreachValues.addElement(new TextElement("("));
// foreach 所有插入的列,比较是否存在
XmlElement foreachInsertColumnsCheck = new XmlElement("foreach");
foreachInsertColumnsCheck.addAttribute(new Attribute("collection", "insertColumns"));
foreachInsertColumnsCheck.addAttribute(new Attribute("item", "column"));
foreachInsertColumnsCheck.addAttribute(new Attribute("separator", ","));
// 所有表字段
List<IntrospectedColumn> columns = ListUtilities.removeIdentityAndGeneratedAlwaysColumns(introspectedTable.getAllColumns());
for (int i = 0; i < columns.size(); i++) {
IntrospectedColumn introspectedColumn = columns.get(i);
XmlElement check = new XmlElement("if");
check.addAttribute(new Attribute("test", "'"+introspectedColumn.getActualColumnName()+"' == column.value"));
check.addElement(new TextElement(MyBatis3FormattingUtilities.getParameterClause(introspectedColumn, "item.")));
foreachInsertColumnsCheck.addElement(check);
}
foreachValues.addElement(foreachInsertColumnsCheck);
foreachValues.addElement(new TextElement(")"));
when.addElement(foreachValues);
choose.addElement(when);
// 普通不带insertColumns参数实现
XmlElement otherwise = new XmlElement("otherwise");
this.addNormalBatchInsertXml(otherwise, introspectedTable);
choose.addElement(otherwise);
element.addElement(choose);
if (context.getPlugins().sqlMapInsertElementGenerated(element, introspectedTable)) {
document.getRootElement().addElement(element);
logger.debug("itfsw(批量插入插件):" + introspectedTable.getMyBatis3XmlMapperFileName() + "增加batchInsert实现方法。");
}
} else {
XmlElement element = new XmlElement("insert"); //$NON-NLS-1$
element.addAttribute(new Attribute("id", METHOD_BATCH_INSERT)); //$NON-NLS-1$
// 参数类型
element.addAttribute(new Attribute("parameterType", FullyQualifiedJavaType.getNewListInstance().getFullyQualifiedName()));
// 添加注释(!!!必须添加注释,overwrite覆盖生成时,@see XmlFileMergerJaxp.isGeneratedNode会去判断注释中是否存在OLD_ELEMENT_TAGS中的一点,例子:@mbg.generated)
CommentTools.addComment(element);
// 使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中。所以只支持MYSQL和SQLServer
CommTools.useGeneratedKeys(element, introspectedTable);
// 普通插入语句
this.addNormalBatchInsertXml(element, introspectedTable);
document.getRootElement().addElement(element);
logger.debug("itfsw(批量插入插件):" + introspectedTable.getMyBatis3XmlMapperFileName() + "增加batchInsert实现方法。");
}
return true;
}
/**
* 普通不带insertColumns的插入语句Xml实现
*
* @param element
* @param introspectedTable
*/
private void addNormalBatchInsertXml(XmlElement element, IntrospectedTable introspectedTable) {
StringBuilder insertClause = new StringBuilder();
StringBuilder valuesClause = new StringBuilder();
insertClause.append("insert into "); //$NON-NLS-1$
insertClause.append(introspectedTable.getFullyQualifiedTableNameAtRuntime());
insertClause.append(" ("); //$NON-NLS-1$
valuesClause.append(" ("); //$NON-NLS-1$
List<String> valuesClauses = new ArrayList<String>();
List<IntrospectedColumn> columns = ListUtilities.removeIdentityAndGeneratedAlwaysColumns(introspectedTable.getAllColumns());
for (int i = 0; i < columns.size(); i++) {
IntrospectedColumn introspectedColumn = columns.get(i);
insertClause.append(MyBatis3FormattingUtilities.getEscapedColumnName(introspectedColumn));
// 生成foreach下插入values
valuesClause.append(MyBatis3FormattingUtilities.getParameterClause(introspectedColumn, "item."));
if (i + 1 < columns.size()) {
insertClause.append(", "); //$NON-NLS-1$
valuesClause.append(", "); //$NON-NLS-1$
}
}
insertClause.append(')');
element.addElement(new TextElement(insertClause.toString()));
valuesClause.append(')');
valuesClauses.add(valuesClause.toString());
// 添加foreach节点
XmlElement foreachElement = new XmlElement("foreach");
foreachElement.addAttribute(new Attribute("collection", "list"));
foreachElement.addAttribute(new Attribute("item", "item"));
foreachElement.addAttribute(new Attribute("separator", ","));
for (String clause : valuesClauses) {
foreachElement.addElement(new TextElement(clause));
}
// values 构建
element.addElement(new TextElement("values"));
element.addElement(foreachElement);
}
}
@@ -16,6 +16,7 @@
package com.itfsw.mybatis.generator.plugins;
import com.itfsw.mybatis.generator.plugins.utils.CommTools;
import com.itfsw.mybatis.generator.plugins.utils.CommentTools;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
@@ -27,7 +28,8 @@ import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.codegen.mybatis3.ListUtilities;
import org.mybatis.generator.codegen.mybatis3.MyBatis3FormattingUtilities;
import org.mybatis.generator.config.GeneratedKey;
import org.mybatis.generator.config.Context;
import org.mybatis.generator.config.PluginConfiguration;
import org.mybatis.generator.internal.util.StringUtility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -58,6 +60,7 @@ public class BatchInsertPlugin extends PluginAdapter {
logger.warn("itfsw:插件" + this.getClass().getTypeName() + "要求运行targetRuntime必须为MyBatis3!");
return false;
}
// 插件使用前提是数据库为MySQL或者SQLserver,因为返回主键使用了JDBC的getGenereatedKeys方法获取主键
if ("com.mysql.jdbc.Driver".equalsIgnoreCase(this.getContext().getJdbcConnectionConfiguration().getDriverClass()) == false
&& "com.microsoft.jdbc.sqlserver.SQLServer".equalsIgnoreCase(this.getContext().getJdbcConnectionConfiguration().getDriverClass()) == false
@@ -65,9 +68,40 @@ public class BatchInsertPlugin extends PluginAdapter {
logger.warn("itfsw:插件" + this.getClass().getTypeName() + "插件使用前提是数据库为MySQL或者SQLserver,因为返回主键使用了JDBC的getGenereatedKeys方法获取主键!");
return false;
}
// 插件使用前提是使用了ModelColumnPlugin插件
try {
Context ctx = getContext();
// 利用反射获取pluginConfigurations属性
java.lang.reflect.Field field = Context.class.getDeclaredField("pluginConfigurations");
field.setAccessible(true);
List<PluginConfiguration> list = (List<PluginConfiguration>) field.get(ctx);
// 检查是否配置了ModelColumnPlugin插件
boolean unFind = true;
for (PluginConfiguration config: list) {
if (ModelColumnPlugin.class.getName().equals(config.getConfigurationType())){
unFind = false;
}
}
// 建议使用ModelColumnPlugin插件
if (unFind){
logger.warn("itfsw:插件" + this.getClass().getTypeName() + "插件需配合com.itfsw.mybatis.generator.plugins.ModelColumnPlugin插件使用!");
return false;
}
} catch (Exception e) {
logger.error(e.getLocalizedMessage());
}
// TODO
logger.warn("itfsw:插件" + this.getClass().getTypeName() + "插件如之前使用1.0.5-的插件可继续使用com.itfsw.mybatis.generator.plugins.BatchInsertOldPlugin或者修改batchInsert(@Param(\"list\") List<Tb> list, @Param(\"insertColumns\") Tb.Column ... selective)调用为batchInsertSelective!");
return true;
}
/**
* Java Client Methods 生成
* 具体执行顺序 http://www.mybatis.org/generator/reference/pluggingIn.html
@@ -79,22 +113,31 @@ public class BatchInsertPlugin extends PluginAdapter {
*/
@Override
public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
logger.debug("itfsw:生成" + interfaze.getType() + "对应batchInsert方法...");
// 方法生成
Method method = new Method(METHOD_BATCH_INSERT);
// 方法可见性 interface会忽略
// method.setVisibility(JavaVisibility.PUBLIC);
// 返回值类型
method.setReturnType(FullyQualifiedJavaType.getIntInstance());
// 1. batchInsert
Method mBatchInsert = new Method(METHOD_BATCH_INSERT);
mBatchInsert.setReturnType(FullyQualifiedJavaType.getIntInstance());
// 添加参数
FullyQualifiedJavaType type = FullyQualifiedJavaType.getNewListInstance();
type.addTypeArgument(introspectedTable.getRules().calculateAllFieldsClass());
method.addParameter(new Parameter(type, "list", "@Param(\"list\")"));
FullyQualifiedJavaType tList = FullyQualifiedJavaType.getNewListInstance();
tList.addTypeArgument(introspectedTable.getRules().calculateAllFieldsClass());
mBatchInsert.addParameter(new Parameter(tList, "list", "@Param(\"list\")"));
// 添加方法说明
CommentTools.addGeneralMethodComment(method, introspectedTable);
CommentTools.addGeneralMethodComment(mBatchInsert, introspectedTable);
// interface 增加方法
interfaze.addMethod(method);
interfaze.addMethod(mBatchInsert);
logger.debug("itfsw(批量插入插件):" + interfaze.getType().getShortName() + "增加batchInsert方法。");
// 2. batchInsertSelective
Method mBatchInsertSelective = new Method(METHOD_BATCH_INSERT_SELECTIVE);
mBatchInsertSelective.setReturnType(FullyQualifiedJavaType.getIntInstance());
// 添加参数
FullyQualifiedJavaType tSelective = new FullyQualifiedJavaType(introspectedTable.getRules().calculateAllFieldsClass().getShortName()+"."+ModelColumnPlugin.ENUM_NAME);
mBatchInsertSelective.addParameter(new Parameter(tList, "list", "@Param(\"list\")"));
mBatchInsertSelective.addParameter(new Parameter(tSelective, "selective", "@Param(\"selective\")", true));
// 添加方法说明
CommentTools.addGeneralMethodComment(mBatchInsertSelective, introspectedTable);
// interface 增加方法
interfaze.addMethod(mBatchInsertSelective);
logger.debug("itfsw(批量插入插件):" + interfaze.getType().getShortName() + "增加batchInsertSelective方法。");
return true;
}
@@ -109,39 +152,16 @@ public class BatchInsertPlugin extends PluginAdapter {
*/
@Override
public boolean sqlMapDocumentGenerated(Document document, IntrospectedTable introspectedTable) {
// batchInsert
this.generatorBatchInsertXml(document, introspectedTable);
return true;
}
/**
* 生成BatchInsert对应的xml
* @param document
* @param introspectedTable
*/
private void generatorBatchInsertXml(Document document, IntrospectedTable introspectedTable) {
XmlElement element = new XmlElement("insert"); //$NON-NLS-1$
element.addAttribute(new Attribute("id", METHOD_BATCH_INSERT)); //$NON-NLS-1$
// 1. batchInsert
XmlElement batchInsertEle = new XmlElement("insert");
batchInsertEle.addAttribute(new Attribute("id", METHOD_BATCH_INSERT));
// 参数类型
element.addAttribute(new Attribute("parameterType", FullyQualifiedJavaType.getNewListInstance().getFullyQualifiedName()));
batchInsertEle.addAttribute(new Attribute("parameterType", "map"));
// 添加注释(!!!必须添加注释,overwrite覆盖生成时,@see XmlFileMergerJaxp.isGeneratedNode会去判断注释中是否存在OLD_ELEMENT_TAGS中的一点,例子:@mbg.generated)
CommentTools.addComment(element);
CommentTools.addComment(batchInsertEle);
GeneratedKey gk = introspectedTable.getGeneratedKey();
if (gk != null) {
IntrospectedColumn introspectedColumn = introspectedTable.getColumn(gk.getColumn());
// if the column is null, then it's a configuration error. The
// warning has already been reported
if (introspectedColumn != null) {
// 使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中。所以只支持MYSQL和SQLServer
element.addAttribute(new Attribute("useGeneratedKeys", "true")); //$NON-NLS-1$ //$NON-NLS-2$
element.addAttribute(new Attribute("keyProperty", introspectedColumn.getJavaProperty())); //$NON-NLS-1$
element.addAttribute(new Attribute("keyColumn", introspectedColumn.getActualColumnName())); //$NON-NLS-1$
}
}
// 使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中。所以只支持MYSQL和SQLServer
CommTools.useGeneratedKeys(batchInsertEle, introspectedTable);
StringBuilder insertClause = new StringBuilder();
StringBuilder valuesClause = new StringBuilder();
@@ -168,7 +188,7 @@ public class BatchInsertPlugin extends PluginAdapter {
}
insertClause.append(')');
element.addElement(new TextElement(insertClause.toString()));
batchInsertEle.addElement(new TextElement(insertClause.toString()));
valuesClause.append(')');
valuesClauses.add(valuesClause.toString());
@@ -185,11 +205,75 @@ public class BatchInsertPlugin extends PluginAdapter {
}
// values 构建
batchInsertEle.addElement(new TextElement("values"));
batchInsertEle.addElement(foreachElement);
if (context.getPlugins().sqlMapInsertElementGenerated(batchInsertEle, introspectedTable)) {
document.getRootElement().addElement(batchInsertEle);
logger.debug("itfsw(批量插入插件):" + introspectedTable.getMyBatis3XmlMapperFileName() + "增加batchInsert实现方法。");
}
// 2. batchInsertSelective
XmlElement element = new XmlElement("insert");
element.addAttribute(new Attribute("id", METHOD_BATCH_INSERT_SELECTIVE));
// 参数类型
element.addAttribute(new Attribute("parameterType", "map"));
// 添加注释(!!!必须添加注释,overwrite覆盖生成时,@see XmlFileMergerJaxp.isGeneratedNode会去判断注释中是否存在OLD_ELEMENT_TAGS中的一点,例子:@mbg.generated)
CommentTools.addComment(element);
// 使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中。所以只支持MYSQL和SQLServer
CommTools.useGeneratedKeys(element, introspectedTable);
element.addElement(new TextElement("insert into "+introspectedTable.getFullyQualifiedTableNameAtRuntime()+" ("));
XmlElement foreachInsertColumns = new XmlElement("foreach");
foreachInsertColumns.addAttribute(new Attribute("collection", "selective"));
foreachInsertColumns.addAttribute(new Attribute("item", "column"));
foreachInsertColumns.addAttribute(new Attribute("separator", ","));
foreachInsertColumns.addElement(new TextElement("${column.value}"));
element.addElement(foreachInsertColumns);
element.addElement(new TextElement(")"));
// values
element.addElement(new TextElement("values"));
element.addElement(foreachElement);
// foreach values
XmlElement foreachValues = new XmlElement("foreach");
foreachValues.addAttribute(new Attribute("collection", "list"));
foreachValues.addAttribute(new Attribute("item", "item"));
foreachValues.addAttribute(new Attribute("separator", ","));
foreachValues.addElement(new TextElement("("));
// foreach 所有插入的列,比较是否存在
XmlElement foreachInsertColumnsCheck = new XmlElement("foreach");
foreachInsertColumnsCheck.addAttribute(new Attribute("collection", "selective"));
foreachInsertColumnsCheck.addAttribute(new Attribute("item", "column"));
foreachInsertColumnsCheck.addAttribute(new Attribute("separator", ","));
// 所有表字段
List<IntrospectedColumn> columns1 = ListUtilities.removeIdentityAndGeneratedAlwaysColumns(introspectedTable.getAllColumns());
for (int i = 0; i < columns1.size(); i++) {
IntrospectedColumn introspectedColumn = columns.get(i);
XmlElement check = new XmlElement("if");
check.addAttribute(new Attribute("test", "'"+introspectedColumn.getActualColumnName()+"' == column.value"));
check.addElement(new TextElement(MyBatis3FormattingUtilities.getParameterClause(introspectedColumn, "item.")));
foreachInsertColumnsCheck.addElement(check);
}
foreachValues.addElement(foreachInsertColumnsCheck);
foreachValues.addElement(new TextElement(")"));
element.addElement(foreachValues);
if (context.getPlugins().sqlMapInsertElementGenerated(element, introspectedTable)) {
document.getRootElement().addElement(element);
logger.debug("itfsw(批量插入插件):" + introspectedTable.getMyBatis3XmlMapperFileName() + "增加batchInsertSelective实现方法。");
}
return true;
}
}
}
@@ -16,13 +16,6 @@
package com.itfsw.mybatis.generator.plugins;
import com.itfsw.mybatis.generator.plugins.utils.CommentTools;
import com.itfsw.mybatis.generator.plugins.utils.InnerInterface;
import com.itfsw.mybatis.generator.plugins.utils.InnerInterfaceWrapperToInnerClass;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.internal.util.StringUtility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -36,121 +29,16 @@ import java.util.List;
* @time:2016/12/28 14:56
* ---------------------------------------------------------------------------
*/
public class CriteriaBuilderPlugin extends PluginAdapter {
@Deprecated
public class CriteriaBuilderPlugin extends ExampleEnhancedPlugin{
private static final Logger logger = LoggerFactory.getLogger(CriteriaBuilderPlugin.class);
/**
* {@inheritDoc}
*/
@Override
public boolean validate(List<String> warnings) {
// 插件使用前提是targetRuntime为MyBatis3
if (StringUtility.stringHasValue(getContext().getTargetRuntime()) && "MyBatis3".equalsIgnoreCase(getContext().getTargetRuntime()) == false ){
logger.warn("itfsw:插件"+this.getClass().getTypeName()+"要求运行targetRuntime必须为MyBatis3!");
return false;
}
return true;
}
/**
* ModelExample Methods 生成
* 具体执行顺序 http://www.mybatis.org/generator/reference/pluggingIn.html
*
* @param topLevelClass
* @param introspectedTable
* @return
*/
@Override
public boolean modelExampleClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
List<InnerClass> innerClasses = topLevelClass.getInnerClasses();
for (InnerClass innerClass : innerClasses) {
if ("Criteria".equals(innerClass.getType().getShortName())) {
// 工厂方法
addFactoryMethodToCriteria(topLevelClass, innerClass, introspectedTable);
// andIf
addAndIfMethodToCriteria(topLevelClass, innerClass, introspectedTable);
}
}
List<Method> methods = topLevelClass.getMethods();
for (Method method : methods) {
if (!"createCriteriaInternal".equals(method.getName()))
continue;
method.getBodyLines().set(0, "Criteria criteria = new Criteria(this);");
logger.debug("itfsw:CriteriaBuilder修改Example的createCriteriaInternal方法,修改构造Criteria时传入Example对象");
}
return true;
}
/**
* 添加工厂方法
*
* @param topLevelClass
* @param innerClass
* @param introspectedTable
*/
private void addFactoryMethodToCriteria(TopLevelClass topLevelClass, InnerClass innerClass, IntrospectedTable introspectedTable) {
Field f = new Field("example", topLevelClass.getType());
f.setVisibility(JavaVisibility.PRIVATE);
innerClass.addField(f);
// overwrite constructor
List<Method> methods = innerClass.getMethods();
for (Method method : methods) {
if (method.isConstructor()) {
method.addParameter(new Parameter(topLevelClass.getType(), "example"));
method.addBodyLine("this.example = example;");
logger.debug("itfsw:CriteriaBuilder修改Criteria的构造方法,增加example参数");
}
}
// add factory method "example"
Method method = new Method("example");
method.setVisibility(JavaVisibility.PUBLIC);
method.setReturnType(topLevelClass.getType());
method.addBodyLine("return this.example;");
CommentTools.addGeneralMethodComment(method, introspectedTable);
innerClass.addMethod(method);
logger.debug("itfsw:CriteriaBuilder增加工厂方法example");
}
/**
* 增强Criteria的链式调用,添加andIf(boolean addIf, CriteriaAdd add)方法,实现链式调用中按条件增加查询语句
*
* @param topLevelClass
* @param innerClass
* @param introspectedTable
*/
private void addAndIfMethodToCriteria(TopLevelClass topLevelClass, InnerClass innerClass, IntrospectedTable introspectedTable){
// 添加接口CriteriaAdd
InnerInterface criteriaAddInterface = new InnerInterface("ICriteriaAdd");
criteriaAddInterface.setVisibility(JavaVisibility.PUBLIC);
CommentTools.addInterfaceComment(criteriaAddInterface, introspectedTable);
// ICriteriaAdd增加接口add
Method addMethod = new Method("add");
addMethod.setReturnType(innerClass.getType());
addMethod.addParameter(new Parameter(innerClass.getType(), "add"));
CommentTools.addGeneralMethodComment(addMethod, introspectedTable);
criteriaAddInterface.addMethod(addMethod);
logger.debug("itfsw:Criteria.ICriteriaAdd增加接口add");
InnerClass innerClassWrapper = new InnerInterfaceWrapperToInnerClass(criteriaAddInterface);
innerClass.addInnerClass(innerClassWrapper);
// 添加andIf方法
Method method = new Method("andIf");
method.setVisibility(JavaVisibility.PUBLIC);
method.setReturnType(innerClass.getType());
method.addParameter(new Parameter(FullyQualifiedJavaType.getBooleanPrimitiveInstance(), "ifAdd"));
method.addParameter(new Parameter(criteriaAddInterface.getType(), "add"));
method.addBodyLine("if (ifAdd) {");
method.addBodyLine("add.add(this);");
method.addBodyLine("}");
method.addBodyLine("return this;");
CommentTools.addGeneralMethodComment(method, introspectedTable);
innerClass.addMethod(method);
logger.debug("itfsw:Criteria增加方法andIf");
logger.warn("itfsw:插件"+this.getClass().getTypeName()+"插件已经过时,请使用com.itfsw.mybatis.generator.plugins.ExampleEnhancedPlugin插件替换!");
return super.validate(warnings);
}
}
@@ -0,0 +1,186 @@
package com.itfsw.mybatis.generator.plugins;
import com.itfsw.mybatis.generator.plugins.utils.CommentTools;
import com.itfsw.mybatis.generator.plugins.utils.InnerInterface;
import com.itfsw.mybatis.generator.plugins.utils.InnerInterfaceWrapperToInnerClass;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.internal.util.StringUtility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
* ---------------------------------------------------------------------------
* Example 增强插件
* ---------------------------------------------------------------------------
* @author: hewei
* @time:2017/1/16 16:28
* ---------------------------------------------------------------------------
*/
public class ExampleEnhancedPlugin extends PluginAdapter {
private static final Logger logger = LoggerFactory.getLogger(ExampleEnhancedPlugin.class);
/**
* {@inheritDoc}
*/
@Override
public boolean validate(List<String> warnings) {
// 插件使用前提是targetRuntime为MyBatis3
if (StringUtility.stringHasValue(getContext().getTargetRuntime()) && "MyBatis3".equalsIgnoreCase(getContext().getTargetRuntime()) == false ){
logger.warn("itfsw:插件"+this.getClass().getTypeName()+"要求运行targetRuntime必须为MyBatis3!");
return false;
}
return true;
}
/**
* ModelExample Methods 生成
* 具体执行顺序 http://www.mybatis.org/generator/reference/pluggingIn.html
*
* @param topLevelClass
* @param introspectedTable
* @return
*/
@Override
public boolean modelExampleClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
List<InnerClass> innerClasses = topLevelClass.getInnerClasses();
for (InnerClass innerClass : innerClasses) {
if ("Criteria".equals(innerClass.getType().getShortName())) {
// 工厂方法
addFactoryMethodToCriteria(topLevelClass, innerClass, introspectedTable);
// andIf
addAndIfMethodToCriteria(topLevelClass, innerClass, introspectedTable);
}
}
List<Method> methods = topLevelClass.getMethods();
for (Method method : methods) {
if (!"createCriteriaInternal".equals(method.getName()))
continue;
method.getBodyLines().set(0, "Criteria criteria = new Criteria(this);");
logger.debug("itfsw(Example增强插件):"+topLevelClass.getType().getShortName()+"修改createCriteriaInternal方法,修改构造Criteria时传入Example对象");
}
// orderBy方法
addOrderByMethodToExample(topLevelClass, introspectedTable);
return true;
}
/**
* 添加工厂方法
*
* @param topLevelClass
* @param innerClass
* @param introspectedTable
*/
private void addFactoryMethodToCriteria(TopLevelClass topLevelClass, InnerClass innerClass, IntrospectedTable introspectedTable) {
Field f = new Field("example", topLevelClass.getType());
f.setVisibility(JavaVisibility.PRIVATE);
innerClass.addField(f);
// overwrite constructor
List<Method> methods = innerClass.getMethods();
for (Method method : methods) {
if (method.isConstructor()) {
method.addParameter(new Parameter(topLevelClass.getType(), "example"));
method.addBodyLine("this.example = example;");
logger.debug("itfsw(Example增强插件):"+topLevelClass.getType().getShortName()+"修改构造方法,增加example参数");
}
}
// add factory method "example"
Method method = new Method("example");
method.setVisibility(JavaVisibility.PUBLIC);
method.setReturnType(topLevelClass.getType());
method.addBodyLine("return this.example;");
CommentTools.addGeneralMethodComment(method, introspectedTable);
innerClass.addMethod(method);
logger.debug("itfsw(Example增强插件):"+topLevelClass.getType().getShortName()+"."+innerClass.getType().getShortName()+"增加工厂方法example");
}
/**
* 增强Criteria的链式调用,添加andIf(boolean addIf, CriteriaAdd add)方法,实现链式调用中按条件增加查询语句
*
* @param topLevelClass
* @param innerClass
* @param introspectedTable
*/
private void addAndIfMethodToCriteria(TopLevelClass topLevelClass, InnerClass innerClass, IntrospectedTable introspectedTable){
// 添加接口CriteriaAdd
InnerInterface criteriaAddInterface = new InnerInterface("ICriteriaAdd");
criteriaAddInterface.setVisibility(JavaVisibility.PUBLIC);
CommentTools.addInterfaceComment(criteriaAddInterface, introspectedTable);
logger.debug("itfsw(Example增强插件):"+topLevelClass.getType().getShortName()+"."+innerClass.getType().getShortName()+"增加接口ICriteriaAdd");
// ICriteriaAdd增加接口add
Method addMethod = new Method("add");
addMethod.setReturnType(innerClass.getType());
addMethod.addParameter(new Parameter(innerClass.getType(), "add"));
CommentTools.addGeneralMethodComment(addMethod, introspectedTable);
criteriaAddInterface.addMethod(addMethod);
logger.debug("itfsw(Example增强插件):"+topLevelClass.getType().getShortName()+"."+innerClass.getType().getShortName()+"."+criteriaAddInterface.getType().getShortName()+"增加方法add");
InnerClass innerClassWrapper = new InnerInterfaceWrapperToInnerClass(criteriaAddInterface);
innerClass.addInnerClass(innerClassWrapper);
// 添加andIf方法
Method method = new Method("andIf");
method.setVisibility(JavaVisibility.PUBLIC);
method.setReturnType(innerClass.getType());
method.addParameter(new Parameter(FullyQualifiedJavaType.getBooleanPrimitiveInstance(), "ifAdd"));
method.addParameter(new Parameter(criteriaAddInterface.getType(), "add"));
method.addBodyLine("if (ifAdd) {");
method.addBodyLine("add.add(this);");
method.addBodyLine("}");
method.addBodyLine("return this;");
CommentTools.addGeneralMethodComment(method, introspectedTable);
innerClass.addMethod(method);
logger.debug("itfsw(Example增强插件):"+topLevelClass.getType().getShortName()+"."+innerClass.getType().getShortName()+"增加方法andIf");
}
/**
* Example增强了setOrderByClause方法,新增orderBy(String orderByClause)方法直接返回example,增强链式调用,可以一路.下去了。
*
* @param topLevelClass
* @param introspectedTable
*/
private void addOrderByMethodToExample(TopLevelClass topLevelClass, IntrospectedTable introspectedTable){
// 添加orderBy
Method method = new Method("orderBy");
method.setVisibility(JavaVisibility.PUBLIC);
method.setReturnType(topLevelClass.getType());
method.addParameter(new Parameter(FullyQualifiedJavaType.getStringInstance(), "orderByClause"));
method.addBodyLine("this.setOrderByClause(orderByClause);");
method.addBodyLine("return this;");
CommentTools.addGeneralMethodComment(method, introspectedTable);
topLevelClass.addMethod(method);
logger.debug("itfsw(Example增强插件):"+topLevelClass.getType().getShortName()+"增加方法orderBy");
// 添加orderBy
Method mOrderByMore = new Method("orderBy");
mOrderByMore.setVisibility(JavaVisibility.PUBLIC);
mOrderByMore.setReturnType(topLevelClass.getType());
mOrderByMore.addParameter(new Parameter(FullyQualifiedJavaType.getStringInstance(), "orderByClauses", true));
mOrderByMore.addBodyLine("StringBuffer sb = new StringBuffer();");
mOrderByMore.addBodyLine("for (int i = 0; i < orderByClauses.length; i++) {");
mOrderByMore.addBodyLine("sb.append(orderByClauses[i]);");
mOrderByMore.addBodyLine("if (i < orderByClauses.length - 1) {");
mOrderByMore.addBodyLine("sb.append(\" , \");");
mOrderByMore.addBodyLine("}");
mOrderByMore.addBodyLine("}");
mOrderByMore.addBodyLine("this.setOrderByClause(sb.toString());");
mOrderByMore.addBodyLine("return this;");
CommentTools.addGeneralMethodComment(mOrderByMore, introspectedTable);
topLevelClass.addMethod(mOrderByMore);
logger.debug("itfsw(Example增强插件):"+topLevelClass.getType().getShortName()+"增加方法orderBy(String ... orderByClauses)");
}
}
@@ -80,7 +80,7 @@ public class ExampleTargetPlugin extends PluginAdapter {
introspectedTable.setExampleType(newExampleType);
logger.debug("itfsw:修改"+exampleType+"的包到"+this.targetPackage);
logger.debug("itfsw(Example 目标包修改插件):修改"+introspectedTable.getExampleType()+"的包到"+this.targetPackage);
}
}
@@ -82,7 +82,7 @@ public class LimitPlugin extends PluginAdapter {
rows.setType(integerWrapper);
CommentTools.addFieldComment(rows, introspectedTable);
topLevelClass.addField(rows);
logger.debug("itfsw:分页插件增加Example的offset和rows字段");
logger.debug("itfsw(MySQL分页插件):"+topLevelClass.getType().getShortName()+"增加offset和rows字段");
// 增加getter && setter 方法
Method setOffset = new Method();
@@ -116,38 +116,44 @@ public class LimitPlugin extends PluginAdapter {
getRows.addBodyLine("return rows;");
CommentTools.addGeneralMethodComment(getRows, introspectedTable);
topLevelClass.addMethod(getRows);
logger.debug("itfsw:分页插件增加Example的offset和rows的getter和setter");
logger.debug("itfsw(MySQL分页插件):"+topLevelClass.getType().getShortName()+"增加offset和rows的getter和setter实现。");
// 提供几个快捷方法
Method setLimit = new Method();
setLimit.setVisibility(JavaVisibility.PUBLIC);
setLimit.setReturnType(topLevelClass.getType());
setLimit.setName("limit");
setLimit.addParameter(new Parameter(integerWrapper, "rows"));
setLimit.addBodyLine("this.rows = rows;");
setLimit.addBodyLine("return this;");
CommentTools.addGeneralMethodComment(setLimit, introspectedTable);
topLevelClass.addMethod(setLimit);
Method setLimit2 = new Method();
setLimit2.setVisibility(JavaVisibility.PUBLIC);
setLimit2.setReturnType(topLevelClass.getType());
setLimit2.setName("limit");
setLimit2.addParameter(new Parameter(integerWrapper, "offset"));
setLimit2.addParameter(new Parameter(integerWrapper, "rows"));
setLimit2.addBodyLine("this.offset = offset;");
setLimit2.addBodyLine("this.rows = rows;");
setLimit2.addBodyLine("return this;");
CommentTools.addGeneralMethodComment(setLimit2, introspectedTable);
topLevelClass.addMethod(setLimit2);
logger.debug("itfsw:分页插件增加Example的limit方法");
logger.debug("itfsw(MySQL分页插件):"+topLevelClass.getType().getShortName()+"增加limit方法。");
Method setPage = new Method();
setPage.setVisibility(JavaVisibility.PUBLIC);
setPage.setReturnType(topLevelClass.getType());
setPage.setName("page");
setPage.addParameter(new Parameter(integerWrapper, "page"));
setPage.addParameter(new Parameter(integerWrapper, "pageSize"));
setPage.addBodyLine("this.offset = page * pageSize;");
setPage.addBodyLine("this.rows = pageSize;");
setPage.addBodyLine("return this;");
CommentTools.addGeneralMethodComment(setPage, introspectedTable);
topLevelClass.addMethod(setPage);
logger.debug("itfsw:分页插件增加Example的page方法");
logger.debug("itfsw(MySQL分页插件):"+topLevelClass.getType().getShortName()+"增加page方法");
// !!! clear 方法增加 offset 和 rows的清理
List<Method> methodList = topLevelClass.getMethods();
@@ -155,7 +161,7 @@ public class LimitPlugin extends PluginAdapter {
if (method.getName().equals("clear")){
method.addBodyLine("rows = null;");
method.addBodyLine("offset = null;");
logger.debug("itfsw:分页插件修正Example的clear方法,增加rows和offset字段的清空");
logger.debug("itfsw(MySQL分页插件):"+topLevelClass.getType().getShortName()+"修改clear方法,增加rows和offset字段的清空");
}
}
@@ -187,6 +193,8 @@ public class LimitPlugin extends PluginAdapter {
element.addElement(ifLimitNotNullElement);
logger.debug("itfsw(MySQL分页插件):"+introspectedTable.getMyBatis3XmlMapperFileName()+"selectByExample方法增加分页条件。");
return true;
}
@@ -116,10 +116,14 @@ public class LogicalDeletePlugin extends PluginAdapter {
|| JDBCType.VARCHAR == type){
this.logicalDeleteColumn = column;
} else {
logger.warn("itfsw:插件"+this.getClass().getTypeName()+"逻辑删除列的类型不支持(请使用数字列,字符串列,布尔列)!");
logger.warn("itfsw(逻辑删除插件):"+introspectedTable.getFullyQualifiedTable()+"逻辑删除列("+introspectedTable.getTableConfigurationProperty(LOGICAL_DELETE_COLUMN_KEY)+")的类型不在支持范围(请使用数字列,字符串列,布尔列)!");
}
}
}
if (introspectedTable.getTableConfigurationProperty(LOGICAL_DELETE_COLUMN_KEY) != null && this.logicalDeleteColumn == null){
logger.warn("itfsw(逻辑删除插件):"+introspectedTable.getFullyQualifiedTable()+"没有找到您配置的逻辑删除列("+introspectedTable.getTableConfigurationProperty(LOGICAL_DELETE_COLUMN_KEY)+")!");
}
}
/**
@@ -145,6 +149,7 @@ public class LogicalDeletePlugin extends PluginAdapter {
CommentTools.addGeneralMethodComment(mLogicalDeleteByExample, introspectedTable);
// interface 增加方法
interfaze.addMethod(mLogicalDeleteByExample);
logger.debug("itfsw(逻辑删除插件):"+interfaze.getType().getShortName()+"增加方法logicalDeleteByExample。");
// 2. 判断是否有主键,生成主键删除方法
if (introspectedTable.hasPrimaryKeyColumns()){
@@ -190,6 +195,7 @@ public class LogicalDeletePlugin extends PluginAdapter {
// interface 增加方法
interfaze.addImportedTypes(importedTypes);
interfaze.addMethod(mLogicalDeleteByPrimaryKey);
logger.debug("itfsw(逻辑删除插件):"+interfaze.getType().getShortName()+"增加方法logicalDeleteByPrimaryKey。");
}
}
return true;
@@ -241,6 +247,7 @@ public class LogicalDeletePlugin extends PluginAdapter {
logicalDeleteByExample.addElement(XmlElementGeneratorTools.getUpdateByExampleIncludeElement(introspectedTable));
document.getRootElement().addElement(logicalDeleteByExample);
logger.debug("itfsw(逻辑删除插件):"+introspectedTable.getMyBatis3XmlMapperFileName()+"增加方法logicalDeleteByExample的实现。");
// 2. 判断是否有主键,生成主键删除方法
if (introspectedTable.hasPrimaryKeyColumns()){
@@ -306,6 +313,7 @@ public class LogicalDeletePlugin extends PluginAdapter {
}
document.getRootElement().addElement(logicalDeleteByPrimaryKey);
logger.debug("itfsw(逻辑删除插件):"+introspectedTable.getMyBatis3XmlMapperFileName()+"增加方法logicalDeleteByPrimaryKey的实现。");
}
}
return true;
@@ -342,6 +350,7 @@ public class LogicalDeletePlugin extends PluginAdapter {
// 常量插入到第一位
ArrayList<Field> fields = (ArrayList<Field>) topLevelClass.getFields();
fields.add(0, field);
logger.debug("itfsw(逻辑删除插件):"+topLevelClass.getType().getShortName()+"增加方法DEL_FLAG的常量。");
}
return true;
}
@@ -401,6 +410,7 @@ public class LogicalDeletePlugin extends PluginAdapter {
method.addBodyLine(sb.toString());
innerClass.addMethod(method);
logger.debug("itfsw(逻辑删除插件):"+topLevelClass.getType().getShortName()+"."+innerClass.getType().getShortName()+"增加andDeleted方法。");
}
}
}
@@ -69,22 +69,23 @@ public class ModelBuilderPlugin extends PluginAdapter {
InnerClass innerClass = new InnerClass(BUILDER_CLASS_NAME);
innerClass.setVisibility(JavaVisibility.PUBLIC);
innerClass.setStatic(true);
CommentTools.addClassComment(innerClass, introspectedTable);
logger.debug("itfsw:生成内部Builder类");
CommentTools.addInnerClassComment(innerClass, introspectedTable);
logger.debug("itfsw(数据Model链式构建插件):"+topLevelClass.getType().getShortName()+"增加内部Builder类。");
// 构建内部obj变量
Field f = new Field("obj", topLevelClass.getType());
f.setVisibility(JavaVisibility.PRIVATE);
CommentTools.addFieldComment(f, introspectedTable);
innerClass.addField(f);
// 构造构造方法
Method constructor = new Method(BUILDER_CLASS_NAME);
constructor.setVisibility(JavaVisibility.PUBLIC);
constructor.setConstructor(true);
constructor.addBodyLine(new StringBuilder("this.obj = new ")
.append(topLevelClass.getType().getShortName()).append("();").toString());
constructor.addBodyLine(new StringBuilder("this.obj = new ").append(topLevelClass.getType().getShortName()).append("();").toString());
CommentTools.addGeneralMethodComment(constructor, introspectedTable);
innerClass.addMethod(constructor);
logger.debug("itfsw:生成内部Builder类构造方法");
logger.debug("itfsw(数据Model链式构建插件):"+topLevelClass.getType().getShortName()+".Builder增加的构造方法。");
// !!可能Model存在复合主键情况,字段要加上这些
if (topLevelClass.getSuperClass() != null && topLevelClass.getSuperClass().compareTo(new FullyQualifiedJavaType(introspectedTable.getPrimaryKeyType())) == 0){
@@ -101,7 +102,7 @@ public class ModelBuilderPlugin extends PluginAdapter {
method.addBodyLine(new StringBuilder().append("return this;").toString());
CommentTools.addGeneralMethodComment(method, introspectedTable);
innerClass.addMethod(method);
logger.debug("itfsw:生成内部Builder类的复合主键字段对应方法"+field.getName());
logger.debug("itfsw(数据Model链式构建插件):"+topLevelClass.getType().getShortName()+".Builder增加"+method.getName()+"方法(复合主键)。");
}
}
@@ -119,7 +120,7 @@ public class ModelBuilderPlugin extends PluginAdapter {
method.addBodyLine(new StringBuilder().append("return this;").toString());
CommentTools.addGeneralMethodComment(method, introspectedTable);
innerClass.addMethod(method);
logger.debug("itfsw:生成内部Builder类的普通字段对应方法"+field.getName());
logger.debug("itfsw(数据Model链式构建插件):"+topLevelClass.getType().getShortName()+".Builder增加"+method.getName()+"方法。");
}
Method build = new Method("build");
@@ -128,7 +129,7 @@ public class ModelBuilderPlugin extends PluginAdapter {
build.addBodyLine("return this.obj;");
CommentTools.addGeneralMethodComment(build, introspectedTable);
innerClass.addMethod(build);
logger.debug("itfsw:生成内部Builder类的build方法");
logger.debug("itfsw(数据Model链式构建插件):"+topLevelClass.getType().getShortName()+".Builder增加build方法。");
topLevelClass.addInnerClass(innerClass);
return true;
@@ -0,0 +1,137 @@
/*
* Copyright (c) 2017.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.itfsw.mybatis.generator.plugins;
import com.itfsw.mybatis.generator.plugins.utils.CommentTools;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.internal.util.JavaBeansUtil;
import org.mybatis.generator.internal.util.StringUtility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
* ---------------------------------------------------------------------------
* 数据Model属性对应Column获取插件
* ---------------------------------------------------------------------------
* @author: hewei
* @time:2017/1/17 11:20
* ---------------------------------------------------------------------------
*/
public class ModelColumnPlugin extends PluginAdapter {
public static final String ENUM_NAME = "Column"; // 内部Enum名
private static final Logger logger = LoggerFactory.getLogger(ModelColumnPlugin.class);
/**
* {@inheritDoc}
*/
@Override
public boolean validate(List<String> warnings) {
// 插件使用前提是targetRuntime为MyBatis3
if (StringUtility.stringHasValue(getContext().getTargetRuntime()) && "MyBatis3".equalsIgnoreCase(getContext().getTargetRuntime()) == false ){
logger.warn("itfsw:插件"+this.getClass().getTypeName()+"要求运行targetRuntime必须为MyBatis3!");
return false;
}
return true;
}
/**
* Model Methods 生成
* 具体执行顺序 http://www.mybatis.org/generator/reference/pluggingIn.html
*
* @param topLevelClass
* @param introspectedTable
* @return
*/
@Override
public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
List<Field> fields = topLevelClass.getFields();
// 生成内部枚举
InnerEnum innerEnum = new InnerEnum(new FullyQualifiedJavaType(ENUM_NAME));
innerEnum.setVisibility(JavaVisibility.PUBLIC);
innerEnum.setStatic(true);
CommentTools.addInnerEnumComment(innerEnum, introspectedTable);
logger.debug("itfsw(数据Model属性对应Column获取插件):"+topLevelClass.getType().getShortName()+"增加内部Builder类。");
// 生成属性和构造函数
Field columnField = new Field("column", FullyQualifiedJavaType.getStringInstance());
columnField.setVisibility(JavaVisibility.PRIVATE);
columnField.setFinal(true);
CommentTools.addFieldComment(columnField, introspectedTable);
innerEnum.addField(columnField);
Method mValue = new Method("value");
mValue.setVisibility(JavaVisibility.PUBLIC);
mValue.setReturnType(FullyQualifiedJavaType.getStringInstance());
mValue.addBodyLine("return this.column;");
CommentTools.addGeneralMethodComment(mValue, introspectedTable);
innerEnum.addMethod(mValue);
Method mGetValue = new Method("getValue");
mGetValue.setVisibility(JavaVisibility.PUBLIC);
mGetValue.setReturnType(FullyQualifiedJavaType.getStringInstance());
mGetValue.addBodyLine("return this.column;");
CommentTools.addGeneralMethodComment(mGetValue, introspectedTable);
innerEnum.addMethod(mGetValue);
Method constructor = new Method(ENUM_NAME);
constructor.setConstructor(true);
constructor.addBodyLine("this.column = column;");
constructor.addParameter(new Parameter(FullyQualifiedJavaType.getStringInstance(), "column"));
CommentTools.addGeneralMethodComment(constructor, introspectedTable);
innerEnum.addMethod(constructor);
logger.debug("itfsw(数据Model属性对应Column获取插件):"+topLevelClass.getType().getShortName()+".Column增加构造方法和column属性。");
// Enum枚举
for (IntrospectedColumn introspectedColumn : introspectedTable.getAllColumns()) {
Field field = JavaBeansUtil.getJavaBeansField(introspectedColumn, context, introspectedTable);
StringBuffer sb = new StringBuffer();
sb.append(field.getName());
sb.append("(\"");
sb.append(introspectedColumn.getActualColumnName());
sb.append("\")");
innerEnum.addEnumConstant(sb.toString());
logger.debug("itfsw(数据Model属性对应Column获取插件):" + topLevelClass.getType().getShortName() + ".Column增加" + field.getName() + "枚举。");
}
// asc 和 desc 方法
Method desc = new Method("desc");
desc.setVisibility(JavaVisibility.PUBLIC);
desc.setReturnType(FullyQualifiedJavaType.getStringInstance());
desc.addBodyLine("return this.column + \" DESC\";");
CommentTools.addGeneralMethodComment(desc, introspectedTable);
innerEnum.addMethod(desc);
Method asc = new Method("asc");
asc.setVisibility(JavaVisibility.PUBLIC);
asc.setReturnType(FullyQualifiedJavaType.getStringInstance());
asc.addBodyLine("return this.column + \" ASC\";");
CommentTools.addGeneralMethodComment(asc, introspectedTable);
innerEnum.addMethod(asc);
logger.debug("itfsw(数据Model属性对应Column获取插件):" + topLevelClass.getType().getShortName() + ".Column增加asc()和desc()方法。");
topLevelClass.addInnerEnum(innerEnum);
return true;
}
}
@@ -69,7 +69,6 @@ public class SelectOneByExamplePlugin extends PluginAdapter {
*/
@Override
public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
logger.debug("itfsw:生成"+interfaze.getType()+"对应SelectOneByExample方法...");
// 方法生成
Method method = new Method(METHOD_NAME);
// 方法可见性 interface会忽略
@@ -85,6 +84,7 @@ public class SelectOneByExamplePlugin extends PluginAdapter {
// interface 增加方法
interfaze.addMethod(method);
logger.debug("itfsw(查询单条数据插件):"+interfaze.getType().getShortName()+"增加SelectOneByExample方法。");
return true;
}
@@ -98,8 +98,6 @@ public class SelectOneByExamplePlugin extends PluginAdapter {
*/
@Override
public boolean sqlMapDocumentGenerated(Document document, IntrospectedTable introspectedTable) {
logger.debug("itfsw:生成表"+introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime()+"("+ (introspectedTable.hasBLOBColumns() ? "有" : "无")+"Blob类型)的mapping.xml对应SelectOneByExample方法...");
//数据库表名
String tableName = introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime();
@@ -178,6 +176,7 @@ public class SelectOneByExamplePlugin extends PluginAdapter {
// 添加到根节点
document.getRootElement().addElement(selectOneElement);
logger.debug("itfsw(查询单条数据插件):"+introspectedTable.getMyBatis3XmlMapperFileName()+"增加SelectOneByExample方法("+(introspectedTable.hasBLOBColumns() ? "有" : "无")+"Blob类型))。");
return true;
}
@@ -0,0 +1,334 @@
/*
* Copyright (c) 2017.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.itfsw.mybatis.generator.plugins;
import com.itfsw.mybatis.generator.plugins.utils.CommTools;
import com.itfsw.mybatis.generator.plugins.utils.CommentTools;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.api.dom.xml.*;
import org.mybatis.generator.codegen.mybatis3.MyBatis3FormattingUtilities;
import org.mybatis.generator.internal.util.StringUtility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
* ---------------------------------------------------------------------------
* 存在即更新插件
* ---------------------------------------------------------------------------
* @author: hewei
* @time:2017/3/21 10:59
* ---------------------------------------------------------------------------
*/
public class UpsertPlugin extends PluginAdapter {
private static final Logger logger = LoggerFactory.getLogger(BatchInsertPlugin.class);
public static final String METHOD_UPSERT = "upsert"; // 方法名
public static final String METHOD_UPSERT_SELECTIVE = "upsertSelective"; // 方法名
/**
* {@inheritDoc}
*/
@Override
public boolean validate(List<String> warnings) {
// 插件使用前提是targetRuntime为MyBatis3
if (StringUtility.stringHasValue(getContext().getTargetRuntime()) && "MyBatis3".equalsIgnoreCase(getContext().getTargetRuntime()) == false) {
logger.warn("itfsw:插件" + this.getClass().getTypeName() + "要求运行targetRuntime必须为MyBatis3!");
return false;
}
// 插件使用前提是数据库为MySQL
if ("com.mysql.jdbc.Driver".equalsIgnoreCase(this.getContext().getJdbcConnectionConfiguration().getDriverClass()) == false){
logger.warn("itfsw:插件" + this.getClass().getTypeName() + "插件使用前提是数据库为MySQL!");
return false;
}
return true;
}
/**
* Java Client Methods 生成
* 具体执行顺序 http://www.mybatis.org/generator/reference/pluggingIn.html
*
* @param interfaze
* @param topLevelClass
* @param introspectedTable
* @return
*/
@Override
public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
// ====================================== 1. upsert ======================================
Method mUpsert = new Method(METHOD_UPSERT);
// 返回值类型
mUpsert.setReturnType(FullyQualifiedJavaType.getIntInstance());
// 添加参数
mUpsert.addParameter(new Parameter(introspectedTable.getRules().calculateAllFieldsClass(), "record"));
// 添加方法说明
CommentTools.addGeneralMethodComment(mUpsert, introspectedTable);
// interface 增加方法
interfaze.addMethod(mUpsert);
logger.debug("itfsw(存在即更新插件):" + interfaze.getType().getShortName() + "增加upsert方法。");
// ====================================== 2. upsertSelective ======================================
Method mUpsertSelective = new Method(METHOD_UPSERT_SELECTIVE);
// 返回值类型
mUpsertSelective.setReturnType(FullyQualifiedJavaType.getIntInstance());
// 添加参数
mUpsertSelective.addParameter(new Parameter(introspectedTable.getRules().calculateAllFieldsClass(), "record"));
// 添加方法说明
CommentTools.addGeneralMethodComment(mUpsertSelective, introspectedTable);
// interface 增加方法
interfaze.addMethod(mUpsertSelective);
logger.debug("itfsw(存在即更新插件):" + interfaze.getType().getShortName() + "增加upsertSelective方法。");
return true;
}
/**
* SQL Map Methods 生成
* 具体执行顺序 http://www.mybatis.org/generator/reference/pluggingIn.html
*
* @param document
* @param introspectedTable
* @return
*/
@Override
public boolean sqlMapDocumentGenerated(Document document, IntrospectedTable introspectedTable) {
// ====================================== 1. upsert ======================================
XmlElement eleUpsert = new XmlElement("insert");
eleUpsert.addAttribute(new Attribute("id", METHOD_UPSERT));
// 添加注释(!!!必须添加注释,overwrite覆盖生成时,@see XmlFileMergerJaxp.isGeneratedNode会去判断注释中是否存在OLD_ELEMENT_TAGS中的一点,例子:@mbg.generated)
CommentTools.addComment(eleUpsert);
// 参数类型
eleUpsert.addAttribute(new Attribute("parameterType", introspectedTable.getRules().calculateAllFieldsClass().getFullyQualifiedName()));
// 使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中。所以只支持MYSQL和SQLServer
CommTools.useGeneratedKeys(eleUpsert, introspectedTable);
// insert
eleUpsert.addElement(new TextElement("insert into " + introspectedTable.getFullyQualifiedTableNameAtRuntime()));
eleUpsert.addElement(this.generateInsertClause(introspectedTable));
eleUpsert.addElement(new TextElement("values"));
eleUpsert.addElement(this.generateValuesClause(introspectedTable));
eleUpsert.addElement(new TextElement("on duplicate key update "));
eleUpsert.addElement(this.generateDuplicateClause(introspectedTable));
document.getRootElement().addElement(eleUpsert);
logger.debug("itfsw(存在即更新插件):" + introspectedTable.getMyBatis3XmlMapperFileName() + "增加upsert实现方法。");
// ====================================== 2. upsertSelective ======================================
XmlElement eleUpsertSelective = new XmlElement("insert");
eleUpsertSelective.addAttribute(new Attribute("id", METHOD_UPSERT_SELECTIVE));
// 添加注释(!!!必须添加注释,overwrite覆盖生成时,@see XmlFileMergerJaxp.isGeneratedNode会去判断注释中是否存在OLD_ELEMENT_TAGS中的一点,例子:@mbg.generated)
CommentTools.addComment(eleUpsertSelective);
// 参数类型
eleUpsertSelective.addAttribute(new Attribute("parameterType", introspectedTable.getRules().calculateAllFieldsClass().getFullyQualifiedName()));
// 使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中。所以只支持MYSQL和SQLServer
CommTools.useGeneratedKeys(eleUpsertSelective, introspectedTable);
// insert
eleUpsertSelective.addElement(new TextElement("insert into " + introspectedTable.getFullyQualifiedTableNameAtRuntime()));
eleUpsertSelective.addElement(this.generateInsertSelectiveClause(introspectedTable));
eleUpsertSelective.addElement(new TextElement("values"));
eleUpsertSelective.addElement(this.generateValuesSelectiveClause(introspectedTable));
eleUpsertSelective.addElement(new TextElement("on duplicate key update "));
eleUpsertSelective.addElement(this.generateDuplicateSelectiveClause(introspectedTable));
document.getRootElement().addElement(eleUpsertSelective);
logger.debug("itfsw(存在即更新插件):" + introspectedTable.getMyBatis3XmlMapperFileName() + "增加upsertSelective实现方法。");
return true;
}
/**
* 普通insert
*
* @param introspectedTable
* @return
*/
private Element generateInsertClause(IntrospectedTable introspectedTable){
StringBuilder insertClause = new StringBuilder();
insertClause.append(" (");
List<IntrospectedColumn> columns = introspectedTable.getAllColumns();
for (int i = 0; i < columns.size(); i++) {
IntrospectedColumn introspectedColumn = columns.get(i);
insertClause.append(MyBatis3FormattingUtilities.getEscapedColumnName(introspectedColumn));
if (i + 1 < columns.size()) {
insertClause.append(", ");
}
}
insertClause.append(") ");
return new TextElement(insertClause.toString());
}
/**
* 普通 values
*
* @param introspectedTable
* @return
*/
private Element generateValuesClause(IntrospectedTable introspectedTable){
StringBuilder valuesClause = new StringBuilder();
valuesClause.append(" (");
List<IntrospectedColumn> columns = introspectedTable.getAllColumns();
for (int i = 0; i < columns.size(); i++) {
IntrospectedColumn introspectedColumn = columns.get(i);
valuesClause.append(MyBatis3FormattingUtilities.getParameterClause(introspectedColumn));
if (i + 1 < columns.size()) {
valuesClause.append(", ");
}
}
valuesClause.append(") ");
return new TextElement(valuesClause.toString());
}
/**
* 普通duplicate
*
* @param introspectedTable
* @return
*/
private Element generateDuplicateClause(IntrospectedTable introspectedTable){
StringBuilder duplicateClause = new StringBuilder();
List<IntrospectedColumn> columns = introspectedTable.getAllColumns();
for (int i = 0; i < columns.size(); i++) {
IntrospectedColumn introspectedColumn = columns.get(i);
duplicateClause.append(MyBatis3FormattingUtilities.getEscapedColumnName(introspectedColumn));
duplicateClause.append(" = ");
duplicateClause.append(MyBatis3FormattingUtilities.getParameterClause(introspectedColumn));
if (i + 1 < columns.size()) {
duplicateClause.append(", ");
}
}
return new TextElement(duplicateClause.toString());
}
/**
* 普通insert
*
* @param introspectedTable
* @return
*/
private Element generateInsertSelectiveClause(IntrospectedTable introspectedTable){
XmlElement insertTrimEle = new XmlElement("trim");
insertTrimEle.addAttribute(new Attribute("prefix", "("));
insertTrimEle.addAttribute(new Attribute("suffix", ")"));
insertTrimEle.addAttribute(new Attribute("suffixOverrides", ","));
StringBuffer sb = new StringBuffer();
for (IntrospectedColumn introspectedColumn : introspectedTable.getAllColumns()) {
XmlElement insertNotNullElement = new XmlElement("if"); //$NON-NLS-1$
sb.setLength(0);
sb.append(introspectedColumn.getJavaProperty());
sb.append(" != null");
insertNotNullElement.addAttribute(new Attribute("test", sb.toString()));
sb.setLength(0);
sb.append(MyBatis3FormattingUtilities.getEscapedColumnName(introspectedColumn));
sb.append(',');
insertNotNullElement.addElement(new TextElement(sb.toString()));
insertTrimEle.addElement(insertNotNullElement);
}
return insertTrimEle;
}
/**
* 普通 values
*
* @param introspectedTable
* @return
*/
private Element generateValuesSelectiveClause(IntrospectedTable introspectedTable){
XmlElement valuesTrimEle = new XmlElement("trim");
valuesTrimEle.addAttribute(new Attribute("prefix", "("));
valuesTrimEle.addAttribute(new Attribute("suffix", ")"));
valuesTrimEle.addAttribute(new Attribute("suffixOverrides", ","));
StringBuffer sb = new StringBuffer();
for (IntrospectedColumn introspectedColumn : introspectedTable.getAllColumns()) {
XmlElement valuesNotNullElement = new XmlElement("if"); //$NON-NLS-1$
sb.setLength(0);
sb.append(introspectedColumn.getJavaProperty());
sb.append(" != null");
valuesNotNullElement.addAttribute(new Attribute("test", sb.toString()));
sb.setLength(0);
sb.append(MyBatis3FormattingUtilities.getParameterClause(introspectedColumn));
sb.append(',');
valuesNotNullElement.addElement(new TextElement(sb.toString()));
valuesTrimEle.addElement(valuesNotNullElement);
}
return valuesTrimEle;
}
/**
* 普通duplicate
*
* @param introspectedTable
* @return
*/
private Element generateDuplicateSelectiveClause(IntrospectedTable introspectedTable){
XmlElement duplicateTrimEle = new XmlElement("trim");
duplicateTrimEle.addAttribute(new Attribute("suffixOverrides", ","));
StringBuffer sb = new StringBuffer();
for (IntrospectedColumn introspectedColumn : introspectedTable.getAllColumns()) {
XmlElement duplicateNotNullElement = new XmlElement("if"); //$NON-NLS-1$
sb.setLength(0);
sb.append(introspectedColumn.getJavaProperty());
sb.append(" != null");
duplicateNotNullElement.addAttribute(new Attribute("test", sb.toString()));
sb.setLength(0);
sb.append(MyBatis3FormattingUtilities.getEscapedColumnName(introspectedColumn));
sb.append(" = ");
sb.append(MyBatis3FormattingUtilities.getParameterClause(introspectedColumn));
sb.append(",");
duplicateNotNullElement.addElement(new TextElement(sb.toString()));
duplicateTrimEle.addElement(duplicateNotNullElement);
}
return duplicateTrimEle;
}
}
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2017.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.itfsw.mybatis.generator.plugins.utils;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.config.GeneratedKey;
/**
* ---------------------------------------------------------------------------
* 一些通用工具集
* ---------------------------------------------------------------------------
* @author: hewei
* @time:2017/3/22 14:03
* ---------------------------------------------------------------------------
*/
public class CommTools {
/**
* 使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中。所以只支持MYSQL和SQLServer
*
* @param element
* @param introspectedTable
*/
public static void useGeneratedKeys(XmlElement element, IntrospectedTable introspectedTable){
GeneratedKey gk = introspectedTable.getGeneratedKey();
if (gk != null) {
IntrospectedColumn introspectedColumn = introspectedTable.getColumn(gk.getColumn());
// if the column is null, then it's a configuration error. The
// warning has already been reported
if (introspectedColumn != null) {
// 使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中。所以只支持MYSQL和SQLServer
element.addAttribute(new Attribute("useGeneratedKeys", "true")); //$NON-NLS-1$ //$NON-NLS-2$
element.addAttribute(new Attribute("keyProperty", introspectedColumn.getJavaProperty())); //$NON-NLS-1$
element.addAttribute(new Attribute("keyColumn", introspectedColumn.getActualColumnName())); //$NON-NLS-1$
}
}
}
}
@@ -17,10 +17,7 @@
package com.itfsw.mybatis.generator.plugins.utils;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.InnerClass;
import org.mybatis.generator.api.dom.java.Interface;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.*;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.config.MergeConstants;
@@ -62,7 +59,7 @@ public class CommentTools {
* @param innerClass 类
* @param introspectedTable 表
*/
public static void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable) {
public static void addInnerClassComment(InnerClass innerClass, IntrospectedTable introspectedTable) {
StringBuilder sb = new StringBuilder();
innerClass.addJavaDocLine("/**"); //$NON-NLS-1$
innerClass.addJavaDocLine(" * 这是Mybatis Generator拓展插件生成的类(请勿删除)."); //$NON-NLS-1$
@@ -75,6 +72,25 @@ public class CommentTools {
innerClass.addJavaDocLine(" */"); //$NON-NLS-1$
}
/**
* 生成通用内部Enum注释
*
* @param innerEnum 类
* @param introspectedTable 表
*/
public static void addInnerEnumComment(InnerEnum innerEnum, IntrospectedTable introspectedTable) {
StringBuilder sb = new StringBuilder();
innerEnum.addJavaDocLine("/**"); //$NON-NLS-1$
innerEnum.addJavaDocLine(" * 这是Mybatis Generator拓展插件生成的枚举(请勿删除)."); //$NON-NLS-1$
sb.append(" * This class corresponds to the database table "); //$NON-NLS-1$
sb.append(introspectedTable.getFullyQualifiedTable());
innerEnum.addJavaDocLine(sb.toString());
innerEnum.addJavaDocLine(" *");
innerEnum.addJavaDocLine(" * "+MergeConstants.NEW_ELEMENT_TAG);
innerEnum.addJavaDocLine(" * @author hewei");
innerEnum.addJavaDocLine(" */"); //$NON-NLS-1$
}
/**
* 生成通用方法注解
*