瀏覽代碼

新增 service 层测试

= 8 年之前
父節點
當前提交
d105be2937
共有 100 個文件被更改,包括 11177 次插入3478 次删除
  1. 1 0
      .gitignore
  2. 246 0
      CHANGELOG.md
  3. 201 0
      LICENSE
  4. 61 33
      README.md
  5. 14 1
      mybatis-plus/.gitignore
  6. 129 12
      mybatis-plus/pom.xml
  7. 0 121
      mybatis-plus/readme.md
  8. 0 1
      mybatis-plus/src/main/java/.gitignore
  9. 二進制
      mybatis-plus/src/main/java/com/.DS_Store
  10. 0 1
      mybatis-plus/src/main/java/com/.gitignore
  11. 0 1
      mybatis-plus/src/main/java/com/baomidou/.gitignore
  12. 0 241
      mybatis-plus/src/main/java/com/baomidou/framework/service/IService.java
  13. 0 149
      mybatis-plus/src/main/java/com/baomidou/framework/service/impl/ServiceImpl.java
  14. 0 9
      mybatis-plus/src/main/java/com/baomidou/framework/service/package-info.java
  15. 0 1
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/.gitignore
  16. 230 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/MybatisAbstractSQL.java
  17. 54 20
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/MybatisConfiguration.java
  18. 137 32
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/MybatisDefaultParameterHandler.java
  19. 660 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/MybatisMapperAnnotationBuilder.java
  20. 102 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/MybatisMapperRegistry.java
  21. 14 23
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/MybatisSessionFactoryBuilder.java
  22. 365 333
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/MybatisXMLConfigBuilder.java
  23. 380 362
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/MybatisXMLMapperBuilder.java
  24. 376 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/activerecord/Model.java
  25. 28 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/activerecord/package-info.java
  26. 0 1
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/annotations/.gitignore
  27. 32 6
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/annotations/TableField.java
  28. 11 7
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/annotations/TableId.java
  29. 13 2
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/annotations/TableName.java
  30. 41 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/entity/CountOptimize.java
  31. 395 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/entity/GlobalConfiguration.java
  32. 158 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/entity/TableFieldInfo.java
  33. 67 18
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/entity/TableInfo.java
  34. 4 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/entity/package-info.java
  35. 111 68
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/enums/DBType.java
  36. 58 49
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/enums/FieldStrategy.java
  37. 70 53
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/enums/IdType.java
  38. 75 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/enums/Optimize.java
  39. 63 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/enums/SqlLike.java
  40. 89 91
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/enums/SqlMethod.java
  41. 4 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/enums/package-info.java
  42. 4 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/exceptions/package-info.java
  43. 132 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/AbstractGenerator.java
  44. 259 826
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/AutoGenerator.java
  45. 0 137
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/ConfigDataSource.java
  46. 0 279
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/ConfigGenerator.java
  47. 78 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/InjectionConfig.java
  48. 69 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/ConstVal.java
  49. 163 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/DataSourceConfig.java
  50. 55 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/FileOutConfig.java
  51. 179 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/GlobalConfig.java
  52. 17 6
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/ITypeConvert.java
  53. 138 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/PackageConfig.java
  54. 269 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/StrategyConfig.java
  55. 88 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/TemplateConfig.java
  56. 546 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/builder/ConfigBuilder.java
  57. 4 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/builder/package-info.java
  58. 59 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/converts/MySqlTypeConvert.java
  59. 54 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/converts/OracleTypeConvert.java
  60. 59 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/converts/PostgreSqlTypeConvert.java
  61. 57 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/converts/SqlServerTypeConvert.java
  62. 4 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/package-info.java
  63. 123 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/po/TableField.java
  64. 221 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/po/TableInfo.java
  65. 4 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/po/package-info.java
  66. 63 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/rules/DbColumnType.java
  67. 38 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/rules/DbType.java
  68. 144 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/rules/NamingStrategy.java
  69. 134 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/rules/QuerySQL.java
  70. 4 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/rules/package-info.java
  71. 1 1
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/package-info.java
  72. 521 283
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/AutoSqlInjector.java
  73. 100 92
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/BaseMapper.java
  74. 61 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/Condition.java
  75. 81 50
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/EntityWrapper.java
  76. 41 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/IMetaObjectHandler.java
  77. 55 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/ISqlInjector.java
  78. 178 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/SqlHelper.java
  79. 312 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/SqlPlus.java
  80. 142 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/SqlRunner.java
  81. 643 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/Wrapper.java
  82. 27 11
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/Page.java
  83. 113 77
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/PaginationInterceptor.java
  84. 141 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/PerformanceInterceptor.java
  85. 159 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/SqlExplainInterceptor.java
  86. 88 14
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/pagination/DialectFactory.java
  87. 89 28
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/pagination/Pagination.java
  88. 69 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/pagination/dialects/DB2Dialect.java
  89. 39 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/pagination/dialects/H2Dialect.java
  90. 2 2
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/pagination/dialects/OracleDialect.java
  91. 71 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/pagination/dialects/SQLServer2005Dialect.java
  92. 332 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/service/IService.java
  93. 297 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/service/impl/ServiceImpl.java
  94. 4 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/service/impl/package-info.java
  95. 4 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/service/package-info.java
  96. 296 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/spring/MybatisMapperRefresh.java
  97. 58 37
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/spring/MybatisSqlSessionFactoryBean.java
  98. 4 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/spring/package-info.java
  99. 54 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/toolkit/CollectionUtils.java
  100. 41 0
      mybatis-plus/src/main/java/com/baomidou/mybatisplus/toolkit/DruidUtils.java

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+.DS_Store

+ 246 - 0
CHANGELOG.md

@@ -0,0 +1,246 @@
+# CHANGELOG
+
+## [v2.0.1] 2017.01.15
+
+1.解决EntityWrapper对布尔类型构造sql语句错误
+2.全局配置初始化日志提示调整
+3.Mybatis依赖升级至3.4.2,Mybatis-Spring依赖升级至1.3.1
+4.Service中补充方法(selectObjs,selectMaps)
+5.解决selectCount数据库返回null报错问题
+6.支持PostgreSql代码生成
+7.拓展支持外部提供转义字符以及关键字列表
+8.开放数据库表无主键依然注入MP的CRUD(无主键不能使用MP的xxById方法)
+9.解决EntityWrapper拼接SQL时,首次调用OR方法不起作用的问题
+10.sqlServer代码生成(基于2008版本)
+11.解决生成代码时未导入BigDecimal问题.
+12.释放自动读取数据库时的数据库连接
+13.优化全局校验机制(机制为EMPTY增加忽略Date类型)
+14.优化注入,避免扫描到BaseMapper
+15.优化注入,去除多余注入方法
+16.SQLlikeType改名为SqlLike
+17.解决热加载关联查询错误问题
+18.SqlQuery改名为SqlRunner
+19.优化完善代码生成器
+20.修复代码生成器未导入@tableName
+21.全局配置需要手动添加MP的默认注入类,更改为自动注入简化配置
+22.Wrapper增加ne方法
+23.修复Mybatis动态参数无法生成totalCount问题
+24.代码结构优化,生成器模板优化
+25.解决issus[138,140,142,148,151,152,153,156,157],具体请查看里程碑[mybatis-plus 2.0.1 计划](http://git.oschina.net/baomidou/mybatis-plus/milestones/2)中所有issus
+
+## [v2.0.0] 2016.12.11
+
+1.支持全局大写命名策略
+2.自动分页Count语句优化
+3.优化现有全局配置策略
+4.优化全局验证策略
+5.优化代码生成器(之前硬编码,现使用模板形式)
+6.优化注入通用方法ByMap逻辑
+7.添加自动选择数据库类型
+8.改善SqlExplainInterceptor(自行判断MySQL版本不支持该拦截器则直接放行(版本过低小于5.6.3))
+9.修复部分特殊字符字符多次转义的问题
+10.优化现有EntityWrapper添加Wrapper父类以及Condition链式查询
+11.Wrapper类使LIKE方法兼容多种数据库
+12.优化日志使用原生Mybatis自带的日志输出提示信息
+13.修复使用缓存导致使用分页无法计算Count值
+14.修复PerformanceInterceptor替换`?`导致打印SQL不准确问题,并添加格式化SQL选项
+15.添加多种数据库支持,请查看DBType
+16.添加字符串类型字段非空校验策略(字符串类型自动判断非空以及非空字符串)
+17.Wrapper添加类似QBC查询(eq、gt、lt等等)
+18.支持AR模式(需继承Model)
+19.合并所有Selective通用方法(例如:去除之前的insert方法并把之前的insetSelective改名为insert)
+20.解决sql剥离器会去除`--`的情况
+21.支持MySQL关键词,自动转义
+22.精简底层Service、Mapper继承结构
+23.不喜欢在XML中写SQL的福音,新增执行SQL方式,具体请查看SqlQuery
+24.优化代码结构
+25.解决issus[95,96,98,100,103,104,108,114,119,121,123,124,125,126,127,128,131,133,134,135],具体请查看里程碑[mybatis-plus 2.0 计划](http://git.oschina.net/baomidou/mybatis-plus/milestones/1)中所有issus
+
+## [v1.4.9] 2016.10.28
+
+1、ServiceImpl去除@Transactional注解、去除Slf4j依赖
+2、解决使用EntityWrapper查询时,参数为特殊字符时,存在sql注入问题
+3、调整Mybatis驼峰配置顺序 MybatisPlus > Mybatis
+4、优化分页插件并修复分页溢出设置不起作用问题
+5、去除DBKeywordsProcessor,添加MySQL自动转义关键词
+6、代码生成器新增支持TEXT、TIME、TIMESTAMP类型生成
+7、新增批量插入方法
+8、代码生成器新增Controller层代码生成
+9、调整EntityWrapper类部分List入参为Collection
+10、代码生成器优化支持 resultMap
+
+## [v1.4.8] 2016.10.12
+
+1、insertOrUpdate增加主键空字符串判断
+2、支持Mybatis原生驼峰配置 mapUnderscoreToCamelCase 开关设置
+3、支持 TableField FieldStrategy 注解全局配置
+4、SelectOne、SelectCount方法支持EntityWrapper方式
+5、oracle 代码生成器支持 Integer Long Dobule 类型区分
+6、修复INPUT主键策略InsertOrUpdate方法Bug
+7、EntityWrapper IN 添加可变数组支持
+8、基础Mapper、Servcie通用方法PK参数类型更改至Serializable
+9、当selectOne结果集不唯一时,添加警告提示(需开启日志warn模式)
+10、baseService添加logger,子类直接调用logger不用重新定义(需slf4j依赖)
+
+## [v1.4.7] 2016.09.27
+
+1、主键注解 I 改为 PK 方便理解,去掉 mapper 注解
+2、性能分析插件,特殊处理 $ 符内容
+3、添加自动提交事务说明,新增事务测试
+4、支持 resultMap 实体结果集映射
+5、增加#TableField(el = "")表达式,当该Field为对象时, 可使用#{对象.属性}来映射到数据表、及测试
+6、新增 typeHanler 级联查询支持
+7、新增验证字段策略枚举类
+8、代码生成器支持实体构建者模型设置
+9、代码生成器新增实体常量生成支持
+10、CRUD 新增 insertOrUpdate 方法
+11、解决MessageFormat.format格式化数字类型sql错误
+12、EntityWrapper添加 EXISTS、IN、BETWEEN AND(感谢D.Yang提出)方法支持
+13、支持 mysql5.7+ json enum 类型,代码生成
+14、支持无XML依然注入CRUD方法
+15、修改Mybatis原生配置文件加载顺序
+
+## [v1.4.6] 2016.09.05
+
+- 新增无 @TableId 注解跳过注入SQL
+- 支持非表映射对象插入不执行填充
+- xxxByMap 支持 null 查询
+
+## [v1.4.5] 2016.08.28
+
+- 新增 XML 修改自动热加载功能
+- 添加自动处理EntityWrapper方法中的MessageFormat Params类型为字符串的参数
+- 新增表公共字段自动填充功能
+
+## [v1.4.4] 2016.08.25
+
+- entitywrapper所有条件类方法支持传入null参数,该条件不会附件到SQL语句中
+- TSQLPlus更名为TSqlPlus与整体命名保持一致。
+- 修复mysql关键字bug----将关键字映射转换加上``符号,增加xml文件生成时可自定义文件后缀名
+- 关闭资源前增加非空判断,避免错误sql引起的空指针错误,增加选择 current>pages 判断
+- TSQL 相关类实现序列化支持 dubbo
+- 增加 mybatis 自动热加载插件
+- 支持数据库 order key 等关键词转义 curd 操作
+
+## [v1.4.3] 2016.08.23
+
+- 优化 Sequence 兼容无法获取 mac 情况
+- 兼容用户设置 ID 空字符串,自动填充
+- 纯大写命名,转为小写属性
+- 修改EntityWrapper符合T-SQL语法标准的条件进行方法封装定义
+- 升级 1.4.3 测试传递依赖
+
+## [v1.4.0] 2016.08.17
+
+- 增加自定义 select 结果集,优化 page 分页
+- 未考虑 函数,去掉 field 优化
+- 新增 delete update 全表操作禁止执行拦截器
+
+## [v1.3.9] 2016.08.09
+
+- 修复 bug
+- 解决插入 map 异常
+- 插入 map 不处理,原样返回
+- 优化 IdWorker 生成器
+- 支持自定义 LanguageDriver
+- 支持代码生成自定义类名
+- 升级 mybatis 3.4.1 依赖
+
+## [v1.3.6] 2016.07.28
+
+- 支持全局表字段下划线命名设置
+- 增加自定义 注入 sql 方法
+- 优化分页总记录数为0不执行列表查询逻辑
+- 自动生成 xml 基础字段增加 AS 处理
+- 支持字段子查询
+
+## [v1.3.5] 2016.07.24
+
+- 升级 1.3.5 支持全局表字段下划线命名设置
+- 添加发现设置多个主键注解抛出异常
+- 添加无主键主键启动异常
+- 去掉重置 getDefaultScriptingLanuageInstance
+- 修改歧义重载方法
+
+## [v1.3.3] 2016.07.15
+
+- 处理 SimpleDateFormat 非现场安全问题
+- 修改 oracle 分页 bug 修复
+- oracle TIMESTAMP 生成支持 bug 修复
+
+## [v1.3.2] 2016.07.12
+
+- service 暴露 sqlSegment 的方法调用
+- 新增 sql 执行性能分析 plugins
+- 新增 deleteByMap , selectByMap
+
+## [v1.3.0] 2016.07.07
+
+- 支持 like 比较等查询 sqlSegment 实现
+- 支持 typeAliasesPackage 通配符扫描, 无 count 分页查询
+- mybatis mapper 方法调用执行原理测试
+- 添加 IOC 演示用例
+
+## [v1.2.17] 2016.06.15
+
+- 优化 代码生成器 感谢 yanghu pull request
+- 调整 sql 加载顺序 xmlSql > curdSql
+- 支持 CURD 二级缓存
+- 增加缓存测试,及特殊字符测试
+
+## [v1.2.15] 2016.04.27
+
+- 新增 支持oracle 自动代码生成,测试 功能
+- 新增 UUID 策略
+- 演示demo 点击 spring-wind
+- 新增支持单表 count 查询
+
+## [v1.2.12] 2016.04.22
+
+- 添加 service 层支持泛型 id 支持,自动生成代码优化
+- 升级 mybatis 为 3.4.0 ,mybatis-spring 为 1.3.0
+
+## [v1.2.11] 2016.04.18
+
+- 新增批量更新,支持 oracle 批量操作
+- 去掉,移植至 spring-wind 的文档
+- 支持 jdk1.5 修改 param 描述
+- 添加数据库类型
+
+## [v1.2.9] 2016.04.10
+
+- EntityWrapper 新增无 order by 构造方法
+- MailHelper 重载 sendMail 方法
+- 新增 String 主键ID 支持 CommonMapper
+- 原来方法 selectList 分离为 selectList , selectPage 两个方法
+- 优化代码生成器,添加文档说明、其他
+
+## [v1.2.8] 2016.04.02
+
+- 优化生成代码处理大写字段,支持自动生成 entity mapper service 文件
+- 优化分页 index 超出逻辑,新增 5 个 CRUD 操作方法
+- 开放模板引擎 getHtmltext 方法
+- 优化邮件发送配置添加说明文档
+- 添加文档说明、其他
+
+## [v1.2.6] 2016.03.29
+
+- 优化代码 service 层封装,抽离 list 、 page 方法
+- 优化分页 count sql 语句
+- 改进 mail 工具类
+- 完善 framework 对 spring 框架的支持
+- 添加文档说明、其他
+
+## [v1.2.5] 2016.03.25
+
+- 独立支持id泛型的 baseMapper
+- 更完善的自动生成工具
+- 支持实体封装排序
+- 分页插件完善
+- 抽离 service 主键泛型支持
+
+## [v1.2.2] 2016.03.14
+
+- 注解 ID 区分 AUTO 数据库自增,ID_WORKER 自动填充自定义自增ID , INPUT 手动输入 。
+- 优化代码及自动生成器功能。
+- 其他

+ 201 - 0
LICENSE

@@ -0,0 +1,201 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "{}"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright 2011-2016 hubin.
+
+   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.

+ 61 - 33
README.md

@@ -1,23 +1,58 @@
-![mybatis-plus](http://git.oschina.net/uploads/images/2016/0218/124639_f4ea3095_12260.png "mybatis 增强工具包")
+![Mybatis-Plus-Logo](http://git.oschina.net/uploads/images/2016/0824/211639_4d931e7f_12260.png "logo")
 
-#mybatis-plus 
+[![license](https://img.shields.io/github/license/baomidou/mybatis-plus.svg?maxAge=2592000)](http://www.apache.org/licenses/LICENSE-2.0)
+[![GitHub release](https://img.shields.io/github/release/baomidou/mybatis-plus.svg?maxAge=2592000)](https://github.com/baomidou/mybatis-plus)
 
-mybatis 增强工具包,简化 CURD 操作。
 
-[mybatis-plus 实践及架构原理](http://git.oschina.net/juapk/mybatis-plus/attach_files)
+  `如果你喜欢 Hibernate ,可以尝试使用`
 
-[演示 DEMO](http://git.oschina.net/juapk/SpringWind)
+- [Hibernate-Plus](http://git.oschina.net/baomidou/hibernate-plus)
 
-> 启动加载 XML 配置时注入单表 SQL 操作 ,为 简化开发工作 提高生产率 而生。 
 
-> Mybatis + 只做增强不做改变,这里不提倡 sql 写在代码中。
+> 为简化开发工作、提高生产率而生
 
-> 技术讨论 QQ 群 492238239 
+# 简介 | Intro
 
+Mybatis 增强工具包 - 只做增强不做改变,简化`CRUD`操作
 
-Maven 坐标
-===========
-```
+> 技术讨论 QQ 群 492238239 如满,加群 121472998 [(有钱的捧个钱场【点击捐赠】, 没钱的捧个人场)](http://git.oschina.net/uploads/images/2015/1222/211207_0acab44e_12260.png)
+
+# 优点 | Advantages
+
+- **纯正血统**:完全继承原生 `Mybatis` 的所有特性
+- **最少依赖**:仅仅依赖`Mybatis`以及`Mybatis-Spring`
+- **性能损耗小**:启动即会自动注入基本CURD ,性能无损耗,直接面向对象操作
+- **自动热加载**:Mapper对应的xml可以热加载,大大减少重启Web服务器时间,提升开发效率
+- **自动生成代码**:包含自动生成代码类以及Maven插件,通过少量配置,即可快速生成Mybatis对应的xml、mapper、entity、service、serviceimpl层代码,减少开发时间
+- **自定义操作**:支持自定义Sql注入,实现个性化操作
+- **自定义转义规则**:支持数据库关键词(例如:`order`、`key`等)自动转义,支持自定义关键词
+- **多种主键策略**:支持多达4种主键策略,可自由配置,若无将会自动填充,更有充满黑科技的`分布式全局唯一ID生成器`
+- **无缝分页插件**:基于Mybatis物理分页,无需关心具体操作,等同于编写基本`selectList`查询
+- **性能分析**:自带Sql性能分析插件,开发测试时,能有效解决慢查询
+- **全局拦截**:提供全表`delete`、`update`操作智能分析阻断
+- **避免Sql注入**:内置Sql注入内容剥离器,预防Sql注入攻击
+
+# 文档 | Documentation
+
+[中文](http://mp.baomidou.com/) | [English](http://mp.baomidou.com/en/)
+
+# 原理 | Principle
+
+[Mybatis-Plus 实践及架构原理](http://git.oschina.net/baomidou/mybatis-plus/attach_files)
+
+# 应用实例 | Demo
+
+[Spring-MVC](https://git.oschina.net/baomidou/mybatisplus-spring-mvc)
+
+[Spring-Boot](https://git.oschina.net/baomidou/mybatisplus-spring-boot)
+
+[SSM-实战 Demo](http://git.oschina.net/juapk/SpringWind)
+
+# 下载地址 | Download
+
+[点此去下载](http://maven.aliyun.com/nexus/#nexus-search;quick~mybatis-plus)
+
+```xml
 <dependency>
     <groupId>com.baomidou</groupId>
     <artifactId>mybatis-plus</artifactId>
@@ -25,37 +60,30 @@ Maven 坐标
 </dependency>
 ```
 
+# 结构目录 | Architecture
 
-功能
-===========
-1、单表 CURD (简单 + 批量)操作,自动完成。
+![项目结构说明](http://git.oschina.net/uploads/images/2016/0821/161516_58956b85_12260.png "项目结构说明")
 
-2、分页插件,Count 查询 自动 或 自定义 SQL 查询。
+# 其他开源项目 | Other Project
 
-3、Spring 根据不同环境加载不同配置支持。
+- [基于Cookie的SSO中间件 Kisso](http://git.oschina.net/baomidou/kisso)
+- [Java快速开发框架 SpringWind](http://git.oschina.net/juapk/SpringWind)
+- [基于Hibernate扩展 Hibernate-Plus](http://git.oschina.net/baomidou/hibernate-plus)
 
-![项目结构说明](http://git.oschina.net/uploads/images/2016/0427/104817_6ebcc3eb_12260.png "项目结构说明")
+# 期望 | Futures
 
+> 欢迎提出更好的意见,帮助完善 Mybatis-Plus
 
-http://baomidou.com/
+# 版权 | License
 
-[java 基于 Cookie 的 SSO 中间件 kisso](http://git.oschina.net/juapk/kisso)
+[Apache License 2.0](http://www.apache.org/licenses/LICENSE-2.0)
 
+# 捐赠 | Donate
 
-捐赠 mybatis-plus
-====================
-![捐赠 mybatis-plus](http://git.oschina.net/uploads/images/2015/1222/211207_0acab44e_12260.png "支持一下mybatis-plus")
-
+> [捐赠记录,感谢你们的支持!](http://git.oschina.net/baomidou/kisso/wikis/%E6%8D%90%E8%B5%A0%E8%AE%B0%E5%BD%95)
 
-Futures
-====================
-1、欢迎提出更好的意见,帮助完善 mybatis-plus 
-
-copyright
-====================
-Apache License, Version 2.0
+![捐赠 mybatis-plus](http://git.oschina.net/uploads/images/2015/1222/211207_0acab44e_12260.png "支持一下mybatis-plus")
 
+# 关注我 | About Me
 
-关注我
-====================
-![程序员日记](http://git.oschina.net/uploads/images/2016/0121/093728_1bc1658f_12260.png "程序员日记")
+![程序员日记](http://git.oschina.net/uploads/images/2016/0121/093728_1bc1658f_12260.png "程序员日记")

+ 14 - 1
mybatis-plus/.gitignore

@@ -1,4 +1,17 @@
 /target/
 /.settings/
-/.classpath
 /.project
+/.classpath
+
+# IntelliJ project files
+.idea
+*.iml
+out
+html
+
+# gradle
+.gradle
+build
+
+# MacOS
+.DS_Store

+ 129 - 12
mybatis-plus/pom.xml

@@ -3,11 +3,11 @@
 	<modelVersion>4.0.0</modelVersion>
 	<groupId>com.baomidou</groupId>
 	<artifactId>mybatis-plus</artifactId>
-	<version>1.2.16</version>
+	<version>2.0.2</version>
 	<packaging>jar</packaging>
 
 	<name>mybatis-plus</name>
-	<description>mybatis-plus is an enhanced version of mybaits. </description>
+	<description>mybatis-plus is an enhanced version of mybaits.</description>
 	<url>http://maven.apache.org</url>
 
 	<licenses>
@@ -31,16 +31,26 @@
 	</scm>
 
 	<properties>
+		<!-- <gpg.keyname>F4B46FB9</gpg.keyname> -->
 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-		<mybatis-spring.version>1.3.0</mybatis-spring.version>
-		<mybatis.version>3.4.0</mybatis.version>
+		<mybatis-spring.version>1.3.1</mybatis-spring.version>
+		<commons.dbcp2.version>2.1.1</commons.dbcp2.version>
+		<commons.pool2.version>2.4.2</commons.pool2.version>
+		<sqljdbc4.version>4.0</sqljdbc4.version>
+		<mybatis.version>3.4.2</mybatis.version>
+		<jsqlparser.version>0.9.6</jsqlparser.version>
+		<alibaba.druid.version>1.0.24</alibaba.druid.version>
 		<slf4j.version>1.7.21</slf4j.version>
 		<logback-classic.version>1.1.7</logback-classic.version>
 		<mysql-connector-java.version>5.1.38</mysql-connector-java.version>
 		<ojdbc14.version>10.2.0.5.0</ojdbc14.version>
+		<postgresql.version>9.4.1212</postgresql.version>
 		<servlet-api.version>2.5</servlet-api.version>
-		<spring.version>4.2.5.RELEASE</spring.version>
-		<mybatis-ehcache.version>1.0.3</mybatis-ehcache.version>
+		<spring.version>4.3.5.RELEASE</spring.version>
+		<aspectjweaver.version>1.8.9</aspectjweaver.version>
+		<mybatis-ehcache.version>1.1.0</mybatis-ehcache.version>
+		<junit.version>4.12</junit.version>
+		<velocity.version>1.7</velocity.version>
 	</properties>
 
 	<dependencies>
@@ -66,9 +76,10 @@
 			<version>${slf4j.version}</version>
 			<scope>provided</scope>
 		</dependency>
+		<!-- spring begin -->
 		<dependency>
 			<groupId>org.springframework</groupId>
-			<artifactId>spring-jdbc</artifactId>
+			<artifactId>spring-context</artifactId>
 			<version>${spring.version}</version>
 			<scope>provided</scope>
 		</dependency>
@@ -78,6 +89,18 @@
 			<version>${spring.version}</version>
 			<scope>provided</scope>
 		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-tx</artifactId>
+			<version>${spring.version}</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-jdbc</artifactId>
+			<version>${spring.version}</version>
+			<scope>provided</scope>
+		</dependency>
 		<dependency>
 			<groupId>org.springframework</groupId>
 			<artifactId>spring-context-support</artifactId>
@@ -85,12 +108,39 @@
 			<scope>provided</scope>
 		</dependency>
 		<dependency>
-		    <groupId>org.mybatis.caches</groupId>
-		    <artifactId>mybatis-ehcache</artifactId>
-		    <version>${mybatis-ehcache.version}</version>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-test</artifactId>
+			<version>${spring.version}</version>
 			<scope>test</scope>
 		</dependency>
-
+		<dependency>
+			<groupId>org.aspectj</groupId>
+			<artifactId>aspectjweaver</artifactId>
+			<version>${aspectjweaver.version}</version>
+			<scope>provided</scope>
+		</dependency>
+		<!-- spring end -->
+		<!--jsqlparser -->
+		<dependency>
+			<groupId>com.github.jsqlparser</groupId>
+			<artifactId>jsqlparser</artifactId>
+			<version>${jsqlparser.version}</version>
+			<scope>provided</scope>
+		</dependency>
+		<!--druid -->
+		<dependency>
+			<groupId>com.alibaba</groupId>
+			<artifactId>druid</artifactId>
+			<version>${alibaba.druid.version}</version>
+			<scope>provided</scope>
+		</dependency>
+		<!-- generator vm -->
+		<dependency>
+			<groupId>org.apache.velocity</groupId>
+			<artifactId>velocity</artifactId>
+			<version>${velocity.version}</version>
+			<scope>provided</scope>
+		</dependency>
 		<!-- test begin -->
 		<dependency>
 			<groupId>mysql</groupId>
@@ -98,6 +148,12 @@
 			<version>${mysql-connector-java.version}</version>
 			<scope>test</scope>
 		</dependency>
+		<dependency>
+			<groupId>org.mybatis.caches</groupId>
+			<artifactId>mybatis-ehcache</artifactId>
+			<version>${mybatis-ehcache.version}</version>
+			<scope>test</scope>
+		</dependency>
 		<dependency>
 			<groupId>com.oracle</groupId>
 			<artifactId>ojdbc14</artifactId>
@@ -110,9 +166,59 @@
 			<version>${logback-classic.version}</version>
 			<scope>test</scope>
 		</dependency>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<version>${junit.version}</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.commons</groupId>
+			<artifactId>commons-dbcp2</artifactId>
+			<version>${commons.dbcp2.version}</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.commons</groupId>
+			<artifactId>commons-pool2</artifactId>
+			<version>${commons.pool2.version}</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>com.microsoft.sqlserver</groupId>
+			<artifactId>sqljdbc4</artifactId>
+			<version>${sqljdbc4.version}</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.postgresql</groupId>
+			<artifactId>postgresql</artifactId>
+			<version>${postgresql.version}</version>
+			<scope>test</scope>
+		</dependency>
 		<!-- test end -->
 	</dependencies>
 
+	<!-- 发版时注释START -->
+	<build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-source-plugin</artifactId>
+				<version>2.2.1</version>
+				<executions>
+					<execution>
+						<phase>package</phase>
+						<goals>
+							<goal>jar-no-fork</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+	<!-- 发版时注释END -->
+
 	<profiles>
 		<profile>
 			<id>release</id>
@@ -143,6 +249,8 @@
 								<goals>
 									<goal>jar</goal>
 								</goals>
+								<!-- <configuration> <additionalparam>-Xdoclint:none</additionalparam> 
+									</configuration> -->
 							</execution>
 						</executions>
 					</plugin>
@@ -150,7 +258,7 @@
 					<plugin>
 						<groupId>org.apache.maven.plugins</groupId>
 						<artifactId>maven-gpg-plugin</artifactId>
-						<version>1.5</version>
+						<version>1.6</version>
 						<executions>
 							<execution>
 								<phase>verify</phase>
@@ -160,6 +268,15 @@
 							</execution>
 						</executions>
 					</plugin>
+					<!-- skipJunitTest -->
+					<plugin>
+						<groupId>org.apache.maven.plugins</groupId>
+						<artifactId>maven-surefire-plugin</artifactId>
+						<version>2.19.1</version>
+						<configuration>
+							<skipTests>true</skipTests>
+						</configuration>
+					</plugin>
 				</plugins>
 			</build>
 			<distributionManagement>

+ 0 - 121
mybatis-plus/readme.md

@@ -1,121 +0,0 @@
-
-# Mbatis-Plus 使用文档
-
-> 	更多文档查看 /mybatis-plus/src/test/resources/wiki
-
-# 插入
-
-> 	插入一条(id 如果不传入会自动生成)
-
-	long id = IdWorker.getId();
-	int rlt = userMapper.insert(new User(id, "abc", 18, 0));
-
-
-> 	插入一条记录(选择字段, null 字段不插入)
-	int rlt = userMapper.insertSelective(new User("abc", 18));
-
-
-> 	批量插入
-
-	List<User> ul = new ArrayList<User>();
-	//手动输入 ID
-	ul.add(new User(11L, "1", 1, 0));
-	ul.add(new User(12L, "2", 2, 1));
-	ul.add(new User(13L, "3", 3, 1));
-	ul.add(new User(14L, "delname", 4, 0));
-	ul.add(new User(15L, "5", 5, 1));
-	ul.add(new User(16L, "6", 6, 0));
-	ul.add(new User(17L, "7", 7, 0));
-	//使用 ID_WORKER 自动生成 ID
-	ul.add(new User("8", 8, 1));
-	ul.add(new User("9", 9, 1));
-	rlt = userMapper.insertBatch(ul);
-
-
-# 删除
-
-> 	删除一条
-
-	int rlt = userMapper.deleteById(id);
-
-
-> 	批量删除
-
-	List<Long> il = new ArrayList<Long>();
-	il.add(16L);
-	il.add(17L);
-	int rlt = userMapper.deleteBatchIds(il);
-
-
-> 	按照条件删除
-
-	int rlt = userMapper.deleteSelective(new User(14L, "delname"));
-
-
-
-# 修改
-
-> 	修改
-
-	int rlt = userMapper.updateById(new User(12L, "MybatisPlus"));
-
-
-> 	根据 ID 选择修改
-
-	int rlt = userMapper.updateSelectiveById(new User(12L, "MybatisPlus"));
-
-
-> 	根据 whereEntity 条件,更新记录(支持 null 查询无条件更新)
-
-	int rlt = userMapper.update(new User("55", 55, 5), new User(15L, "5"));
-
-
-> 	根据 whereEntity 条件,选择更新记录(支持 null 查询无条件更新)
-
-	int rlt = userMapper.updateSelective(new User("00"), new User(15L, "55"));
-
-
-> 	根据ID 批量更新
-
-	List<User> userList = new ArrayList<User>();
-	userList.add(new User(11L, "updateBatchById-1", 1, 1));
-	userList.add(new User(12L, "updateBatchById-2", 2, 2));
-	userList.add(new User(13L, "updateBatchById-3", 3, 3));
-	int rlt = userMapper.updateBatchById(userList);
-
-
-# 查询
-
-> 	根据ID查询
-
-	User user = userMapper.selectById(12L);
-
-> 	根据ID批量查询
-
-	List<Long> idList = new ArrayList<Long>();
-	idList.add(11L);
-	idList.add(12L);
-	List<User> ul1 = userMapper.selectBatchIds(idList);
-
-> 	根据条件查询
-
-	User userOne = userMapper.selectOne(new User("MybatisPlus"));
-
-> 	根据条件查询总记录数(支持 null 查询无条件查询)
-
-	int count = userMapper.selectCount(null);
-
-> 	查询列表 id 排序
-
-	List<User> ul2 = userMapper.selectList(new EntityWrapper<User>(null, "id DESC"));
-
-> 	翻页查询 id 排序
-
-	Page<User> page = new Page<User>(1, 2);
-	EntityWrapper<User> ew = new EntityWrapper<User>(new User(1), "id DESC");
-	List<User> paginList = userMapper.selectPage(page, ew);
-	page.setRecords(paginList);
-	for ( int i = 0 ; i < page.getRecords().size() ; i++ ) {
-		print(page.getRecords().get(i));
-	}
-

+ 0 - 1
mybatis-plus/src/main/java/.gitignore

@@ -1 +0,0 @@
-/.DS_Store

二進制
mybatis-plus/src/main/java/com/.DS_Store


+ 0 - 1
mybatis-plus/src/main/java/com/.gitignore

@@ -1 +0,0 @@
-/.DS_Store

+ 0 - 1
mybatis-plus/src/main/java/com/baomidou/.gitignore

@@ -1 +0,0 @@
-/.DS_Store

+ 0 - 241
mybatis-plus/src/main/java/com/baomidou/framework/service/IService.java

@@ -1,241 +0,0 @@
-/**
- * Copyright (c) 2011-2016, hubin (jobob@qq.com).
- *
- * 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.baomidou.framework.service;
-
-import java.util.List;
-
-import org.apache.ibatis.annotations.Param;
-
-import com.baomidou.mybatisplus.mapper.EntityWrapper;
-import com.baomidou.mybatisplus.plugins.Page;
-
-/**
- * <p>
- * 顶级 Service
- * </p>
- * 
- * @author hubin
- * @Date 2016-04-20
- */
-public interface IService<T, I> {
-
-
-	/**
-	 * <p>
-	 * 插入一条记录
-	 * </p>
-	 * @param entity
-	 * 				实体对象
-	 * @return boolean
-	 */
-	boolean insert( T entity );
-
-
-	/**
-	 * <p>
-	 * 插入一条记录(选择字段, null 字段不插入)
-	 * </p>
-	 * @param entity
-	 * 				实体对象
-	 * @return boolean
-	 */
-	boolean insertSelective( T entity );
-
-
-	/**
-	 * <p>
-	 * 插入(批量),该方法不适合 Oracle
-	 * </p>
-	 * @param entityList
-	 * 				实体对象列表
-	 * @return boolean
-	 */
-	boolean insertBatch( List<T> entityList );
-
-
-	/**
-	 * <p>
-	 * 根据 ID 删除
-	 * </p>
-	 * @param id
-	 * 			主键ID
-	 * @return boolean
-	 */
-	boolean deleteById( I id );
-
-
-	/**
-	 * <p>
-	 * 根据 entity 条件,删除记录
-	 * </p>
-	 * @param entity
-	 * 				实体对象
-	 * @return boolean
-	 */
-	boolean deleteSelective( T entity );
-
-
-	/**
-	 * <p>
-	 * 删除(根据ID 批量删除)
-	 * </p>
-	 * @param idList
-	 * 				主键ID列表
-	 * @return boolean
-	 */
-	boolean deleteBatchIds( List<I> idList );
-
-
-	/**
-	 * <p>
-	 * 根据 ID 修改
-	 * </p>
-	 * @param entity
-	 * 				实体对象
-	 * @return boolean
-	 */
-	boolean updateById( T entity );
-
-
-	/**
-	 * <p>
-	 * 根据 ID 选择修改
-	 * </p>
-	 * @param entity
-	 * 				实体对象
-	 * @return boolean
-	 */
-	boolean updateSelectiveById( T entity );
-
-
-	/**
-	 * <p>
-	 * 根据 whereEntity 条件,更新记录
-	 * </p>
-	 * @param entity
-	 * 				实体对象
-	 * @param whereEntity
-	 * 				实体查询条件(可以为 null)
-	 * @return boolean
-	 */
-	boolean update( T entity, T whereEntity );
-
-
-	/**
-	 * <p>
-	 * 根据 whereEntity 条件,选择更新记录
-	 * </p>
-	 * @param entity
-	 * 				实体对象
-	 * @param whereEntity
-	 * 				实体查询条件(可以为 null)
-	 * @return boolean
-	 */
-	boolean updateSelective( T entity, T whereEntity );
-
-	
-	/**
-	 * <p>
-	 * 根据ID 批量更新
-	 * </p>
-	 * @param entityList
-	 * 				实体对象列表
-	 * @return boolean
-	 */
-	boolean updateBatchById( List<T> entityList );
-
-	/**
-	 * <p>
-	 * 根据 ID 查询
-	 * </p>
-	 * @param id
-	 * 			主键ID
-	 * @return T
-	 */
-	T selectById( I id );
-
-
-	/**
-	 * <p>
-	 * 查询(根据ID 批量查询)
-	 * </p>
-	 * @param idList
-	 * 				主键ID列表
-	 * @return List<T>
-	 */
-	List<T> selectBatchIds( List<I> idList );
-
-
-	/**
-	 * <p>
-	 * 根据 entity 条件,查询一条记录
-	 * </p>
-	 * @param entity
-	 * 				实体对象
-	 * @return T
-	 */
-	T selectOne( T entity );
-	
-	
-	/**
-	 * <p>
-	 * 根据 entity 条件,查询总记录数
-	 * </p>
-	 * @param entity
-	 * 				实体对象
-	 * @return int
-	 */
-	int selectCount( @Param("ew" ) T entity);
-
-
-	/**
-	 * <p>
-	 * 查询列表
-	 * </p>
-	 * 
-	 * @param entity
-	 * 				实体对象
-	 * @param orderByField
-	 * 				对应 EntityWrapper 类中 orderByField 字段
-	 * 				{@link EntityWrapper}
-	 * @return
-	 */
-	List<T> selectList( T entity, String orderByField );
-
-
-	List<T> selectList( T entity );
-
-
-	/**
-	 * <p>
-	 * 翻页查询
-	 * </p>
-	 * 
-	 * @param page
-	 * 				翻页对象
-	 * @param entity
-	 * 				实体对象
-	 * @param orderByField
-	 * 				对应 EntityWrapper 类中 orderByField 字段
-	 * 				{@link EntityWrapper}
-	 * @return
-	 */
-	Page<T> selectPage( Page<T> page, T entity, String orderByField );
-
-
-	Page<T> selectPage( Page<T> page, T entity );
-
-}

+ 0 - 149
mybatis-plus/src/main/java/com/baomidou/framework/service/impl/ServiceImpl.java

@@ -1,149 +0,0 @@
-/**
- * Copyright (c) 2011-2016, hubin (jobob@qq.com).
- *
- * 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.baomidou.framework.service.impl;
-
-import java.util.List;
-
-import org.springframework.beans.factory.annotation.Autowired;
-
-import com.baomidou.framework.service.IService;
-import com.baomidou.mybatisplus.mapper.BaseMapper;
-import com.baomidou.mybatisplus.mapper.EntityWrapper;
-import com.baomidou.mybatisplus.plugins.Page;
-
-/**
- * <p>
- * IService 实现类( 泛型:M 是 mapper 对象, T 是实体 , I 是主键泛型 )
- * </p>
- * 
- * @author hubin
- * @Date 2016-04-20
- */
-public class ServiceImpl<M extends BaseMapper<T, I>, T, I> implements IService<T, I> {
-
-	@Autowired
-	protected M baseMapper;
-
-
-	/**
-	 * 判断数据库操作是否成功
-	 * 
-	 * @param result
-	 *            数据库操作返回影响条数
-	 * @return boolean
-	 */
-	protected boolean retBool( int result ) {
-		return (result >= 1) ? true : false;
-	}
-
-
-	public boolean insert( T entity ) {
-		return retBool(baseMapper.insert(entity));
-	}
-
-
-	public boolean insertSelective( T entity ) {
-		return retBool(baseMapper.insertSelective(entity));
-	}
-
-
-	public boolean insertBatch( List<T> entityList ) {
-		return retBool(baseMapper.insertBatch(entityList));
-	}
-
-
-	public boolean deleteById( I id ) {
-		return retBool(baseMapper.deleteById(id));
-	}
-
-
-	public boolean deleteSelective( T entity ) {
-		return retBool(baseMapper.deleteSelective(entity));
-	}
-
-
-	public boolean deleteBatchIds( List<I> idList ) {
-		return retBool(baseMapper.deleteBatchIds(idList));
-	}
-
-
-	public boolean updateById( T entity ) {
-		return retBool(baseMapper.updateById(entity));
-	}
-
-
-	public boolean updateSelectiveById( T entity ) {
-		return retBool(baseMapper.updateSelectiveById(entity));
-	}
-
-
-	public boolean update( T entity, T whereEntity ) {
-		return retBool(baseMapper.update(entity, whereEntity));
-	}
-
-
-	public boolean updateSelective( T entity, T whereEntity ) {
-		return retBool(baseMapper.updateSelective(entity, whereEntity));
-	}
-
-
-	public boolean updateBatchById(List<T> entityList) {
-		return retBool(baseMapper.updateBatchById(entityList));
-	}
-
-
-	public T selectById( I id ) {
-		return baseMapper.selectById(id);
-	}
-
-
-	public List<T> selectBatchIds( List<I> idList ) {
-		return baseMapper.selectBatchIds(idList);
-	}
-
-
-	public T selectOne( T entity ) {
-		return baseMapper.selectOne(entity);
-	}
-
-
-	public int selectCount(T entity) {
-		return baseMapper.selectCount(entity);
-	}
-
-
-	public List<T> selectList( T entity, String orderByField ) {
-		return baseMapper.selectList(new EntityWrapper<T>(entity, orderByField));
-	}
-
-
-	public List<T> selectList( T entity ) {
-		return baseMapper.selectList(new EntityWrapper<T>(entity, null));
-	}
-
-
-	public Page<T> selectPage( Page<T> page, T entity, String orderByField ) {
-		page.setRecords(baseMapper.selectPage(page, new EntityWrapper<T>(entity, orderByField)));
-		return page;
-	}
-
-
-	public Page<T> selectPage( Page<T> page, T entity ) {
-		page.setRecords(baseMapper.selectPage(page, new EntityWrapper<T>(entity, null)));
-		return page;
-	}
-
-}

+ 0 - 9
mybatis-plus/src/main/java/com/baomidou/framework/service/package-info.java

@@ -1,9 +0,0 @@
-package com.baomidou.framework.service;
-
-/**
- * 
- * service 超级抽象类
- * 
- * @author hubin
- * 
- */

+ 0 - 1
mybatis-plus/src/main/java/com/baomidou/mybatisplus/.gitignore

@@ -1 +0,0 @@
-/.DS_Store

+ 230 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/MybatisAbstractSQL.java

@@ -0,0 +1,230 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.baomidou.mybatisplus;
+
+import com.baomidou.mybatisplus.toolkit.StringUtils;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <p>
+ * 重定义 AbstractSQL ,实现标准TSQL的 查询条件自定义
+ * </p>
+ *
+ * @author yanghu
+ * @Date 2016-08-22
+ */
+@SuppressWarnings("serial")
+public abstract class MybatisAbstractSQL<T> implements Serializable {
+
+    private static final String AND = " AND ";
+    private static final String OR = " OR ";
+    private static final String AND_NEW = ") \nAND (";
+    private static final String OR_NEW = ") \nOR (";
+
+    /**
+     * SQL条件
+     */
+    private SQLCondition sql = new SQLCondition();
+
+    /**
+     * 子类泛型实现
+     *
+     * @return 泛型实例
+     */
+    public abstract T getSelf();
+
+    public T WHERE(String conditions) {
+        sql().where.add(conditions);
+        sql().lastList = sql().where;
+        return getSelf();
+    }
+
+    public T OR() {
+        sql().lastList.add(OR);
+        return getSelf();
+    }
+
+    public T OR_NEW() {
+        sql().lastList.add(OR_NEW);
+        return getSelf();
+    }
+
+    public T AND() {
+        sql().lastList.add(AND);
+        return getSelf();
+    }
+
+    public T AND_NEW() {
+        sql().lastList.add(AND_NEW);
+        return getSelf();
+    }
+
+    public T GROUP_BY(String columns) {
+        sql().groupBy.add(columns);
+        return getSelf();
+    }
+
+    public T HAVING(String conditions) {
+        sql().having.add(conditions);
+        sql().lastList = sql().having;
+        return getSelf();
+    }
+
+    public T ORDER_BY(String columns) {
+        sql().orderBy.add(columns);
+        return getSelf();
+    }
+
+    private SQLCondition sql() {
+        return sql;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sql().sql(sb);
+        return sb.toString();
+    }
+
+    /**
+     * SQL连接器
+     */
+	private static class SafeAppendable implements Serializable {
+        private final Appendable appendable;
+        private boolean empty = true;
+
+        public SafeAppendable(Appendable appendable) {
+            super();
+            this.appendable = appendable;
+        }
+
+        public SafeAppendable append(CharSequence charSequence) {
+            try {
+                if (empty && charSequence.length() > 0) {
+                    empty = false;
+                }
+                appendable.append(charSequence);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+            return this;
+        }
+
+        public boolean isEmpty() {
+            return empty;
+        }
+
+    }
+
+    /**
+     * SQL条件类
+     */
+	private static class SQLCondition implements Serializable {
+
+        List<String> where = new ArrayList<String>();
+        List<String> having = new ArrayList<String>();
+        List<String> groupBy = new ArrayList<String>();
+        List<String> orderBy = new ArrayList<String>();
+        List<String> lastList = new ArrayList<String>();
+        List<String> andOr = new ArrayList<String>();
+
+        public SQLCondition() {
+            andOr.add(AND);
+            andOr.add(OR);
+            andOr.add(AND_NEW);
+            andOr.add(OR_NEW);
+        }
+
+        /**
+         * 构建SQL的条件
+         *
+         * @param builder     连接器
+         * @param keyword     TSQL中的关键字
+         * @param parts       SQL条件语句集合
+         * @param open        起始符号
+         * @param close       结束符号
+         * @param conjunction 连接条件
+         */
+        private void sqlClause(SafeAppendable builder, String keyword, List<String> parts, String open, String close,
+                               String conjunction) {
+            parts = clearNull(parts);
+            if (!parts.isEmpty()) {
+                if (!builder.isEmpty()) {
+                    builder.append("\n");
+                }
+
+                builder.append(keyword);
+                builder.append(" ");
+                builder.append(open);
+                String last = "__";
+                for (int i = 0, n = parts.size(); i < n; i++) {
+                    String part = parts.get(i);
+                    if (i > 0) {
+                        if (andOr.contains(part) || andOr.contains(last)) {
+                            builder.append(part);
+                            last = part;
+                            continue;
+                        } else {
+                            builder.append(conjunction);
+                        }
+                    }
+                    builder.append(part);
+                }
+                builder.append(close);
+            }
+        }
+
+        /**
+         * 清除LIST中的NULL和空字符串
+         *
+         * @param parts 原LIST列表
+         * @return
+         */
+        private List<String> clearNull(List<String> parts) {
+            List<String> temps = new ArrayList<String>();
+            for (String part : parts) {
+                if (StringUtils.isEmpty(part)) {
+                    continue;
+                }
+                temps.add(part);
+            }
+            return temps;
+        }
+
+        /**
+         * 按标准顺序连接并构建SQL
+         *
+         * @param builder 连接器
+         * @return
+         */
+        private String buildSQL(SafeAppendable builder) {
+            sqlClause(builder, "WHERE", where, "(", ")", AND);
+            sqlClause(builder, "GROUP BY", groupBy, "", "", ", ");
+            sqlClause(builder, "HAVING", having, "(", ")", AND);
+            sqlClause(builder, "ORDER BY", orderBy, "", "", ", ");
+            return builder.toString();
+        }
+
+        public String sql(Appendable appendable) {
+            SafeAppendable builder = new SafeAppendable(appendable);
+            return buildSQL(builder);
+        }
+    }
+}

+ 54 - 20
mybatis-plus/src/main/java/com/baomidou/mybatisplus/MybatisConfiguration.java

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2011-2014, hubin (jobob@qq.com).
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
  *
  * 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
@@ -15,30 +15,34 @@
  */
 package com.baomidou.mybatisplus;
 
-import java.util.logging.Logger;
-
+import org.apache.ibatis.binding.MapperRegistry;
+import org.apache.ibatis.logging.Log;
+import org.apache.ibatis.logging.LogFactory;
 import org.apache.ibatis.mapping.MappedStatement;
-import org.apache.ibatis.scripting.LanguageDriver;
 import org.apache.ibatis.session.Configuration;
+import org.apache.ibatis.session.SqlSession;
 
-import com.baomidou.mybatisplus.mapper.DBType;
+import com.baomidou.mybatisplus.entity.GlobalConfiguration;
 
 /**
  * <p>
  * replace default Configuration class
  * </p>
- * 
+ * <p>
+ * Caratacus 2016/9/25 replace mapperRegistry
+ * </p>
+ *
  * @author hubin
  * @Date 2016-01-23
  */
 public class MybatisConfiguration extends Configuration {
 
-	protected final Logger logger = Logger.getLogger("MybatisConfiguration");
-	
-	/**
-	 * 数据库类型(默认 MySql)
+	private static final Log logger = LogFactory.getLog(MybatisConfiguration.class);
+
+	/*
+	 * Mapper 注册
 	 */
-	public static DBType DB_TYPE = DBType.MYSQL;
+	public final MybatisMapperRegistry mybatisMapperRegistry = new MybatisMapperRegistry(this);
 
 	/**
 	 * 初始化调用
@@ -59,14 +63,20 @@ public class MybatisConfiguration extends Configuration {
 	 */
 	@Override
 	public void addMappedStatement(MappedStatement ms) {
-		logger.fine(" addMappedStatement: " + ms.getId());
-		System.out.println(ms.getId());
-		if (this.mappedStatements.containsKey(ms.getId())) {
+		logger.debug(" addMappedStatement: " + ms.getId());
+		if (GlobalConfiguration.getGlobalConfig(ms.getConfiguration()).isRefresh()) {
 			/*
-			 * 说明已加载了xml中的节点; 忽略mapper中的SqlProvider数据
+			 * 支持是否自动刷新 XML 变更内容,开发环境使用【 注:生产环境勿用!】
 			 */
-			logger.severe("mapper[" + ms.getId() + "] is ignored, because it's exists, maybe from xml file");
-			return;
+			this.mappedStatements.remove(ms.getId());
+		} else {
+			if (this.mappedStatements.containsKey(ms.getId())) {
+				/*
+				 * 说明已加载了xml中的节点; 忽略mapper中的SqlProvider数据
+				 */
+				logger.error("mapper[" + ms.getId() + "] is ignored, because it's exists, maybe from xml file");
+				return;
+			}
 		}
 		super.addMappedStatement(ms);
 	}
@@ -81,9 +91,33 @@ public class MybatisConfiguration extends Configuration {
 	}
 
 	@Override
-	public LanguageDriver getDefaultScriptingLanuageInstance() {
-		/* 设置自定义 driver */
-		return languageRegistry.getDriver(MybatisXMLLanguageDriver.class);
+	public MapperRegistry getMapperRegistry() {
+		return mybatisMapperRegistry;
+	}
+
+	@Override
+	public <T> void addMapper(Class<T> type) {
+		mybatisMapperRegistry.addMapper(type);
+	}
+
+	@Override
+	public void addMappers(String packageName, Class<?> superType) {
+		mybatisMapperRegistry.addMappers(packageName, superType);
+	}
+
+	@Override
+	public void addMappers(String packageName) {
+		mybatisMapperRegistry.addMappers(packageName);
+	}
+
+	@Override
+	public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
+		return mybatisMapperRegistry.getMapper(type, sqlSession);
+	}
+
+	@Override
+	public boolean hasMapper(Class<?> type) {
+		return mybatisMapperRegistry.hasMapper(type);
 	}
 
 }

+ 137 - 32
mybatis-plus/src/main/java/com/baomidou/mybatisplus/MybatisDefaultParameterHandler.java

@@ -15,22 +15,36 @@
  */
 package com.baomidou.mybatisplus;
 
+import java.lang.reflect.Field;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
-import java.util.UUID;
 
+import org.apache.ibatis.executor.ErrorContext;
 import org.apache.ibatis.mapping.BoundSql;
 import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.mapping.ParameterMapping;
+import org.apache.ibatis.mapping.ParameterMode;
 import org.apache.ibatis.mapping.SqlCommandType;
 import org.apache.ibatis.reflection.MetaObject;
 import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
+import org.apache.ibatis.session.Configuration;
+import org.apache.ibatis.type.JdbcType;
+import org.apache.ibatis.type.TypeException;
+import org.apache.ibatis.type.TypeHandler;
+import org.apache.ibatis.type.TypeHandlerRegistry;
 
-import com.baomidou.mybatisplus.annotations.IdType;
+import com.baomidou.mybatisplus.entity.GlobalConfiguration;
+import com.baomidou.mybatisplus.entity.TableInfo;
+import com.baomidou.mybatisplus.enums.IdType;
+import com.baomidou.mybatisplus.mapper.IMetaObjectHandler;
 import com.baomidou.mybatisplus.toolkit.IdWorker;
-import com.baomidou.mybatisplus.toolkit.TableInfo;
+import com.baomidou.mybatisplus.toolkit.MapUtils;
+import com.baomidou.mybatisplus.toolkit.StringUtils;
 import com.baomidou.mybatisplus.toolkit.TableInfoHelper;
 
 /**
@@ -43,8 +57,31 @@ import com.baomidou.mybatisplus.toolkit.TableInfoHelper;
  */
 public class MybatisDefaultParameterHandler extends DefaultParameterHandler {
 
+	/**
+	 * @see org.apache.ibatis.mapping.BoundSql
+	 */
+	private static Field additionalParametersField;
+	private final TypeHandlerRegistry typeHandlerRegistry;
+	private final MappedStatement mappedStatement;
+	private final Object parameterObject;
+	private BoundSql boundSql;
+	private Configuration configuration;
+	static {
+		try {
+			additionalParametersField = BoundSql.class.getDeclaredField("additionalParameters");
+			additionalParametersField.setAccessible(true);
+		} catch (NoSuchFieldException e) {
+			// ignored, Because it will never happen.
+		}
+	}
+
 	public MybatisDefaultParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
 		super(mappedStatement, processBatch(mappedStatement, parameterObject), boundSql);
+		this.mappedStatement = mappedStatement;
+		this.configuration = mappedStatement.getConfiguration();
+		this.typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();
+		this.parameterObject = parameterObject;
+		this.boundSql = boundSql;
 	}
 
 	/**
@@ -58,16 +95,31 @@ public class MybatisDefaultParameterHandler extends DefaultParameterHandler {
 	 * @return
 	 */
 	protected static Object processBatch(MappedStatement ms, Object parameterObject) {
-		Collection<Object> parameters = getParameters(parameterObject);
-		if (parameters != null) {
-			List<Object> objList = new ArrayList<Object>();
-			for (Object parameter : parameters) {
-				objList.add(populateKeys(ms, parameter));
+		if (ms.getSqlCommandType() == SqlCommandType.INSERT) {
+			/**
+			 * 只处理插入操作
+			 */
+			Collection<Object> parameters = getParameters(parameterObject);
+			if (null != parameters) {
+				List<Object> objList = new ArrayList<Object>();
+				for (Object parameter : parameters) {
+					TableInfo tableInfo = TableInfoHelper.getTableInfo(parameter.getClass());
+					if (null != tableInfo) {
+						objList.add(populateKeys(tableInfo, ms, parameter));
+					} else {
+						/*
+						 * 非表映射类不处理
+						 */
+						objList.add(parameter);
+					}
+				}
+				return objList;
+			} else {
+				TableInfo tableInfo = TableInfoHelper.getTableInfo(parameterObject.getClass());
+				return populateKeys(tableInfo, ms, parameterObject);
 			}
-			return objList;
-		} else {
-			return populateKeys(ms, parameterObject);
 		}
+		return parameterObject;
 	}
 
 	/**
@@ -106,37 +158,90 @@ public class MybatisDefaultParameterHandler extends DefaultParameterHandler {
 	 * 填充主键 ID
 	 * </p>
 	 * 
+	 * @param tableInfo
 	 * @param ms
 	 * @param parameterObject
 	 *            插入数据库对象
 	 * @return
 	 */
-	protected static Object populateKeys( MappedStatement ms, Object parameterObject ) {
-		if ( ms.getSqlCommandType() == SqlCommandType.INSERT ) {
-			TableInfo tableInfo = TableInfoHelper.getTableInfo(parameterObject.getClass());
-			if ( tableInfo != null && tableInfo.getIdType().getKey() >= 2 ){
-				MetaObject metaParam = ms.getConfiguration().newMetaObject(parameterObject);
-				Object idValue = metaParam.getValue(tableInfo.getKeyProperty());
-				/* 自定义 ID */
-				if ( idValue == null ) {
-					if ( tableInfo.getIdType() == IdType.ID_WORKER ) {
-						metaParam.setValue(tableInfo.getKeyProperty(), IdWorker.getId());
-					} else if ( tableInfo.getIdType() == IdType.UUID ) {
-						metaParam.setValue(tableInfo.getKeyProperty(), get32UUID());
-					}
+	protected static Object populateKeys(TableInfo tableInfo, MappedStatement ms, Object parameterObject) {
+		if (null != tableInfo && StringUtils.isNotEmpty(tableInfo.getKeyProperty()) && null != tableInfo.getIdType()
+				&& tableInfo.getIdType().getKey() >= 2) {
+			MetaObject metaObject = ms.getConfiguration().newMetaObject(parameterObject);
+			Object idValue = metaObject.getValue(tableInfo.getKeyProperty());
+			/* 自定义 ID */
+			if (StringUtils.checkValNull(idValue)) {
+				if (tableInfo.getIdType() == IdType.ID_WORKER) {
+					metaObject.setValue(tableInfo.getKeyProperty(), IdWorker.getId());
+				} else if (tableInfo.getIdType() == IdType.UUID) {
+					metaObject.setValue(tableInfo.getKeyProperty(), IdWorker.get32UUID());
 				}
-				return metaParam.getOriginalObject();
 			}
+			/* 自定义元对象填充控制器 */
+			IMetaObjectHandler metaObjectHandler = GlobalConfiguration.getMetaObjectHandler(ms.getConfiguration());
+			if (null != metaObjectHandler) {
+				metaObjectHandler.insertFill(metaObject);
+			}
+			return metaObject.getOriginalObject();
 		}
+		/*
+		 * 不处理
+		 */
 		return parameterObject;
 	}
 
-	/**
-	 * <p>
-	 * 获取去掉"-" UUID
-	 * </p>
-	 */
-	protected static synchronized String get32UUID() {
-		return UUID.randomUUID().toString().replace("-", "");
+	@SuppressWarnings({ "rawtypes", "unchecked" })
+	@Override
+	public void setParameters(PreparedStatement ps) {
+		// 反射获取动态参数
+		Map<String, Object> additionalParameters = null;
+		try {
+			additionalParameters = (Map<String, Object>) additionalParametersField.get(boundSql);
+		} catch (IllegalAccessException e) {
+			// ignored, Because it will never happen.
+		}
+		ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
+		List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
+		if (parameterMappings != null) {
+			for (int i = 0; i < parameterMappings.size(); i++) {
+				ParameterMapping parameterMapping = parameterMappings.get(i);
+				if (parameterMapping.getMode() != ParameterMode.OUT) {
+					Object value;
+					String propertyName = parameterMapping.getProperty();
+					if (boundSql.hasAdditionalParameter(propertyName)) { // issue
+																			// #448
+																			// ask
+																			// first
+																			// for
+																			// additional
+																			// params
+						value = boundSql.getAdditionalParameter(propertyName);
+					} else if (parameterObject == null) {
+						value = null;
+					} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
+						value = parameterObject;
+					} else {
+						MetaObject metaObject = configuration.newMetaObject(parameterObject);
+						value = metaObject.getValue(propertyName);
+						if (value == null && MapUtils.isNotEmpty(additionalParameters)) {
+							// issue #138
+							value = additionalParameters.get(propertyName);
+						}
+					}
+					TypeHandler typeHandler = parameterMapping.getTypeHandler();
+					JdbcType jdbcType = parameterMapping.getJdbcType();
+					if (value == null && jdbcType == null) {
+						jdbcType = configuration.getJdbcTypeForNull();
+					}
+					try {
+						typeHandler.setParameter(ps, i + 1, value, jdbcType);
+					} catch (TypeException e) {
+						throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
+					} catch (SQLException e) {
+						throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
+					}
+				}
+			}
+		}
 	}
 }

+ 660 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/MybatisMapperAnnotationBuilder.java

@@ -0,0 +1,660 @@
+/**
+ * Copyright 2009-2016 the original author or authors.
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.baomidou.mybatisplus;
+
+import com.baomidou.mybatisplus.entity.GlobalConfiguration;
+import com.baomidou.mybatisplus.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Arg;
+import org.apache.ibatis.annotations.CacheNamespace;
+import org.apache.ibatis.annotations.CacheNamespaceRef;
+import org.apache.ibatis.annotations.Case;
+import org.apache.ibatis.annotations.ConstructorArgs;
+import org.apache.ibatis.annotations.Delete;
+import org.apache.ibatis.annotations.DeleteProvider;
+import org.apache.ibatis.annotations.Insert;
+import org.apache.ibatis.annotations.InsertProvider;
+import org.apache.ibatis.annotations.Lang;
+import org.apache.ibatis.annotations.MapKey;
+import org.apache.ibatis.annotations.Options;
+import org.apache.ibatis.annotations.Options.FlushCachePolicy;
+import org.apache.ibatis.annotations.Property;
+import org.apache.ibatis.annotations.Result;
+import org.apache.ibatis.annotations.ResultMap;
+import org.apache.ibatis.annotations.ResultType;
+import org.apache.ibatis.annotations.Results;
+import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.SelectKey;
+import org.apache.ibatis.annotations.SelectProvider;
+import org.apache.ibatis.annotations.TypeDiscriminator;
+import org.apache.ibatis.annotations.Update;
+import org.apache.ibatis.annotations.UpdateProvider;
+import org.apache.ibatis.binding.BindingException;
+import org.apache.ibatis.binding.MapperMethod.ParamMap;
+import org.apache.ibatis.builder.BuilderException;
+import org.apache.ibatis.builder.IncompleteElementException;
+import org.apache.ibatis.builder.MapperBuilderAssistant;
+import org.apache.ibatis.builder.annotation.MapperAnnotationBuilder;
+import org.apache.ibatis.builder.annotation.MethodResolver;
+import org.apache.ibatis.builder.annotation.ProviderSqlSource;
+import org.apache.ibatis.cursor.Cursor;
+import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;
+import org.apache.ibatis.executor.keygen.KeyGenerator;
+import org.apache.ibatis.executor.keygen.NoKeyGenerator;
+import org.apache.ibatis.executor.keygen.SelectKeyGenerator;
+import org.apache.ibatis.io.Resources;
+import org.apache.ibatis.mapping.Discriminator;
+import org.apache.ibatis.mapping.FetchType;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.mapping.ResultFlag;
+import org.apache.ibatis.mapping.ResultMapping;
+import org.apache.ibatis.mapping.ResultSetType;
+import org.apache.ibatis.mapping.SqlCommandType;
+import org.apache.ibatis.mapping.SqlSource;
+import org.apache.ibatis.mapping.StatementType;
+import org.apache.ibatis.parsing.PropertyParser;
+import org.apache.ibatis.reflection.TypeParameterResolver;
+import org.apache.ibatis.scripting.LanguageDriver;
+import org.apache.ibatis.session.Configuration;
+import org.apache.ibatis.session.ResultHandler;
+import org.apache.ibatis.session.RowBounds;
+import org.apache.ibatis.type.JdbcType;
+import org.apache.ibatis.type.TypeHandler;
+import org.apache.ibatis.type.UnknownTypeHandler;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+/**
+ * <p>
+ * 继承 MapperAnnotationBuilder 没有XML配置文件注入基础CRUD方法
+ * </p>
+ * 
+ * @author Caratacus
+ * @Date 2017-01-04
+ */
+public class MybatisMapperAnnotationBuilder extends MapperAnnotationBuilder {
+
+	private final Set<Class<? extends Annotation>> sqlAnnotationTypes = new HashSet<Class<? extends Annotation>>();
+	private final Set<Class<? extends Annotation>> sqlProviderAnnotationTypes = new HashSet<Class<? extends Annotation>>();
+
+	private Configuration configuration;
+	private MapperBuilderAssistant assistant;
+	private Class<?> type;
+
+	public MybatisMapperAnnotationBuilder(Configuration configuration, Class<?> type) {
+		super(configuration, type);
+		String resource = type.getName().replace('.', '/') + ".java (best guess)";
+		this.assistant = new MapperBuilderAssistant(configuration, resource);
+		this.configuration = configuration;
+		this.type = type;
+		sqlAnnotationTypes.add(Select.class);
+		sqlAnnotationTypes.add(Insert.class);
+		sqlAnnotationTypes.add(Update.class);
+		sqlAnnotationTypes.add(Delete.class);
+		sqlProviderAnnotationTypes.add(SelectProvider.class);
+		sqlProviderAnnotationTypes.add(InsertProvider.class);
+		sqlProviderAnnotationTypes.add(UpdateProvider.class);
+		sqlProviderAnnotationTypes.add(DeleteProvider.class);
+	}
+
+	public void parse() {
+		String resource = type.toString();
+		if (!configuration.isResourceLoaded(resource)) {
+			boolean existXml = loadXmlResource();
+			configuration.addLoadedResource(resource);
+			assistant.setCurrentNamespace(type.getName());
+			parseCache();
+			parseCacheRef();
+			Method[] methods = type.getMethods();
+			// TODO 注入存在 xxMapper.xml CURD (应该在注解之前注入)
+			inspectInject(existXml);
+			for (Method method : methods) {
+				try {
+					// issue #237
+					if (!method.isBridge()) {
+						parseStatement(method);
+					}
+				} catch (IncompleteElementException e) {
+					configuration.addIncompleteMethod(new MethodResolver(this, method));
+				}
+			}
+
+		}
+		parsePendingMethods();
+	}
+
+	/*
+	 * 注入 CURD 动态 SQL(XML不存在时注入)
+	 */
+	private void inspectInject(boolean flag) {
+		if (!flag && BaseMapper.class.isAssignableFrom(type)) {
+			GlobalConfiguration.getSqlInjector(configuration).inspectInject(assistant, type);
+		}
+	}
+
+	private void parsePendingMethods() {
+		Collection<MethodResolver> incompleteMethods = configuration.getIncompleteMethods();
+		synchronized (incompleteMethods) {
+			Iterator<MethodResolver> iter = incompleteMethods.iterator();
+			while (iter.hasNext()) {
+				try {
+					iter.next().resolve();
+					iter.remove();
+				} catch (IncompleteElementException e) {
+					// This method is still missing a resource
+				}
+			}
+		}
+	}
+
+	/**
+	 * 是否存在XML(该方法并不能客观的判断resource的路径,只是Mybatis默认认为的xml路径)
+	 *
+	 * @return boolean ture存在,flase不存在
+	 */
+	// TODO 该方法改为返回 boolean 判断是否存在 xxxMapper.xml
+	private boolean loadXmlResource() {
+		boolean flag = true;
+		// Spring may not know the real resource name so we check a flag
+		// to prevent loading again a resource twice
+		// this flag is set at MybatisXMLMapperBuilder#bindMapperForNamespace
+		if (!configuration.isResourceLoaded("namespace:" + type.getName())) {
+			String xmlResource = type.getName().replace('.', '/') + ".xml";
+			InputStream inputStream = null;
+			try {
+				inputStream = Resources.getResourceAsStream(type.getClassLoader(), xmlResource);
+			} catch (IOException e) {
+				// ignore, resource is not required
+				flag = false;
+			}
+			if (inputStream != null) {
+				MybatisXMLMapperBuilder xmlParser = new MybatisXMLMapperBuilder(inputStream, assistant.getConfiguration(),
+						xmlResource, configuration.getSqlFragments(), type.getName());
+				xmlParser.parse();
+			}
+		}
+		return flag;
+	}
+
+	private void parseCache() {
+		CacheNamespace cacheDomain = type.getAnnotation(CacheNamespace.class);
+		if (cacheDomain != null) {
+			Integer size = cacheDomain.size() == 0 ? null : cacheDomain.size();
+			Long flushInterval = cacheDomain.flushInterval() == 0 ? null : cacheDomain.flushInterval();
+			Properties props = convertToProperties(cacheDomain.properties());
+			assistant.useNewCache(cacheDomain.implementation(), cacheDomain.eviction(), flushInterval, size,
+					cacheDomain.readWrite(), cacheDomain.blocking(), props);
+		}
+	}
+
+	private Properties convertToProperties(Property[] properties) {
+		if (properties.length == 0) {
+			return null;
+		}
+		Properties props = new Properties();
+		for (Property property : properties) {
+			props.setProperty(property.name(), PropertyParser.parse(property.value(), configuration.getVariables()));
+		}
+		return props;
+	}
+
+	private void parseCacheRef() {
+		CacheNamespaceRef cacheDomainRef = type.getAnnotation(CacheNamespaceRef.class);
+		if (cacheDomainRef != null) {
+			Class<?> refType = cacheDomainRef.value();
+			String refName = cacheDomainRef.name();
+			if (refType == void.class && refName.isEmpty()) {
+				throw new BuilderException("Should be specified either value() or name() attribute in the @CacheNamespaceRef");
+			}
+			if (refType != void.class && !refName.isEmpty()) {
+				throw new BuilderException("Cannot use both value() and name() attribute in the @CacheNamespaceRef");
+			}
+			String namespace = (refType != void.class) ? refType.getName() : refName;
+			assistant.useCacheRef(namespace);
+		}
+	}
+
+	private String parseResultMap(Method method) {
+		Class<?> returnType = getReturnType(method);
+		ConstructorArgs args = method.getAnnotation(ConstructorArgs.class);
+		Results results = method.getAnnotation(Results.class);
+		TypeDiscriminator typeDiscriminator = method.getAnnotation(TypeDiscriminator.class);
+		String resultMapId = generateResultMapName(method);
+		applyResultMap(resultMapId, returnType, argsIf(args), resultsIf(results), typeDiscriminator);
+		return resultMapId;
+	}
+
+	private String generateResultMapName(Method method) {
+		Results results = method.getAnnotation(Results.class);
+		if (results != null && !results.id().isEmpty()) {
+			return type.getName() + "." + results.id();
+		}
+		StringBuilder suffix = new StringBuilder();
+		for (Class<?> c : method.getParameterTypes()) {
+			suffix.append("-");
+			suffix.append(c.getSimpleName());
+		}
+		if (suffix.length() < 1) {
+			suffix.append("-void");
+		}
+		return type.getName() + "." + method.getName() + suffix;
+	}
+
+	private void applyResultMap(String resultMapId, Class<?> returnType, Arg[] args, Result[] results,
+			TypeDiscriminator discriminator) {
+		List<ResultMapping> resultMappings = new ArrayList<ResultMapping>();
+		applyConstructorArgs(args, returnType, resultMappings);
+		applyResults(results, returnType, resultMappings);
+		Discriminator disc = applyDiscriminator(resultMapId, returnType, discriminator);
+		// TODO add AutoMappingBehaviour
+		assistant.addResultMap(resultMapId, returnType, null, disc, resultMappings, null);
+		createDiscriminatorResultMaps(resultMapId, returnType, discriminator);
+	}
+
+	private void createDiscriminatorResultMaps(String resultMapId, Class<?> resultType, TypeDiscriminator discriminator) {
+		if (discriminator != null) {
+			for (Case c : discriminator.cases()) {
+				String caseResultMapId = resultMapId + "-" + c.value();
+				List<ResultMapping> resultMappings = new ArrayList<ResultMapping>();
+				// issue #136
+				applyConstructorArgs(c.constructArgs(), resultType, resultMappings);
+				applyResults(c.results(), resultType, resultMappings);
+				// TODO add AutoMappingBehaviour
+				assistant.addResultMap(caseResultMapId, c.type(), resultMapId, null, resultMappings, null);
+			}
+		}
+	}
+
+	private Discriminator applyDiscriminator(String resultMapId, Class<?> resultType, TypeDiscriminator discriminator) {
+		if (discriminator != null) {
+			String column = discriminator.column();
+			Class<?> javaType = discriminator.javaType() == void.class ? String.class : discriminator.javaType();
+			JdbcType jdbcType = discriminator.jdbcType() == JdbcType.UNDEFINED ? null : discriminator.jdbcType();
+			@SuppressWarnings("unchecked")
+			Class<? extends TypeHandler<?>> typeHandler = (Class<? extends TypeHandler<?>>) (discriminator.typeHandler() == UnknownTypeHandler.class ? null
+					: discriminator.typeHandler());
+			Case[] cases = discriminator.cases();
+			Map<String, String> discriminatorMap = new HashMap<String, String>();
+			for (Case c : cases) {
+				String value = c.value();
+				String caseResultMapId = resultMapId + "-" + value;
+				discriminatorMap.put(value, caseResultMapId);
+			}
+			return assistant.buildDiscriminator(resultType, column, javaType, jdbcType, typeHandler, discriminatorMap);
+		}
+		return null;
+	}
+
+	void parseStatement(Method method) {
+		Class<?> parameterTypeClass = getParameterType(method);
+		LanguageDriver languageDriver = getLanguageDriver(method);
+		SqlSource sqlSource = getSqlSourceFromAnnotations(method, parameterTypeClass, languageDriver);
+		if (sqlSource != null) {
+			Options options = method.getAnnotation(Options.class);
+			final String mappedStatementId = type.getName() + "." + method.getName();
+			Integer fetchSize = null;
+			Integer timeout = null;
+			StatementType statementType = StatementType.PREPARED;
+			ResultSetType resultSetType = ResultSetType.FORWARD_ONLY;
+			SqlCommandType sqlCommandType = getSqlCommandType(method);
+			boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
+			boolean flushCache = !isSelect;
+			boolean useCache = isSelect;
+
+			KeyGenerator keyGenerator;
+			String keyProperty = "id";
+			String keyColumn = null;
+			if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) {
+				// first check for SelectKey annotation - that overrides
+				// everything else
+				SelectKey selectKey = method.getAnnotation(SelectKey.class);
+				if (selectKey != null) {
+					keyGenerator = handleSelectKeyAnnotation(selectKey, mappedStatementId, getParameterType(method),
+							languageDriver);
+					keyProperty = selectKey.keyProperty();
+				} else if (options == null) {
+					keyGenerator = configuration.isUseGeneratedKeys() ? new Jdbc3KeyGenerator() : new NoKeyGenerator();
+				} else {
+					keyGenerator = options.useGeneratedKeys() ? new Jdbc3KeyGenerator() : new NoKeyGenerator();
+					keyProperty = options.keyProperty();
+					keyColumn = options.keyColumn();
+				}
+			} else {
+				keyGenerator = new NoKeyGenerator();
+			}
+
+			if (options != null) {
+				if (FlushCachePolicy.TRUE.equals(options.flushCache())) {
+					flushCache = true;
+				} else if (FlushCachePolicy.FALSE.equals(options.flushCache())) {
+					flushCache = false;
+				}
+				useCache = options.useCache();
+				fetchSize = options.fetchSize() > -1 || options.fetchSize() == Integer.MIN_VALUE ? options.fetchSize() : null; // issue
+																																// #348
+				timeout = options.timeout() > -1 ? options.timeout() : null;
+				statementType = options.statementType();
+				resultSetType = options.resultSetType();
+			}
+
+			String resultMapId = null;
+			ResultMap resultMapAnnotation = method.getAnnotation(ResultMap.class);
+			if (resultMapAnnotation != null) {
+				String[] resultMaps = resultMapAnnotation.value();
+				StringBuilder sb = new StringBuilder();
+				for (String resultMap : resultMaps) {
+					if (sb.length() > 0) {
+						sb.append(",");
+					}
+					sb.append(resultMap);
+				}
+				resultMapId = sb.toString();
+			} else if (isSelect) {
+				resultMapId = parseResultMap(method);
+			}
+
+			assistant.addMappedStatement(mappedStatementId, sqlSource, statementType, sqlCommandType, fetchSize, timeout,
+			// ParameterMapID
+					null, parameterTypeClass, resultMapId, getReturnType(method), resultSetType, flushCache, useCache,
+					// TODO gcode issue #577
+					false, keyGenerator, keyProperty, keyColumn,
+					// DatabaseID
+					null, languageDriver,
+					// ResultSets
+					options != null ? nullOrEmpty(options.resultSets()) : null);
+		}
+	}
+
+	private LanguageDriver getLanguageDriver(Method method) {
+		Lang lang = method.getAnnotation(Lang.class);
+		Class<?> langClass = null;
+		if (lang != null) {
+			langClass = lang.value();
+		}
+		return assistant.getLanguageDriver(langClass);
+	}
+
+	private Class<?> getParameterType(Method method) {
+		Class<?> parameterType = null;
+		Class<?>[] parameterTypes = method.getParameterTypes();
+		for (Class<?> currentParameterType : parameterTypes) {
+			if (!RowBounds.class.isAssignableFrom(currentParameterType)
+					&& !ResultHandler.class.isAssignableFrom(currentParameterType)) {
+				if (parameterType == null) {
+					parameterType = currentParameterType;
+				} else {
+					// issue #135
+					parameterType = ParamMap.class;
+				}
+			}
+		}
+		return parameterType;
+	}
+
+	private Class<?> getReturnType(Method method) {
+		Class<?> returnType = method.getReturnType();
+		Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, type);
+		if (resolvedReturnType instanceof Class) {
+			returnType = (Class<?>) resolvedReturnType;
+			if (returnType.isArray()) {
+				returnType = returnType.getComponentType();
+			}
+			// gcode issue #508
+			if (void.class.equals(returnType)) {
+				ResultType rt = method.getAnnotation(ResultType.class);
+				if (rt != null) {
+					returnType = rt.value();
+				}
+			}
+		} else if (resolvedReturnType instanceof ParameterizedType) {
+			ParameterizedType parameterizedType = (ParameterizedType) resolvedReturnType;
+			Class<?> rawType = (Class<?>) parameterizedType.getRawType();
+			if (Collection.class.isAssignableFrom(rawType) || Cursor.class.isAssignableFrom(rawType)) {
+				Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
+				if (actualTypeArguments != null && actualTypeArguments.length == 1) {
+					Type returnTypeParameter = actualTypeArguments[0];
+					if (returnTypeParameter instanceof Class<?>) {
+						returnType = (Class<?>) returnTypeParameter;
+					} else if (returnTypeParameter instanceof ParameterizedType) {
+						// (gcode issue #443) actual type can be a also a
+						// parameterized type
+						returnType = (Class<?>) ((ParameterizedType) returnTypeParameter).getRawType();
+					} else if (returnTypeParameter instanceof GenericArrayType) {
+						Class<?> componentType = (Class<?>) ((GenericArrayType) returnTypeParameter).getGenericComponentType();
+						// (gcode issue #525) support List<byte[]>
+						returnType = Array.newInstance(componentType, 0).getClass();
+					}
+				}
+			} else if (method.isAnnotationPresent(MapKey.class) && Map.class.isAssignableFrom(rawType)) {
+				// (gcode issue 504) Do not look into Maps if there is not
+				// MapKey annotation
+				Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
+				if (actualTypeArguments != null && actualTypeArguments.length == 2) {
+					Type returnTypeParameter = actualTypeArguments[1];
+					if (returnTypeParameter instanceof Class<?>) {
+						returnType = (Class<?>) returnTypeParameter;
+					} else if (returnTypeParameter instanceof ParameterizedType) {
+						// (gcode issue 443) actual type can be a also a
+						// parameterized type
+						returnType = (Class<?>) ((ParameterizedType) returnTypeParameter).getRawType();
+					}
+				}
+			}
+		}
+
+		return returnType;
+	}
+
+	private SqlSource getSqlSourceFromAnnotations(Method method, Class<?> parameterType, LanguageDriver languageDriver) {
+		try {
+			Class<? extends Annotation> sqlAnnotationType = getSqlAnnotationType(method);
+			Class<? extends Annotation> sqlProviderAnnotationType = getSqlProviderAnnotationType(method);
+			if (sqlAnnotationType != null) {
+				if (sqlProviderAnnotationType != null) {
+					throw new BindingException("You cannot supply both a static SQL and SqlProvider to method named "
+							+ method.getName());
+				}
+				Annotation sqlAnnotation = method.getAnnotation(sqlAnnotationType);
+				final String[] strings = (String[]) sqlAnnotation.getClass().getMethod("value").invoke(sqlAnnotation);
+				return buildSqlSourceFromStrings(strings, parameterType, languageDriver);
+			} else if (sqlProviderAnnotationType != null) {
+				Annotation sqlProviderAnnotation = method.getAnnotation(sqlProviderAnnotationType);
+				return new ProviderSqlSource(assistant.getConfiguration(), sqlProviderAnnotation);
+			}
+			return null;
+		} catch (Exception e) {
+			throw new BuilderException("Could not find value method on SQL annotation.  Cause: " + e, e);
+		}
+	}
+
+	private SqlSource buildSqlSourceFromStrings(String[] strings, Class<?> parameterTypeClass, LanguageDriver languageDriver) {
+		final StringBuilder sql = new StringBuilder();
+		for (String fragment : strings) {
+			sql.append(fragment);
+			sql.append(" ");
+		}
+		return languageDriver.createSqlSource(configuration, sql.toString().trim(), parameterTypeClass);
+	}
+
+	private SqlCommandType getSqlCommandType(Method method) {
+		Class<? extends Annotation> type = getSqlAnnotationType(method);
+
+		if (type == null) {
+			type = getSqlProviderAnnotationType(method);
+
+			if (type == null) {
+				return SqlCommandType.UNKNOWN;
+			}
+
+			if (type == SelectProvider.class) {
+				type = Select.class;
+			} else if (type == InsertProvider.class) {
+				type = Insert.class;
+			} else if (type == UpdateProvider.class) {
+				type = Update.class;
+			} else if (type == DeleteProvider.class) {
+				type = Delete.class;
+			}
+		}
+
+		return SqlCommandType.valueOf(type.getSimpleName().toUpperCase(Locale.ENGLISH));
+	}
+
+	private Class<? extends Annotation> getSqlAnnotationType(Method method) {
+		return chooseAnnotationType(method, sqlAnnotationTypes);
+	}
+
+	private Class<? extends Annotation> getSqlProviderAnnotationType(Method method) {
+		return chooseAnnotationType(method, sqlProviderAnnotationTypes);
+	}
+
+	private Class<? extends Annotation> chooseAnnotationType(Method method, Set<Class<? extends Annotation>> types) {
+		for (Class<? extends Annotation> type : types) {
+			Annotation annotation = method.getAnnotation(type);
+			if (annotation != null) {
+				return type;
+			}
+		}
+		return null;
+	}
+
+	private void applyResults(Result[] results, Class<?> resultType, List<ResultMapping> resultMappings) {
+		for (Result result : results) {
+			List<ResultFlag> flags = new ArrayList<ResultFlag>();
+			if (result.id()) {
+				flags.add(ResultFlag.ID);
+			}
+			@SuppressWarnings("unchecked")
+			Class<? extends TypeHandler<?>> typeHandler = (Class<? extends TypeHandler<?>>) ((result.typeHandler() == UnknownTypeHandler.class) ? null
+					: result.typeHandler());
+			ResultMapping resultMapping = assistant.buildResultMapping(resultType, nullOrEmpty(result.property()),
+					nullOrEmpty(result.column()), result.javaType() == void.class ? null : result.javaType(),
+					result.jdbcType() == JdbcType.UNDEFINED ? null : result.jdbcType(),
+					hasNestedSelect(result) ? nestedSelectId(result) : null, null, null, null, typeHandler, flags, null, null,
+					isLazy(result));
+			resultMappings.add(resultMapping);
+		}
+	}
+
+	private String nestedSelectId(Result result) {
+		String nestedSelect = result.one().select();
+		if (nestedSelect.length() < 1) {
+			nestedSelect = result.many().select();
+		}
+		if (!nestedSelect.contains(".")) {
+			nestedSelect = type.getName() + "." + nestedSelect;
+		}
+		return nestedSelect;
+	}
+
+	private boolean isLazy(Result result) {
+		boolean isLazy = configuration.isLazyLoadingEnabled();
+		if (result.one().select().length() > 0 && FetchType.DEFAULT != result.one().fetchType()) {
+			isLazy = (result.one().fetchType() == FetchType.LAZY);
+		} else if (result.many().select().length() > 0 && FetchType.DEFAULT != result.many().fetchType()) {
+			isLazy = (result.many().fetchType() == FetchType.LAZY);
+		}
+		return isLazy;
+	}
+
+	private boolean hasNestedSelect(Result result) {
+		if (result.one().select().length() > 0 && result.many().select().length() > 0) {
+			throw new BuilderException("Cannot use both @One and @Many annotations in the same @Result");
+		}
+		return result.one().select().length() > 0 || result.many().select().length() > 0;
+	}
+
+	private void applyConstructorArgs(Arg[] args, Class<?> resultType, List<ResultMapping> resultMappings) {
+		for (Arg arg : args) {
+			List<ResultFlag> flags = new ArrayList<ResultFlag>();
+			flags.add(ResultFlag.CONSTRUCTOR);
+			if (arg.id()) {
+				flags.add(ResultFlag.ID);
+			}
+			@SuppressWarnings("unchecked")
+			Class<? extends TypeHandler<?>> typeHandler = (Class<? extends TypeHandler<?>>) (arg.typeHandler() == UnknownTypeHandler.class ? null
+					: arg.typeHandler());
+			ResultMapping resultMapping = assistant.buildResultMapping(resultType, null, nullOrEmpty(arg.column()),
+					arg.javaType() == void.class ? null : arg.javaType(),
+					arg.jdbcType() == JdbcType.UNDEFINED ? null : arg.jdbcType(), nullOrEmpty(arg.select()),
+					nullOrEmpty(arg.resultMap()), null, null, typeHandler, flags, null, null, false);
+			resultMappings.add(resultMapping);
+		}
+	}
+
+	private String nullOrEmpty(String value) {
+		return value == null || value.trim().length() == 0 ? null : value;
+	}
+
+	private Result[] resultsIf(Results results) {
+		return results == null ? new Result[0] : results.value();
+	}
+
+	private Arg[] argsIf(ConstructorArgs args) {
+		return args == null ? new Arg[0] : args.value();
+	}
+
+	private KeyGenerator handleSelectKeyAnnotation(SelectKey selectKeyAnnotation, String baseStatementId,
+			Class<?> parameterTypeClass, LanguageDriver languageDriver) {
+		String id = baseStatementId + SelectKeyGenerator.SELECT_KEY_SUFFIX;
+		Class<?> resultTypeClass = selectKeyAnnotation.resultType();
+		StatementType statementType = selectKeyAnnotation.statementType();
+		String keyProperty = selectKeyAnnotation.keyProperty();
+		String keyColumn = selectKeyAnnotation.keyColumn();
+		boolean executeBefore = selectKeyAnnotation.before();
+
+		// defaults
+		boolean useCache = false;
+		KeyGenerator keyGenerator = new NoKeyGenerator();
+		Integer fetchSize = null;
+		Integer timeout = null;
+		boolean flushCache = false;
+		String parameterMap = null;
+		String resultMap = null;
+		ResultSetType resultSetTypeEnum = null;
+
+		SqlSource sqlSource = buildSqlSourceFromStrings(selectKeyAnnotation.statement(), parameterTypeClass, languageDriver);
+		SqlCommandType sqlCommandType = SqlCommandType.SELECT;
+
+		assistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap,
+				parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, false, keyGenerator,
+				keyProperty, keyColumn, null, languageDriver, null);
+
+		id = assistant.applyCurrentNamespace(id, false);
+
+		MappedStatement keyStatement = configuration.getMappedStatement(id, false);
+		SelectKeyGenerator answer = new SelectKeyGenerator(keyStatement, executeBefore);
+		configuration.addKeyGenerator(id, answer);
+		return answer;
+	}
+
+}

+ 102 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/MybatisMapperRegistry.java

@@ -0,0 +1,102 @@
+/**
+ *    Copyright 2009-2015 the original author or authors.
+ *
+ *    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.baomidou.mybatisplus;
+
+import com.baomidou.mybatisplus.entity.GlobalConfiguration;
+import org.apache.ibatis.binding.BindingException;
+import org.apache.ibatis.binding.MapperProxyFactory;
+import org.apache.ibatis.binding.MapperRegistry;
+import org.apache.ibatis.session.Configuration;
+import org.apache.ibatis.session.SqlSession;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * <p>
+ * 继承至MapperRegistry
+ * </p>
+ *
+ * @author Caratacus
+ * @Date 2016-09-26
+ */
+public class MybatisMapperRegistry extends MapperRegistry {
+
+	private final Configuration config;
+	private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();
+
+	public MybatisMapperRegistry(Configuration config) {
+		super(config);
+		this.config = config;
+		// TODO注入SqlRunner
+		GlobalConfiguration.getSqlInjector(config).injectSqlRunner(config);
+	}
+
+	@SuppressWarnings("unchecked")
+	public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
+		final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
+		if (mapperProxyFactory == null) {
+			throw new BindingException("Type " + type + " is not known to the MybatisPlusMapperRegistry.");
+		}
+		try {
+			return mapperProxyFactory.newInstance(sqlSession);
+		} catch (Exception e) {
+			throw new BindingException("Error getting mapper instance. Cause: " + e, e);
+		}
+	}
+
+	public <T> boolean hasMapper(Class<T> type) {
+		return knownMappers.containsKey(type);
+	}
+
+	public <T> void addMapper(Class<T> type) {
+		if (type.isInterface()) {
+			if (hasMapper(type)) {
+				// TODO 如果之前注入 直接返回
+				return;
+				// throw new BindingException("Type " + type +
+				// " is already known to the MybatisPlusMapperRegistry.");
+			}
+			boolean loadCompleted = false;
+			try {
+				knownMappers.put(type, new MapperProxyFactory<T>(type));
+				// It's important that the type is added before the parser is
+				// run
+				// otherwise the binding may automatically be attempted by the
+				// mapper parser. If the type is already known, it won't try.
+
+				// TODO 自定义无 XML 注入
+				MybatisMapperAnnotationBuilder parser = new MybatisMapperAnnotationBuilder(config, type);
+				parser.parse();
+				loadCompleted = true;
+			} finally {
+				if (!loadCompleted) {
+					knownMappers.remove(type);
+				}
+			}
+		}
+	}
+
+	/**
+	 * @since 3.2.2
+	 */
+	public Collection<Class<?>> getMappers() {
+		return Collections.unmodifiableCollection(knownMappers.keySet());
+	}
+
+}

+ 14 - 23
mybatis-plus/src/main/java/com/baomidou/mybatisplus/MybatisSessionFactoryBuilder.java

@@ -15,7 +15,6 @@
  */
 package com.baomidou.mybatisplus;
 
-import java.io.IOException;
 import java.io.InputStream;
 import java.io.Reader;
 import java.util.Properties;
@@ -25,7 +24,8 @@ import org.apache.ibatis.executor.ErrorContext;
 import org.apache.ibatis.session.SqlSessionFactory;
 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
 
-import com.baomidou.mybatisplus.mapper.DBType;
+import com.baomidou.mybatisplus.entity.GlobalConfiguration;
+import com.baomidou.mybatisplus.toolkit.IOUtils;
 
 /**
  * <p>
@@ -37,46 +37,37 @@ import com.baomidou.mybatisplus.mapper.DBType;
  */
 public class MybatisSessionFactoryBuilder extends SqlSessionFactoryBuilder {
 
+	private GlobalConfiguration globalConfig = GlobalConfiguration.defaults();
 
 	@Override
-	public SqlSessionFactory build( Reader reader, String environment, Properties properties ) {
+	public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
 		try {
 			MybatisXMLConfigBuilder parser = new MybatisXMLConfigBuilder(reader, environment, properties);
-			return build(parser.parse());
-		} catch ( Exception e ) {
+			return globalConfig.signGlobalConfig(build(parser.parse()));
+		} catch (Exception e) {
 			throw ExceptionFactory.wrapException("Error building SqlSession.", e);
 		} finally {
 			ErrorContext.instance().reset();
-			try {
-				reader.close();
-			} catch ( IOException e ) {
-				// Intentionally ignore. Prefer previous error.
-			}
+			IOUtils.closeQuietly(reader);
 		}
 	}
 
-
 	@Override
-	public SqlSessionFactory build( InputStream inputStream, String environment, Properties properties ) {
+	public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
 		try {
 			MybatisXMLConfigBuilder parser = new MybatisXMLConfigBuilder(inputStream, environment, properties);
-			return build(parser.parse());
-		} catch ( Exception e ) {
+			return globalConfig.signGlobalConfig(build(parser.parse()));
+		} catch (Exception e) {
 			throw ExceptionFactory.wrapException("Error building SqlSession.", e);
 		} finally {
 			ErrorContext.instance().reset();
-			try {
-				inputStream.close();
-			} catch ( IOException e ) {
-				// Intentionally ignore. Prefer previous error.
-			}
+			IOUtils.closeQuietly(inputStream);
 		}
 	}
 
-
-	//TODO 注入数据库类型
-	public void setDbType( String dbType ) {
-		MybatisConfiguration.DB_TYPE = DBType.getDBType(dbType);
+	// TODO 注入全局配置
+	public void setGlobalConfig(GlobalConfiguration globalConfig) {
+		this.globalConfig = globalConfig;
 	}
 
 }

+ 365 - 333
mybatis-plus/src/main/java/com/baomidou/mybatisplus/MybatisXMLConfigBuilder.java

@@ -1,12 +1,12 @@
 /**
  * Copyright (c) 2011-2014, hubin (jobob@qq.com).
- *
+ * <p>
  * 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
- *
+ * <p>
  * http://www.apache.org/licenses/LICENSE-2.0
- *
+ * <p>
  * 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
@@ -15,19 +15,16 @@
  */
 package com.baomidou.mybatisplus;
 
-import java.io.InputStream;
-import java.io.Reader;
-import java.util.Properties;
-
-import javax.sql.DataSource;
-
 import org.apache.ibatis.builder.BaseBuilder;
 import org.apache.ibatis.builder.BuilderException;
 import org.apache.ibatis.builder.xml.XMLMapperEntityResolver;
 import org.apache.ibatis.datasource.DataSourceFactory;
 import org.apache.ibatis.executor.ErrorContext;
 import org.apache.ibatis.executor.loader.ProxyFactory;
+import org.apache.ibatis.io.ResolverUtil;
 import org.apache.ibatis.io.Resources;
+import org.apache.ibatis.io.VFS;
+import org.apache.ibatis.logging.Log;
 import org.apache.ibatis.mapping.DatabaseIdProvider;
 import org.apache.ibatis.mapping.Environment;
 import org.apache.ibatis.parsing.XNode;
@@ -46,362 +43,397 @@ import org.apache.ibatis.session.LocalCacheScope;
 import org.apache.ibatis.transaction.TransactionFactory;
 import org.apache.ibatis.type.JdbcType;
 
+import javax.sql.DataSource;
+import java.io.InputStream;
+import java.io.Reader;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.Set;
+
 /**
  * <p>
  * Copy from XMLConfigBuilder in Mybatis and replace default Configuration class
  * by MybatisConfiguration class
  * </p>
- * 
+ *
  * @author hubin
- * @Date 2016-04-20
+ * @Date 2017-01-04
  */
 public class MybatisXMLConfigBuilder extends BaseBuilder {
 
-	private boolean parsed;
-	private XPathParser parser;
-	private String environment;
-	private ReflectorFactory localReflectorFactory = new DefaultReflectorFactory();
+    private boolean parsed;
+    private XPathParser parser;
+    private String environment;
+    private ReflectorFactory localReflectorFactory = new DefaultReflectorFactory();
+
+    public MybatisXMLConfigBuilder(Reader reader) {
+        this(reader, null, null);
+    }
 
-	public MybatisXMLConfigBuilder(Reader reader) {
-		this(reader, null, null);
-	}
+    public MybatisXMLConfigBuilder(Reader reader, String environment) {
+        this(reader, environment, null);
+    }
 
-	public MybatisXMLConfigBuilder(Reader reader, String environment) {
-		this(reader, environment, null);
-	}
+    public MybatisXMLConfigBuilder(Reader reader, String environment, Properties props) {
+        this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props);
+    }
 
-	public MybatisXMLConfigBuilder(Reader reader, String environment, Properties props) {
-		this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props);
-	}
+    public MybatisXMLConfigBuilder(InputStream inputStream) {
+        this(inputStream, null, null);
+    }
 
-	public MybatisXMLConfigBuilder(InputStream inputStream) {
-		this(inputStream, null, null);
-	}
+    public MybatisXMLConfigBuilder(InputStream inputStream, String environment) {
+        this(inputStream, environment, null);
+    }
 
-	public MybatisXMLConfigBuilder(InputStream inputStream, String environment) {
-		this(inputStream, environment, null);
-	}
+    public MybatisXMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
+        this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
+    }
 
-	public MybatisXMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
-		this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
-	}
+    private MybatisXMLConfigBuilder(XPathParser parser, String environment, Properties props) {
+        //TODO 自定义 Configuration
+        super(new MybatisConfiguration());
+        ErrorContext.instance().resource("SQL Mapper Configuration");
+        this.configuration.setVariables(props);
+        this.parsed = false;
+        this.environment = environment;
+        this.parser = parser;
+    }
 
-	private MybatisXMLConfigBuilder(XPathParser parser, String environment, Properties props) {
-		//TODO 自定义 Configuration
-		super(new MybatisConfiguration());
-		ErrorContext.instance().resource("SQL Mapper Configuration");
-		this.configuration.setVariables(props);
-		this.parsed = false;
-		this.environment = environment;
-		this.parser = parser;
-	}
+    public Configuration parse() {
+        if (parsed) {
+            throw new BuilderException("Each XMLConfigBuilder can only be used once.");
+        }
+        parsed = true;
+        parseConfiguration(parser.evalNode("/configuration"));
+        return configuration;
+    }
 
-	public Configuration parse() {
-		if (parsed) {
-			throw new BuilderException("Each MybatisXMLConfigBuilder can only be used once.");
-		}
-		parsed = true;
-		parseConfiguration(parser.evalNode("/configuration"));
-		return configuration;
-	}
+    private void parseConfiguration(XNode root) {
+        try {
+            //issue #117 read properties first
+            propertiesElement(root.evalNode("properties"));
+            Properties settings = settingsAsProperties(root.evalNode("settings"));
+            loadCustomVfs(settings);
+            typeAliasesElement(root.evalNode("typeAliases"));
+            pluginElement(root.evalNode("plugins"));
+            objectFactoryElement(root.evalNode("objectFactory"));
+            objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
+            reflectorFactoryElement(root.evalNode("reflectorFactory"));
+            settingsElement(settings);
+            // read it after objectFactory and objectWrapperFactory issue #631
+            environmentsElement(root.evalNode("environments"));
+            databaseIdProviderElement(root.evalNode("databaseIdProvider"));
+            typeHandlerElement(root.evalNode("typeHandlers"));
+            mapperElement(root.evalNode("mappers"));
+        } catch (Exception e) {
+            throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
+        }
+    }
 
-	private void parseConfiguration(XNode root) {
-		try {
-			Properties settings = settingsAsPropertiess(root.evalNode("settings"));
-			// issue #117 read properties first
-			propertiesElement(root.evalNode("properties"));
-			loadCustomVfs(settings);
-			typeAliasesElement(root.evalNode("typeAliases"));
-			pluginElement(root.evalNode("plugins"));
-			objectFactoryElement(root.evalNode("objectFactory"));
-			objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
-			reflectionFactoryElement(root.evalNode("reflectionFactory"));
-			settingsElement(settings);
-			// read it after objectFactory and objectWrapperFactory issue #631
-			environmentsElement(root.evalNode("environments"));
-			databaseIdProviderElement(root.evalNode("databaseIdProvider"));
-			typeHandlerElement(root.evalNode("typeHandlers"));
-			mapperElement(root.evalNode("mappers"));
-		} catch (Exception e) {
-			throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
-		}
-	}
+    private Properties settingsAsProperties(XNode context) {
+        if (context == null) {
+            return new Properties();
+        }
+        Properties props = context.getChildrenAsProperties();
+        // Check that all settings are known to the configuration class
+        MetaClass metaConfig = MetaClass.forClass(Configuration.class, localReflectorFactory);
+        for (Object key : props.keySet()) {
+            if (!metaConfig.hasSetter(String.valueOf(key))) {
+                throw new BuilderException("The setting " + key + " is not known.  Make sure you spelled it correctly (case sensitive).");
+            }
+        }
+        return props;
+    }
 
-	private Properties settingsAsPropertiess(XNode context) {
-		if (context == null) {
-			return new Properties();
-		}
-		Properties props = context.getChildrenAsProperties();
-		// Check that all settings are known to the configuration class
-		MetaClass metaConfig = MetaClass.forClass(Configuration.class, localReflectorFactory);
-		for (Object key : props.keySet()) {
-			if (!metaConfig.hasSetter(String.valueOf(key))) {
-				throw new BuilderException(
-						"The setting " + key + " is not known.  Make sure you spelled it correctly (case sensitive).");
-			}
-		}
-		return props;
-	}
+    private void loadCustomVfs(Properties props) throws ClassNotFoundException {
+        String value = props.getProperty("vfsImpl");
+        if (value != null) {
+            String[] clazzes = value.split(",");
+            for (String clazz : clazzes) {
+                if (!clazz.isEmpty()) {
+                    @SuppressWarnings("unchecked")
+                    Class<? extends VFS> vfsImpl = (Class<? extends VFS>)Resources.classForName(clazz);
+                    configuration.setVfsImpl(vfsImpl);
+                }
+            }
+        }
+    }
 
-	private void loadCustomVfs(Properties props) throws ClassNotFoundException {
-		String value = props.getProperty("vfsImpl");
-		if (value != null) {
-			String[] clazzes = value.split(",");
-			for (String clazz : clazzes) {
-				if (!clazz.isEmpty()) {
-					configuration.setVfsImpl(Resources.classForName(clazz));
-				}
-			}
-		}
-	}
+    private void typeAliasesElement(XNode parent) {
+        if (parent != null) {
+            for (XNode child : parent.getChildren()) {
+                if ("package".equals(child.getName())) {
+                    String typeAliasPackage = child.getStringAttribute("name");
+                    configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);
+                } else {
+                    String alias = child.getStringAttribute("alias");
+                    String type = child.getStringAttribute("type");
+                    try {
+                        Class<?> clazz = Resources.classForName(type);
+                        if (alias == null) {
+                            typeAliasRegistry.registerAlias(clazz);
+                        } else {
+                            typeAliasRegistry.registerAlias(alias, clazz);
+                        }
+                    } catch (ClassNotFoundException e) {
+                        throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e);
+                    }
+                }
+            }
+        }
+    }
 
-	private void typeAliasesElement(XNode parent) {
-		if (parent != null) {
-			for (XNode child : parent.getChildren()) {
-				if ("package".equals(child.getName())) {
-					String typeAliasPackage = child.getStringAttribute("name");
-					configuration.getTypeAliasRegistry().registerAliases(typeAliasPackage);
-				} else {
-					String alias = child.getStringAttribute("alias");
-					String type = child.getStringAttribute("type");
-					try {
-						Class<?> clazz = Resources.classForName(type);
-						if (alias == null) {
-							typeAliasRegistry.registerAlias(clazz);
-						} else {
-							typeAliasRegistry.registerAlias(alias, clazz);
-						}
-					} catch (ClassNotFoundException e) {
-						throw new BuilderException("Error registering typeAlias for '" + alias + "'. Cause: " + e, e);
-					}
-				}
-			}
-		}
-	}
+    private void pluginElement(XNode parent) throws Exception {
+        if (parent != null) {
+            for (XNode child : parent.getChildren()) {
+                String interceptor = child.getStringAttribute("interceptor");
+                Properties properties = child.getChildrenAsProperties();
+                Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
+                interceptorInstance.setProperties(properties);
+                configuration.addInterceptor(interceptorInstance);
+            }
+        }
+    }
 
-	private void pluginElement(XNode parent) throws Exception {
-		if (parent != null) {
-			for (XNode child : parent.getChildren()) {
-				String interceptor = child.getStringAttribute("interceptor");
-				Properties properties = child.getChildrenAsProperties();
-				Interceptor interceptorInstance = (Interceptor) resolveClass(interceptor).newInstance();
-				interceptorInstance.setProperties(properties);
-				configuration.addInterceptor(interceptorInstance);
-			}
-		}
-	}
+    private void objectFactoryElement(XNode context) throws Exception {
+        if (context != null) {
+            String type = context.getStringAttribute("type");
+            Properties properties = context.getChildrenAsProperties();
+            ObjectFactory factory = (ObjectFactory) resolveClass(type).newInstance();
+            factory.setProperties(properties);
+            configuration.setObjectFactory(factory);
+        }
+    }
 
-	private void objectFactoryElement(XNode context) throws Exception {
-		if (context != null) {
-			String type = context.getStringAttribute("type");
-			Properties properties = context.getChildrenAsProperties();
-			ObjectFactory factory = (ObjectFactory) resolveClass(type).newInstance();
-			factory.setProperties(properties);
-			configuration.setObjectFactory(factory);
-		}
-	}
+    private void objectWrapperFactoryElement(XNode context) throws Exception {
+        if (context != null) {
+            String type = context.getStringAttribute("type");
+            ObjectWrapperFactory factory = (ObjectWrapperFactory) resolveClass(type).newInstance();
+            configuration.setObjectWrapperFactory(factory);
+        }
+    }
 
-	private void objectWrapperFactoryElement(XNode context) throws Exception {
-		if (context != null) {
-			String type = context.getStringAttribute("type");
-			ObjectWrapperFactory factory = (ObjectWrapperFactory) resolveClass(type).newInstance();
-			configuration.setObjectWrapperFactory(factory);
-		}
-	}
+    private void reflectorFactoryElement(XNode context) throws Exception {
+        if (context != null) {
+            String type = context.getStringAttribute("type");
+            ReflectorFactory factory = (ReflectorFactory) resolveClass(type).newInstance();
+            configuration.setReflectorFactory(factory);
+        }
+    }
 
-	private void reflectionFactoryElement(XNode context) throws Exception {
-		if (context != null) {
-			String type = context.getStringAttribute("type");
-			ReflectorFactory factory = (ReflectorFactory) resolveClass(type).newInstance();
-			configuration.setReflectorFactory(factory);
-		}
-	}
+    private void propertiesElement(XNode context) throws Exception {
+        if (context != null) {
+            Properties defaults = context.getChildrenAsProperties();
+            String resource = context.getStringAttribute("resource");
+            String url = context.getStringAttribute("url");
+            if (resource != null && url != null) {
+                throw new BuilderException("The properties element cannot specify both a URL and a resource based property file reference.  Please specify one or the other.");
+            }
+            if (resource != null) {
+                defaults.putAll(Resources.getResourceAsProperties(resource));
+            } else if (url != null) {
+                defaults.putAll(Resources.getUrlAsProperties(url));
+            }
+            Properties vars = configuration.getVariables();
+            if (vars != null) {
+                defaults.putAll(vars);
+            }
+            parser.setVariables(defaults);
+            configuration.setVariables(defaults);
+        }
+    }
 
-	private void propertiesElement(XNode context) throws Exception {
-		if (context != null) {
-			Properties defaults = context.getChildrenAsProperties();
-			String resource = context.getStringAttribute("resource");
-			String url = context.getStringAttribute("url");
-			if (resource != null && url != null) {
-				throw new BuilderException(
-						"The properties element cannot specify both a URL and a resource based property file reference.  Please specify one or the other.");
-			}
-			if (resource != null) {
-				defaults.putAll(Resources.getResourceAsProperties(resource));
-			} else if (url != null) {
-				defaults.putAll(Resources.getUrlAsProperties(url));
-			}
-			Properties vars = configuration.getVariables();
-			if (vars != null) {
-				defaults.putAll(vars);
-			}
-			parser.setVariables(defaults);
-			configuration.setVariables(defaults);
-		}
-	}
+    private void settingsElement(Properties props) throws Exception {
+        configuration.setAutoMappingBehavior(AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
+        configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
+        configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
+        configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory")));
+        configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
+        configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), false));
+        configuration.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
+        configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true));
+        configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false));
+        configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
+        configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));
+        configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null));
+        configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
+        configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
+        configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
+        configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
+        configuration.setLazyLoadTriggerMethods(stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
+        configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
+        configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage")));
+        configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false));
+        configuration.setUseActualParamName(booleanValueOf(props.getProperty("useActualParamName"), true));
+        configuration.setReturnInstanceForEmptyRow(booleanValueOf(props.getProperty("returnInstanceForEmptyRow"), false));
+        configuration.setLogPrefix(props.getProperty("logPrefix"));
+        @SuppressWarnings("unchecked")
+        Class<? extends Log> logImpl = (Class<? extends Log>)resolveClass(props.getProperty("logImpl"));
+        configuration.setLogImpl(logImpl);
+        configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
+    }
 
-	private void settingsElement(Properties props) throws Exception {
-		configuration.setAutoMappingBehavior(
-				AutoMappingBehavior.valueOf(props.getProperty("autoMappingBehavior", "PARTIAL")));
-		configuration.setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior
-				.valueOf(props.getProperty("autoMappingUnknownColumnBehavior", "NONE")));
-		configuration.setCacheEnabled(booleanValueOf(props.getProperty("cacheEnabled"), true));
-		configuration.setProxyFactory((ProxyFactory) createInstance(props.getProperty("proxyFactory")));
-		configuration.setLazyLoadingEnabled(booleanValueOf(props.getProperty("lazyLoadingEnabled"), false));
-		configuration.setAggressiveLazyLoading(booleanValueOf(props.getProperty("aggressiveLazyLoading"), true));
-		configuration
-				.setMultipleResultSetsEnabled(booleanValueOf(props.getProperty("multipleResultSetsEnabled"), true));
-		configuration.setUseColumnLabel(booleanValueOf(props.getProperty("useColumnLabel"), true));
-		configuration.setUseGeneratedKeys(booleanValueOf(props.getProperty("useGeneratedKeys"), false));
-		configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));
-		configuration.setDefaultStatementTimeout(integerValueOf(props.getProperty("defaultStatementTimeout"), null));
-		configuration.setDefaultFetchSize(integerValueOf(props.getProperty("defaultFetchSize"), null));
-		configuration.setMapUnderscoreToCamelCase(booleanValueOf(props.getProperty("mapUnderscoreToCamelCase"), false));
-		configuration.setSafeRowBoundsEnabled(booleanValueOf(props.getProperty("safeRowBoundsEnabled"), false));
-		configuration.setLocalCacheScope(LocalCacheScope.valueOf(props.getProperty("localCacheScope", "SESSION")));
-		configuration.setJdbcTypeForNull(JdbcType.valueOf(props.getProperty("jdbcTypeForNull", "OTHER")));
-		configuration.setLazyLoadTriggerMethods(
-				stringSetValueOf(props.getProperty("lazyLoadTriggerMethods"), "equals,clone,hashCode,toString"));
-		configuration.setSafeResultHandlerEnabled(booleanValueOf(props.getProperty("safeResultHandlerEnabled"), true));
-		configuration.setDefaultScriptingLanguage(resolveClass(props.getProperty("defaultScriptingLanguage")));
-		configuration.setCallSettersOnNulls(booleanValueOf(props.getProperty("callSettersOnNulls"), false));
-		configuration.setLogPrefix(props.getProperty("logPrefix"));
-		configuration.setLogImpl(resolveClass(props.getProperty("logImpl")));
-		configuration.setConfigurationFactory(resolveClass(props.getProperty("configurationFactory")));
-	}
+    private void environmentsElement(XNode context) throws Exception {
+        if (context != null) {
+            if (environment == null) {
+                environment = context.getStringAttribute("default");
+            }
+            for (XNode child : context.getChildren()) {
+                String id = child.getStringAttribute("id");
+                if (isSpecifiedEnvironment(id)) {
+                    TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
+                    DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
+                    DataSource dataSource = dsFactory.getDataSource();
+                    Environment.Builder environmentBuilder = new Environment.Builder(id)
+                            .transactionFactory(txFactory)
+                            .dataSource(dataSource);
+                    configuration.setEnvironment(environmentBuilder.build());
+                }
+            }
+        }
+    }
 
-	private void environmentsElement(XNode context) throws Exception {
-		if (context != null) {
-			if (environment == null) {
-				environment = context.getStringAttribute("default");
-			}
-			for (XNode child : context.getChildren()) {
-				String id = child.getStringAttribute("id");
-				if (isSpecifiedEnvironment(id)) {
-					TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
-					DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
-					DataSource dataSource = dsFactory.getDataSource();
-					Environment.Builder environmentBuilder = new Environment.Builder(id).transactionFactory(txFactory)
-							.dataSource(dataSource);
-					configuration.setEnvironment(environmentBuilder.build());
-				}
-			}
-		}
-	}
+    private void databaseIdProviderElement(XNode context) throws Exception {
+        DatabaseIdProvider databaseIdProvider = null;
+        if (context != null) {
+            String type = context.getStringAttribute("type");
+            // awful patch to keep backward compatibility
+            if ("VENDOR".equals(type)) {
+                type = "DB_VENDOR";
+            }
+            Properties properties = context.getChildrenAsProperties();
+            databaseIdProvider = (DatabaseIdProvider) resolveClass(type).newInstance();
+            databaseIdProvider.setProperties(properties);
+        }
+        Environment environment = configuration.getEnvironment();
+        if (environment != null && databaseIdProvider != null) {
+            String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
+            configuration.setDatabaseId(databaseId);
+        }
+    }
 
-	private void databaseIdProviderElement(XNode context) throws Exception {
-		DatabaseIdProvider databaseIdProvider = null;
-		if (context != null) {
-			String type = context.getStringAttribute("type");
-			// awful patch to keep backward compatibility
-			if ("VENDOR".equals(type)) {
-				type = "DB_VENDOR";
-			}
-			Properties properties = context.getChildrenAsProperties();
-			databaseIdProvider = (DatabaseIdProvider) resolveClass(type).newInstance();
-			databaseIdProvider.setProperties(properties);
-		}
-		Environment environment = configuration.getEnvironment();
-		if (environment != null && databaseIdProvider != null) {
-			String databaseId = databaseIdProvider.getDatabaseId(environment.getDataSource());
-			configuration.setDatabaseId(databaseId);
-		}
-	}
+    private TransactionFactory transactionManagerElement(XNode context) throws Exception {
+        if (context != null) {
+            String type = context.getStringAttribute("type");
+            Properties props = context.getChildrenAsProperties();
+            TransactionFactory factory = (TransactionFactory) resolveClass(type).newInstance();
+            factory.setProperties(props);
+            return factory;
+        }
+        throw new BuilderException("Environment declaration requires a TransactionFactory.");
+    }
 
-	private TransactionFactory transactionManagerElement(XNode context) throws Exception {
-		if (context != null) {
-			String type = context.getStringAttribute("type");
-			Properties props = context.getChildrenAsProperties();
-			TransactionFactory factory = (TransactionFactory) resolveClass(type).newInstance();
-			factory.setProperties(props);
-			return factory;
-		}
-		throw new BuilderException("Environment declaration requires a TransactionFactory.");
-	}
+    private DataSourceFactory dataSourceElement(XNode context) throws Exception {
+        if (context != null) {
+            String type = context.getStringAttribute("type");
+            Properties props = context.getChildrenAsProperties();
+            DataSourceFactory factory = (DataSourceFactory) resolveClass(type).newInstance();
+            factory.setProperties(props);
+            return factory;
+        }
+        throw new BuilderException("Environment declaration requires a DataSourceFactory.");
+    }
 
-	private DataSourceFactory dataSourceElement(XNode context) throws Exception {
-		if (context != null) {
-			String type = context.getStringAttribute("type");
-			Properties props = context.getChildrenAsProperties();
-			DataSourceFactory factory = (DataSourceFactory) resolveClass(type).newInstance();
-			factory.setProperties(props);
-			return factory;
-		}
-		throw new BuilderException("Environment declaration requires a DataSourceFactory.");
-	}
+    private void typeHandlerElement(XNode parent) throws Exception {
+        if (parent != null) {
+            for (XNode child : parent.getChildren()) {
+                if ("package".equals(child.getName())) {
+                    String typeHandlerPackage = child.getStringAttribute("name");
+                    typeHandlerRegistry.register(typeHandlerPackage);
+                } else {
+                    String javaTypeName = child.getStringAttribute("javaType");
+                    String jdbcTypeName = child.getStringAttribute("jdbcType");
+                    String handlerTypeName = child.getStringAttribute("handler");
+                    Class<?> javaTypeClass = resolveClass(javaTypeName);
+                    JdbcType jdbcType = resolveJdbcType(jdbcTypeName);
+                    Class<?> typeHandlerClass = resolveClass(handlerTypeName);
+                    if (javaTypeClass != null) {
+                        if (jdbcType == null) {
+                            typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
+                        } else {
+                            typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
+                        }
+                    } else {
+                        typeHandlerRegistry.register(typeHandlerClass);
+                    }
+                }
+            }
+        }
+    }
 
-	private void typeHandlerElement(XNode parent) throws Exception {
-		if (parent != null) {
-			for (XNode child : parent.getChildren()) {
-				if ("package".equals(child.getName())) {
-					String typeHandlerPackage = child.getStringAttribute("name");
-					typeHandlerRegistry.register(typeHandlerPackage);
-				} else {
-					String javaTypeName = child.getStringAttribute("javaType");
-					String jdbcTypeName = child.getStringAttribute("jdbcType");
-					String handlerTypeName = child.getStringAttribute("handler");
-					Class<?> javaTypeClass = resolveClass(javaTypeName);
-					JdbcType jdbcType = resolveJdbcType(jdbcTypeName);
-					Class<?> typeHandlerClass = resolveClass(handlerTypeName);
-					if (javaTypeClass != null) {
-						if (jdbcType == null) {
-							typeHandlerRegistry.register(javaTypeClass, typeHandlerClass);
-						} else {
-							typeHandlerRegistry.register(javaTypeClass, jdbcType, typeHandlerClass);
-						}
-					} else {
-						typeHandlerRegistry.register(typeHandlerClass);
-					}
-				}
-			}
-		}
-	}
+    private void mapperElement(XNode parent) throws Exception {
+        /**
+         * 定义集合 用来分类放置mybatis的Mapper与XML 按顺序依次遍历
+         */
+        if (parent != null) {
+            //指定在classpath中的mapper文件
+            Set<String> resources = new HashSet<String>();
+            //指向一个mapper接口
+            Set<Class<?>> mapperClasses = new HashSet<Class<?>>();
+            setResource(parent, resources, mapperClasses);
+            // 依次遍历 首先 resource 然后 mapper
+            for (String resource : resources) {
+                ErrorContext.instance().resource(resource);
+                InputStream inputStream = Resources.getResourceAsStream(resource);
+                //TODO
+                MybatisXMLMapperBuilder mapperParser = new MybatisXMLMapperBuilder(inputStream, configuration, resource,
+                        configuration.getSqlFragments());
+                mapperParser.parse();
+            }
+            for (Class<?> mapper : mapperClasses) {
+                //TODO
+                configuration.addMapper(mapper);
+            }
+        }
+    }
 
-	private void mapperElement(XNode parent) throws Exception {
-		if (parent != null) {
-			for (XNode child : parent.getChildren()) {
-				if ("package".equals(child.getName())) {
-					String mapperPackage = child.getStringAttribute("name");
-					configuration.addMappers(mapperPackage);
-				} else {
-					String resource = child.getStringAttribute("resource");
-					String url = child.getStringAttribute("url");
-					String mapperClass = child.getStringAttribute("class");
-					if (resource != null && url == null && mapperClass == null) {
-						ErrorContext.instance().resource(resource);
-						InputStream inputStream = Resources.getResourceAsStream(resource);
-						//TODO
-						MybatisXMLMapperBuilder mapperParser = new MybatisXMLMapperBuilder(inputStream, configuration, resource,
-								configuration.getSqlFragments());
-						mapperParser.parse();
-					} else if (resource == null && url != null && mapperClass == null) {
-						ErrorContext.instance().resource(url);
-						InputStream inputStream = Resources.getUrlAsStream(url);
-						//TODO
-						MybatisXMLMapperBuilder mapperParser = new MybatisXMLMapperBuilder(inputStream, configuration, url,
-								configuration.getSqlFragments());
-						mapperParser.parse();
-					} else if (resource == null && url == null && mapperClass != null) {
-						Class<?> mapperInterface = Resources.classForName(mapperClass);
-						configuration.addMapper(mapperInterface);
-					} else {
-						throw new BuilderException(
-								"A mapper element may only specify a url, resource or class, but not more than one.");
-					}
-				}
-			}
-		}
-	}
+    /**
+     * 查找mybatis配置文件填充至Set集合
+     *
+     * @param parent 节点
+     * @param resources
+     * @param mapper
+     * @throws ClassNotFoundException
+     */
+    private void setResource(XNode parent, Set<String> resources, Set<Class<?>> mapper) throws ClassNotFoundException {
+        for (XNode child : parent.getChildren()) {
+            if ("package".equals(child.getName())) {
+                String mapperPackage = child.getStringAttribute("name");
+                ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
+                resolverUtil.find(new ResolverUtil.IsA(Object.class), mapperPackage);
+                Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
+                for (Class<?> mapperClass : mapperSet) {
+                    mapper.add(mapperClass);
+                }
+            } else {
+                String resource = child.getStringAttribute("resource");
+                String url = child.getStringAttribute("url");
+                String mapperClass = child.getStringAttribute("class");
+                if (resource != null && url == null && mapperClass == null) {
+                    resources.add(resource);
+                } else if (resource == null && url != null && mapperClass == null) {
+                    resources.add(url);
+                } else if (resource == null && url == null && mapperClass != null) {
+                    Class<?> mapperInterface = Resources.classForName(mapperClass);
+                    mapper.add(mapperInterface);
+                } else {
+                    throw new BuilderException(
+                            "A mapper element may only specify a url, resource or class, but not more than one.");
+                }
+            }
+        }
+    }
 
-	private boolean isSpecifiedEnvironment(String id) {
-		if (environment == null) {
-			throw new BuilderException("No environment specified.");
-		} else if (id == null) {
-			throw new BuilderException("Environment requires an id attribute.");
-		} else if (environment.equals(id)) {
-			return true;
-		}
-		return false;
-	}
+    private boolean isSpecifiedEnvironment(String id) {
+        if (environment == null) {
+            throw new BuilderException("No environment specified.");
+        } else if (id == null) {
+            throw new BuilderException("Environment requires an id attribute.");
+        } else if (environment.equals(id)) {
+            return true;
+        }
+        return false;
+    }
 
-}
+}

+ 380 - 362
mybatis-plus/src/main/java/com/baomidou/mybatisplus/MybatisXMLMapperBuilder.java

@@ -49,8 +49,9 @@ import org.apache.ibatis.session.Configuration;
 import org.apache.ibatis.type.JdbcType;
 import org.apache.ibatis.type.TypeHandler;
 
-import com.baomidou.mybatisplus.mapper.AutoSqlInjector;
+import com.baomidou.mybatisplus.entity.GlobalConfiguration;
 import com.baomidou.mybatisplus.mapper.BaseMapper;
+import com.baomidou.mybatisplus.toolkit.StringUtils;
 
 /**
  * <p>
@@ -65,367 +66,384 @@ import com.baomidou.mybatisplus.mapper.BaseMapper;
  */
 public class MybatisXMLMapperBuilder extends BaseBuilder {
 
-  private XPathParser parser;
-  private MapperBuilderAssistant builderAssistant;
-  private Map<String, XNode> sqlFragments;
-  private String resource;
-
-  @Deprecated
-  public MybatisXMLMapperBuilder(Reader reader, Configuration configuration, String resource, Map<String, XNode> sqlFragments, String namespace) {
-    this(reader, configuration, resource, sqlFragments);
-    this.builderAssistant.setCurrentNamespace(namespace);
-  }
-
-  @Deprecated
-  public MybatisXMLMapperBuilder(Reader reader, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
-    this(new XPathParser(reader, true, configuration.getVariables(), new XMLMapperEntityResolver()),
-        configuration, resource, sqlFragments);
-  }
-
-  public MybatisXMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map<String, XNode> sqlFragments, String namespace) {
-    this(inputStream, configuration, resource, sqlFragments);
-    this.builderAssistant.setCurrentNamespace(namespace);
-  }
-
-  public MybatisXMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
-    this(new XPathParser(inputStream, true, configuration.getVariables(), new XMLMapperEntityResolver()),
-        configuration, resource, sqlFragments);
-  }
-
-  private MybatisXMLMapperBuilder(XPathParser parser, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
-    super(configuration);
-    this.builderAssistant = new MapperBuilderAssistant(configuration, resource);
-    this.parser = parser;
-    this.sqlFragments = sqlFragments;
-    this.resource = resource;
-  }
-
-  public void parse() {
-    if (!configuration.isResourceLoaded(resource)) {
-      configurationElement(parser.evalNode("/mapper"));
-      configuration.addLoadedResource(resource);
-      bindMapperForNamespace();
-    }
-
-    parsePendingResultMaps();
-    parsePendingChacheRefs();
-    parsePendingStatements();
-  }
-
-  public XNode getSqlFragment(String refid) {
-    return sqlFragments.get(refid);
-  }
-
-  private void configurationElement(XNode context) {
-    try {
-      String namespace = context.getStringAttribute("namespace");
-      if (namespace == null || namespace.equals("")) {
-        throw new BuilderException("Mapper's namespace cannot be empty");
-      }
-      builderAssistant.setCurrentNamespace(namespace);
-      cacheRefElement(context.evalNode("cache-ref"));
-      cacheElement(context.evalNode("cache"));
-      parameterMapElement(context.evalNodes("/mapper/parameterMap"));
-      resultMapElements(context.evalNodes("/mapper/resultMap"));
-      sqlElement(context.evalNodes("/mapper/sql"));
-      buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
-    } catch (Exception e) {
-      throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e);
-    }
-  }
-
-  private void buildStatementFromContext(List<XNode> list) {
-    if (configuration.getDatabaseId() != null) {
-      buildStatementFromContext(list, configuration.getDatabaseId());
-    }
-    buildStatementFromContext(list, null);
-  }
-
-  private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
-    for (XNode context : list) {
-      final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
-      try {
-        statementParser.parseStatementNode();
-      } catch (IncompleteElementException e) {
-        configuration.addIncompleteStatement(statementParser);
-      }
-    }
-  }
-
-  private void parsePendingResultMaps() {
-    Collection<ResultMapResolver> incompleteResultMaps = configuration.getIncompleteResultMaps();
-    synchronized (incompleteResultMaps) {
-      Iterator<ResultMapResolver> iter = incompleteResultMaps.iterator();
-      while (iter.hasNext()) {
-        try {
-          iter.next().resolve();
-          iter.remove();
-        } catch (IncompleteElementException e) {
-          // ResultMap is still missing a resource...
-        }
-      }
-    }
-  }
-
-  private void parsePendingChacheRefs() {
-    Collection<CacheRefResolver> incompleteCacheRefs = configuration.getIncompleteCacheRefs();
-    synchronized (incompleteCacheRefs) {
-      Iterator<CacheRefResolver> iter = incompleteCacheRefs.iterator();
-      while (iter.hasNext()) {
-        try {
-          iter.next().resolveCacheRef();
-          iter.remove();
-        } catch (IncompleteElementException e) {
-          // Cache ref is still missing a resource...
-        }
-      }
-    }
-  }
-
-  private void parsePendingStatements() {
-    Collection<XMLStatementBuilder> incompleteStatements = configuration.getIncompleteStatements();
-    synchronized (incompleteStatements) {
-      Iterator<XMLStatementBuilder> iter = incompleteStatements.iterator();
-      while (iter.hasNext()) {
-        try {
-          iter.next().parseStatementNode();
-          iter.remove();
-        } catch (IncompleteElementException e) {
-          // Statement is still missing a resource...
-        }
-      }
-    }
-  }
-
-  private void cacheRefElement(XNode context) {
-    if (context != null) {
-      configuration.addCacheRef(builderAssistant.getCurrentNamespace(), context.getStringAttribute("namespace"));
-      CacheRefResolver cacheRefResolver = new CacheRefResolver(builderAssistant, context.getStringAttribute("namespace"));
-      try {
-        cacheRefResolver.resolveCacheRef();
-      } catch (IncompleteElementException e) {
-        configuration.addIncompleteCacheRef(cacheRefResolver);
-      }
-    }
-  }
-
-  private void cacheElement(XNode context) throws Exception {
-    if (context != null) {
-      String type = context.getStringAttribute("type", "PERPETUAL");
-      Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type);
-      String eviction = context.getStringAttribute("eviction", "LRU");
-      Class<? extends Cache> evictionClass = typeAliasRegistry.resolveAlias(eviction);
-      Long flushInterval = context.getLongAttribute("flushInterval");
-      Integer size = context.getIntAttribute("size");
-      boolean readWrite = !context.getBooleanAttribute("readOnly", false);
-      boolean blocking = context.getBooleanAttribute("blocking", false);
-      Properties props = context.getChildrenAsProperties();
-      builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);
-    }
-  }
-
-  private void parameterMapElement(List<XNode> list) throws Exception {
-    for (XNode parameterMapNode : list) {
-      String id = parameterMapNode.getStringAttribute("id");
-      String type = parameterMapNode.getStringAttribute("type");
-      Class<?> parameterClass = resolveClass(type);
-      List<XNode> parameterNodes = parameterMapNode.evalNodes("parameter");
-      List<ParameterMapping> parameterMappings = new ArrayList<ParameterMapping>();
-      for (XNode parameterNode : parameterNodes) {
-        String property = parameterNode.getStringAttribute("property");
-        String javaType = parameterNode.getStringAttribute("javaType");
-        String jdbcType = parameterNode.getStringAttribute("jdbcType");
-        String resultMap = parameterNode.getStringAttribute("resultMap");
-        String mode = parameterNode.getStringAttribute("mode");
-        String typeHandler = parameterNode.getStringAttribute("typeHandler");
-        Integer numericScale = parameterNode.getIntAttribute("numericScale");
-        ParameterMode modeEnum = resolveParameterMode(mode);
-        Class<?> javaTypeClass = resolveClass(javaType);
-        JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
-        @SuppressWarnings("unchecked")
-        Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler);
-        ParameterMapping parameterMapping = builderAssistant.buildParameterMapping(parameterClass, property, javaTypeClass, jdbcTypeEnum, resultMap, modeEnum, typeHandlerClass, numericScale);
-        parameterMappings.add(parameterMapping);
-      }
-      builderAssistant.addParameterMap(id, parameterClass, parameterMappings);
-    }
-  }
-
-  private void resultMapElements(List<XNode> list) throws Exception {
-    for (XNode resultMapNode : list) {
-      try {
-        resultMapElement(resultMapNode);
-      } catch (IncompleteElementException e) {
-        // ignore, it will be retried
-      }
-    }
-  }
-
-  private ResultMap resultMapElement(XNode resultMapNode) throws Exception {
-    return resultMapElement(resultMapNode, Collections.<ResultMapping> emptyList());
-  }
-
-  private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings) throws Exception {
-    ErrorContext.instance().activity("processing " + resultMapNode.getValueBasedIdentifier());
-    String id = resultMapNode.getStringAttribute("id",
-        resultMapNode.getValueBasedIdentifier());
-    String type = resultMapNode.getStringAttribute("type",
-        resultMapNode.getStringAttribute("ofType",
-            resultMapNode.getStringAttribute("resultType",
-                resultMapNode.getStringAttribute("javaType"))));
-    String extend = resultMapNode.getStringAttribute("extends");
-    Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping");
-    Class<?> typeClass = resolveClass(type);
-    Discriminator discriminator = null;
-    List<ResultMapping> resultMappings = new ArrayList<ResultMapping>();
-    resultMappings.addAll(additionalResultMappings);
-    List<XNode> resultChildren = resultMapNode.getChildren();
-    for (XNode resultChild : resultChildren) {
-      if ("constructor".equals(resultChild.getName())) {
-        processConstructorElement(resultChild, typeClass, resultMappings);
-      } else if ("discriminator".equals(resultChild.getName())) {
-        discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings);
-      } else {
-        List<ResultFlag> flags = new ArrayList<ResultFlag>();
-        if ("id".equals(resultChild.getName())) {
-          flags.add(ResultFlag.ID);
-        }
-        resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));
-      }
-    }
-    ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);
-    try {
-      return resultMapResolver.resolve();
-    } catch (IncompleteElementException  e) {
-      configuration.addIncompleteResultMap(resultMapResolver);
-      throw e;
-    }
-  }
-
-  private void processConstructorElement(XNode resultChild, Class<?> resultType, List<ResultMapping> resultMappings) throws Exception {
-    List<XNode> argChildren = resultChild.getChildren();
-    for (XNode argChild : argChildren) {
-      List<ResultFlag> flags = new ArrayList<ResultFlag>();
-      flags.add(ResultFlag.CONSTRUCTOR);
-      if ("idArg".equals(argChild.getName())) {
-        flags.add(ResultFlag.ID);
-      }
-      resultMappings.add(buildResultMappingFromContext(argChild, resultType, flags));
-    }
-  }
-
-  private Discriminator processDiscriminatorElement(XNode context, Class<?> resultType, List<ResultMapping> resultMappings) throws Exception {
-    String column = context.getStringAttribute("column");
-    String javaType = context.getStringAttribute("javaType");
-    String jdbcType = context.getStringAttribute("jdbcType");
-    String typeHandler = context.getStringAttribute("typeHandler");
-    Class<?> javaTypeClass = resolveClass(javaType);
-    @SuppressWarnings("unchecked")
-    Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler);
-    JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
-    Map<String, String> discriminatorMap = new HashMap<String, String>();
-    for (XNode caseChild : context.getChildren()) {
-      String value = caseChild.getStringAttribute("value");
-      String resultMap = caseChild.getStringAttribute("resultMap", processNestedResultMappings(caseChild, resultMappings));
-      discriminatorMap.put(value, resultMap);
-    }
-    return builderAssistant.buildDiscriminator(resultType, column, javaTypeClass, jdbcTypeEnum, typeHandlerClass, discriminatorMap);
-  }
-
-  private void sqlElement(List<XNode> list) throws Exception {
-    if (configuration.getDatabaseId() != null) {
-      sqlElement(list, configuration.getDatabaseId());
-    }
-    sqlElement(list, null);
-  }
-
-  private void sqlElement(List<XNode> list, String requiredDatabaseId) throws Exception {
-    for (XNode context : list) {
-      String databaseId = context.getStringAttribute("databaseId");
-      String id = context.getStringAttribute("id");
-      id = builderAssistant.applyCurrentNamespace(id, false);
-      if (databaseIdMatchesCurrent(id, databaseId, requiredDatabaseId)) {
-        sqlFragments.put(id, context);
-      }
-    }
-  }
-  
-  private boolean databaseIdMatchesCurrent(String id, String databaseId, String requiredDatabaseId) {
-    if (requiredDatabaseId != null) {
-      if (!requiredDatabaseId.equals(databaseId)) {
-        return false;
-      }
-    } else {
-      if (databaseId != null) {
-        return false;
-      }
-      // skip this fragment if there is a previous one with a not null databaseId
-      if (this.sqlFragments.containsKey(id)) {
-        XNode context = this.sqlFragments.get(id);
-        if (context.getStringAttribute("databaseId") != null) {
-          return false;
-        }
-      }
-    }
-    return true;
-  }
-
-  private ResultMapping buildResultMappingFromContext(XNode context, Class<?> resultType, List<ResultFlag> flags) throws Exception {
-    String property = context.getStringAttribute("property");
-    String column = context.getStringAttribute("column");
-    String javaType = context.getStringAttribute("javaType");
-    String jdbcType = context.getStringAttribute("jdbcType");
-    String nestedSelect = context.getStringAttribute("select");
-    String nestedResultMap = context.getStringAttribute("resultMap",
-        processNestedResultMappings(context, Collections.<ResultMapping> emptyList()));
-    String notNullColumn = context.getStringAttribute("notNullColumn");
-    String columnPrefix = context.getStringAttribute("columnPrefix");
-    String typeHandler = context.getStringAttribute("typeHandler");
-    String resultSet = context.getStringAttribute("resultSet");
-    String foreignColumn = context.getStringAttribute("foreignColumn");
-    boolean lazy = "lazy".equals(context.getStringAttribute("fetchType", configuration.isLazyLoadingEnabled() ? "lazy" : "eager"));
-    Class<?> javaTypeClass = resolveClass(javaType);
-    @SuppressWarnings("unchecked")
-    Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler);
-    JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
-    return builderAssistant.buildResultMapping(resultType, property, column, javaTypeClass, jdbcTypeEnum, nestedSelect, nestedResultMap, notNullColumn, columnPrefix, typeHandlerClass, flags, resultSet, foreignColumn, lazy);
-  }
-  
-  private String processNestedResultMappings(XNode context, List<ResultMapping> resultMappings) throws Exception {
-    if ("association".equals(context.getName())
-        || "collection".equals(context.getName())
-        || "case".equals(context.getName())) {
-      if (context.getStringAttribute("select") == null) {
-        ResultMap resultMap = resultMapElement(context, resultMappings);
-        return resultMap.getId();
-      }
-    }
-    return null;
-  }
-
-  private void bindMapperForNamespace() {
-    String namespace = builderAssistant.getCurrentNamespace();
-    if (namespace != null) {
-      Class<?> boundType = null;
-      try {
-        boundType = Resources.classForName(namespace);
-      } catch (ClassNotFoundException e) {
-        //ignore, bound type is not required
-      }
-      if (boundType != null) {
-        if (!configuration.hasMapper(boundType)) {
-          // Spring may not know the real resource name so we set a flag
-          // to prevent loading again this resource from the mapper interface
-          // look at MapperAnnotationBuilder#loadXmlResource
-          configuration.addLoadedResource("namespace:" + namespace);
-          configuration.addMapper(boundType);
-        }
-        //TODO 注入 CURD 动态 SQL
-		if (BaseMapper.class.isAssignableFrom(boundType)) {
-			new AutoSqlInjector(configuration, MybatisConfiguration.DB_TYPE).inject(builderAssistant, boundType);
+	private XPathParser parser;
+	private MapperBuilderAssistant builderAssistant;
+	private Map<String, XNode> sqlFragments;
+	private String resource;
+
+	@Deprecated
+	public MybatisXMLMapperBuilder(Reader reader, Configuration configuration, String resource,
+								   Map<String, XNode> sqlFragments, String namespace) {
+		this(reader, configuration, resource, sqlFragments);
+		this.builderAssistant.setCurrentNamespace(namespace);
+	}
+
+	@Deprecated
+	public MybatisXMLMapperBuilder(Reader reader, Configuration configuration, String resource,
+			Map<String, XNode> sqlFragments) {
+		this(new XPathParser(reader, true, configuration.getVariables(), new XMLMapperEntityResolver()), configuration,
+				resource, sqlFragments);
+	}
+
+	public MybatisXMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource,
+			Map<String, XNode> sqlFragments, String namespace) {
+		this(inputStream, configuration, resource, sqlFragments);
+		this.builderAssistant.setCurrentNamespace(namespace);
+	}
+
+	public MybatisXMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource,
+			Map<String, XNode> sqlFragments) {
+		this(new XPathParser(inputStream, true, configuration.getVariables(), new XMLMapperEntityResolver()),
+				configuration, resource, sqlFragments);
+	}
+
+	private MybatisXMLMapperBuilder(XPathParser parser, Configuration configuration, String resource,
+			Map<String, XNode> sqlFragments) {
+		super(configuration);
+		this.builderAssistant = new MapperBuilderAssistant(configuration, resource);
+		this.parser = parser;
+		this.sqlFragments = sqlFragments;
+		this.resource = resource;
+	}
+
+	public void parse() {
+		if (!configuration.isResourceLoaded(resource)) {
+			configurationElement(parser.evalNode("/mapper"));
+			configuration.addLoadedResource(resource);
+			bindMapperForNamespace();
 		}
-      }
-    }
-  }
+		parsePendingResultMaps();
+		parsePendingChacheRefs();
+		parsePendingStatements();
+	}
+
+	public XNode getSqlFragment(String refid) {
+		return sqlFragments.get(refid);
+	}
+
+	private void configurationElement(XNode context) {
+		try {
+			String namespace = context.getStringAttribute("namespace");
+			if (StringUtils.isEmpty(namespace)) {
+				throw new BuilderException("Mapper's namespace cannot be empty");
+			}
+			builderAssistant.setCurrentNamespace(namespace);
+			cacheRefElement(context.evalNode("cache-ref"));
+			cacheElement(context.evalNode("cache"));
+			parameterMapElement(context.evalNodes("/mapper/parameterMap"));
+			resultMapElements(context.evalNodes("/mapper/resultMap"));
+			sqlElement(context.evalNodes("/mapper/sql"));
+			buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
+		} catch (Exception e) {
+			throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e);
+		}
+	}
+
+	private void buildStatementFromContext(List<XNode> list) {
+		if (configuration.getDatabaseId() != null) {
+			buildStatementFromContext(list, configuration.getDatabaseId());
+		}
+		buildStatementFromContext(list, null);
+	}
+
+	private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
+		for (XNode context : list) {
+			final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant,
+					context, requiredDatabaseId);
+			try {
+				statementParser.parseStatementNode();
+			} catch (IncompleteElementException e) {
+				configuration.addIncompleteStatement(statementParser);
+			}
+		}
+	}
+
+	private void parsePendingResultMaps() {
+		Collection<ResultMapResolver> incompleteResultMaps = configuration.getIncompleteResultMaps();
+		synchronized (incompleteResultMaps) {
+			Iterator<ResultMapResolver> iter = incompleteResultMaps.iterator();
+			while (iter.hasNext()) {
+				try {
+					iter.next().resolve();
+					iter.remove();
+				} catch (IncompleteElementException e) {
+					// ResultMap is still missing a resource...
+				}
+			}
+		}
+	}
+
+	private void parsePendingChacheRefs() {
+		Collection<CacheRefResolver> incompleteCacheRefs = configuration.getIncompleteCacheRefs();
+		synchronized (incompleteCacheRefs) {
+			Iterator<CacheRefResolver> iter = incompleteCacheRefs.iterator();
+			while (iter.hasNext()) {
+				try {
+					iter.next().resolveCacheRef();
+					iter.remove();
+				} catch (IncompleteElementException e) {
+					// Cache ref is still missing a resource...
+				}
+			}
+		}
+	}
+
+	private void parsePendingStatements() {
+		Collection<XMLStatementBuilder> incompleteStatements = configuration.getIncompleteStatements();
+		synchronized (incompleteStatements) {
+			Iterator<XMLStatementBuilder> iter = incompleteStatements.iterator();
+			while (iter.hasNext()) {
+				try {
+					iter.next().parseStatementNode();
+					iter.remove();
+				} catch (IncompleteElementException e) {
+					// Statement is still missing a resource...
+				}
+			}
+		}
+	}
+
+	private void cacheRefElement(XNode context) {
+		if (context != null) {
+			configuration.addCacheRef(builderAssistant.getCurrentNamespace(), context.getStringAttribute("namespace"));
+			CacheRefResolver cacheRefResolver = new CacheRefResolver(builderAssistant,
+					context.getStringAttribute("namespace"));
+			try {
+				cacheRefResolver.resolveCacheRef();
+			} catch (IncompleteElementException e) {
+				configuration.addIncompleteCacheRef(cacheRefResolver);
+			}
+		}
+	}
+
+	private void cacheElement(XNode context) throws Exception {
+		if (context != null) {
+			String type = context.getStringAttribute("type", "PERPETUAL");
+			Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type);
+			String eviction = context.getStringAttribute("eviction", "LRU");
+			Class<? extends Cache> evictionClass = typeAliasRegistry.resolveAlias(eviction);
+			Long flushInterval = context.getLongAttribute("flushInterval");
+			Integer size = context.getIntAttribute("size");
+			boolean readWrite = !context.getBooleanAttribute("readOnly", false);
+			boolean blocking = context.getBooleanAttribute("blocking", false);
+			Properties props = context.getChildrenAsProperties();
+			builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);
+		}
+	}
+
+	private void parameterMapElement(List<XNode> list) throws Exception {
+		for (XNode parameterMapNode : list) {
+			String id = parameterMapNode.getStringAttribute("id");
+			String type = parameterMapNode.getStringAttribute("type");
+			Class<?> parameterClass = resolveClass(type);
+			List<XNode> parameterNodes = parameterMapNode.evalNodes("parameter");
+			List<ParameterMapping> parameterMappings = new ArrayList<ParameterMapping>();
+			for (XNode parameterNode : parameterNodes) {
+				String property = parameterNode.getStringAttribute("property");
+				String javaType = parameterNode.getStringAttribute("javaType");
+				String jdbcType = parameterNode.getStringAttribute("jdbcType");
+				String resultMap = parameterNode.getStringAttribute("resultMap");
+				String mode = parameterNode.getStringAttribute("mode");
+				String typeHandler = parameterNode.getStringAttribute("typeHandler");
+				Integer numericScale = parameterNode.getIntAttribute("numericScale");
+				ParameterMode modeEnum = resolveParameterMode(mode);
+				Class<?> javaTypeClass = resolveClass(javaType);
+				JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
+				@SuppressWarnings("unchecked")
+				Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(
+						typeHandler);
+				ParameterMapping parameterMapping = builderAssistant.buildParameterMapping(parameterClass, property,
+						javaTypeClass, jdbcTypeEnum, resultMap, modeEnum, typeHandlerClass, numericScale);
+				parameterMappings.add(parameterMapping);
+			}
+			builderAssistant.addParameterMap(id, parameterClass, parameterMappings);
+		}
+	}
+
+	private void resultMapElements(List<XNode> list) throws Exception {
+		for (XNode resultMapNode : list) {
+			try {
+				resultMapElement(resultMapNode);
+			} catch (IncompleteElementException e) {
+				// ignore, it will be retried
+			}
+		}
+	}
+
+	private ResultMap resultMapElement(XNode resultMapNode) throws Exception {
+		return resultMapElement(resultMapNode, Collections.<ResultMapping> emptyList());
+	}
+
+	private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings)
+			throws Exception {
+		ErrorContext.instance().activity("processing " + resultMapNode.getValueBasedIdentifier());
+		String id = resultMapNode.getStringAttribute("id", resultMapNode.getValueBasedIdentifier());
+		String type = resultMapNode.getStringAttribute("type", resultMapNode.getStringAttribute("ofType",
+				resultMapNode.getStringAttribute("resultType", resultMapNode.getStringAttribute("javaType"))));
+		String extend = resultMapNode.getStringAttribute("extends");
+		Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping");
+		Class<?> typeClass = resolveClass(type);
+		Discriminator discriminator = null;
+		List<ResultMapping> resultMappings = new ArrayList<ResultMapping>();
+		resultMappings.addAll(additionalResultMappings);
+		List<XNode> resultChildren = resultMapNode.getChildren();
+		for (XNode resultChild : resultChildren) {
+			if ("constructor".equals(resultChild.getName())) {
+				processConstructorElement(resultChild, typeClass, resultMappings);
+			} else if ("discriminator".equals(resultChild.getName())) {
+				discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings);
+			} else {
+				List<ResultFlag> flags = new ArrayList<ResultFlag>();
+				if ("id".equals(resultChild.getName())) {
+					flags.add(ResultFlag.ID);
+				}
+				resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));
+			}
+		}
+		ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend,
+				discriminator, resultMappings, autoMapping);
+		try {
+			return resultMapResolver.resolve();
+		} catch (IncompleteElementException e) {
+			configuration.addIncompleteResultMap(resultMapResolver);
+			throw e;
+		}
+	}
+
+	private void processConstructorElement(XNode resultChild, Class<?> resultType, List<ResultMapping> resultMappings)
+			throws Exception {
+		List<XNode> argChildren = resultChild.getChildren();
+		for (XNode argChild : argChildren) {
+			List<ResultFlag> flags = new ArrayList<ResultFlag>();
+			flags.add(ResultFlag.CONSTRUCTOR);
+			if ("idArg".equals(argChild.getName())) {
+				flags.add(ResultFlag.ID);
+			}
+			resultMappings.add(buildResultMappingFromContext(argChild, resultType, flags));
+		}
+	}
+
+	private Discriminator processDiscriminatorElement(XNode context, Class<?> resultType,
+			List<ResultMapping> resultMappings) throws Exception {
+		String column = context.getStringAttribute("column");
+		String javaType = context.getStringAttribute("javaType");
+		String jdbcType = context.getStringAttribute("jdbcType");
+		String typeHandler = context.getStringAttribute("typeHandler");
+		Class<?> javaTypeClass = resolveClass(javaType);
+		@SuppressWarnings("unchecked")
+		Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler);
+		JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
+		Map<String, String> discriminatorMap = new HashMap<String, String>();
+		for (XNode caseChild : context.getChildren()) {
+			String value = caseChild.getStringAttribute("value");
+			String resultMap = caseChild.getStringAttribute("resultMap",
+					processNestedResultMappings(caseChild, resultMappings));
+			discriminatorMap.put(value, resultMap);
+		}
+		return builderAssistant.buildDiscriminator(resultType, column, javaTypeClass, jdbcTypeEnum, typeHandlerClass,
+				discriminatorMap);
+	}
+
+	private void sqlElement(List<XNode> list) throws Exception {
+		if (configuration.getDatabaseId() != null) {
+			sqlElement(list, configuration.getDatabaseId());
+		}
+		sqlElement(list, null);
+	}
+
+	private void sqlElement(List<XNode> list, String requiredDatabaseId) throws Exception {
+		for (XNode context : list) {
+			String databaseId = context.getStringAttribute("databaseId");
+			String id = context.getStringAttribute("id");
+			id = builderAssistant.applyCurrentNamespace(id, false);
+			if (databaseIdMatchesCurrent(id, databaseId, requiredDatabaseId)) {
+				sqlFragments.put(id, context);
+			}
+		}
+	}
+
+	private boolean databaseIdMatchesCurrent(String id, String databaseId, String requiredDatabaseId) {
+		if (requiredDatabaseId != null) {
+			if (!requiredDatabaseId.equals(databaseId)) {
+				return false;
+			}
+		} else {
+			if (databaseId != null) {
+				return false;
+			}
+			// skip this fragment if there is a previous one with a not null
+			// databaseId
+			if (this.sqlFragments.containsKey(id)) {
+				XNode context = this.sqlFragments.get(id);
+				if (context.getStringAttribute("databaseId") != null) {
+					return false;
+				}
+			}
+		}
+		return true;
+	}
+
+	private ResultMapping buildResultMappingFromContext(XNode context, Class<?> resultType, List<ResultFlag> flags)
+			throws Exception {
+		String property = context.getStringAttribute("property");
+		String column = context.getStringAttribute("column");
+		String javaType = context.getStringAttribute("javaType");
+		String jdbcType = context.getStringAttribute("jdbcType");
+		String nestedSelect = context.getStringAttribute("select");
+		String nestedResultMap = context.getStringAttribute("resultMap",
+				processNestedResultMappings(context, Collections.<ResultMapping> emptyList()));
+		String notNullColumn = context.getStringAttribute("notNullColumn");
+		String columnPrefix = context.getStringAttribute("columnPrefix");
+		String typeHandler = context.getStringAttribute("typeHandler");
+		String resultSet = context.getStringAttribute("resultSet");
+		String foreignColumn = context.getStringAttribute("foreignColumn");
+		boolean lazy = "lazy".equals(
+				context.getStringAttribute("fetchType", configuration.isLazyLoadingEnabled() ? "lazy" : "eager"));
+		Class<?> javaTypeClass = resolveClass(javaType);
+		@SuppressWarnings("unchecked")
+		Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler);
+		JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
+		return builderAssistant.buildResultMapping(resultType, property, column, javaTypeClass, jdbcTypeEnum,
+				nestedSelect, nestedResultMap, notNullColumn, columnPrefix, typeHandlerClass, flags, resultSet,
+				foreignColumn, lazy);
+	}
+
+	private String processNestedResultMappings(XNode context, List<ResultMapping> resultMappings) throws Exception {
+		if ("association".equals(context.getName()) || "collection".equals(context.getName())
+				|| "case".equals(context.getName())) {
+			if (context.getStringAttribute("select") == null) {
+				ResultMap resultMap = resultMapElement(context, resultMappings);
+				return resultMap.getId();
+			}
+		}
+		return null;
+	}
+
+	private void bindMapperForNamespace() {
+		String namespace = builderAssistant.getCurrentNamespace();
+		if (namespace != null) {
+			Class<?> boundType = null;
+			try {
+				boundType = Resources.classForName(namespace);
+			} catch (ClassNotFoundException e) {
+				// ignore, bound type is not required
+			}
+			if (boundType != null) {
+				if (!configuration.hasMapper(boundType)) {
+					// Spring may not know the real resource name so we set a
+					// flag
+					// to prevent loading again this resource from the mapper
+					// interface
+					// look at MapperAnnotationBuilder#loadXmlResource
+					configuration.addLoadedResource("namespace:" + namespace);
+					configuration.addMapper(boundType);
+				}
+				//TODO 注入 CURD 动态 SQL
+				if (BaseMapper.class.isAssignableFrom(boundType)) {
+					GlobalConfiguration.getSqlInjector(configuration).inspectInject(builderAssistant, boundType);
+				}
+			}
+		}
+	}
 
 }

+ 376 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/activerecord/Model.java

@@ -0,0 +1,376 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.activerecord;
+
+import com.baomidou.mybatisplus.enums.SqlMethod;
+import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
+import com.baomidou.mybatisplus.mapper.Condition;
+import com.baomidou.mybatisplus.mapper.SqlHelper;
+import com.baomidou.mybatisplus.mapper.SqlRunner;
+import com.baomidou.mybatisplus.mapper.Wrapper;
+import com.baomidou.mybatisplus.plugins.Page;
+import com.baomidou.mybatisplus.toolkit.StringUtils;
+import org.apache.ibatis.session.SqlSession;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * ActiveRecord 模式 CRUD
+ * </p>
+ *
+ * @author hubin
+ * @param <T>
+ * @Date 2016-11-06
+ */
+@SuppressWarnings({ "serial", "rawtypes" })
+public abstract class Model<T extends Model> implements Serializable {
+
+	/**
+	 * <p>
+	 * 插入
+	 * </p>
+	 */
+	public boolean insert() {
+		return SqlHelper.retBool(sqlSession().insert(sqlStatement(SqlMethod.INSERT_ONE), this));
+	}
+
+	/**
+	 * <p>
+	 * 插入 OR 更新
+	 * </p>
+	 */
+	public boolean insertOrUpdate() {
+		if (StringUtils.checkValNull(pkVal())) {
+			// insert
+			return insert();
+		} else {
+			/*
+			 * 更新成功直接返回,失败执行插入逻辑
+			 */
+			boolean rlt = updateById();
+			if (!rlt) {
+				return insert();
+			}
+			return rlt;
+		}
+	}
+
+	/**
+	 * <p>
+	 * 根据 ID 删除
+	 * </p>
+	 *
+	 * @param id
+	 *            主键ID
+	 * @return
+	 */
+	public boolean deleteById(Serializable id) {
+		return SqlHelper.retBool(sqlSession().delete(sqlStatement(SqlMethod.DELETE_BY_ID), id));
+	}
+
+	/**
+	 * <p>
+	 * 根据主键删除
+	 * </p>
+	 *
+	 * @return
+	 */
+	public boolean deleteById() {
+		if (StringUtils.checkValNull(pkVal())) {
+			throw new MybatisPlusException("deleteById primaryKey is null.");
+		}
+		return deleteById(this.pkVal());
+	}
+
+	/**
+	 * <p>
+	 * 删除记录
+	 * </p>
+	 *
+	 * @param whereClause
+	 *            查询条件
+	 * @param args
+	 *            查询条件值
+	 * @return
+	 */
+	public boolean delete(String whereClause, Object... args) {
+		return delete(Condition.instance().where(whereClause, args));
+	}
+
+	/**
+	 * <p>
+	 * 删除记录
+	 * </p>
+	 *
+	 * @param wrapper
+	 * @return
+	 */
+	public boolean delete(Wrapper wrapper) {
+		Map<String, Object> map = new HashMap<String, Object>();
+		// delete
+		map.put("ew", wrapper);
+		return SqlHelper.retBool(sqlSession().delete(sqlStatement(SqlMethod.DELETE), map));
+	}
+
+	/**
+	 * <p>
+	 * 更新
+	 * </p>
+	 *
+	 * @return
+	 */
+	public boolean updateById() {
+		if (StringUtils.checkValNull(pkVal())) {
+			throw new MybatisPlusException("updateById primaryKey is null.");
+		}
+		// updateById
+		return SqlHelper.retBool(sqlSession().update(sqlStatement(SqlMethod.UPDATE_BY_ID), this));
+	}
+
+	/**
+	 * <p>
+	 * 执行 SQL 更新
+	 * </p>
+	 *
+	 * @param whereClause
+	 *            查询条件
+	 * @param args
+	 *            查询条件值
+	 * @return
+	 */
+	public boolean update(String whereClause, Object... args) {
+		// update
+		return update(Condition.instance().where(whereClause, args));
+	}
+
+	/**
+	 * <p>
+	 * 执行 SQL 更新
+	 * </p>
+	 *
+	 * @param wrapper
+	 * @return
+	 */
+	public boolean update(Wrapper wrapper) {
+		Map<String, Object> map = new HashMap<String, Object>();
+		map.put("et", this);
+		map.put("ew", wrapper);
+		// update
+		return SqlHelper.retBool(sqlSession().update(sqlStatement(SqlMethod.UPDATE), map));
+	}
+
+	/**
+	 * <p>
+	 * 查询所有
+	 * </p>
+	 *
+	 * @return
+	 */
+	public List<T> selectAll() {
+		return sqlSession().selectList(sqlStatement(SqlMethod.SELECT_LIST));
+	}
+
+	/**
+	 * <p>
+	 * 根据 ID 查询
+	 * </p>
+	 *
+	 * @param id
+	 *            主键ID
+	 * @return
+	 */
+	public T selectById(Serializable id) {
+		return sqlSession().selectOne(sqlStatement(SqlMethod.SELECT_BY_ID), id);
+	}
+
+	/**
+	 * <p>
+	 * 根据主键查询
+	 * </p>
+	 *
+	 * @return
+	 */
+	public T selectById() {
+		if (StringUtils.checkValNull(pkVal())) {
+			throw new MybatisPlusException("selectById primaryKey is null.");
+		}
+		return selectById(this.pkVal());
+	}
+
+	/**
+	 * <p>
+	 * 查询总记录数
+	 * </p>
+	 *
+	 * @param wrapper
+	 * @return
+	 */
+
+	public List<T> selectList(Wrapper wrapper) {
+		Map<String, Object> map = new HashMap<String, Object>();
+		map.put("ew", wrapper);
+		return sqlSession().selectList(sqlStatement(SqlMethod.SELECT_LIST), map);
+	}
+
+	/**
+	 * <p>
+	 * 查询所有
+	 * </p>
+	 *
+	 * @param whereClause
+	 * @param args
+	 * @return
+	 */
+	public List<T> selectList(String whereClause, Object... args) {
+		return selectList(Condition.instance().where(whereClause, args));
+	}
+
+	/**
+	 * <p>
+	 * 查询一条记录
+	 * </p>
+	 *
+	 * @param wrapper
+	 * @return
+	 */
+	public T selectOne(Wrapper wrapper) {
+		return SqlHelper.getObject(selectList(wrapper));
+	}
+
+	/**
+	 * <p>
+	 * 查询一条记录
+	 * </p>
+	 *
+	 * @param whereClause
+	 * @param args
+	 * @return
+	 */
+	public T selectOne(String whereClause, Object... args) {
+		return selectOne(Condition.instance().where(whereClause, args));
+	}
+
+	/**
+	 * <p>
+	 * 翻页查询
+	 * </p>
+	 *
+	 * @param page
+	 *            翻页查询条件
+	 * @param wrapper
+	 * @return
+	 */
+	public Page<T> selectPage(Page<T> page, Wrapper<T> wrapper) {
+		Map<String, Object> map = new HashMap<String, Object>();
+		SqlHelper.fillWrapper(page, wrapper);
+		map.put("ew", wrapper);
+		List<T> tl = sqlSession().selectList(sqlStatement(SqlMethod.SELECT_PAGE), map, page);
+		page.setRecords(tl);
+		return page;
+	}
+
+	/**
+	 * <p>
+	 * 查询所有(分页)
+	 * </p>
+	 *
+	 * @param page
+	 * @param whereClause
+	 * @param args
+	 * @return
+	 */
+	@SuppressWarnings("unchecked")
+	public Page<T> selectPage(Page<T> page, String whereClause, Object... args) {
+		return selectPage(page, Condition.instance().where(whereClause, args));
+	}
+
+	/**
+	 * <p>
+	 * 查询总数
+	 * </p>
+	 *
+	 * @param whereClause
+	 *            查询条件
+	 * @param args
+	 *            查询条件值
+	 * @return
+	 */
+	public int selectCount(String whereClause, Object... args) {
+		return selectCount(Condition.instance().where(whereClause, args));
+	}
+
+	/**
+	 * <p>
+	 * 查询总数
+	 * </p>
+	 *
+	 * @param wrapper
+	 * @return
+	 */
+	public int selectCount(Wrapper wrapper) {
+		Map<String, Object> map = new HashMap<String, Object>();
+		map.put("ew", wrapper);
+		return SqlHelper.retCount(sqlSession().<Integer> selectOne(sqlStatement(SqlMethod.SELECT_COUNT), map));
+	}
+
+	/**
+	 * <p>
+	 * 执行 SQL
+	 * </p>
+	 */
+	public SqlRunner sql() {
+		return new SqlRunner(getClass());
+	}
+
+	/**
+	 * <p>
+	 * 获取Session 默认自动提交
+	 * <p/>
+	 */
+	protected SqlSession sqlSession() {
+		return SqlHelper.sqlSession(getClass());
+	}
+
+	/**
+	 * 获取SqlStatement
+	 *
+	 * @param sqlMethod
+	 * @return
+	 */
+	protected String sqlStatement(SqlMethod sqlMethod) {
+		return sqlStatement(sqlMethod.getMethod());
+	}
+
+	/**
+	 * 获取SqlStatement
+	 *
+	 * @param sqlMethod
+	 * @return
+	 */
+	protected String sqlStatement(String sqlMethod) {
+		return SqlHelper.table(getClass()).getSqlStatement(sqlMethod);
+	}
+
+	/**
+	 * 主键值
+	 */
+	protected abstract Serializable pkVal();
+
+}

+ 28 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/activerecord/package-info.java

@@ -0,0 +1,28 @@
+/*
+ * The MIT License
+ *
+ * Copyright 2014 redraiment.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * ActiveRecord是Java的ORM框架,灵感来自Ruby on Rails的ActiveRecord。
+ */
+package com.baomidou.mybatisplus.activerecord;

+ 0 - 1
mybatis-plus/src/main/java/com/baomidou/mybatisplus/annotations/.gitignore

@@ -1 +0,0 @@
-/.DS_Store

+ 32 - 6
mybatis-plus/src/main/java/com/baomidou/mybatisplus/annotations/TableField.java

@@ -20,30 +20,56 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+import com.baomidou.mybatisplus.enums.FieldStrategy;
+
 /**
  * <p>
  * 表字段标识
  * </p>
  * 
- * @author hubin
- * @Date 2016-01-23
+ * @author hubin sjy
+ * @Date 2016-09-09
  */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.FIELD)
 public @interface TableField {
-	
+
 	/**
+	 * <p>
 	 * 字段值(驼峰命名方式,该值可无)
+	 * </p>
 	 */
 	String value() default "";
-	
+
+	/**
+	 * <p>
+	 * 当该Field为类对象时, 可使用#{对象.属性}来映射到数据表.
+	 * </p>
+	 * <p>
+	 * 支持:@TableField(el = "role, jdbcType=BIGINT)<br>
+	 * 支持:@TableField(el = "role, typeHandler=com.baomidou.xx.typehandler.PhoneTypeHandler")
+	 * </p>
+	 */
+	String el() default "";
+
 	/**
-	 * 
 	 * <p>
 	 * 是否为数据库表字段
 	 * </p>
+	 * <p>
 	 * 默认 true 存在,false 不存在
-	 * 
+	 * </p>
 	 */
 	boolean exist() default true;
+
+	/**
+	 * <p>
+	 * 字段验证
+	 * </p>
+	 * <p>
+	 * 默认 非 null 判断
+	 * </p>
+	 */
+	FieldStrategy validate() default FieldStrategy.NOT_NULL;
+
 }

+ 11 - 7
mybatis-plus/src/main/java/com/baomidou/mybatisplus/annotations/TableId.java

@@ -20,6 +20,8 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+import com.baomidou.mybatisplus.enums.IdType;
+
 /**
  * <p>
  * 表主键标识
@@ -32,17 +34,19 @@ import java.lang.annotation.Target;
 @Target(ElementType.FIELD)
 public @interface TableId {
 
-	/**
+	/*
+	 * <p>
 	 * 字段值(驼峰命名方式,该值可无)
+	 * </p>
 	 */
 	String value() default "";
 
-	/**
-	 * 
-	 * 主键ID,默认 ID 自增
-	 * 
+	/*
+	 * <p>
+	 * 主键ID,默认 INPUT
+	 * </p>
 	 * {@link IdType}
-	 * 
 	 */
-	IdType type() default IdType.ID_WORKER;
+	IdType type() default IdType.INPUT;
+
 }

+ 13 - 2
mybatis-plus/src/main/java/com/baomidou/mybatisplus/annotations/TableName.java

@@ -22,7 +22,7 @@ import java.lang.annotation.Target;
 
 /**
  * <p>
- * 数据库表
+ * 数据库表相关
  * </p>
  * 
  * @author hubin
@@ -32,7 +32,18 @@ import java.lang.annotation.Target;
 @Target(ElementType.TYPE)
 public @interface TableName {
 
-	/** 表名 **/
+	/*
+	 * <p>
+	 * 实体对应的表名
+	 * </p>
+	 */
 	String value() default "";
 
+	/*
+	 * <p>
+	 * 实体映射结果集
+	 * </p>
+	 */
+	String resultMap() default "";
+
 }

+ 41 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/entity/CountOptimize.java

@@ -0,0 +1,41 @@
+package com.baomidou.mybatisplus.entity;
+
+/**
+ * <p>
+ * 优化Count SQL实体
+ * </p>
+ *
+ * @author Caratacus
+ * @Date 2016-11-13
+ */
+public class CountOptimize {
+	/**
+	 * 是否排序
+	 */
+	private boolean orderBy = true;
+	/**
+	 * 优化后计算Count的SQL
+	 */
+	private String countSQL;
+
+	public boolean isOrderBy() {
+		return orderBy;
+	}
+
+	public void setOrderBy(boolean orderBy) {
+		this.orderBy = orderBy;
+	}
+
+	public String getCountSQL() {
+		return countSQL;
+	}
+
+	public void setCountSQL(String countSQL) {
+		this.countSQL = countSQL;
+	}
+
+	public static CountOptimize newInstance() {
+		return new CountOptimize();
+	}
+
+}

+ 395 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/entity/GlobalConfiguration.java

@@ -0,0 +1,395 @@
+/**
+ * Copyright (c) 2011-2014, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.entity;
+
+import com.baomidou.mybatisplus.enums.DBType;
+import com.baomidou.mybatisplus.enums.FieldStrategy;
+import com.baomidou.mybatisplus.enums.IdType;
+import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
+import com.baomidou.mybatisplus.mapper.AutoSqlInjector;
+import com.baomidou.mybatisplus.mapper.IMetaObjectHandler;
+import com.baomidou.mybatisplus.mapper.ISqlInjector;
+import com.baomidou.mybatisplus.toolkit.IOUtils;
+import com.baomidou.mybatisplus.toolkit.JdbcUtils;
+import com.baomidou.mybatisplus.toolkit.SqlReservedWords;
+import com.baomidou.mybatisplus.toolkit.StringUtils;
+import com.baomidou.mybatisplus.toolkit.TableInfoHelper;
+import org.apache.ibatis.logging.Log;
+import org.apache.ibatis.logging.LogFactory;
+import org.apache.ibatis.session.Configuration;
+import org.apache.ibatis.session.ExecutorType;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.mybatis.spring.SqlSessionTemplate;
+
+import javax.sql.DataSource;
+import java.io.Serializable;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentSkipListSet;
+
+/**
+ * <p>
+ * Mybatis全局缓存
+ * </p>
+ *
+ * @author Caratacus
+ * @Date 2016-12-06
+ */
+@SuppressWarnings("serial")
+public class GlobalConfiguration implements Cloneable, Serializable {
+
+	// 日志
+	private static final Log logger = LogFactory.getLog(GlobalConfiguration.class);
+	/**
+	 * 缓存全局信息
+	 */
+	private static final Map<String, GlobalConfiguration> GLOBAL_CONFIG = new ConcurrentHashMap<String, GlobalConfiguration>();
+	/**
+	 * 默认参数
+	 */
+	public static final GlobalConfiguration DEFAULT = new GlobalConfiguration();
+
+	// 数据库类型(默认 MySql)
+	private DBType dbType = DBType.MYSQL;
+	// 主键类型(默认 ID_WORKER)
+	private IdType idType = IdType.ID_WORKER;
+	// 表名、字段名、是否使用下划线命名(默认 false)
+	private boolean dbColumnUnderline = false;
+	// SQL注入器
+	private ISqlInjector sqlInjector;
+	// 元对象字段填充控制器
+	private IMetaObjectHandler metaObjectHandler = null;
+	// 字段验证策略
+	private FieldStrategy fieldStrategy = FieldStrategy.NOT_NULL;
+	// 是否刷新mapper
+	private boolean isRefresh = false;
+	// 是否自动获取DBType
+	private boolean isAutoSetDbType = true;
+	// 是否大写命名
+	private boolean isCapitalMode = false;
+	// 标识符
+	private String identifierQuote;
+	// 缓存当前Configuration的SqlSessionFactory
+	private SqlSessionFactory sqlSessionFactory;
+	// 缓存已注入CRUD的Mapper信息
+	private Set<String> mapperRegistryCache = new ConcurrentSkipListSet<String>();
+	// 单例重用SqlSession
+	private SqlSession sqlSession;
+	// 批量SqlSession
+	private SqlSession sqlsessionBatch;
+
+	public GlobalConfiguration() {
+		// 构造方法
+	}
+
+	public GlobalConfiguration(ISqlInjector sqlInjector) {
+		this.sqlInjector = sqlInjector;
+	}
+
+	public DBType getDbType() {
+		return dbType;
+	}
+
+	public void setDbType(String dbType) {
+		this.dbType = DBType.getDBType(dbType);
+		this.isAutoSetDbType = false;
+	}
+
+	public void setDbTypeByJdbcUrl(String jdbcUrl) {
+		this.dbType = JdbcUtils.getDbType(jdbcUrl);
+	}
+
+	public IdType getIdType() {
+		return idType;
+	}
+
+	public void setIdType(int idType) {
+		this.idType = IdType.getIdType(idType);
+	}
+
+	public boolean isDbColumnUnderline() {
+		return dbColumnUnderline;
+	}
+
+	public void setDbColumnUnderline(boolean dbColumnUnderline) {
+		this.dbColumnUnderline = dbColumnUnderline;
+	}
+
+	public ISqlInjector getSqlInjector() {
+		return sqlInjector;
+	}
+
+	public void setSqlInjector(ISqlInjector sqlInjector) {
+		this.sqlInjector = sqlInjector;
+	}
+
+	public IMetaObjectHandler getMetaObjectHandler() {
+		return metaObjectHandler;
+	}
+
+	public void setMetaObjectHandler(IMetaObjectHandler metaObjectHandler) {
+		this.metaObjectHandler = metaObjectHandler;
+	}
+
+	public FieldStrategy getFieldStrategy() {
+		return fieldStrategy;
+	}
+
+	public void setFieldStrategy(int fieldStrategy) {
+		this.fieldStrategy = FieldStrategy.getFieldStrategy(fieldStrategy);
+	}
+
+	public boolean isRefresh() {
+		return isRefresh;
+	}
+
+	public void setRefresh(boolean refresh) {
+		this.isRefresh = refresh;
+	}
+
+	public boolean isAutoSetDbType() {
+		return isAutoSetDbType;
+	}
+
+	public void setAutoSetDbType(boolean autoSetDbType) {
+		this.isAutoSetDbType = autoSetDbType;
+	}
+
+	public Set<String> getMapperRegistryCache() {
+		return mapperRegistryCache;
+	}
+
+	public void setMapperRegistryCache(Set<String> mapperRegistryCache) {
+		this.mapperRegistryCache = mapperRegistryCache;
+	}
+
+	public SqlSessionFactory getSqlSessionFactory() {
+		return sqlSessionFactory;
+	}
+
+	public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) {
+		this.sqlSessionFactory = sqlSessionFactory;
+		this.sqlSession = new SqlSessionTemplate(sqlSessionFactory);
+		this.sqlsessionBatch = new SqlSessionTemplate(sqlSessionFactory, ExecutorType.BATCH);
+	}
+
+	public boolean isCapitalMode() {
+		return isCapitalMode;
+	}
+
+	public void setCapitalMode(boolean isCapitalMode) {
+		this.isCapitalMode = isCapitalMode;
+	}
+
+	public String getIdentifierQuote() {
+		return identifierQuote;
+	}
+
+	public void setIdentifierQuote(String identifierQuote) {
+		this.identifierQuote = identifierQuote;
+	}
+
+	public void setSqlKeywords(String sqlKeywords) {
+		if (StringUtils.isNotEmpty(sqlKeywords)) {
+			SqlReservedWords.RESERVED_WORDS.addAll(StringUtils.splitWorker(sqlKeywords.toUpperCase(), ",", -1, false));
+		}
+	}
+
+	public SqlSession getSqlSession() {
+		return sqlSession;
+	}
+
+	public SqlSession getSqlsessionBatch() {
+		return sqlsessionBatch;
+	}
+
+	@Override
+	protected GlobalConfiguration clone() throws CloneNotSupportedException {
+		return (GlobalConfiguration) super.clone();
+	}
+
+	/**
+	 * 获取当前的SqlSessionFactory
+	 *
+	 * @param clazz
+	 * @return
+	 */
+	public static SqlSessionFactory currentSessionFactory(Class<?> clazz) {
+		String configMark = TableInfoHelper.getTableInfo(clazz).getConfigMark();
+		GlobalConfiguration mybatisGlobalConfig = GlobalConfiguration.getGlobalConfig(configMark);
+		return mybatisGlobalConfig.getSqlSessionFactory();
+	}
+
+	/**
+	 * 获取默认MybatisGlobalConfig
+	 *
+	 * @return
+	 */
+	public static GlobalConfiguration defaults() {
+		try {
+			GlobalConfiguration clone = DEFAULT.clone();
+			clone.setSqlInjector(new AutoSqlInjector());
+			return clone;
+		} catch (CloneNotSupportedException e) {
+			throw new MybatisPlusException("ERROR: CLONE MybatisGlobalConfig DEFAULT FAIL !  Cause:" + e);
+		}
+	}
+
+	/**
+	 * <p>
+	 * 设置全局设置(以configuration地址值作为Key)
+	 * <p/>
+	 *
+	 * @param configuration
+	 * @param mybatisGlobalConfig
+	 * @return
+	 */
+	public static void setGlobalConfig(Configuration configuration, GlobalConfiguration mybatisGlobalConfig) {
+		if (configuration == null || mybatisGlobalConfig == null) {
+			new MybatisPlusException("Error: Could not setGlobalConfig");
+		}
+		// 设置全局设置
+		GLOBAL_CONFIG.put(configuration.toString(), mybatisGlobalConfig);
+	}
+
+	/**
+	 * <p>
+	 * 标记全局设置 (统一所有入口)
+	 * </p>
+	 *
+	 * @param sqlSessionFactory
+	 * @return
+	 */
+	public SqlSessionFactory signGlobalConfig(SqlSessionFactory sqlSessionFactory) {
+		if (null != sqlSessionFactory) {
+			setGlobalConfig(sqlSessionFactory.getConfiguration(), this);
+		}
+		return sqlSessionFactory;
+	}
+
+	/**
+	 * 获取MybatisGlobalConfig (统一所有入口)
+	 *
+	 * @param configuration
+	 * @return
+	 */
+	public static GlobalConfiguration getGlobalConfig(Configuration configuration) {
+		if (configuration == null) {
+			throw new MybatisPlusException("Error: You need Initialize MybatisConfiguration !");
+		}
+		return getGlobalConfig(configuration.toString());
+	}
+
+	/**
+	 * 获取MybatisGlobalConfig (统一所有入口)
+	 *
+	 * @param configMark
+	 * @return
+	 */
+	public static GlobalConfiguration getGlobalConfig(String configMark) {
+		GlobalConfiguration cache = GLOBAL_CONFIG.get(configMark);
+		if (cache == null) {
+			// 没有获取全局配置初始全局配置
+			logger.debug("DeBug: MyBatis Plus Global configuration Initializing !");
+			GLOBAL_CONFIG.put(configMark, DEFAULT);
+			return DEFAULT;
+		}
+		return cache;
+	}
+
+	public static DBType getDbType(Configuration configuration) {
+		return getGlobalConfig(configuration).getDbType();
+	}
+
+	public static IdType getIdType(Configuration configuration) {
+		return getGlobalConfig(configuration).getIdType();
+	}
+
+	public static boolean isDbColumnUnderline(Configuration configuration) {
+		return getGlobalConfig(configuration).isDbColumnUnderline();
+	}
+
+	public static ISqlInjector getSqlInjector(Configuration configuration) {
+		// fix #140
+		GlobalConfiguration globalConfiguration = getGlobalConfig(configuration);
+		ISqlInjector sqlInjector = globalConfiguration.getSqlInjector();
+		if (sqlInjector == null) {
+			sqlInjector = new AutoSqlInjector();
+			globalConfiguration.setSqlInjector(sqlInjector);
+		}
+		return sqlInjector;
+	}
+
+	public static IMetaObjectHandler getMetaObjectHandler(Configuration configuration) {
+		return getGlobalConfig(configuration).getMetaObjectHandler();
+	}
+
+	public static FieldStrategy getFieldStrategy(Configuration configuration) {
+		return getGlobalConfig(configuration).getFieldStrategy();
+	}
+
+	public static boolean isRefresh(Configuration configuration) {
+		return getGlobalConfig(configuration).isRefresh();
+	}
+
+	public static boolean isAutoSetDbType(Configuration configuration) {
+		return getGlobalConfig(configuration).isAutoSetDbType();
+	}
+
+	public static Set<String> getMapperRegistryCache(Configuration configuration) {
+		return getGlobalConfig(configuration).getMapperRegistryCache();
+	}
+
+	public static String getIdentifierQuote(Configuration configuration) {
+		return getGlobalConfig(configuration).getIdentifierQuote();
+	}
+
+	public static SqlSession getSqlSession(Configuration configuration) {
+		return getGlobalConfig(configuration).getSqlSession();
+	}
+
+	public static SqlSession getSqlsessionBatch(Configuration configuration) {
+		return getGlobalConfig(configuration).getSqlsessionBatch();
+	}
+
+	/**
+	 * 设置元数据相关属性
+	 *
+	 * @param dataSource
+	 * @param globalConfig
+	 */
+	public static void setMetaData(DataSource dataSource, GlobalConfiguration globalConfig) {
+		Connection connection = null;
+		try {
+			connection = dataSource.getConnection();
+			String jdbcUrl = connection.getMetaData().getURL();
+			// 设置全局关键字
+			globalConfig.setSqlKeywords(connection.getMetaData().getSQLKeywords());
+			// 自动设置数据库类型
+			if (globalConfig.isAutoSetDbType()) {
+				globalConfig.setDbTypeByJdbcUrl(jdbcUrl);
+			}
+		} catch (SQLException e) {
+			logger.warn("Warn: GlobalConfiguration setMetaData Fail !  Cause:" + e);
+		} finally {
+			IOUtils.closeQuietly(connection);
+		}
+	}
+}

+ 158 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/entity/TableFieldInfo.java

@@ -0,0 +1,158 @@
+/**
+ * Copyright (c) 2011-2014, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.entity;
+
+import com.baomidou.mybatisplus.enums.FieldStrategy;
+import com.baomidou.mybatisplus.toolkit.SqlReservedWords;
+import com.baomidou.mybatisplus.toolkit.StringUtils;
+
+/**
+ * <p>
+ * 数据库表字段反射信息
+ * </p>
+ *
+ * @author hubin sjy
+ * @Date 2016-09-09
+ */
+public class TableFieldInfo {
+
+	/**
+	 * <p>
+	 * 是否有存在字段名与属性名关联
+	 * </p>
+	 * true , false
+	 */
+	private boolean related = false;
+
+	/**
+	 * 字段名
+	 */
+	private String column;
+
+	/**
+	 * 属性名
+	 */
+	private String property;
+
+	/**
+	 * 属性表达式#{property}, 可以指定jdbcType, typeHandler等
+	 */
+	private String el;
+	/**
+	 * 属性类型
+	 */
+	private String propertyType;
+
+	/**
+	 * 字段策略【 默认,自判断 null 】
+	 */
+	private FieldStrategy fieldStrategy = FieldStrategy.NOT_NULL;
+
+	/**
+	 * <p>
+	 * 存在 TableField 注解构造函数
+	 * </p>
+	 */
+	public TableFieldInfo(GlobalConfiguration globalConfig, String column, String property, String el,
+			FieldStrategy fieldStrategy, String propertyType) {
+		if (globalConfig.isDbColumnUnderline()) {
+			/* 开启字段下划线申明 */
+			this.related = true;
+		} else if (!column.equals(property)) {
+			/* 没有开启下划线申明 但是column与property不等的情况下设置related为true */
+			this.related = true;
+		}
+		this.setColumn(globalConfig, column);
+		this.property = property;
+		this.el = el;
+		/*
+		 * 优先使用单个字段注解,否则使用全局配置
+		 */
+		if (fieldStrategy != FieldStrategy.NOT_NULL) {
+			this.fieldStrategy = fieldStrategy;
+		} else {
+			this.fieldStrategy = globalConfig.getFieldStrategy();
+		}
+		this.propertyType = propertyType;
+	}
+
+	public TableFieldInfo(GlobalConfiguration globalConfig, String column, String propertyType) {
+		if (globalConfig.isDbColumnUnderline()) {
+			/* 开启字段下划线申明 */
+			this.related = true;
+			this.setColumn(globalConfig, StringUtils.camelToUnderline(column));
+		} else {
+			this.setColumn(globalConfig, column);
+		}
+		this.property = column;
+		this.el = column;
+		this.fieldStrategy = globalConfig.getFieldStrategy();
+		this.propertyType = propertyType;
+	}
+
+	public boolean isRelated() {
+		return related;
+	}
+
+	public void setRelated(boolean related) {
+		this.related = related;
+	}
+
+	public String getColumn() {
+		return column;
+	}
+
+	public void setColumn(GlobalConfiguration globalConfig, String column) {
+		String temp = SqlReservedWords.convert(globalConfig, column);
+		if (globalConfig.isCapitalMode() && !isRelated()) {
+			// 全局大写,非注解指定
+			temp = temp.toUpperCase();
+		}
+		this.column = temp;
+	}
+
+	public String getProperty() {
+		return property;
+	}
+
+	public void setProperty(String property) {
+		this.property = property;
+	}
+
+	public String getEl() {
+		return el;
+	}
+
+	public void setEl(String el) {
+		this.el = el;
+	}
+
+	public FieldStrategy getFieldStrategy() {
+		return fieldStrategy;
+	}
+
+	public void setFieldStrategy(FieldStrategy fieldStrategy) {
+		this.fieldStrategy = fieldStrategy;
+	}
+
+	public String getPropertyType() {
+		return propertyType;
+	}
+
+	public void setPropertyType(String propertyType) {
+		this.propertyType = propertyType;
+	}
+}

+ 67 - 18
mybatis-plus/src/main/java/com/baomidou/mybatisplus/toolkit/TableInfo.java → mybatis-plus/src/main/java/com/baomidou/mybatisplus/entity/TableInfo.java

@@ -13,11 +13,14 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.baomidou.mybatisplus.toolkit;
+package com.baomidou.mybatisplus.entity;
 
 import java.util.List;
 
-import com.baomidou.mybatisplus.annotations.IdType;
+import org.apache.ibatis.session.Configuration;
+
+import com.baomidou.mybatisplus.enums.IdType;
+import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
 
 /**
  * <p>
@@ -39,6 +42,11 @@ public class TableInfo {
 	 */
 	private String tableName;
 
+	/**
+	 * 表映射结果集
+	 */
+	private String resultMap;
+
 	/**
 	 * <p>
 	 * 主键是否有存在字段名与属性名关联
@@ -62,64 +70,105 @@ public class TableInfo {
 	 */
 	private List<TableFieldInfo> fieldList;
 
+	/**
+	 * 命名空间
+	 */
+	private String currentNamespace;
+	/**
+	 * MybatisConfiguration 标记 (Configuration内存地址值)
+	 */
+	private String configMark;
+
+	/**
+	 * <p>
+	 * 获得注入的 SQL Statement
+	 * </p>
+	 * 
+	 * @param sqlMethod
+	 *            MybatisPlus 支持 SQL 方法
+	 * @return
+	 */
+	public String getSqlStatement(String sqlMethod) {
+		StringBuffer statement = new StringBuffer();
+		statement.append(currentNamespace);
+		statement.append(".");
+		statement.append(sqlMethod);
+		return statement.toString();
+	}
 
 	public IdType getIdType() {
 		return idType;
 	}
 
-
-	public void setIdType( IdType idType ) {
+	public void setIdType(IdType idType) {
 		this.idType = idType;
 	}
 
-
 	public String getTableName() {
 		return tableName;
 	}
 
-
-	public void setTableName( String tableName ) {
+	public void setTableName(String tableName) {
 		this.tableName = tableName;
 	}
 
+	public String getResultMap() {
+		return resultMap;
+	}
+
+	public void setResultMap(String resultMap) {
+		this.resultMap = resultMap;
+	}
 
 	public boolean isKeyRelated() {
 		return keyRelated;
 	}
 
-
-	public void setKeyRelated( boolean keyRelated ) {
+	public void setKeyRelated(boolean keyRelated) {
 		this.keyRelated = keyRelated;
 	}
 
-
 	public String getKeyProperty() {
 		return keyProperty;
 	}
 
-
-	public void setKeyProperty( String keyProperty ) {
+	public void setKeyProperty(String keyProperty) {
 		this.keyProperty = keyProperty;
 	}
 
-
 	public String getKeyColumn() {
 		return keyColumn;
 	}
 
-
-	public void setKeyColumn( String keyColumn ) {
+	public void setKeyColumn(String keyColumn) {
 		this.keyColumn = keyColumn;
 	}
 
-
 	public List<TableFieldInfo> getFieldList() {
 		return fieldList;
 	}
 
-
-	public void setFieldList( List<TableFieldInfo> fieldList ) {
+	public void setFieldList(List<TableFieldInfo> fieldList) {
 		this.fieldList = fieldList;
 	}
 
+	public String getCurrentNamespace() {
+		return currentNamespace;
+	}
+
+	public void setCurrentNamespace(String currentNamespace) {
+		this.currentNamespace = currentNamespace;
+	}
+
+	public String getConfigMark() {
+		return configMark;
+	}
+
+	public void setConfigMark(Configuration configuration) {
+		if (configuration == null) {
+			throw new MybatisPlusException("Error: You need Initialize MybatisConfiguration !");
+		}
+		this.configMark = configuration.toString();
+	}
+
 }

+ 4 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/entity/package-info.java

@@ -0,0 +1,4 @@
+/**
+ * 实体类
+ */
+package com.baomidou.mybatisplus.entity;

+ 111 - 68
mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/DBType.java → mybatis-plus/src/main/java/com/baomidou/mybatisplus/enums/DBType.java

@@ -1,68 +1,111 @@
-/**
- * Copyright (c) 2011-2014, hubin (jobob@qq.com).
- *
- * 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.baomidou.mybatisplus.mapper;
-
-/**
- * <p>
- * MybatisPlus 数据库类型
- * </p>
- * 
- * @author hubin
- * @Date 2016-04-15
- */
-public enum DBType {
-	MYSQL("mysql", "MySql数据库"), ORACLE("oracle", "Oracle数据库");
-
-	private final String db;
-
-	private final String desc;
-
-
-	DBType( final String db, final String desc ) {
-		this.db = db;
-		this.desc = desc;
-	}
-
-
-	/**
-	 * <p>
-	 * 获取数据库类型(默认 MySql)
-	 * </p>
-	 * 
-	 * @param dbType
-	 *            数据库类型字符串
-	 * @return
-	 */
-	public static DBType getDBType( String dbType ) {
-		for ( DBType dt : DBType.values() ) {
-			if ( dt.getDb().equals(dbType) ) {
-				return dt;
-			}
-		}
-		return MYSQL;
-	}
-
-
-	public String getDb() {
-		return this.db;
-	}
-
-
-	public String getDesc() {
-		return this.desc;
-	}
-
-}
+/**
+ * Copyright (c) 2011-2014, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.enums;
+
+/**
+ * <p>
+ * MybatisPlus 数据库类型
+ * </p>
+ *
+ * @author hubin
+ * @Date 2016-04-15
+ */
+public enum DBType {
+	/**
+	 * MYSQL
+	 */
+	MYSQL("mysql", "`%s`", "MySql数据库"),
+	/**
+	 * ORACLE
+	 */
+	ORACLE("oracle", "", "Oracle数据库"),
+	/**
+	 * DB2
+	 */
+	DB2("db2", "", "DB2数据库"),
+	/**
+	 * H2
+	 */
+	H2("h2", "", "H2数据库"),
+	/**
+	 * HSQL
+	 */
+	HSQL("hsql", "", "HSQL数据库"),
+	/**
+	 * SQLITE
+	 */
+	SQLITE("sqlite", "`%s`", "SQLite数据库"),
+	/**
+	 * POSTGRE
+	 */
+	POSTGRE("postgresql", "", "Postgre数据库"),
+	/**
+	 * SQLSERVER2005
+	 */
+	SQLSERVER2005("sqlserver2005", "[%s]", "SQLServer2005数据库"),
+	/**
+	 * SQLSERVER
+	 */
+	SQLSERVER("sqlserver", "[%s]", "SQLServer数据库"),
+	/**
+	 * UNKONWN DB
+	 */
+	OTHER("other", "", "其他数据库");
+
+	private final String db;
+
+	private final String quote;
+
+	private final String desc;
+
+	DBType(final String db, final String quote, final String desc) {
+		this.db = db;
+		this.quote = quote;
+		this.desc = desc;
+	}
+
+	/**
+	 * <p>
+	 * 获取数据库类型(默认 MySql)
+	 * </p>
+	 *
+	 * @param dbType
+	 *            数据库类型字符串
+	 * @return
+	 */
+	public static DBType getDBType(String dbType) {
+		DBType[] dts = DBType.values();
+		for (DBType dt : dts) {
+			if (dt.getDb().equalsIgnoreCase(dbType)) {
+				return dt;
+			}
+		}
+		return MYSQL;
+	}
+
+	public String getDb() {
+		return this.db;
+	}
+
+	public String getQuote() {
+		return this.quote;
+	}
+
+	public String getDesc() {
+		return this.desc;
+	}
+
+}

+ 58 - 49
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/ConfigIdType.java → mybatis-plus/src/main/java/com/baomidou/mybatisplus/enums/FieldStrategy.java

@@ -1,49 +1,58 @@
-/**
- * Copyright (c) 2011-2014, hubin (jobob@qq.com).
- *
- * 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.baomidou.mybatisplus.generator;
-
-/**
- * <p>
- * 数据库表ID类型枚举类
- * </p>
- * 
- * @author hubin
- * @Date 2016-04-21
- */
-public enum ConfigIdType {
-	LONG("0", "Long 类型,主键 ID"),
-	STRING("1", "String 类型,主键 ID"),;
-
-	/** 主键 */
-	private final String key;
-
-	/** 描述 */
-	private final String desc;
-
-	ConfigIdType(final String key, final String desc) {
-		this.key = key;
-		this.desc = desc;
-	}
-
-	public String getKey() {
-		return this.key;
-	}
-
-	public String getDesc() {
-		return this.desc;
-	}
-
-}
+/**
+ * Copyright (c) 2011-2014, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.enums;
+
+/**
+ * <p>
+ * 字段策略枚举类
+ * </p>
+ * 
+ * @author hubin
+ * @Date 2016-09-09
+ */
+public enum FieldStrategy {
+	IGNORED(0, "ignored"), NOT_NULL(1, "not null"), NOT_EMPTY(2, "not empty");
+
+	/** 主键 */
+	private final int key;
+
+	/** 描述 */
+	private final String desc;
+
+	FieldStrategy(final int key, final String desc) {
+		this.key = key;
+		this.desc = desc;
+	}
+
+	public int getKey() {
+		return this.key;
+	}
+
+	public String getDesc() {
+		return this.desc;
+	}
+
+	public static FieldStrategy getFieldStrategy(int key) {
+		FieldStrategy[] fss = FieldStrategy.values();
+		for (FieldStrategy fs : fss) {
+			if (fs.getKey() == key) {
+				return fs;
+			}
+		}
+		return FieldStrategy.NOT_NULL;
+	}
+
+}

+ 70 - 53
mybatis-plus/src/main/java/com/baomidou/mybatisplus/annotations/IdType.java → mybatis-plus/src/main/java/com/baomidou/mybatisplus/enums/IdType.java

@@ -1,53 +1,70 @@
-/**
- * Copyright (c) 2011-2014, hubin (jobob@qq.com).
- *
- * 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.baomidou.mybatisplus.annotations;
-
-/**
- * <p>
- * 生成ID类型枚举类
- * </p>
- * 
- * @author hubin
- * @Date 2015-11-10
- */
-public enum IdType {
-	AUTO(0, "数据库ID自增"),
-	INPUT(1, "用户输入ID"),
-	
-	/* 以下2种类型、只有当插入对象ID 为空,才自动填充。 */
-	ID_WORKER(2, "全局唯一ID"),
-	UUID(3, "全局唯一ID");
-
-	/** 主键 */
-	private final int key;
-
-	/** 描述 */
-	private final String desc;
-
-	IdType(final int key, final String desc) {
-		this.key = key;
-		this.desc = desc;
-	}
-
-	public int getKey() {
-		return this.key;
-	}
-
-	public String getDesc() {
-		return this.desc;
-	}
-
-}
+/**
+ * Copyright (c) 2011-2014, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.enums;
+
+/**
+ * <p>
+ * 生成ID类型枚举类
+ * </p>
+ * 
+ * @author hubin
+ * @Date 2015-11-10
+ */
+public enum IdType {
+	AUTO(0, "数据库ID自增"), INPUT(1, "用户输入ID"),
+
+	/* 以下2种类型、只有当插入对象ID 为空,才自动填充。 */
+	ID_WORKER(2, "全局唯一ID"), UUID(3, "全局唯一ID");
+
+	/** 主键 */
+	private final int key;
+
+	/** 描述 */
+	private final String desc;
+
+	IdType(final int key, final String desc) {
+		this.key = key;
+		this.desc = desc;
+	}
+
+	/**
+	 * <p>
+	 * 主键策略 (默认 ID_WORKER)
+	 * </p>
+	 * 
+	 * @param idType
+	 *            ID 策略类型
+	 * @return
+	 */
+	public static IdType getIdType(int idType) {
+		IdType[] its = IdType.values();
+		for (IdType it : its) {
+			if (it.getKey() == idType) {
+				return it;
+			}
+		}
+		return ID_WORKER;
+	}
+
+	public int getKey() {
+		return this.key;
+	}
+
+	public String getDesc() {
+		return this.desc;
+	}
+
+}

+ 75 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/enums/Optimize.java

@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) 2011-2014, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.enums;
+
+/**
+ * <p>
+ * Count优化枚举
+ * </p>
+ * 
+ * @author Caratacus
+ * @Date 2016-11-30
+ */
+public enum Optimize {
+	/**
+	 * 默认支持方式
+	 */
+	DEFAULT("default", "默认方式"),
+	/**
+	 * aliDruid,需添加相关依赖jar包
+	 */
+	ALI_DRUID("aliDruid", "依赖aliDruid模式"),
+	/**
+	 * jsqlparser方式,需添加相关依赖jar包
+	 */
+	JSQLPARSER("jsqlparser", "jsqlparser方式");
+
+	private final String optimize;
+
+	private final String desc;
+
+	Optimize(final String optimize, final String desc) {
+		this.optimize = optimize;
+		this.desc = desc;
+	}
+
+	/**
+	 * <p>
+	 * 获取优化类型.如果没有找到默认DEFAULT
+	 * </p>
+	 * 
+	 * @param optimizeType
+	 *            优化方式
+	 * @return
+	 */
+	public static Optimize getOptimizeType(String optimizeType) {
+		for (Optimize optimize : Optimize.values()) {
+			if (optimize.getOptimize().equalsIgnoreCase(optimizeType)) {
+				return optimize;
+			}
+		}
+		return DEFAULT;
+	}
+
+	public String getOptimize() {
+		return this.optimize;
+	}
+
+	public String getDesc() {
+		return this.desc;
+	}
+
+}

+ 63 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/enums/SqlLike.java

@@ -0,0 +1,63 @@
+/**
+ * Copyright (c) 2011-2014, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.enums;
+
+/**
+ * <p>
+ * SQL like 枚举
+ * </p>
+ * 
+ * @author Caratacus
+ * @Date 2016-12-4
+ */
+public enum SqlLike {
+	/**
+	 * LEFT
+	 */
+	LEFT("left", "左边%"),
+	/**
+	 * RIGHT
+	 */
+	RIGHT("right", "右边%"),
+	/**
+	 * CUSTOM
+	 */
+	CUSTOM("custom", "定制"),
+	/**
+	 * DEFAULT
+	 */
+	DEFAULT("default", "两边%");
+
+	/** 主键 */
+	private final String type;
+
+	/** 描述 */
+	private final String desc;
+
+	SqlLike(final String type, final String desc) {
+		this.type = type;
+		this.desc = desc;
+	}
+
+	public String getType() {
+		return type;
+	}
+
+	public String getDesc() {
+		return desc;
+	}
+
+}

+ 89 - 91
mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/SqlMethod.java → mybatis-plus/src/main/java/com/baomidou/mybatisplus/enums/SqlMethod.java

@@ -1,91 +1,89 @@
-/**
- * Copyright (c) 2011-2014, hubin (jobob@qq.com).
- *
- * 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.baomidou.mybatisplus.mapper;
-
-/**
- * <p>
- * MybatisPlus 支持 SQL 方法
- * </p>
- * 
- * @author hubin
- * @Date 2016-01-23
- */
-public enum SqlMethod {
-
-	/**
-	 * 插入
-	 */
-	INSERT_ONE("insert", "插入一条数据", "<script>INSERT INTO %s %s VALUES %s</script>"),
-	INSERT_ONE_SELECTIVE("insertSelective", "插入一条数据(选择字段, null 字段不插入)", "<script>INSERT INTO %s %s VALUES %s</script>"),
-	INSERT_BATCH_MYSQL("insertBatch", "mysql 批量插入数据", "<script>INSERT INTO %s %s VALUES \n<foreach item=\"item\" index=\"index\" collection=\"list\" separator=\",\">%s\n</foreach></script>"),
-	INSERT_BATCH_ORACLE("insertBatch", "oracle 批量插入数据", "<script>INSERT INTO %s %s \n<foreach item=\"item\" index=\"index\" collection=\"list\" separator=\"UNION ALL\">%s\n</foreach></script>"),
-	
-	/**
-	 * 删除
-	 */
-	DELETE_BY_ID("deleteById", "根据ID 删除一条数据", "DELETE FROM %s WHERE %s=#{%s}"),
-	DELETE_SELECTIVE("deleteSelective", "根据 entity 条件删除记录", "<script>DELETE FROM %s %s</script>"),
-	DELETE_BATCH("deleteBatchIds", "根据ID集合,批量删除数据", "<script>DELETE FROM %s WHERE %s IN (%s)</script>"),
-	
-	/**
-	 * 修改
-	 */
-	UPDATE_BY_ID("updateById", "根据ID 修改数据", "<script>UPDATE %s %s WHERE %s=#{et.%s}</script>"),
-	UPDATE_BATCH_BY_ID_MYSQL("updateBatchById", "mysql 根据ID 批量修改数据", "<script>UPDATE %s %s WHERE %s IN (<foreach collection=\"list\" separator=\",\" item=\"i\" index=\"index\">#{i.%s}</foreach>)</script>"),
-	UPDATE_BATCH_BY_ID_ORACLE("updateBatchById", "oracle 根据ID 批量修改数据", "<script><foreach collection=\"list\" item=\"item\" index=\"index\" open=\"BEGIN\" close=\";END;\" separator=\";\">UPDATE %s %s WHERE %s=#{item.%s}</foreach></script>"),
-	UPDATE_SELECTIVE_BY_ID("updateSelectiveById", "根据ID 选择修改数据", "<script>UPDATE %s %s WHERE %s=#{et.%s}</script>"),
-	UPDATE("update", "根据 whereEntity 条件,更新记录", "<script>UPDATE %s %s %s</script>"),
-	UPDATE_SELECTIVE("updateSelective", "根据 whereEntity 条件,选择更新记录", "<script>UPDATE %s %s %s</script>"),
-	
-	/**
-	 * 查询
-	 */
-	SELECT_BY_ID("selectById", "根据ID 查询一条数据", "SELECT %s FROM %s WHERE %s=#{%s}"),
-	SELECT_BATCH("selectBatchIds", "根据ID集合,批量查询数据", "<script>SELECT %s FROM %s WHERE %s IN (%s)</script>"),
-	SELECT_ONE("selectOne", "查询满足条件一条数据", "<script>SELECT %s FROM %s %s</script>"),
-	SELECT_COUNT("selectCount", "查询满足条件总记录数", "<script>SELECT COUNT(1) FROM %s %s</script>"),
-	SELECT_LIST("selectList", "查询满足条件所有数据", "<script>SELECT %s FROM %s %s</script>"),
-	SELECT_PAGE("selectPage", "查询满足条件所有数据(并翻页)", "<script>SELECT %s FROM %s %s</script>");
-	
-	private final String method;
-	
-	private final String desc;
-
-	private final String sql;
-
-
-	SqlMethod( final String method, final String desc, final String sql ) {
-		this.method = method;
-		this.desc = desc;
-		this.sql = sql;
-	}
-
-
-	public String getMethod() {
-		return this.method;
-	}
-
-
-	public String getDesc() {
-		return this.desc;
-	}
-
-
-	public String getSql() {
-		return this.sql;
-	}
-
-}
+/**
+ * Copyright (c) 2011-2014, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.enums;
+
+/**
+ * <p>
+ * MybatisPlus 支持 SQL 方法
+ * </p>
+ * 
+ * @author hubin
+ * @Date 2016-01-23
+ */
+public enum SqlMethod {
+
+	/**
+	 * 插入
+	 */
+	INSERT_ONE("insert", "插入一条数据", "<script>INSERT INTO %s %s VALUES %s</script>"),
+
+	/**
+	 * 删除
+	 */
+	DELETE_BY_ID("deleteById", "根据ID 删除一条数据", "DELETE FROM %s WHERE %s=#{%s}"),
+	DELETE_BY_MAP("deleteByMap", "根据columnMap 条件删除记录", "<script>DELETE FROM %s %s</script>"),
+	DELETE("delete", "根据 entity 条件删除记录", "<script>DELETE FROM %s %s</script>"),
+	DELETE_BATCH_BY_IDS("deleteBatchIds", "根据ID集合,批量删除数据", "<script>DELETE FROM %s WHERE %s IN (%s)</script>"),
+
+	/**
+	 * 修改
+	 */
+	UPDATE_BY_ID("updateById", "根据ID 修改数据", "<script>UPDATE %s %s WHERE %s=#{%s}</script>"),
+	UPDATE("update", "根据 whereEntity 条件,更新记录", "<script>UPDATE %s %s %s</script>"),
+
+	/**
+	 * 查询
+	 */
+	SELECT_BY_ID("selectById", "根据ID 查询一条数据", "SELECT %s FROM %s WHERE %s=#{%s}"),
+	SELECT_BY_MAP("selectByMap", "根据columnMap 查询一条数据", "<script>SELECT %s FROM %s %s</script>"),
+	SELECT_BATCH_BY_IDS("selectBatchIds", "根据ID集合,批量查询数据", "<script>SELECT %s FROM %s WHERE %s IN (%s)</script>"),
+	SELECT_ONE("selectOne", "查询满足条件一条数据", "<script>SELECT %s FROM %s %s</script>"),
+	SELECT_COUNT("selectCount", "查询满足条件总记录数", "<script>SELECT COUNT(1) FROM %s %s</script>"),
+	SELECT_LIST("selectList", "查询满足条件所有数据", "<script>SELECT %s FROM %s %s</script>"),
+	SELECT_PAGE("selectPage", "查询满足条件所有数据(并翻页)", "<script>SELECT %s FROM %s %s</script>"),
+	SELECT_MAPS("selectMaps", "查询满足条件所有数据", "<script>SELECT %s FROM %s %s</script>"),
+	SELECT_MAPS_PAGE("selectMapsPage", "查询满足条件所有数据(并翻页)", "<script>SELECT %s FROM %s %s</script>"),
+	SELECT_OBJS("selectObjs", "查询满足条件所有数据", "<script>SELECT %s FROM %s %s</script>");
+
+	private final String method;
+	
+	private final String desc;
+
+	private final String sql;
+
+
+	SqlMethod( final String method, final String desc, final String sql ) {
+		this.method = method;
+		this.desc = desc;
+		this.sql = sql;
+	}
+
+
+	public String getMethod() {
+		return this.method;
+	}
+
+
+	public String getDesc() {
+		return this.desc;
+	}
+
+
+	public String getSql() {
+		return this.sql;
+	}
+
+}

+ 4 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/enums/package-info.java

@@ -0,0 +1,4 @@
+/**
+ * 枚举类
+ */
+package com.baomidou.mybatisplus.enums;

+ 4 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/exceptions/package-info.java

@@ -0,0 +1,4 @@
+/**
+ * 异常类
+ */
+package com.baomidou.mybatisplus.exceptions;

+ 132 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/AbstractGenerator.java

@@ -0,0 +1,132 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.baomidou.mybatisplus.generator;
+
+import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
+import com.baomidou.mybatisplus.generator.config.GlobalConfig;
+import com.baomidou.mybatisplus.generator.config.PackageConfig;
+import com.baomidou.mybatisplus.generator.config.StrategyConfig;
+import com.baomidou.mybatisplus.generator.config.TemplateConfig;
+import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
+
+/**
+ * <p>
+ * 插件基类,用于属性配置 设计成抽象类主要是用于后期可扩展,共享参数配置。
+ * </p>
+ *
+ * @author YangHu
+ * @since 2016/8/30
+ */
+public abstract class AbstractGenerator {
+
+	/**
+	 * 数据源配置
+	 */
+	private DataSourceConfig dataSource;
+
+	/**
+	 * 数据库表配置
+	 */
+	private StrategyConfig strategy;
+
+	/**
+	 * 包 相关配置
+	 */
+	private PackageConfig packageInfo;
+
+	/**
+	 * 模板 相关配置
+	 */
+	private TemplateConfig template;
+
+	/**
+	 * 全局 相关配置
+	 */
+	private GlobalConfig globalConfig;
+
+	protected ConfigBuilder config;
+
+	protected InjectionConfig injectionConfig;
+
+	/**
+	 * 初始化配置
+	 */
+	protected void initConfig() {
+		if (null == config) {
+			config = new ConfigBuilder(packageInfo, dataSource, strategy, template, globalConfig);
+			if (null != injectionConfig) {
+				injectionConfig.setConfig(config);
+			}
+		}
+	}
+
+	public DataSourceConfig getDataSource() {
+		return dataSource;
+	}
+
+	public void setDataSource(DataSourceConfig dataSource) {
+		this.dataSource = dataSource;
+	}
+
+	public StrategyConfig getStrategy() {
+		return strategy;
+	}
+
+	public void setStrategy(StrategyConfig strategy) {
+		this.strategy = strategy;
+	}
+
+	public PackageConfig getPackageInfo() {
+		return packageInfo;
+	}
+
+	public void setPackageInfo(PackageConfig packageInfo) {
+		this.packageInfo = packageInfo;
+	}
+
+	public TemplateConfig getTemplate() {
+		return template;
+	}
+
+	public void setTemplate(TemplateConfig template) {
+		this.template = template;
+	}
+
+	public ConfigBuilder getConfig() {
+		return config;
+	}
+
+	public void setConfig(ConfigBuilder config) {
+		this.config = config;
+	}
+
+	public GlobalConfig getGlobalConfig() {
+		return globalConfig;
+	}
+
+	public void setGlobalConfig(GlobalConfig globalConfig) {
+		this.globalConfig = globalConfig;
+	}
+
+	public InjectionConfig getCfg() {
+		return injectionConfig;
+	}
+
+	public void setCfg(InjectionConfig injectionConfig) {
+		this.injectionConfig = injectionConfig;
+	}
+
+}

+ 259 - 826
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/AutoGenerator.java

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2011-2014, hubin (jobob@qq.com).
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
  * <p>
  * 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
@@ -20,836 +20,269 @@ import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.OutputStreamWriter;
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Arrays;
+import java.text.SimpleDateFormat;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-
-import com.baomidou.mybatisplus.annotations.IdType;
-import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
+import java.util.Properties;
+
+import org.apache.ibatis.logging.Log;
+import org.apache.ibatis.logging.LogFactory;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.Velocity;
+import org.apache.velocity.app.VelocityEngine;
+
+import com.baomidou.mybatisplus.generator.config.ConstVal;
+import com.baomidou.mybatisplus.generator.config.FileOutConfig;
+import com.baomidou.mybatisplus.generator.config.TemplateConfig;
+import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
+import com.baomidou.mybatisplus.generator.config.po.TableInfo;
+import com.baomidou.mybatisplus.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.toolkit.StringUtils;
 
 /**
- * <p>
- * 映射文件自动生成类
- * </p>
- *
- * @author hubin yanghu
- * @Date 2016-06-12
+ * 生成文件
+ * 
+ * @author YangHu, tangguo
+ * @since 2016-08-30
  */
-public class AutoGenerator {
-
-    private ConfigGenerator config;
-
-    public ConfigGenerator getConfig() {
-        return config;
-    }
-
-    public void setConfig(ConfigGenerator config) {
-        this.config = config;
-    }
-
-    public AutoGenerator() {
-
-    }
-
-    public AutoGenerator(ConfigGenerator config) {
-        this.config = config;
-    }
-
-    private static String PATH_ENTITY = null;
-    private static String PATH_MAPPER = null;
-    private static String PATH_XML = null;
-    private static String PATH_SERVICE = null;
-    private static String PATH_SERVICE_IMPL = null;
-
-    private static boolean FILE_OVERRIDE = false;
-
-    private static final String JAVA_SUFFIX = ".java";
-    private static final String XML_SUFFIX = ".xml";
-
-    /**
-     * run 执行
-     */
-    public static void run(ConfigGenerator config) {
-        if (config == null) {
-            throw new MybatisPlusException(" ConfigGenerator is null. ");
-        } else if (config.getIdType() == null) {
-            throw new MybatisPlusException("ConfigGenerator IdType is null");
-        }
-
-        /**
-         * 检查文件夹是否存在
-         */
-        File gf = new File(config.getSaveDir());
-        if (!gf.exists()) {
-            gf.mkdirs();
-        }
-
-        /**
-         * 修改设置最终目录的逻辑
-         */
-        String saveDir = gf.getPath();
-        PATH_ENTITY = getFilePath(saveDir, getPathFromPackageName(config.getEntityPackage()));
-        PATH_MAPPER = getFilePath(saveDir, getPathFromPackageName(config.getMapperPackage()));
-        PATH_XML = getFilePath(saveDir, getPathFromPackageName(config.getXmlPackage()));
-        PATH_SERVICE = getFilePath(saveDir, getPathFromPackageName(config.getServicePackage()));
-        PATH_SERVICE_IMPL = getFilePath(saveDir, getPathFromPackageName(config.getServiceImplPackage()));
-
-
-        /**
-         * 新生成的文件是否覆盖现有文件
-         */
-        FILE_OVERRIDE = config.isFileOverride();
-
-
-        /**
-         * 开启生成映射关系
-         */
-        new AutoGenerator(config).generate();
-
-        /**
-         * 自动打开生成文件的目录
-         * <p>
-         * 根据 osName 执行相应命令
-         * </p>
-         */
-        try {
-            String osName = System.getProperty("os.name");
-            if (osName != null) {
-                if (osName.contains("Mac")) {
-                    Runtime.getRuntime().exec("open " + config.getSaveDir());
-                } else if (osName.contains("Windows")) {
-                    Runtime.getRuntime().exec("cmd /c start " + config.getSaveDir());
-                } else {
-                    System.err.println("save dir:" + config.getSaveDir());
-                }
-            }
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-        System.out.println(" generate success! ");
-    }
-
-    /**
-     * 根据包名转换成具体路径
-     *
-     * @param packageName
-     * @return
-     */
-    private static String getPathFromPackageName(String packageName) {
-        if (null == packageName || "".equals(packageName)) {
-            return "";
-        }
-        return packageName.replace(".", File.separator);
-    }
-
-    /**
-     * 生成文件地址
-     *
-     * @param segment 文件地址片段
-     * @return
-     */
-    private static String getFilePath(String savePath, String segment) {
-        File folder = new File(savePath + File.separator + segment);
-        if (!folder.exists()) {
-            folder.mkdirs();
-        }
-        return folder.getPath();
-    }
-
-    /**
-     * 生成映射文件
-     */
-    public void generate() {
-        Connection conn = null;
-        try {
-            /**
-             * 创建连接
-             */
-            Class.forName(config.getDbDriverName());
-            conn = DriverManager.getConnection(config.getDbUrl(), config.getDbUser(), config.getDbPassword());
-
-            /**
-             * 获取数据库表相关信息
-             */
-            boolean isOracle = false;
-            if (config.getConfigDataSource() == ConfigDataSource.ORACLE) {
-                isOracle = true;
-            }
-
-            /**
-             * 根据配置获取应该生成文件的表信息
-             */
-            List<String> tables = getTables(conn);
-            if (null == tables) {
-                return;
-            }
-
-            Map<String, String> tableComments = getTableComment(conn);
-            for (String table : tables) {
-                List<String> columns = new ArrayList<String>();
-                List<String> types = new ArrayList<String>();
-                List<String> comments = new ArrayList<String>();
-                Map<String, IdInfo> idMap = new HashMap<String, IdInfo>();
-                String tableFieldsSql = String.format(config.getConfigDataSource().getTableFieldsSql(), table);
-                ResultSet results = conn.prepareStatement(tableFieldsSql).executeQuery();
-                while (results.next()) {
-                    String field = results.getString(config.getConfigDataSource().getFieldName());
-                    columns.add(field);
-                    types.add(results.getString(config.getConfigDataSource().getFieldType()));
-                    comments.add(results.getString(config.getConfigDataSource().getFieldComment()));
-                    if (!isOracle) {
-                        /* MYSQL 主键ID 处理方式 */
-                        String key = results.getString(config.getConfigDataSource().getFieldKey());
-                        if ("PRI".equals(key)) {
-                            boolean autoIncrement = false;
-                            if ("auto_increment".equals(results.getString("EXTRA"))) {
-                                autoIncrement = true;
-                            }
-                            idMap.put(field, new IdInfo(field, autoIncrement));
-                        }
-                    }
-                }
-                if (isOracle) {
-                    /* ORACLE 主键ID 处理方式 */
-                    String idSql = String.format("SELECT A.COLUMN_NAME FROM USER_CONS_COLUMNS A, USER_CONSTRAINTS B WHERE A.CONSTRAINT_NAME = B.CONSTRAINT_NAME AND B.CONSTRAINT_TYPE = 'P' AND A.TABLE_NAME = '%s'", table);
-                    ResultSet rs = conn.prepareStatement(idSql).executeQuery();
-                    while (rs.next()) {
-                        String field = rs.getString(config.getConfigDataSource().getFieldKey());
-                        idMap.put(field, new IdInfo(field, false));
-                    }
-                }
-                String beanName = getBeanName(table, config.isDbPrefix());
-                String mapperName = beanName + "Mapper";
-                String serviceName = "I" + beanName + "Service";
-                String serviceImplName = beanName + "ServiceImpl";
-
-                /**
-                 * 根据文件覆盖标志决定是否生成映射文件
-                 */
-                if (valideFile(PATH_ENTITY, beanName, JAVA_SUFFIX)) {
-                    buildEntityBean(columns, types, comments, tableComments.get(table), idMap, table, beanName);
-                }
-                if (valideFile(PATH_MAPPER, mapperName, JAVA_SUFFIX)) {
-                    buildMapper(beanName, mapperName);
-                }
-                if (valideFile(PATH_XML, mapperName, XML_SUFFIX)) {
-                    buildMapperXml(columns, types, comments, idMap, mapperName);
-                }
-                if (valideFile(PATH_SERVICE, serviceName, JAVA_SUFFIX)) {
-                    buildService(beanName, serviceName);
-                }
-                if (valideFile(PATH_SERVICE_IMPL, serviceImplName, JAVA_SUFFIX)) {
-                    buildServiceImpl(beanName, serviceImplName, serviceName, mapperName);
-                }
-            }
-        } catch (Exception e) {
-            e.printStackTrace();
-        } finally {
-            if (conn != null) {
-                try {
-                    conn.close();
-                } catch (SQLException e) {
-                    e.printStackTrace();
-                }
-            }
-        }
-    }
-
-    /**
-     * 根据是否覆盖标志决定是否覆盖当前已存在的文件
-     *
-     * @param dirPath
-     * @param beanName
-     * @param suffix
-     * @return
-     */
-    private boolean valideFile(String dirPath, String beanName, String suffix) {
-        File file = new File(dirPath, beanName + suffix);
-        return !file.exists() || FILE_OVERRIDE;
-    }
-
-
-    /**
-     * 检查配置的所有表是否在dbTables里存在.
-     * <ul>
-     * <li>如果未配置,则返回所有表</li>
-     * <li>所有都存在直接返回custTables.</li>
-     * <li>如果发现有不存在表名直接返回null。</li>
-     * </ul>
-     *
-     * @return
-     * @throws SQLException
-     */
-    private List<String> getTables(Connection conn) throws SQLException {
-        List<String> tables = new ArrayList<String>();
-        PreparedStatement pstate = conn.prepareStatement(config.getConfigDataSource().getTablesSql());
-        ResultSet results = pstate.executeQuery();
-        while (results.next()) {
-            tables.add(results.getString(1));
-        }
-
-        String[] tableNames = config.getTableNames();
-		if (null == tableNames || tableNames.length == 0) {
-            return tables;
-        }
-
-        // 循环判断是否配置的所有表都在当前库中存在
-        List<String> custTables = Arrays.asList(tableNames);
-        List<String> notExistTables = new ArrayList<String>();
-        for (String tb : custTables) {
-            if (!tables.contains(tb)) {
-                notExistTables.add(tb);
-            }
-        }
-        if (notExistTables.size() == 0) {
-            return custTables;
-        }
-        // 如果有错误的表名,打印到控制台,且返回null
-        System.err.println("tablename " + notExistTables.toString() + " is not exist!! ==> stop generate!!");
-        return null;
-    }
-
-    /**
-     * 生成 beanName
-     *
-     * @param table 表名
-     * @return beanName
-     */
-    private String getBeanName(String table, boolean includePrefix) {
-        StringBuilder sb = new StringBuilder();
-        if (table.contains("_")) {
-            String[] tables = table.split("_");
-            int l = tables.length;
-            int s = 0;
-            if (includePrefix) {
-                s = 1;
-            }
-            for (int i = s; i < l; i++) {
-                String temp = tables[i].trim();
-                sb.append(temp.substring(0, 1).toUpperCase()).append(temp.substring(1).toLowerCase());
-            }
-        } else {
-            sb.append(table.substring(0, 1).toUpperCase()).append(table.substring(1).toLowerCase());
-        }
-        return sb.toString();
-    }
-
-
-    private String processType(String type) {
-        if (config.getConfigDataSource() == ConfigDataSource.ORACLE) {
-            return oracleProcessType(type);
-        }
-        return mysqlProcessType(type);
-    }
-
-
-    /**
-     * MYSQL字段类型转换
-     *
-     * @param type 字段类型
-     * @return
-     */
-    private String mysqlProcessType(String type) {
-        if (type.contains("char")) {
-            return "String";
-        } else if (type.contains("bigint")) {
-            return "Long";
-        } else if (type.contains("int")) {
-            return "Integer";
-        } else if (type.contains("date") || type.contains("timestamp")) {
-            return "Date";
-        } else if (type.contains("text")) {
-            return "String";
-        } else if (type.contains("bit")) {
-            return "Boolean";
-        } else if (type.contains("decimal")) {
-            return "BigDecimal";
-        } else if (type.contains("blob")) {
-            return "byte[]";
-        } else if (type.contains("float")) {
-            return "Float";
-        } else if (type.contains("double")) {
-            return "Double";
-        }
-        return null;
-    }
-
-    /**
-     * ORACLE字段类型转换
-     *
-     * @param type 字段类型
-     * @return
-     */
-    private String oracleProcessType(String type) {
-        if (type.contains("CHAR")) {
-            return "String";
-        } else if (type.contains("DATE")) {
-            return "Date";
-        } else if (type.contains("NUMBER")) {
-            return "Double";
-        } else if (type.contains("FLOAT")) {
-            return "Float";
-        } else if (type.contains("BLOB")) {
-            return "Object";
-        } else if (type.contains("RAW")) {
-            return "byte[]";
-        }
-        return null;
-    }
-
-    /**
-     * 字段是否为日期类型
-     *
-     * @param types 字段类型列表
-     * @return
-     */
-    private boolean isDate(List<String> types) {
-//        int size = types.size();
-        for (String type : types) {
-            if (type.contains("date") || type.contains("timestamp")) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * 字段是否为浮点数类型
-     *
-     * @param types 字段类型列表
-     * @return
-     */
-    private boolean isDecimal(List<String> types) {
-        for (String type : types) {
-            if (type.contains("decimal")) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private String processField(String field) {
-        /*
-         * 驼峰命名直接返回
-		 */
-        if (config.isColumnHump()) {
-            return field;
-        }
-
-		/* 
-		 * 处理下划线分割命名字段
-		 */
-        StringBuilder sb = new StringBuilder(field.length());
-        String[] fields = field.split("_");
-        sb.append(fields[0].toLowerCase());
-        for (int i = 1; i < fields.length; i++) {
-            String temp = fields[i];
-            sb.append(temp.substring(0, 1).toUpperCase());
-            sb.append(temp.substring(1).toLowerCase());
-        }
-        return sb.toString();
-    }
-
-    /**
-     * 构建类上面的注释
-     *
-     * @param bw
-     * @param text
-     * @return
-     * @throws IOException
-     */
-    private BufferedWriter buildClassComment(BufferedWriter bw, String text) throws IOException {
-        bw.newLine();
-        bw.write("/**");
-        bw.newLine();
-        bw.write(" *");
-        bw.newLine();
-        bw.write(" * " + text);
-        bw.newLine();
-        bw.write(" *");
-        bw.newLine();
-        bw.write(" */");
-        return bw;
-    }
-
-    /**
-     * 生成实体类
-     *
-     * @param columns
-     * @param types
-     * @param comments
-     * @throws IOException
-     */
-    private void buildEntityBean(List<String> columns, List<String> types, List<String> comments, String tableComment,
-                                 Map<String, IdInfo> idMap, String table, String beanName) throws IOException {
-        File beanFile = new File(PATH_ENTITY, beanName + ".java");
-        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(beanFile)));
-        bw.write("package " + config.getEntityPackage() + ";");
-        bw.newLine();
-        bw.newLine();
-        bw.write("import java.io.Serializable;");
-        bw.newLine();
-        if (isDate(types)) {
-            bw.write("import java.util.Date;");
-            bw.newLine();
-        }
-        if (isDecimal(types)) {
-            bw.write("import java.math.BigDecimal;");
-            bw.newLine();
-        }
-        bw.newLine();
-        if (config.getIdType() != IdType.ID_WORKER) {
-            bw.write("import com.baomidou.mybatisplus.annotations.IdType;");
-            bw.newLine();
-        }
-        bw.write("import com.baomidou.mybatisplus.annotations.TableField;");
-        bw.newLine();
-        bw.write("import com.baomidou.mybatisplus.annotations.TableId;");
-        bw.newLine();
-        bw.write("import com.baomidou.mybatisplus.annotations.TableName;");
-        bw.newLine();
-        bw = buildClassComment(bw, tableComment);
-        bw.newLine();
-        bw.write("@TableName(value = \"" + table + "\")");
-        bw.newLine();
-        bw.write("public class " + beanName + " implements Serializable {");
-        bw.newLine();
-        bw.newLine();
-        bw.write("\t@TableField(exist = false)");
-        bw.newLine();
-        bw.write("\tprivate static final long serialVersionUID = 1L;");
-        bw.newLine();
-        int size = columns.size();
-        for (int i = 0; i < size; i++) {
-            bw.newLine();
-            bw.write("\t/** " + comments.get(i) + " */");
-            bw.newLine();
-			/*
-			 * 判断ID 添加注解
-			 * <br>
-			 * isLine 是否包含下划线
-			 */
-            String column = columns.get(i);
-            String field = processField(column);
-            boolean isLine = column.contains("_");
-            IdInfo idInfo = idMap.get(column);
-            if (idInfo != null) {
-                //@TableId(value = "test_id", type = IdType.AUTO_INCREMENT)
-                bw.write("\t@TableId");
-                String idType = toIdType();
-                if (idInfo.isAutoIncrement()) {
-                    System.err.println(" Table :{ " + table + " } ID is Auto increment");
-                    if (isLine) {
-                        bw.write("(value = \"" + column + "\"");
-                        if (idType != null) {
-                            bw.write(", ");
-                            bw.write(idType);
-                        }
-                        bw.write(")");
-                    } else if (idType != null) {
-                        bw.write("(");
-                        bw.write(idType);
-                        bw.write(")");
-                    }
-                } else {
-                    if (isLine) {
-                        bw.write("(value = \"" + column + "\"");
-                        if (idType != null) {
-                            bw.write(", ");
-                            bw.write(idType);
-                        }
-                        bw.write(")");
-                    } else if (idType != null) {
-                        bw.write("(");
-                        bw.write(idType);
-                        bw.write(")");
-                    }
-                }
-                bw.newLine();
-            } else if (isLine) {
-                //@TableField(value = "test_type", exist = false)
-                bw.write("\t@TableField(value = \"" + column + "\")");
-                bw.newLine();
-            }
-            bw.write("\tprivate " + processType(types.get(i)) + " " + field + ";");
-            bw.newLine();
-        }
-
-		/*
-		 * 生成get 和 set方法
-		 */
-        for (int i = 0; i < size; i++) {
-            String _tempType = processType(types.get(i));
-            String _tempField = processField(columns.get(i));
-            String _field = _tempField.substring(0, 1).toUpperCase() + _tempField.substring(1);
-            bw.newLine();
-            bw.write("\tpublic " + _tempType + " get" + _field + "() {");
-            bw.newLine();
-            bw.write("\t\treturn this." + _tempField + ";");
-            bw.newLine();
-            bw.write("\t}");
-            bw.newLine();
-            bw.newLine();
-            bw.write("\tpublic void set" + _field + "(" + _tempType + " " + _tempField + ") {");
-            bw.newLine();
-            bw.write("\t\tthis." + _tempField + " = " + _tempField + ";");
-            bw.newLine();
-            bw.write("\t}");
-            bw.newLine();
-        }
-
-        bw.newLine();
-        bw.write("}");
-        bw.newLine();
-        bw.flush();
-        bw.close();
-    }
-
-    public String toIdType() {
-        if (config.getIdType() == IdType.AUTO) {
-            return "type = IdType.AUTO";
-        } else if (config.getIdType() == IdType.INPUT) {
-            return "type = IdType.INPUT";
-        } else if (config.getIdType() == IdType.UUID) {
-            return "type = IdType.UUID";
-        }
-        return null;
-    }
-
-    /**
-     * 构建Mapper文件
-     *
-     * @param beanName
-     * @param mapperName
-     * @throws IOException
-     */
-    private void buildMapper(String beanName, String mapperName) throws IOException {
-        File mapperFile = new File(PATH_MAPPER, mapperName + ".java");
-        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(mapperFile), "utf-8"));
-        bw.write("package " + config.getMapperPackage() + ";");
-        bw.newLine();
-        bw.newLine();
-        bw.write("import " + config.getEntityPackage() + "." + beanName + ";");
-        bw.newLine();
-        if (config.getConfigIdType() == ConfigIdType.STRING) {
-            bw.write("import com.baomidou.mybatisplus.mapper.CommonMapper;");
-        } else {
-            bw.write("import com.baomidou.mybatisplus.mapper.AutoMapper;");
-        }
-        bw.newLine();
-
-        bw = buildClassComment(bw, beanName + " 表数据库控制层接口");
-        bw.newLine();
-        if (config.getConfigIdType() == ConfigIdType.STRING) {
-            bw.write("public interface " + mapperName + " extends CommonMapper<" + beanName + "> {");
-        } else {
-            bw.write("public interface " + mapperName + " extends AutoMapper<" + beanName + "> {");
-        }
-        bw.newLine();
-        bw.newLine();
-
-        // ----------定义mapper中的方法End----------
-        bw.newLine();
-        bw.write("}");
-        bw.flush();
-        bw.close();
-    }
-
-    /**
-     * 构建实体类映射XML文件
-     *
-     * @param columns
-     * @param types
-     * @param comments
-     * @throws IOException
-     */
-    private void buildMapperXml(List<String> columns, List<String> types, List<String> comments,
-                                Map<String, IdInfo> idMap, String mapperName) throws IOException {
-        File mapperXmlFile = new File(PATH_XML, mapperName + ".xml");
-        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(mapperXmlFile)));
-        bw.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
-        bw.newLine();
-        bw.write("<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">");
-        bw.newLine();
-        bw.write("<mapper namespace=\"" + config.getMapperPackage() + "." + mapperName + "\">");
-        bw.newLine();
-        bw.newLine();
-
-		/*
-		 * 下面开始写SqlMapper中的方法
-		 */
-        buildSQL(bw, idMap, columns);
-
-        bw.write("</mapper>");
-        bw.flush();
-        bw.close();
-    }
-
-    /**
-     * 构建service文件
-     *
-     * @param beanName
-     * @param serviceName
-     * @throws IOException
-     */
-    private void buildService(String beanName, String serviceName) throws IOException {
-        File serviceFile = new File(PATH_SERVICE, serviceName + ".java");
-        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(serviceFile), "utf-8"));
-        bw.write("package " + config.getServicePackage() + ";");
-        bw.newLine();
-        bw.newLine();
-        bw.write("import " + config.getEntityPackage() + "." + beanName + ";");
-        bw.newLine();
-        if (config.getConfigIdType() == ConfigIdType.STRING) {
-            bw.write("import com.baomidou.framework.service.ICommonService;");
-        } else {
-            bw.write("import com.baomidou.framework.service.ISuperService;");
-        }
-        bw.newLine();
-
-        bw = buildClassComment(bw, beanName + " 表数据服务层接口");
-        bw.newLine();
-        if (config.getConfigIdType() == ConfigIdType.STRING) {
-            bw.write("public interface " + serviceName + " extends ICommonService<" + beanName + "> {");
-        } else {
-            bw.write("public interface " + serviceName + " extends ISuperService<" + beanName + "> {");
-        }
-        bw.newLine();
-        bw.newLine();
-
-        // ----------定义service中的方法End----------
-        bw.newLine();
-        bw.write("}");
-        bw.flush();
-        bw.close();
-    }
-
-    /**
-     * 构建service实现类文件
-     *
-     * @param beanName
-     * @param serviceImplName
-     * @param mapperName
-     * @throws IOException
-     */
-    private void buildServiceImpl(String beanName, String serviceImplName, String serviceName, String mapperName) throws IOException {
-        File serviceFile = new File(PATH_SERVICE_IMPL, serviceImplName + ".java");
-        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(serviceFile), "utf-8"));
-        bw.write("package " + config.getServicePackage() + ".impl;");
-        bw.newLine();
-        bw.newLine();
-        bw.write("import org.springframework.stereotype.Service;");
-        bw.newLine();
-        bw.newLine();
-        bw.write("import " + config.getMapperPackage() + "." + mapperName + ";");
-        bw.newLine();
-        bw.write("import " + config.getEntityPackage() + "." + beanName + ";");
-        bw.newLine();
-        bw.write("import " + config.getServicePackage() + "." + serviceName + ";");
-        bw.newLine();
-
-        String superServiceImpl = config.getSuperServiceImpl();
-        bw.write("import " + superServiceImpl + ";");
-        bw.newLine();
-
-        bw = buildClassComment(bw, beanName + " 表数据服务层接口实现类");
-        bw.newLine();
-        bw.write("@Service");
-        bw.newLine();
-        superServiceImpl = superServiceImpl.substring(superServiceImpl.lastIndexOf(".") + 1);
-        bw.write("public class " + serviceImplName + " extends " + superServiceImpl
-                + "<" + mapperName + ", " + beanName + "> implements " + serviceName + " {");
-        bw.newLine();
-        bw.newLine();
-
-        // ----------定义service中的方法End----------
-        bw.newLine();
-        bw.write("}");
-        bw.flush();
-        bw.close();
-    }
-
-    /**
-     * 通用返回参数
-     *
-     * @param bw
-     * @param idMap
-     * @param columns
-     * @throws IOException
-     */
-    private void buildSQL(BufferedWriter bw, Map<String, IdInfo> idMap, List<String> columns) throws IOException {
-        int size = columns.size();
-        bw.write("\t<!-- 通用查询结果列-->");
-        bw.newLine();
-        bw.write("\t<sql id=\"Base_Column_List\">");
-        bw.newLine();
-
-        for (int i = 0; i < size; i++) {
-            String column = columns.get(i);
-            IdInfo idInfo = idMap.get(column);
-            if (idInfo != null) {
-                bw.write("\t\t " + idInfo.getValue());
-            } else {
-                bw.write(" " + column);
-            }
-            if (i != size - 1) {
-                bw.write(",");
-            }
-        }
-        bw.newLine();
-        bw.write("\t</sql>");
-        bw.newLine();
-        bw.newLine();
-    }
-
-    /**
-     * 获取所有的数据库表注释
-     *
-     * @return
-     * @throws SQLException
-     */
-    private Map<String, String> getTableComment(Connection conn) throws SQLException {
-        Map<String, String> maps = new HashMap<String, String>();
-        PreparedStatement pstate = conn.prepareStatement(config.getConfigDataSource().getTableCommentsSql());
-        ResultSet results = pstate.executeQuery();
-        while (results.next()) {
-            maps.put(results.getString(config.getConfigDataSource().getTableName()),
-                    results.getString(config.getConfigDataSource().getTableComment()));
-        }
-        return maps;
-    }
-
-    class IdInfo {
-        private String value;
-        private boolean autoIncrement;
-
-        public IdInfo(String value, boolean autoIncrement) {
-            this.value = value;
-            this.autoIncrement = autoIncrement;
-
-        }
-
-        public String getValue() {
-            return value;
-        }
-
-        public void setValue(String value) {
-            this.value = value;
-        }
-
-        public boolean isAutoIncrement() {
-            return autoIncrement;
-        }
+public class AutoGenerator extends AbstractGenerator {
+
+	private static final Log logger = LogFactory.getLog(AutoGenerator.class);
+
+	/**
+	 * velocity引擎
+	 */
+	private VelocityEngine engine;
+
+	/**
+	 * 生成代码
+	 */
+	public void execute() {
+		logger.debug("==========================准备生成文件...==========================");
+		// 初始化配置
+		initConfig();
+		// 创建输出文件路径
+		mkdirs(config.getPathInfo());
+		// 获取上下文
+		Map<String, VelocityContext> ctxData = analyzeData(config);
+		// 循环生成文件
+		for (Map.Entry<String, VelocityContext> ctx : ctxData.entrySet()) {
+			batchOutput(ctx.getKey(), ctx.getValue());
+		}
+		// 打开输出目录
+		if (config.getGlobalConfig().isOpen()) {
+			try {
+				String osName = System.getProperty("os.name");
+				if (osName != null) {
+					if (osName.contains("Mac")) {
+						Runtime.getRuntime().exec("open " + config.getGlobalConfig().getOutputDir());
+					} else if (osName.contains("Windows")) {
+						Runtime.getRuntime().exec("cmd /c start " + config.getGlobalConfig().getOutputDir());
+					} else {
+						logger.debug("文件输出目录:" + config.getGlobalConfig().getOutputDir());
+					}
+				}
+			} catch (IOException e) {
+				e.printStackTrace();
+			}
+		}
+		logger.debug("==========================文件生成完成!!!==========================");
+	}
+
+	/**
+	 * 分析数据
+	 *
+	 * @param config
+	 *            总配置信息
+	 * @return 解析数据结果集
+	 */
+	private Map<String, VelocityContext> analyzeData(ConfigBuilder config) {
+		List<TableInfo> tableList = config.getTableInfoList();
+		Map<String, String> packageInfo = config.getPackageInfo();
+		Map<String, VelocityContext> ctxData = new HashMap<String, VelocityContext>();
+		String superEntityClass = getSuperClassName(config.getSuperEntityClass());
+		String superMapperClass = getSuperClassName(config.getSuperMapperClass());
+		String superServiceClass = getSuperClassName(config.getSuperServiceClass());
+		String superServiceImplClass = getSuperClassName(config.getSuperServiceImplClass());
+		String superControllerClass = getSuperClassName(config.getSuperControllerClass());
+		String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
+		VelocityContext ctx;
+		for (TableInfo tableInfo : tableList) {
+			ctx = new VelocityContext();
+			if (null != injectionConfig) {
+				/**
+				 * 注入自定义配置
+				 */
+				injectionConfig.initMap();
+				ctx.put("cfg", injectionConfig.getMap());
+			}
+			/* ---------- 添加导入包 ---------- */
+			if (tableInfo.isConvert()) {
+				// 表注解
+				tableInfo.setImportPackages("com.baomidou.mybatisplus.annotations.TableName");
+			}
+			if (StringUtils.isNotEmpty(config.getSuperEntityClass())) {
+				// 父实体
+				tableInfo.setImportPackages(config.getSuperEntityClass());
+			}
+			ctx.put("package", packageInfo);
+			ctx.put("author", config.getGlobalConfig().getAuthor());
+			ctx.put("activeRecord", config.getGlobalConfig().isActiveRecord());
+			ctx.put("date", date);
+			ctx.put("table", tableInfo);
+			ctx.put("enableCache", config.getGlobalConfig().isEnableCache());
+			ctx.put("baseResultMap", config.getGlobalConfig().isBaseResultMap());
+			ctx.put("baseColumnList", config.getGlobalConfig().isBaseColumnList());
+			ctx.put("entity", tableInfo.getEntityName());
+			ctx.put("entityColumnConstant", config.getStrategyConfig().isEntityColumnConstant());
+			ctx.put("entityBuliderModel", config.getStrategyConfig().isEntityBuliderModel());
+			ctx.put("superEntityClass", superEntityClass);
+			ctx.put("superMapperClassPackage", config.getSuperMapperClass());
+			ctx.put("superMapperClass", superMapperClass);
+			ctx.put("superServiceClassPackage", config.getSuperServiceClass());
+			ctx.put("superServiceClass", superServiceClass);
+			ctx.put("superServiceImplClassPackage", config.getSuperServiceImplClass());
+			ctx.put("superServiceImplClass", superServiceImplClass);
+			ctx.put("superControllerClassPackage", config.getSuperControllerClass());
+			ctx.put("superControllerClass", superControllerClass);
+			ctxData.put(tableInfo.getEntityName(), ctx);
+		}
+		return ctxData;
+	}
+
+	/**
+	 * 获取类名
+	 * 
+	 * @param classPath
+	 * @return
+	 */
+	private String getSuperClassName(String classPath) {
+		if (StringUtils.isEmpty(classPath))
+			return null;
+		return classPath.substring(classPath.lastIndexOf(".") + 1);
+	}
+
+	/**
+	 * 处理输出目录
+	 *
+	 * @param pathInfo
+	 *            路径信息
+	 */
+	private void mkdirs(Map<String, String> pathInfo) {
+		for (Map.Entry<String, String> entry : pathInfo.entrySet()) {
+			File dir = new File(entry.getValue());
+			if (!dir.exists()) {
+				boolean result = dir.mkdirs();
+				if (result) {
+					logger.debug("创建目录: [" + entry.getValue() + "]");
+				}
+			}
+		}
+	}
+
+	/**
+	 * 合成上下文与模板
+	 *
+	 * @param context
+	 *            vm上下文
+	 */
+	private void batchOutput(String entityName, VelocityContext context) {
+		try {
+			TableInfo tableInfo = (TableInfo) context.get("table");
+			Map<String, String> pathInfo = config.getPathInfo();
+			String entityFile = String.format((pathInfo.get(ConstVal.ENTITY_PATH) + ConstVal.ENTITY_NAME), entityName);
+			String mapperFile = String.format((pathInfo.get(ConstVal.MAPPER_PATH) + File.separator + tableInfo.getMapperName() + ConstVal.JAVA_SUFFIX), entityName);
+			String xmlFile = String.format((pathInfo.get(ConstVal.XML_PATH) + File.separator + tableInfo.getXmlName() + ConstVal.XML_SUFFIX), entityName);
+			String serviceFile = String.format((pathInfo.get(ConstVal.SERIVCE_PATH) + File.separator + tableInfo.getServiceName() + ConstVal.JAVA_SUFFIX), entityName);
+			String implFile = String.format((pathInfo.get(ConstVal.SERVICEIMPL_PATH) + File.separator + tableInfo.getServiceImplName() + ConstVal.JAVA_SUFFIX), entityName);
+			String controllerFile = String.format((pathInfo.get(ConstVal.CONTROLLER_PATH) + File.separator + tableInfo.getControllerName() + ConstVal.JAVA_SUFFIX), entityName);
+
+			TemplateConfig template = config.getTemplate();
+
+			// 根据override标识来判断是否需要创建文件
+			if (isCreate(entityFile)) {
+				vmToFile(context, template.getEntity(), entityFile);
+			}
+			if (isCreate(mapperFile)) {
+				vmToFile(context, template.getMapper(), mapperFile);
+			}
+			if (isCreate(xmlFile)) {
+				vmToFile(context, template.getXml(), xmlFile);
+			}
+			if (isCreate(serviceFile)) {
+				vmToFile(context, template.getService(), serviceFile);
+			}
+			if (isCreate(implFile)) {
+				vmToFile(context, template.getServiceImpl(), implFile);
+			}
+			if (isCreate(controllerFile)) {
+				vmToFile(context, template.getController(), controllerFile);
+			}
+			if (injectionConfig != null) {
+				/**
+				 * 输出自定义文件内容
+				 */
+				List<FileOutConfig> focList = injectionConfig.getFileOutConfigList();
+				if (CollectionUtils.isNotEmpty(focList)) {
+					for (FileOutConfig foc : focList) {
+						vmToFile(context, foc.getTemplatePath(), foc.outputFile(tableInfo));
+					}
+				}
+			}
+
+		} catch (IOException e) {
+			logger.error("无法创建文件,请检查配置信息!", e);
+		}
+	}
+
+	/**
+	 * 将模板转化成为文件
+	 *
+	 * @param context
+	 *            内容对象
+	 * @param templatePath
+	 *            模板文件
+	 * @param outputFile
+	 *            文件生成的目录
+	 */
+	private void vmToFile(VelocityContext context, String templatePath, String outputFile) throws IOException {
+		VelocityEngine velocity = getVelocityEngine();
+		Template template = velocity.getTemplate(templatePath, ConstVal.UTF8);
+		FileOutputStream fos = new FileOutputStream(outputFile);
+		BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(fos, ConstVal.UTF8));
+		template.merge(context, writer);
+		writer.close();
+		logger.debug("模板:" + templatePath + ";  文件:" + outputFile);
+	}
+
+	/**
+	 * 设置模版引擎,主要指向获取模版路径
+	 */
+	private VelocityEngine getVelocityEngine() {
+		if (engine == null) {
+			Properties p = new Properties();
+			p.setProperty(ConstVal.VM_LOADPATH_KEY, ConstVal.VM_LOADPATH_VALUE);
+			p.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, "");
+			p.setProperty(Velocity.ENCODING_DEFAULT, ConstVal.UTF8);
+			p.setProperty(Velocity.INPUT_ENCODING, ConstVal.UTF8);
+			p.setProperty(Velocity.OUTPUT_ENCODING, ConstVal.UTF8);
+			p.setProperty("file.resource.loader.unicode", "true");
+			engine = new VelocityEngine(p);
+		}
+		return engine;
+	}
+
+	/**
+	 * 检测文件是否存在
+	 *
+	 * @return 是否
+	 */
+	private boolean isCreate(String filePath) {
+		File file = new File(filePath);
+		return !file.exists() || config.getGlobalConfig().isFileOverride();
+	}
 
-        public void setAutoIncrement(boolean autoIncrement) {
-            this.autoIncrement = autoIncrement;
-        }
-    }
 }

+ 0 - 137
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/ConfigDataSource.java

@@ -1,137 +0,0 @@
-/**
- * Copyright (c) 2011-2014, hubin (jobob@qq.com).
- *
- * 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.baomidou.mybatisplus.generator;
-
-/**
- * <p>
- * 数据源配置
- * </p>
- * 
- * @author hubin
- * @Date 2016-04-25
- */
-public enum ConfigDataSource {
-	MYSQL("mysql", "show tables", "show table status", "show full fields from %s", "NAME", "COMMENT"
-		,"FIELD","TYPE","COMMENT","KEY"), 
-	ORACLE("oracle", "SELECT * FROM USER_TABLES", "SELECT * FROM USER_TAB_COMMENTS",
-			"SELECT A.COLUMN_NAME, A.DATA_TYPE, B.COMMENTS  FROM USER_TAB_COLUMNS A, USER_COL_COMMENTS B WHERE A.TABLE_NAME=B.TABLE_NAME AND A.COLUMN_NAME = B.COLUMN_NAME AND A.TABLE_NAME='%s'",
-			"TABLE_NAME", "COMMENTS" ,"COLUMN_NAME","DATA_TYPE","COMMENTS","COLUMN_NAME");
-
-	private final String db;
-	private final String tablesSql;
-	private final String tableCommentsSql;
-	private final String tableFieldsSql;
-	private final String tableName;
-	private final String tableComment;
-	private final String fieldName;
-	private final String fieldType;
-	private final String fieldComment;
-	private final String fieldKey;
-
-
-	ConfigDataSource(
-			final String db,
-			final String tablesSql,
-			final String tableCommentsSql,
-			final String tableFieldsSql,
-			final String tableName,
-			final String tableComment,
-			final String fieldName,
-			final String fieldType,
-			final String fieldComment,
-			final String fieldKey ) {
-		this.db = db;
-		this.tablesSql = tablesSql;
-		this.tableCommentsSql = tableCommentsSql;
-		this.tableFieldsSql = tableFieldsSql;
-		this.tableName = tableName;
-		this.tableComment = tableComment;
-		this.fieldName = fieldName;
-		this.fieldType = fieldType;
-		this.fieldComment = fieldComment;
-		this.fieldKey = fieldKey;
-	}
-
-
-	/**
-	 * <p>
-	 * 获取数据库类型(默认 MySql)
-	 * </p>
-	 * 
-	 * @param dbType
-	 *            数据库类型字符串
-	 * @return
-	 */
-	public static ConfigDataSource getConfigDataSource( String dbType ) {
-		for ( ConfigDataSource dt : ConfigDataSource.values() ) {
-			if ( dt.getDb().equals(dbType) ) {
-				return dt;
-			}
-		}
-		return MYSQL;
-	}
-
-
-	public String getDb() {
-		return db;
-	}
-
-
-	public String getTablesSql() {
-		return tablesSql;
-	}
-
-
-	public String getTableCommentsSql() {
-		return tableCommentsSql;
-	}
-
-
-	public String getTableFieldsSql() {
-		return tableFieldsSql;
-	}
-
-
-	public String getTableName() {
-		return tableName;
-	}
-
-
-	public String getTableComment() {
-		return tableComment;
-	}
-
-
-	public String getFieldName() {
-		return fieldName;
-	}
-
-
-	public String getFieldType() {
-		return fieldType;
-	}
-
-
-	public String getFieldComment() {
-		return fieldComment;
-	}
-
-
-	public String getFieldKey() {
-		return fieldKey;
-	}
-
-}

+ 0 - 279
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/ConfigGenerator.java

@@ -1,279 +0,0 @@
-/**
- * Copyright (c) 2011-2014, hubin (jobob@qq.com).
- *
- * 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.baomidou.mybatisplus.generator;
-
-import com.baomidou.mybatisplus.annotations.IdType;
-
-/**
- * <p>
- * 生成器配置类
- * ********************************* 使用前必读 *********************
- * saveDir 文件生成目录
- * entity_package entity 包路径
- * mapper_package mapper 包路径
- * xmlPackage xx_mapper.xml 包路径,默认为mapper/xml
- * servicePackage service 包路径
- * serviceImplPackage serviceImpl包路径,默认为service/impl
- * superServiceImpl service 父类包路径名称
- * tableNames   要生成的表名称,如为空就直接指定所有表.格式为逗号分割
- * fileOverride 是否覆盖当前已有文件
- * -------------------------------------
- * 以下数据库相关配置:
- * -------------------------------------
- * db_include_prefix 表是否包含前缀,例如: tb_xxx 其中 tb_ 为前缀
- * db_driverName 驱动
- * db_user 用户名
- * db_password 密码
- * db_url 连接地址
- **************************************************************
- * </p>
- * 
- * @author hubin
- * @Date 2016-01-23
- */
-public class ConfigGenerator {
-
-	private String saveDir;
-
-	private String entityPackage;
-
-	private String mapperPackage;
-
-    private String xmlPackage;
-
-    private String servicePackage;
-
-    private String serviceImplPackage;
-
-    private String superServiceImpl;
-
-	/*
-	 * 指定生成表名
-	 */
-	private String[] tableNames = null;
-
-	/*
-	 * 是否覆盖当前路径下已有文件(默认 true)
-	 */
-    private boolean fileOverride = true;
-
-    /* db_config */
-    private boolean dbPrefix = false;
-
-	private String dbDriverName;
-
-	private String dbUser;
-
-	private String dbPassword;
-
-	private String dbUrl;
-
-	private IdType idType = null;
-
-	private ConfigDataSource configDataSource = ConfigDataSource.MYSQL;
-
-	private ConfigIdType configIdType = ConfigIdType.LONG;
-
-	/*
-	 * 数据库字段是否为驼峰命名(默认 true)
-	 */
-	private boolean isColumnHump = true;
-
-
-	public String getSaveDir() {
-		return saveDir;
-	}
-
-
-	public void setSaveDir( String saveDir ) {
-		this.saveDir = saveDir;
-	}
-
-
-	public String getEntityPackage() {
-		return entityPackage;
-	}
-
-
-	public void setEntityPackage( String entityPackage ) {
-		this.entityPackage = entityPackage;
-	}
-
-
-	public String getMapperPackage() {
-		return mapperPackage;
-	}
-
-
-	public void setMapperPackage( String mapperPackage ) {
-		this.mapperPackage = mapperPackage;
-	}
-
-
-	public String getServicePackage() {
-		return servicePackage;
-	}
-
-
-	public void setServicePackage( String servicePackage ) {
-		this.servicePackage = servicePackage;
-	}
-
-
-	public String getSuperServiceImpl() {
-		if ( superServiceImpl == null || "".equals(superServiceImpl) ) {
-			if ( this.getConfigIdType() == ConfigIdType.STRING ) {
-				return "com.baomidou.framework.service.impl.CommonServiceImpl";
-			} else {
-				return "com.baomidou.framework.service.impl.SuperServiceImpl";
-			}
-		}
-		return superServiceImpl;
-	}
-
-
-	public void setSuperServiceImpl( String superServiceImpl ) {
-		this.superServiceImpl = superServiceImpl;
-	}
-
-
-	public boolean isDbPrefix() {
-		return dbPrefix;
-	}
-
-
-	public void setDbPrefix( boolean dbPrefix ) {
-		this.dbPrefix = dbPrefix;
-	}
-
-
-	public String getDbDriverName() {
-		return dbDriverName;
-	}
-
-
-	public void setDbDriverName( String dbDriverName ) {
-		this.dbDriverName = dbDriverName;
-	}
-
-
-	public String getDbUser() {
-		return dbUser;
-	}
-
-
-	public void setDbUser( String dbUser ) {
-		this.dbUser = dbUser;
-	}
-
-
-	public String getDbPassword() {
-		return dbPassword;
-	}
-
-
-	public void setDbPassword( String dbPassword ) {
-		this.dbPassword = dbPassword;
-	}
-
-
-	public String getDbUrl() {
-		return dbUrl;
-	}
-
-
-	public void setDbUrl( String dbUrl ) {
-		this.dbUrl = dbUrl;
-	}
-
-
-	public IdType getIdType() {
-		return idType;
-	}
-
-
-	public void setIdType( IdType idType ) {
-		this.idType = idType;
-	}
-
-
-	public boolean isColumnHump() {
-		return isColumnHump;
-	}
-
-
-	public void setColumnHump( boolean isColumnHump ) {
-		this.isColumnHump = isColumnHump;
-	}
-
-
-	public ConfigDataSource getConfigDataSource() {
-		return configDataSource;
-	}
-
-
-	public void setConfigDataSource( ConfigDataSource configDataSource ) {
-		this.configDataSource = configDataSource;
-	}
-
-
-	public ConfigIdType getConfigIdType() {
-		return configIdType;
-	}
-
-
-	public void setConfigIdType( ConfigIdType configIdType ) {
-		this.configIdType = configIdType;
-	}
-
-    public String getXmlPackage() {
-        if (null == xmlPackage || "".equals(xmlPackage)) {
-            xmlPackage = mapperPackage + ".xml";
-        }
-        return xmlPackage;
-    }
-
-    public void setXmlPackage(String xmlPackage) {
-        this.xmlPackage = xmlPackage;
-    }
-
-	public String[] getTableNames() {
-		return tableNames;
-	}
-
-	public void setTableNames( String[] tableNames ) {
-		this.tableNames = tableNames;
-	}
-
-    public boolean isFileOverride() {
-        return fileOverride;
-    }
-
-    public void setFileOverride(boolean fileOverride) {
-        this.fileOverride = fileOverride;
-    }
-
-    public String getServiceImplPackage() {
-        if (null == serviceImplPackage || "".equals(serviceImplPackage)) {
-            serviceImplPackage = servicePackage + ".impl";
-        }
-        return serviceImplPackage;
-    }
-
-    public void setServiceImplPackage(String serviceImplPackage) {
-        this.serviceImplPackage = serviceImplPackage;
-    }
-}

+ 78 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/InjectionConfig.java

@@ -0,0 +1,78 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.baomidou.mybatisplus.generator;
+
+import java.util.List;
+import java.util.Map;
+
+import com.baomidou.mybatisplus.generator.config.FileOutConfig;
+import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
+
+/**
+ * <p>
+ * 抽象的对外接口
+ * </p>
+ *
+ * @author hubin
+ * @since 2016-12-07
+ */
+public abstract class InjectionConfig {
+
+	/**
+	 * 全局配置
+	 */
+	private ConfigBuilder config;
+
+	/**
+	 * 自定义返回配置 Map 对象
+	 */
+	private Map<String, Object> map;
+
+	/**
+	 * 自定义输出文件
+	 */
+	private List<FileOutConfig> fileOutConfigList;
+
+	/**
+	 * 注入自定义 Map 对象
+	 */
+	public abstract void initMap();
+
+	public ConfigBuilder getConfig() {
+		return config;
+	}
+
+	public void setConfig(ConfigBuilder config) {
+		this.config = config;
+	}
+
+	public Map<String, Object> getMap() {
+		return map;
+	}
+
+	public void setMap(Map<String, Object> map) {
+		this.map = map;
+	}
+
+	public List<FileOutConfig> getFileOutConfigList() {
+		return fileOutConfigList;
+	}
+
+	public void setFileOutConfigList(List<FileOutConfig> fileOutConfigList) {
+		this.fileOutConfigList = fileOutConfigList;
+	}
+
+}

+ 69 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/ConstVal.java

@@ -0,0 +1,69 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.baomidou.mybatisplus.generator.config;
+
+import java.io.File;
+import java.nio.charset.Charset;
+
+/**
+ * 定义常量
+ *
+ * @author YangHu, tangguo
+ * @since 2016/8/31
+ */
+public class ConstVal {
+	
+	public static final String MODULENAME = "ModuleName";
+	
+	public static final String ENTITY = "Entity";
+	public static final String SERIVCE = "Service";
+	public static final String SERVICEIMPL = "ServiceImpl";
+	public static final String MAPPER = "Mapper";
+	public static final String XML = "Xml";
+	public static final String CONTROLLER = "Controller";
+
+	public static final String ENTITY_PATH = "entity_path";
+	public static final String SERIVCE_PATH = "serivce_path";
+	public static final String SERVICEIMPL_PATH = "serviceimpl_path";
+	public static final String MAPPER_PATH = "mapper_path";
+	public static final String XML_PATH = "xml_path";
+	public static final String CONTROLLER_PATH = "controller_path";
+
+	public static final String JAVA_TMPDIR = "java.io.tmpdir";
+	public static final String UTF8 = Charset.forName("UTF-8").name();
+	public static final String UNDERLINE = "_";
+
+	public static final String JAVA_SUFFIX = ".java";
+	public static final String XML_SUFFIX = ".xml";
+
+	public static final String TEMPLATE_ENTITY = "/template/entity.java.vm";
+	public static final String TEMPLATE_MAPPER = "/template/mapper.java.vm";
+	public static final String TEMPLATE_XML = "/template/mapper.xml.vm";
+	public static final String TEMPLATE_SERVICE = "/template/service.java.vm";
+	public static final String TEMPLATE_SERVICEIMPL = "/template/serviceImpl.java.vm";
+	public static final String TEMPLATE_CONTROLLER = "/template/controller.java.vm";
+
+	public static final String ENTITY_NAME = File.separator + "%s" + JAVA_SUFFIX;
+
+	// 配置使用classloader加载资源
+	public static final String VM_LOADPATH_KEY = "file.resource.loader.class";
+	public static final String VM_LOADPATH_VALUE = "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader";
+
+	public static final String SUPERD_MAPPER_CLASS = "com.baomidou.mybatisplus.mapper.BaseMapper";
+	public static final String SUPERD_SERVICE_CLASS = "com.baomidou.mybatisplus.service.IService";
+	public static final String SUPERD_SERVICEIMPL_CLASS = "com.baomidou.mybatisplus.service.impl.ServiceImpl";
+	
+}

+ 163 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/DataSourceConfig.java

@@ -0,0 +1,163 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.baomidou.mybatisplus.generator.config;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
+import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
+import com.baomidou.mybatisplus.generator.config.converts.OracleTypeConvert;
+import com.baomidou.mybatisplus.generator.config.converts.PostgreSqlTypeConvert;
+import com.baomidou.mybatisplus.generator.config.converts.SqlServerTypeConvert;
+import com.baomidou.mybatisplus.generator.config.rules.DbType;
+
+/**
+ * <p>
+ * 数据库配置
+ * </p>
+ *
+ * @author YangHu
+ * @since 2016/8/30
+ */
+public class DataSourceConfig {
+
+	/**
+	 * 数据库类型
+	 */
+	private DbType dbType;
+	/**
+	 * 类型转换
+	 */
+	private ITypeConvert typeConvert;
+	/**
+	 * 驱动连接的URL
+	 */
+	private String url;
+	/**
+	 * 驱动名称
+	 */
+	private String driverName;
+	/**
+	 * 数据库连接用户名
+	 */
+	private String username;
+	/**
+	 * 数据库连接密码
+	 */
+	private String password;
+
+	/**
+	 * 判断数据库类型
+	 *
+	 * @return 类型枚举值
+	 */
+	public DbType getDbType() {
+		if (null == dbType) {
+			if (driverName.contains("mysql")) {
+				dbType = DbType.MYSQL;
+			} else if (driverName.contains("oracle")) {
+				dbType = DbType.ORACLE;
+			} else if (driverName.contains("postgresql")) {
+				dbType = DbType.POSTGRE_SQL;
+			} else {
+				throw new MybatisPlusException("Unknown type of database!");
+			}
+		}
+		return dbType;
+	}
+
+	public void setDbType(DbType dbType) {
+		this.dbType = dbType;
+	}
+
+	public ITypeConvert getTypeConvert() {
+		if (null == typeConvert) {
+			switch (getDbType()) {
+			case ORACLE:
+				typeConvert = new OracleTypeConvert();
+				break;
+			case SQL_SERVER:
+				typeConvert = new SqlServerTypeConvert();
+				break;
+			case POSTGRE_SQL:
+				typeConvert = new PostgreSqlTypeConvert();
+				break;
+			default:
+				// 默认 MYSQL
+				typeConvert = new MySqlTypeConvert();
+				break;
+			}
+		}
+		return typeConvert;
+	}
+
+	public void setTypeConvert(ITypeConvert typeConvert) {
+		this.typeConvert = typeConvert;
+	}
+
+	/**
+	 * 创建数据库连接对象
+	 *
+	 * @return Connection
+	 */
+	public Connection getConn() {
+		Connection conn = null;
+		try {
+			Class.forName(driverName);
+			conn = DriverManager.getConnection(url, username, password);
+		} catch (ClassNotFoundException e) {
+			e.printStackTrace();
+		} catch (SQLException e) {
+			e.printStackTrace();
+		}
+		return conn;
+	}
+
+	public String getUrl() {
+		return url;
+	}
+
+	public void setUrl(String url) {
+		this.url = url;
+	}
+
+	public String getDriverName() {
+		return driverName;
+	}
+
+	public void setDriverName(String driverName) {
+		this.driverName = driverName;
+	}
+
+	public String getUsername() {
+		return username;
+	}
+
+	public void setUsername(String username) {
+		this.username = username;
+	}
+
+	public String getPassword() {
+		return password;
+	}
+
+	public void setPassword(String password) {
+		this.password = password;
+	}
+
+}

+ 55 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/FileOutConfig.java

@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.baomidou.mybatisplus.generator.config;
+
+import com.baomidou.mybatisplus.generator.config.po.TableInfo;
+
+/**
+ * <p>
+ * 输出文件配置
+ * </p>
+ *
+ * @author hubin
+ * @since 2017-01-18
+ */
+public abstract class FileOutConfig {
+	/**
+	 * 模板
+	 */
+	private String templatePath;
+
+	/**
+	 * 输出文件
+	 */
+	public abstract String outputFile(TableInfo tableInfo);
+
+	public FileOutConfig() {
+
+	}
+
+	public FileOutConfig(String templatePath) {
+		this.templatePath = templatePath;
+	}
+
+	public String getTemplatePath() {
+		return templatePath;
+	}
+
+	public void setTemplatePath(String templatePath) {
+		this.templatePath = templatePath;
+	}
+
+}

+ 179 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/GlobalConfig.java

@@ -0,0 +1,179 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.baomidou.mybatisplus.generator.config;
+
+/**
+ * <p>
+ * 全局配置
+ * </p>
+ *
+ * @author hubin
+ * @since 2016-12-02
+ */
+public class GlobalConfig {
+	/**
+	 * 生成文件的输出目录【默认 D 盘根目录】
+	 */
+	private String outputDir = "D://";
+
+	/**
+	 * 是否覆盖已有文件
+	 */
+	private boolean fileOverride = false;
+
+	/**
+	 * 是否打开输出目录
+	 */
+	private boolean open = true;
+
+	/**
+	 * 是否在xml中添加二级缓存配置
+	 */
+	private boolean enableCache = true;
+
+	/**
+	 * 开发人员
+	 */
+	private String author;
+
+	/**
+	 * 开启 ActiveRecord 模式
+	 */
+	private boolean activeRecord = true;
+
+	/**
+	 * 开启 BaseResultMap
+	 */
+	private boolean baseResultMap = false;
+
+	/**
+	 * 开启 baseColumnList
+	 */
+	private boolean baseColumnList = false;
+	/**
+	 * 各层文件名称方式,例如: %Action 生成 UserAction
+	 */
+	private String mapperName;
+	private String xmlName;
+	private String serviceName;
+	private String serviceImplName;
+	private String controllerName;
+
+	public String getOutputDir() {
+		return outputDir;
+	}
+
+	public void setOutputDir(String outputDir) {
+		this.outputDir = outputDir;
+	}
+
+	public boolean isFileOverride() {
+		return fileOverride;
+	}
+
+	public void setFileOverride(boolean fileOverride) {
+		this.fileOverride = fileOverride;
+	}
+
+	public boolean isOpen() {
+		return open;
+	}
+
+	public void setOpen(boolean open) {
+		this.open = open;
+	}
+
+	public boolean isEnableCache() {
+		return enableCache;
+	}
+
+	public void setEnableCache(boolean enableCache) {
+		this.enableCache = enableCache;
+	}
+
+	public String getAuthor() {
+		return author;
+	}
+
+	public void setAuthor(String author) {
+		this.author = author;
+	}
+
+	public boolean isActiveRecord() {
+		return activeRecord;
+	}
+
+	public void setActiveRecord(boolean activeRecord) {
+		this.activeRecord = activeRecord;
+	}
+
+	public boolean isBaseResultMap() {
+		return baseResultMap;
+	}
+
+	public void setBaseResultMap(boolean baseResultMap) {
+		this.baseResultMap = baseResultMap;
+	}
+
+	public boolean isBaseColumnList() {
+		return baseColumnList;
+	}
+
+	public void setBaseColumnList(boolean baseColumnList) {
+		this.baseColumnList = baseColumnList;
+	}
+
+	public String getMapperName() {
+		return mapperName;
+	}
+
+	public void setMapperName(String mapperName) {
+		this.mapperName = mapperName;
+	}
+
+	public String getXmlName() {
+		return xmlName;
+	}
+
+	public void setXmlName(String xmlName) {
+		this.xmlName = xmlName;
+	}
+
+	public String getServiceName() {
+		return serviceName;
+	}
+
+	public void setServiceName(String serviceName) {
+		this.serviceName = serviceName;
+	}
+
+	public String getServiceImplName() {
+		return serviceImplName;
+	}
+
+	public void setServiceImplName(String serviceImplName) {
+		this.serviceImplName = serviceImplName;
+	}
+
+	public String getControllerName() {
+		return controllerName;
+	}
+
+	public void setControllerName(String controllerName) {
+		this.controllerName = controllerName;
+	}
+
+}

+ 17 - 6
mybatis-plus/src/main/java/com/baomidou/framework/service/impl/CommonServiceImpl.java → mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/ITypeConvert.java

@@ -13,18 +13,29 @@
  * License for the specific language governing permissions and limitations under
  * the License.
  */
-package com.baomidou.framework.service.impl;
+package com.baomidou.mybatisplus.generator.config;
 
-import com.baomidou.mybatisplus.mapper.CommonMapper;
+import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
 
 /**
  * <p>
- * 主键 String 类型 IService 实现类( 泛型:M 是 mapper 对象, T 是实体 )
+ * 数据库字段类型转换
  * </p>
- * 
+ *
  * @author hubin
- * @Date 2016-04-20
+ * @date 2017-01-20
  */
-public class CommonServiceImpl<M extends CommonMapper<T>, T> extends ServiceImpl<M, T, String> {
+public interface ITypeConvert {
+
+	/**
+	 * <p>
+	 * 执行类型转换
+	 * </p>
+	 * 
+	 * @param fieldType
+	 *            字段类型
+	 * @return
+	 */
+	DbColumnType processTypeConvert(String fieldType);
 
 }

+ 138 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/PackageConfig.java

@@ -0,0 +1,138 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.baomidou.mybatisplus.generator.config;
+
+import com.baomidou.mybatisplus.toolkit.StringUtils;
+
+/**
+ * <p>
+ * 跟包相关的配置项
+ *
+ * @author YangHu, tangguo
+ * @since 2016-08-30
+ */
+public class PackageConfig {
+
+	/**
+	 * 父包名。如果为空,将下面子包名必须写全部, 否则就只需写子包名
+	 */
+	private String parent = "com.baomidou";
+
+	/**
+	 * 父包模块名。
+	 */
+	private String moduleName = null;
+
+	/**
+	 * Entity包名
+	 */
+	private String entity = "entity";
+
+	/**
+	 * Service包名
+	 */
+	private String service = "service";
+
+	/**
+	 * Service Impl包名
+	 */
+	private String serviceImpl = "service.impl";
+	/**
+	 * Mapper包名
+	 */
+	private String mapper = "mapper";
+
+	/**
+	 * Mapper XML包名
+	 */
+	private String xml = "mapper.xml";
+
+	/**
+	 * Controller包名
+	 */
+	private String controller = "web";
+
+	public String getParent() {
+		if (StringUtils.isNotEmpty(moduleName)) {
+			return parent + "." + moduleName;
+		}
+		return parent;
+	}
+
+	public String getModuleName() {
+		return moduleName;
+	}
+
+	public void setModuleName(String moduleName) {
+		this.moduleName = moduleName;
+	}
+
+	public String getEntity() {
+		return entity;
+	}
+
+	public void setEntity(String entity) {
+		this.entity = entity;
+	}
+
+	public String getService() {
+		return service;
+	}
+
+	public void setService(String service) {
+		this.service = service;
+	}
+
+	public String getServiceImpl() {
+		return serviceImpl;
+	}
+
+	public void setServiceImpl(String serviceImpl) {
+		this.serviceImpl = serviceImpl;
+	}
+
+	public String getMapper() {
+		return mapper;
+	}
+
+	public void setMapper(String mapper) {
+		this.mapper = mapper;
+	}
+
+	public String getXml() {
+		return xml;
+	}
+
+	public void setXml(String xml) {
+		this.xml = xml;
+	}
+
+	public void setParent(String parent) {
+		this.parent = parent;
+	}
+
+	public String getController() {
+		if (StringUtils.isEmpty(controller)) {
+			return "web";
+		}
+		return controller;
+	}
+
+	public void setController(String controller) {
+		this.controller = controller;
+	}
+
+}

+ 269 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/StrategyConfig.java

@@ -0,0 +1,269 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.baomidou.mybatisplus.generator.config;
+
+import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
+import com.baomidou.mybatisplus.toolkit.StringUtils;
+
+/**
+ * <p>
+ * 策略配置项
+ * </p>
+ *
+ * @author YangHu, tangguo, hubin
+ * @since 2016/8/30
+ */
+public class StrategyConfig {
+
+	/**
+	 * 表名、字段名、是否使用下划线命名(默认 false)
+	 */
+	public static boolean DB_COLUMN_UNDERLINE = false;
+
+	/**
+	 * 是否大写命名
+	 */
+	private boolean isCapitalMode = false;
+
+	/**
+	 * 数据库表映射到实体的命名策略
+	 */
+	private NamingStrategy naming = NamingStrategy.nochange;
+
+	private NamingStrategy fieldNaming;
+
+	/**
+	 * 表前缀
+	 */
+	private String[] tablePrefix;
+
+	/**
+	 * 自定义继承的Entity类全称,带包名
+	 */
+	private String superEntityClass;
+
+	/**
+	 * 自定义基础的Entity类,公共字段
+	 */
+	private String[] superEntityColumns;
+
+	/**
+	 * 自定义继承的Mapper类全称,带包名
+	 */
+	private String superMapperClass = ConstVal.SUPERD_MAPPER_CLASS;
+
+	/**
+	 * 自定义继承的Service类全称,带包名
+	 */
+	private String superServiceClass = ConstVal.SUPERD_SERVICE_CLASS;
+
+	/**
+	 * 自定义继承的ServiceImpl类全称,带包名
+	 */
+	private String superServiceImplClass = ConstVal.SUPERD_SERVICEIMPL_CLASS;
+
+	/**
+	 * 自定义继承的Controller类全称,带包名
+	 */
+	private String superControllerClass;
+
+	/*
+	 * 需要包含的表名(与exclude二选一配置)
+	 */
+	private String[] include = null;
+
+	/**
+	 * 需要排除的表名
+	 */
+	private String[] exclude = null;
+	/**
+	 * 【实体】是否生成字段常量(默认 false)<br>
+	 * -----------------------------------<br>
+	 * public static final String ID = "test_id";
+	 */
+	private boolean entityColumnConstant = false;
+
+	/**
+	 * 【实体】是否为构建者模型(默认 false)<br>
+	 * -----------------------------------<br>
+	 * public User setName(String name) { this.name = name; return this; }
+	 */
+	private boolean entityBuliderModel = false;
+
+	public void setDbColumnUnderline(boolean dbColumnUnderline) {
+		DB_COLUMN_UNDERLINE = dbColumnUnderline;
+	}
+
+	/**
+	 * <p>
+	 * 大写命名、字段符合大写字母数字下划线命名
+	 * </p>
+	 * 
+	 * @param word
+	 *            待判断字符串
+	 * @return
+	 */
+	public boolean isCapitalModeNaming(String word) {
+		return isCapitalMode && StringUtils.isCapitalMode(word);
+	}
+
+	/**
+	 * <p>
+	 * 表名称包含指定前缀
+	 * </p>
+	 * 
+	 * @param tableName
+	 *            表名称
+	 * @return
+	 */
+	public boolean containsTablePrefix(String tableName) {
+		if (null != tableName) {
+			String[] tps = getTablePrefix();
+			if (null != tps) {
+				for (String tp : tps) {
+					if (tableName.contains(tp)) {
+						return true;
+					}
+				}
+			}
+		}
+		return false;
+	}
+
+	public boolean isCapitalMode() {
+		return isCapitalMode;
+	}
+
+	public void setCapitalMode(boolean isCapitalMode) {
+		this.isCapitalMode = isCapitalMode;
+	}
+
+	public NamingStrategy getNaming() {
+		return naming;
+	}
+
+	public void setNaming(NamingStrategy naming) {
+		this.naming = naming;
+	}
+
+	public NamingStrategy getFieldNaming() {
+		return fieldNaming;
+	}
+
+	public void setFieldNaming(NamingStrategy fieldNaming) {
+		this.fieldNaming = fieldNaming;
+	}
+
+	public String[] getTablePrefix() {
+		return tablePrefix;
+	}
+
+	public void setTablePrefix(String[] tablePrefix) {
+		this.tablePrefix = tablePrefix;
+	}
+
+	public String getSuperEntityClass() {
+		return superEntityClass;
+	}
+
+	public void setSuperEntityClass(String superEntityClass) {
+		this.superEntityClass = superEntityClass;
+	}
+
+	public boolean includeSuperEntityColumns(String fieldName) {
+		if (null != superEntityColumns) {
+			for (String column : superEntityColumns) {
+				if (column.contains(fieldName)) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
+	public String[] getSuperEntityColumns() {
+		return superEntityColumns;
+	}
+
+	public void setSuperEntityColumns(String[] superEntityColumns) {
+		this.superEntityColumns = superEntityColumns;
+	}
+
+	public String getSuperMapperClass() {
+		return superMapperClass;
+	}
+
+	public void setSuperMapperClass(String superMapperClass) {
+		this.superMapperClass = superMapperClass;
+	}
+
+	public String getSuperServiceClass() {
+		return superServiceClass;
+	}
+
+	public void setSuperServiceClass(String superServiceClass) {
+		this.superServiceClass = superServiceClass;
+	}
+
+	public String getSuperServiceImplClass() {
+		return superServiceImplClass;
+	}
+
+	public void setSuperServiceImplClass(String superServiceImplClass) {
+		this.superServiceImplClass = superServiceImplClass;
+	}
+
+	public String getSuperControllerClass() {
+		return superControllerClass;
+	}
+
+	public void setSuperControllerClass(String superControllerClass) {
+		this.superControllerClass = superControllerClass;
+	}
+
+	public String[] getInclude() {
+		return include;
+	}
+
+	public void setInclude(String[] include) {
+		this.include = include;
+	}
+
+	public String[] getExclude() {
+		return exclude;
+	}
+
+	public void setExclude(String[] exclude) {
+		this.exclude = exclude;
+	}
+
+	public boolean isEntityColumnConstant() {
+		return entityColumnConstant;
+	}
+
+	public void setEntityColumnConstant(boolean entityColumnConstant) {
+		this.entityColumnConstant = entityColumnConstant;
+	}
+
+	public boolean isEntityBuliderModel() {
+		return entityBuliderModel;
+	}
+
+	public void setEntityBuliderModel(boolean entityBuliderModel) {
+		this.entityBuliderModel = entityBuliderModel;
+	}
+
+}

+ 88 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/TemplateConfig.java

@@ -0,0 +1,88 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.baomidou.mybatisplus.generator.config;
+
+/**
+ * <p>
+ * 模板路径配置项
+ * </p>
+ * 
+ * @author tzg
+  *@since 2016/11/10
+ */
+public class TemplateConfig {
+
+	private String entity = ConstVal.TEMPLATE_ENTITY;
+
+	private String service = ConstVal.TEMPLATE_SERVICE;
+
+	private String serviceImpl = ConstVal.TEMPLATE_SERVICEIMPL;
+
+	private String mapper = ConstVal.TEMPLATE_MAPPER;
+
+	private String xml = ConstVal.TEMPLATE_XML;
+
+	private String controller = ConstVal.TEMPLATE_CONTROLLER;
+
+	public String getEntity() {
+		return entity;
+	}
+
+	public void setEntity(String entity) {
+		this.entity = entity;
+	}
+
+	public String getService() {
+		return service;
+	}
+
+	public void setService(String service) {
+		this.service = service;
+	}
+
+	public String getServiceImpl() {
+		return serviceImpl;
+	}
+
+	public void setServiceImpl(String serviceImpl) {
+		this.serviceImpl = serviceImpl;
+	}
+
+	public String getMapper() {
+		return mapper;
+	}
+
+	public void setMapper(String mapper) {
+		this.mapper = mapper;
+	}
+
+	public String getXml() {
+		return xml;
+	}
+
+	public void setXml(String xml) {
+		this.xml = xml;
+	}
+
+	public String getController() {
+		return controller;
+	}
+
+	public void setController(String controller) {
+		this.controller = controller;
+	}
+
+}

+ 546 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/builder/ConfigBuilder.java

@@ -0,0 +1,546 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.baomidou.mybatisplus.generator.config.builder;
+
+import java.io.File;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import com.baomidou.mybatisplus.generator.config.ConstVal;
+import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
+import com.baomidou.mybatisplus.generator.config.GlobalConfig;
+import com.baomidou.mybatisplus.generator.config.PackageConfig;
+import com.baomidou.mybatisplus.generator.config.StrategyConfig;
+import com.baomidou.mybatisplus.generator.config.TemplateConfig;
+import com.baomidou.mybatisplus.generator.config.po.TableField;
+import com.baomidou.mybatisplus.generator.config.po.TableInfo;
+import com.baomidou.mybatisplus.generator.config.rules.DbType;
+import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
+import com.baomidou.mybatisplus.generator.config.rules.QuerySQL;
+import com.baomidou.mybatisplus.toolkit.StringUtils;
+
+/**
+ * 配置汇总 传递给文件生成工具
+ *
+ * @author YangHu, tangguo, hubin
+ * @since 2016-08-30
+ */
+public class ConfigBuilder {
+
+	/**
+	 * SQL连接
+	 */
+	private Connection connection;
+	/**
+	 * SQL语句类型
+	 */
+	private QuerySQL querySQL;
+	private String superEntityClass;
+	private String superMapperClass;
+	/**
+	 * service超类定义
+	 */
+	private String superServiceClass;
+	private String superServiceImplClass;
+	private String superControllerClass;
+	/**
+	 * 数据库表信息
+	 */
+	private List<TableInfo> tableInfoList;
+
+	/**
+	 * 包配置详情
+	 */
+	private Map<String, String> packageInfo;
+	/**
+	 * 路径配置信息
+	 */
+	private Map<String, String> pathInfo;
+
+	/**
+	 * 模板路径配置信息
+	 */
+	private TemplateConfig template;
+	
+	/**
+	 * 数据库配置
+	 */
+	private DataSourceConfig dataSourceConfig;
+
+	/**
+	 * 策略配置
+	 */
+	private StrategyConfig strategyConfig;
+
+	/**
+	 * 全局配置信息
+	 */
+	private GlobalConfig globalConfig;
+
+	/**
+	 * 在构造器中处理配置
+	 * 
+	 * @param packageConfig
+	 *            包配置
+	 * @param dataSourceConfig
+	 *            数据源配置
+	 * @param strategyConfig
+	 *            表配置
+	 * @param template
+	 *            模板配置
+	 * @param globalConfig
+	 *            全局配置
+	 */
+	public ConfigBuilder(PackageConfig packageConfig, DataSourceConfig dataSourceConfig, StrategyConfig strategyConfig,
+			TemplateConfig template, GlobalConfig globalConfig) {
+		// 全局配置
+		if (null == globalConfig) {
+			this.globalConfig = new GlobalConfig();
+		} else {
+			this.globalConfig = globalConfig;
+		}
+		// 包配置
+		if (null == packageConfig) {
+			handlerPackage(this.globalConfig.getOutputDir(), new PackageConfig());
+		} else {
+			handlerPackage(this.globalConfig.getOutputDir(), packageConfig);
+		}
+		this.dataSourceConfig = dataSourceConfig;
+		handlerDataSource(dataSourceConfig);
+		// 策略配置
+		if (null == strategyConfig) {
+			this.strategyConfig = new StrategyConfig();
+		} else {
+			this.strategyConfig = strategyConfig;
+		}
+		handlerStrategy(this.strategyConfig);
+		// 模板配置
+		if (null == template) {
+			this.template = new TemplateConfig();
+		} else {
+			this.template = template;
+		}
+	}
+
+	// ************************ 曝露方法 BEGIN*****************************
+
+	/**
+	 * 所有包配置信息
+	 *
+	 * @return 包配置
+	 */
+	public Map<String, String> getPackageInfo() {
+		return packageInfo;
+	}
+
+	/**
+	 * 所有路径配置
+	 *
+	 * @return 路径配置
+	 */
+	public Map<String, String> getPathInfo() {
+		return pathInfo;
+	}
+
+	public String getSuperEntityClass() {
+		return superEntityClass;
+	}
+
+	public String getSuperMapperClass() {
+		return superMapperClass;
+	}
+
+	/**
+	 * 获取超类定义
+	 *
+	 * @return 完整超类名称
+	 */
+	public String getSuperServiceClass() {
+		return superServiceClass;
+	}
+
+	public String getSuperServiceImplClass() {
+		return superServiceImplClass;
+	}
+
+	public String getSuperControllerClass() {
+		return superControllerClass;
+	}
+
+	/**
+	 * 表信息
+	 *
+	 * @return 所有表信息
+	 */
+	public List<TableInfo> getTableInfoList() {
+		return tableInfoList;
+	}
+
+	/**
+	 * 模板路径配置信息
+	 * 
+	 * @return 所以模板路径配置信息
+	 */
+	public TemplateConfig getTemplate() {
+		return template == null ? new TemplateConfig() : template;
+	}
+
+	// ****************************** 曝露方法 END**********************************
+
+	/**
+	 * 处理包配置
+	 *
+	 * @param config
+	 *            PackageConfig
+	 */
+	private void handlerPackage(String outputDir, PackageConfig config) {
+		packageInfo = new HashMap<String, String>();
+		packageInfo.put(ConstVal.MODULENAME, config.getModuleName());
+		packageInfo.put(ConstVal.ENTITY, joinPackage(config.getParent(), config.getEntity()));
+		packageInfo.put(ConstVal.MAPPER, joinPackage(config.getParent(), config.getMapper()));
+		packageInfo.put(ConstVal.XML, joinPackage(config.getParent(), config.getXml()));
+		packageInfo.put(ConstVal.SERIVCE, joinPackage(config.getParent(), config.getService()));
+		packageInfo.put(ConstVal.SERVICEIMPL, joinPackage(config.getParent(), config.getServiceImpl()));
+		packageInfo.put(ConstVal.CONTROLLER, joinPackage(config.getParent(), config.getController()));
+
+		pathInfo = new HashMap<String, String>();
+		pathInfo.put(ConstVal.ENTITY_PATH, joinPath(outputDir, packageInfo.get(ConstVal.ENTITY)));
+		pathInfo.put(ConstVal.MAPPER_PATH, joinPath(outputDir, packageInfo.get(ConstVal.MAPPER)));
+		pathInfo.put(ConstVal.XML_PATH, joinPath(outputDir, packageInfo.get(ConstVal.XML)));
+		pathInfo.put(ConstVal.SERIVCE_PATH, joinPath(outputDir, packageInfo.get(ConstVal.SERIVCE)));
+		pathInfo.put(ConstVal.SERVICEIMPL_PATH, joinPath(outputDir, packageInfo.get(ConstVal.SERVICEIMPL)));
+		pathInfo.put(ConstVal.CONTROLLER_PATH, joinPath(outputDir, packageInfo.get(ConstVal.CONTROLLER)));
+	}
+
+	/**
+	 * 处理数据源配置
+	 *
+	 * @param config
+	 *            DataSourceConfig
+	 */
+	private void handlerDataSource(DataSourceConfig config) {
+		connection = config.getConn();
+		querySQL = getQuerySQL(config.getDbType());
+	}
+
+	/**
+	 * 处理数据库表 加载数据库表、列、注释相关数据集
+	 *
+	 * @param config
+	 *            StrategyConfig
+	 */
+	private void handlerStrategy(StrategyConfig config) {
+		processTypes(config);
+		tableInfoList = getTablesInfo(config);
+	}
+
+	/**
+	 * 处理superClassName,IdClassType,IdStrategy配置
+	 *
+	 * @param config
+	 *            策略配置
+	 */
+	private void processTypes(StrategyConfig config) {
+		if (StringUtils.isEmpty(config.getSuperServiceClass())) {
+			superServiceClass = ConstVal.SUPERD_SERVICE_CLASS;
+		} else {
+			superServiceClass = config.getSuperServiceClass();
+		}
+		if (StringUtils.isEmpty(config.getSuperServiceImplClass())) {
+			superServiceImplClass = ConstVal.SUPERD_SERVICEIMPL_CLASS;
+		} else {
+			superServiceImplClass = config.getSuperServiceImplClass();
+		}
+		if (StringUtils.isEmpty(config.getSuperMapperClass())) {
+			superMapperClass = ConstVal.SUPERD_MAPPER_CLASS;
+		} else {
+			superMapperClass = config.getSuperMapperClass();
+		}
+		superEntityClass = config.getSuperEntityClass();
+		superControllerClass = config.getSuperControllerClass();
+	}
+
+	/**
+	 * 处理表对应的类名称
+	 *
+	 * @param tableList
+	 *            表名称
+	 * @param strategy
+	 *            命名策略
+	 * @param tablePrefix
+	 * @return 补充完整信息后的表
+	 */
+	private List<TableInfo> processTable(List<TableInfo> tableList, NamingStrategy strategy, String[] tablePrefix) {
+		for (TableInfo tableInfo : tableList) {
+			tableInfo.setEntityName(strategyConfig, NamingStrategy.capitalFirst(processName(tableInfo.getName(), strategy, tablePrefix)));
+			if (StringUtils.isNotEmpty(globalConfig.getMapperName())) {
+				tableInfo.setMapperName(String.format(globalConfig.getMapperName(), tableInfo.getEntityName()));
+			} else {
+				tableInfo.setMapperName(tableInfo.getEntityName() + ConstVal.MAPPER);
+			}
+			if (StringUtils.isNotEmpty(globalConfig.getXmlName())) {
+				tableInfo.setXmlName(String.format(globalConfig.getXmlName(), tableInfo.getEntityName()));
+			} else {
+				tableInfo.setXmlName(tableInfo.getEntityName() + ConstVal.MAPPER);
+			}
+			if (StringUtils.isNotEmpty(globalConfig.getServiceName())) {
+				tableInfo.setServiceName(String.format(globalConfig.getServiceName(), tableInfo.getEntityName()));
+			} else {
+				tableInfo.setServiceName("I" + tableInfo.getEntityName() + ConstVal.SERIVCE);
+			}
+			if (StringUtils.isNotEmpty(globalConfig.getServiceImplName())) {
+				tableInfo.setServiceImplName(String.format(globalConfig.getServiceImplName(), tableInfo.getEntityName()));
+			} else {
+				tableInfo.setServiceImplName(tableInfo.getEntityName() + ConstVal.SERVICEIMPL);
+			}
+			if (StringUtils.isNotEmpty(globalConfig.getControllerName())) {
+				tableInfo.setControllerName(String.format(globalConfig.getControllerName(), tableInfo.getEntityName()));
+			} else {
+				tableInfo.setControllerName(tableInfo.getEntityName() + ConstVal.CONTROLLER);
+			}
+		}
+		return tableList;
+	}
+
+	/**
+	 * 获取所有的数据库表信息
+	 *
+	 * @return 表信息
+	 */
+	private List<TableInfo> getTablesInfo(StrategyConfig config) {
+		boolean isInclude = (null != config.getInclude() && config.getInclude().length > 0);
+		boolean isExclude = (null != config.getExclude() && config.getExclude().length > 0);
+		if (isInclude && isExclude) {
+			throw new RuntimeException("<strategy> 标签中 <include> 与 <exclude> 只能配置一项!");
+		}
+		List<TableInfo> tableList = new ArrayList<TableInfo>();
+		Set<String> notExistTables = new HashSet<String>();
+		NamingStrategy strategy = config.getNaming();
+		NamingStrategy fieldStrategy = config.getFieldNaming();
+		PreparedStatement pstate = null;
+		try {
+			pstate = connection.prepareStatement(querySQL.getTableCommentsSql());
+			ResultSet results = pstate.executeQuery();
+			TableInfo tableInfo;
+			while (results.next()) {
+				String tableName = results.getString(querySQL.getTableName());
+				if (StringUtils.isNotEmpty(tableName)) {
+					String tableComment = results.getString(querySQL.getTableComment());
+					tableInfo = new TableInfo();
+					if (isInclude) {
+						for (String includeTab : config.getInclude()) {
+							if (includeTab.equalsIgnoreCase(tableName)) {
+								tableInfo.setName(tableName);
+								tableInfo.setComment(tableComment);
+							} else {
+								notExistTables.add(includeTab);
+							}
+						}
+					} else if (isExclude) {
+						for (String excludeTab : config.getExclude()) {
+							if (!excludeTab.equalsIgnoreCase(tableName)) {
+								tableInfo.setName(tableName);
+								tableInfo.setComment(tableComment);
+							} else {
+								notExistTables.add(excludeTab);
+							}
+						}
+					} else {
+						tableInfo.setName(tableName);
+						tableInfo.setComment(tableComment);
+					}
+					if (StringUtils.isNotEmpty(tableInfo.getName())) {
+						List<TableField> fieldList = getListFields(tableInfo.getName(), fieldStrategy);
+						tableInfo.setFields(fieldList);
+						tableList.add(tableInfo);
+					}
+				} else {
+					System.err.println("当前数据库为空!!!");
+				}
+			}
+			// 将已经存在的表移除
+			for (TableInfo tabInfo : tableList) {
+				notExistTables.remove(tabInfo.getName());
+			}
+			if (notExistTables.size() > 0) {
+				System.err.println("表 " + notExistTables + " 在数据库中不存在!!!");
+			}
+		} catch (SQLException e) {
+			e.printStackTrace();
+		} finally {
+			// 释放资源
+			try {
+				if (pstate != null) {
+					pstate.close();
+				}
+				if (connection != null) {
+					connection.close();
+				}
+			} catch (SQLException e) {
+				e.printStackTrace();
+			}
+		}
+		return processTable(tableList, strategy, config.getTablePrefix());
+	}
+
+	/**
+	 * 将字段信息与表信息关联
+	 *
+	 * @param tableName
+	 *            表名称
+	 * @param strategy
+	 *            命名策略
+	 * @return 表信息
+	 */
+	private List<TableField> getListFields(String tableName, NamingStrategy strategy) throws SQLException {
+		boolean havedId = false;
+		PreparedStatement pstate = connection.prepareStatement(String.format(querySQL.getTableFieldsSql(), tableName));
+		ResultSet results = pstate.executeQuery();
+
+		List<TableField> fieldList = new ArrayList<TableField>();
+		while (results.next()) {
+			TableField field = new TableField();
+			String key = results.getString(querySQL.getFieldKey());
+			// 避免多重主键设置,目前只取第一个找到ID,并放到list中的索引为0的位置
+			boolean isId = StringUtils.isNotEmpty(key) && key.toUpperCase().equals("PRI");
+			// 处理ID
+			if (isId && !havedId) {
+				field.setKeyFlag(true);
+				havedId = true;
+			} else {
+				field.setKeyFlag(false);
+			}
+			// 处理其它信息
+			field.setName(results.getString(querySQL.getFieldName()));
+			if (strategyConfig.includeSuperEntityColumns(field.getName())) {
+				// 跳过公共字段
+				continue;
+			}
+			field.setType(results.getString(querySQL.getFieldType()));
+			field.setPropertyName(strategyConfig, processName(field.getName(), strategy));
+			field.setColumnType(dataSourceConfig.getTypeConvert().processTypeConvert(field.getType()));
+			field.setComment(results.getString(querySQL.getFieldComment()));
+			fieldList.add(field);
+		}
+		return fieldList;
+	}
+
+	/**
+	 * 连接路径字符串
+	 *
+	 * @param parentDir
+	 *            路径常量字符串
+	 * @param packageName
+	 *            包名
+	 * @return 连接后的路径
+	 */
+	private String joinPath(String parentDir, String packageName) {
+		if (StringUtils.isEmpty(parentDir)) {
+			parentDir = System.getProperty(ConstVal.JAVA_TMPDIR);
+		}
+		if (!StringUtils.endsWith(parentDir, File.separator)) {
+			parentDir += File.separator;
+		}
+		packageName = packageName.replaceAll("\\.", "\\" + File.separator);
+		return parentDir + packageName;
+	}
+
+	/**
+	 * 连接父子包名
+	 *
+	 * @param parent
+	 *            父包名
+	 * @param subPackage
+	 *            子包名
+	 * @return 连接后的包名
+	 */
+	private String joinPackage(String parent, String subPackage) {
+		if (StringUtils.isEmpty(parent)) {
+			return subPackage;
+		}
+		return parent + "." + subPackage;
+	}
+
+	/**
+	 * 处理字段名称
+	 *
+	 * @return 根据策略返回处理后的名称
+	 */
+	private String processName(String name, NamingStrategy strategy) {
+		return processName(name, strategy, null);
+	}
+
+	/**
+	 * 处理字段名称
+	 * 
+	 * @param name
+	 * @param strategy
+	 * @param tablePrefix
+	 * @return 根据策略返回处理后的名称
+	 */
+	private String processName(String name, NamingStrategy strategy, String[] tablePrefix) {
+		String propertyName = "";
+		if (strategy == NamingStrategy.remove_prefix_and_camel) {
+			propertyName = NamingStrategy.removePrefixAndCamel(name, tablePrefix);
+		} else if (strategy == NamingStrategy.underline_to_camel) {
+			propertyName = NamingStrategy.underlineToCamel(name);
+		} else if (strategy == NamingStrategy.remove_prefix) {
+			propertyName = NamingStrategy.removePrefix(name, tablePrefix);
+		} else {
+			propertyName = name;
+		}
+		return propertyName;
+	}
+
+	/**
+	 * 获取当前的SQL类型
+	 *
+	 * @return DB类型
+	 */
+	private QuerySQL getQuerySQL(DbType dbType) {
+		for (QuerySQL qs : QuerySQL.values()) {
+			if (qs.getDbType().equals(dbType.getValue())) {
+				return qs;
+			}
+		}
+		return QuerySQL.MYSQL;
+	}
+
+	public StrategyConfig getStrategyConfig() {
+		return strategyConfig;
+	}
+
+	public void setStrategyConfig(StrategyConfig strategyConfig) {
+		this.strategyConfig = strategyConfig;
+	}
+
+	public GlobalConfig getGlobalConfig() {
+		return globalConfig;
+	}
+
+	public void setGlobalConfig(GlobalConfig globalConfig) {
+		this.globalConfig = globalConfig;
+	}
+
+}

+ 4 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/builder/package-info.java

@@ -0,0 +1,4 @@
+/**
+ * 代码生成器,构建类
+ */
+package com.baomidou.mybatisplus.generator.config.builder;

+ 59 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/converts/MySqlTypeConvert.java

@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2011-2016, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.generator.config.converts;
+
+import com.baomidou.mybatisplus.generator.config.ITypeConvert;
+import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
+
+/**
+ * <p>
+ * MYSQL 数据库字段类型转换
+ * </p>
+ *
+ * @author hubin
+ * @date 2017-01-20
+ */
+public class MySqlTypeConvert implements ITypeConvert {
+
+	public DbColumnType processTypeConvert(String fieldType) {
+		String t = fieldType.toLowerCase();
+		if (t.contains("char") || t.contains("text")) {
+			return DbColumnType.STRING;
+		} else if (t.contains("bigint")) {
+			return DbColumnType.LONG;
+		} else if (t.contains("int")) {
+			return DbColumnType.INTEGER;
+		} else if (t.contains("date") || t.contains("time") || t.contains("year")) {
+			return DbColumnType.DATE;
+		} else if (t.contains("text")) {
+			return DbColumnType.STRING;
+		} else if (t.contains("bit")) {
+			return DbColumnType.BOOLEAN;
+		} else if (t.contains("decimal")) {
+			return DbColumnType.BIG_DECIMAL;
+		} else if (t.contains("blob")) {
+			return DbColumnType.BYTE_ARRAY;
+		} else if (t.contains("float")) {
+			return DbColumnType.FLOAT;
+		} else if (t.contains("double")) {
+			return DbColumnType.DOUBLE;
+		} else if (t.contains("json") || t.contains("enum")) {
+			return DbColumnType.STRING;
+		}
+		return DbColumnType.STRING;
+	}
+
+}

+ 54 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/converts/OracleTypeConvert.java

@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) 2011-2016, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.generator.config.converts;
+
+import com.baomidou.mybatisplus.generator.config.ITypeConvert;
+import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
+
+/**
+ * <p>
+ * ORACLE 字段类型转换
+ * </p>
+ *
+ * @author hubin
+ * @date 2017-01-20
+ */
+public class OracleTypeConvert implements ITypeConvert {
+
+	public DbColumnType processTypeConvert(String fieldType) {
+		String t = fieldType.toUpperCase();
+		if (t.contains("CHAR")) {
+			return DbColumnType.STRING;
+		} else if (t.contains("DATE") || t.contains("TIMESTAMP")) {
+			return DbColumnType.DATE;
+		} else if (t.contains("NUMBER")) {
+			if (t.matches("NUMBER\\(+\\d{1}+\\)")) {
+				return DbColumnType.INTEGER;
+			} else if (t.matches("NUMBER\\(+\\d{2}+\\)")) {
+				return DbColumnType.LONG;
+			}
+			return DbColumnType.DOUBLE;
+		} else if (t.contains("FLOAT")) {
+			return DbColumnType.FLOAT;
+		} else if (t.contains("BLOB")) {
+			return DbColumnType.OBJECT;
+		} else if (t.contains("RAW")) {
+			return DbColumnType.BYTE_ARRAY;
+		}
+		return DbColumnType.STRING;
+	}
+
+}

+ 59 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/converts/PostgreSqlTypeConvert.java

@@ -0,0 +1,59 @@
+/**
+ * Copyright (c) 2011-2016, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.generator.config.converts;
+
+import com.baomidou.mybatisplus.generator.config.ITypeConvert;
+import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
+
+/**
+ * <p>
+ * PostgreSQL 字段类型转换
+ * </p>
+ *
+ * @author hubin
+ * @date 2017-01-20
+ */
+public class PostgreSqlTypeConvert implements ITypeConvert {
+
+	public DbColumnType processTypeConvert(String fieldType) {
+		String t = fieldType.toLowerCase();
+		if (t.contains("char") || t.contains("text")) {
+			return DbColumnType.STRING;
+		} else if (t.contains("bigint")) {
+			return DbColumnType.LONG;
+		} else if (t.contains("int")) {
+			return DbColumnType.INTEGER;
+		} else if (t.contains("date") || t.contains("time") || t.contains("year")) {
+			return DbColumnType.DATE;
+		} else if (t.contains("text")) {
+			return DbColumnType.STRING;
+		} else if (t.contains("bit")) {
+			return DbColumnType.BOOLEAN;
+		} else if (t.contains("decimal")) {
+			return DbColumnType.BIG_DECIMAL;
+		} else if (t.contains("blob")) {
+			return DbColumnType.BYTE_ARRAY;
+		} else if (t.contains("float")) {
+			return DbColumnType.FLOAT;
+		} else if (t.contains("double")) {
+			return DbColumnType.DOUBLE;
+		} else if (t.contains("json") || t.contains("enum")) {
+			return DbColumnType.STRING;
+		}
+		return DbColumnType.STRING;
+	}
+
+}

+ 57 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/converts/SqlServerTypeConvert.java

@@ -0,0 +1,57 @@
+/**
+ * Copyright (c) 2011-2016, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.generator.config.converts;
+
+import com.baomidou.mybatisplus.generator.config.ITypeConvert;
+import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
+
+/**
+ * <p>
+ * SQLServer 字段类型转换
+ * </p>
+ *
+ * @author hubin
+ * @date 2017-01-20
+ */
+public class SqlServerTypeConvert implements ITypeConvert {
+
+	public DbColumnType processTypeConvert(String fieldType) {
+		String t = fieldType.toLowerCase();
+		if (t.contains("char") || t.contains("text") || t.contains("xml")) {
+			return DbColumnType.STRING;
+		} else if (t.contains("bigint")) {
+			return DbColumnType.LONG;
+		} else if (t.contains("int")) {
+			return DbColumnType.INTEGER;
+		} else if (t.contains("date") || t.contains("time")) {
+			return DbColumnType.DATE;
+		} else if (t.contains("text")) {
+			return DbColumnType.STRING;
+		} else if (t.contains("bit")) {
+			return DbColumnType.BOOLEAN;
+		} else if (t.contains("decimal") || t.contains("numeric")) {
+			return DbColumnType.DOUBLE;
+		} else if (t.contains("money")) {
+			return DbColumnType.BIG_DECIMAL;
+		} else if (t.contains("binary") || t.contains("image")) {
+			return DbColumnType.BYTE_ARRAY;
+		} else if (t.contains("float") || t.contains("real")) {
+			return DbColumnType.FLOAT;
+		}
+		return DbColumnType.STRING;
+	}
+
+}

+ 4 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/package-info.java

@@ -0,0 +1,4 @@
+/**
+ * 代码生成器,配置相关类
+ */
+package com.baomidou.mybatisplus.generator.config;

+ 123 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/po/TableField.java

@@ -0,0 +1,123 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.baomidou.mybatisplus.generator.config.po;
+
+import com.baomidou.mybatisplus.generator.config.StrategyConfig;
+import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
+import com.baomidou.mybatisplus.toolkit.StringUtils;
+
+/**
+ * <p>
+ * 表字段信息
+ * </p>
+ * 
+ * @author YangHu
+ * @since 2016-12-03
+ */
+public class TableField {
+	private boolean convert;
+	private boolean keyFlag;
+	private String name;
+	private String type;
+	private String propertyName;
+	private DbColumnType columnType;
+	private String comment;
+
+	public boolean isConvert() {
+		return convert;
+	}
+
+	public void setConvert(boolean convert) {
+		this.convert = convert;
+	}
+
+	protected void setConvert(StrategyConfig strategyConfig) {
+		if (strategyConfig.isCapitalModeNaming(name)) {
+			this.convert = false;
+		} else {
+			// 转换字段
+			if (StrategyConfig.DB_COLUMN_UNDERLINE) {
+				// 包含大写处理
+				if (StringUtils.containsUpperCase(name)) {
+					this.convert = true;
+				}
+			} else if (!name.equalsIgnoreCase(propertyName)) {
+				this.convert = true;
+			}
+		}
+	}
+
+	public boolean isKeyFlag() {
+		return keyFlag;
+	}
+
+	public void setKeyFlag(boolean keyFlag) {
+		this.keyFlag = keyFlag;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getType() {
+		return type;
+	}
+
+	public void setType(String type) {
+		this.type = type;
+	}
+
+	public String getPropertyName() {
+		return propertyName;
+	}
+
+	public void setPropertyName(StrategyConfig strategyConfig, String propertyName) {
+		this.propertyName = propertyName;
+		this.setConvert(strategyConfig);
+	}
+
+	public DbColumnType getColumnType() {
+		return columnType;
+	}
+
+	public void setColumnType(DbColumnType columnType) {
+		this.columnType = columnType;
+	}
+
+	public String getPropertyType() {
+		if (null != columnType) {
+			return columnType.getType();
+		}
+		return null;
+	}
+
+	public String getComment() {
+		return comment;
+	}
+
+	public void setComment(String comment) {
+		this.comment = comment;
+	}
+
+	public String getCapitalName() {
+		return propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
+	}
+
+}

+ 221 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/po/TableInfo.java

@@ -0,0 +1,221 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.baomidou.mybatisplus.generator.config.po;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import com.baomidou.mybatisplus.generator.config.StrategyConfig;
+import com.baomidou.mybatisplus.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.toolkit.StringUtils;
+
+/**
+ * <p>
+ * 表信息,关联到当前字段信息
+ * </p>
+ *
+ * @author YangHu
+ * @since 2016/8/30
+ */
+public class TableInfo {
+	private boolean convert;
+	private String name;
+	private String comment;
+
+	private String entityName;
+	private String mapperName;
+	private String xmlName;
+	private String serviceName;
+	private String serviceImplName;
+	private String controllerName;
+
+	private List<TableField> fields;
+	private List<String> importPackages = new ArrayList<String>();
+	private String fieldNames;
+
+	public boolean isConvert() {
+		return convert;
+	}
+
+	public void setConvert(boolean convert) {
+		this.convert = convert;
+	}
+
+	protected void setConvert(StrategyConfig strategyConfig) {
+		if (strategyConfig.containsTablePrefix(name)) {
+			// 包含前缀
+			this.convert = true;
+		} else if (strategyConfig.isCapitalModeNaming(name)) {
+			// 包含
+			this.convert = false;
+		} else {
+			// 转换字段
+			if (StrategyConfig.DB_COLUMN_UNDERLINE) {
+				// 包含大写处理
+				if (StringUtils.containsUpperCase(name)) {
+					this.convert = true;
+				}
+			} else if (!entityName.equalsIgnoreCase(name)) {
+				this.convert = true;
+			}
+		}
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getComment() {
+		return comment;
+	}
+
+	public void setComment(String comment) {
+		this.comment = comment;
+	}
+
+	public String getEntityPath() {
+		StringBuffer ep = new StringBuffer();
+		ep.append(entityName.substring(0, 1).toLowerCase());
+		ep.append(entityName.substring(1));
+		return ep.toString();
+	}
+
+	public String getEntityName() {
+		return entityName;
+	}
+
+	public void setEntityName(StrategyConfig strategyConfig, String entityName) {
+		this.entityName = entityName;
+		this.setConvert(strategyConfig);
+	}
+
+	public String getMapperName() {
+		return mapperName;
+	}
+
+	public void setMapperName(String mapperName) {
+		this.mapperName = mapperName;
+	}
+
+	public String getXmlName() {
+		return xmlName;
+	}
+
+	public void setXmlName(String xmlName) {
+		this.xmlName = xmlName;
+	}
+
+	public String getServiceName() {
+		return serviceName;
+	}
+
+	public void setServiceName(String serviceName) {
+		this.serviceName = serviceName;
+	}
+
+	public String getServiceImplName() {
+		return serviceImplName;
+	}
+
+	public void setServiceImplName(String serviceImplName) {
+		this.serviceImplName = serviceImplName;
+	}
+
+	public String getControllerName() {
+		return controllerName;
+	}
+
+	public void setControllerName(String controllerName) {
+		this.controllerName = controllerName;
+	}
+
+	public List<TableField> getFields() {
+		return fields;
+	}
+
+	public void setFields(List<TableField> fields) {
+		if (CollectionUtils.isNotEmpty(fields)) {
+			this.fields = fields;
+			// 收集导入包信息
+			Set<String> pkgSet = new HashSet<String>();
+			for (TableField field : fields) {
+				if (null != field.getColumnType() && null != field.getColumnType().getPkg()) {
+					pkgSet.add(field.getColumnType().getPkg());
+				}
+				if (field.isKeyFlag() && field.isConvert()) {
+					pkgSet.add("com.baomidou.mybatisplus.annotations.TableId");
+				}
+				if (field.isConvert()) {
+					pkgSet.add("com.baomidou.mybatisplus.annotations.TableField");
+				}
+			}
+			if (!pkgSet.isEmpty()) {
+				this.importPackages = new ArrayList<String>(Arrays.asList(pkgSet.toArray(new String[] {})));
+			}
+		}
+	}
+
+	public List<String> getImportPackages() {
+		return importPackages;
+	}
+
+	public void setImportPackages(String pkg) {
+		importPackages.add(pkg);
+	}
+
+	/**
+	 * 转换filed实体为xmlmapper中的basecolumn字符串信息
+	 *
+	 * @return
+	 */
+	public String getFieldNames() {
+		if (StringUtils.isEmpty(fieldNames)) {
+			StringBuilder names = new StringBuilder();
+			for (int i = 0; i < fields.size(); i++) {
+				TableField fd = fields.get(i);
+				if (i == fields.size() - 1) {
+					names.append(cov2col(fd));
+				} else {
+					names.append(cov2col(fd)).append(", ");
+				}
+			}
+			fieldNames = names.toString();
+		}
+		return fieldNames;
+	}
+
+	/**
+	 * mapper xml中的字字段添加as
+	 *
+	 * @param field
+	 *            字段实体
+	 * @return 转换后的信息
+	 */
+	private String cov2col(TableField field) {
+		if (null != field) {
+			return field.isConvert() ? field.getName() + " AS " + field.getPropertyName() : field.getName();
+		}
+		return StringUtils.EMPTY;
+	}
+
+}

+ 4 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/po/package-info.java

@@ -0,0 +1,4 @@
+/**
+ * 代码生成器,输出相关类
+ */
+package com.baomidou.mybatisplus.generator.config.po;

+ 63 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/rules/DbColumnType.java

@@ -0,0 +1,63 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.baomidou.mybatisplus.generator.config.rules;
+
+/**
+ * <p>
+ * 表字段类型
+ * </p>
+ * 
+ * @author hubin
+ * @since 2017-01-11
+ */
+public enum DbColumnType {
+	STRING("String", null),
+	LONG("Long", null),
+	INTEGER("Integer", null),
+	FLOAT("Float", null),
+	DOUBLE("Double", null),
+	BOOLEAN("Boolean", null),
+	BYTE_ARRAY("byte[]", null),
+	CHARACTER("Character", null),
+	OBJECT("Object", null),
+	DATE("Date", "java.util.Date"),
+	TIME("Time", "java.sql.Time"),
+	BLOB("Blob", "java.sql.Blob"),
+	CLOB("Clob", "java.sql.Clob"),
+	TIMESTAMP("Timestamp", "java.sql.Timestamp"),
+	BIG_INTEGER("BigInteger", "java.math.BigInteger"),
+	BIG_DECIMAL("BigDecimal", "java.math.BigDecimal");
+
+	/** 类型 */
+	private final String type;
+
+	/** 包路径 */
+	private final String pkg;
+
+	DbColumnType(final String type, final String pkg) {
+		this.type = type;
+		this.pkg = pkg;
+	}
+
+	public String getType() {
+		return this.type;
+	}
+
+	public String getPkg() {
+		return this.pkg;
+	}
+
+}

+ 38 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/rules/DbType.java

@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.baomidou.mybatisplus.generator.config.rules;
+
+/**
+ * 数据库类型定义
+ *
+ * @author YangHu
+ * @since 2016/8/30
+ */
+public enum DbType {
+
+	MYSQL("mysql"), ORACLE("oracle"), SQL_SERVER("sql_server"), POSTGRE_SQL("postgre_sql");
+
+	private String value;
+
+	DbType(String value) {
+		this.value = value;
+	}
+
+	public String getValue() {
+		return value;
+	}
+
+}

+ 144 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/rules/NamingStrategy.java

@@ -0,0 +1,144 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.baomidou.mybatisplus.generator.config.rules;
+
+import com.baomidou.mybatisplus.generator.config.ConstVal;
+import com.baomidou.mybatisplus.toolkit.StringUtils;
+
+/**
+ * 从数据库表到文件的命名策略
+ *
+ * @author YangHu, tangguo
+ * @since 2016/8/30
+ */
+public enum NamingStrategy {
+	/**
+	 * 不做任何改变,原样输出
+	 */
+	nochange,
+	/**
+	 * 下划线转驼峰命名
+	 */
+	underline_to_camel,
+	/**
+	 * 仅去掉前缀
+	 */
+	remove_prefix,
+	/**
+	 * 去掉前缀并且转驼峰
+	 */
+	remove_prefix_and_camel;
+
+	public static String underlineToCamel(String name) {
+		// 快速检查
+		if (StringUtils.isEmpty(name)) {
+			// 没必要转换
+			return "";
+		}
+		String tempName = name;
+		StringBuilder result = new StringBuilder();
+		// 大写数字下划线组成转为小写
+		if (StringUtils.isCapitalMode(name)) {
+			tempName = name.toLowerCase();
+		}
+		// 用下划线将原始字符串分割
+		String camels[] = tempName.split(ConstVal.UNDERLINE);
+		for (String camel : camels) {
+			// 跳过原始字符串中开头、结尾的下换线或双重下划线
+			if (StringUtils.isEmpty(camel)) {
+				continue;
+			}
+			// 处理真正的驼峰片段
+			if (result.length() == 0) {
+				// 第一个驼峰片段,全部字母都小写
+				result.append(camel);
+			} else {
+				// 其他的驼峰片段,首字母大写
+				result.append(capitalFirst(camel));
+			}
+		}
+		return result.toString();
+	}
+
+	/**
+	 * 去掉下划线前缀
+	 *
+	 * @param name
+	 * @return
+	 */
+	public static String removePrefix(String name) {
+		if (StringUtils.isEmpty(name)) {
+			return "";
+		}
+		int idx = name.indexOf(ConstVal.UNDERLINE);
+		if (idx == -1) {
+			return name;
+		}
+		return name.substring(idx + 1);
+	}
+
+	/**
+	 * 去掉指定的前缀
+	 * 
+	 * @param name
+	 * @param prefix
+	 * @return
+	 */
+	public static String removePrefix(String name, String[] prefix) {
+		if (StringUtils.isEmpty(name)) {
+			return "";
+		}
+		if (null != prefix) {
+			for (String pf : prefix) {
+				if (name.toLowerCase().matches("^" + pf.toLowerCase() + ".*")) {
+					// 判断是否有匹配的前缀,然后截取前缀
+					// 删除前缀
+					return name.substring(pf.length());
+				}
+			}
+		}
+		return name;
+	}
+
+	/**
+	 * 去掉下划线前缀且将后半部分转成驼峰格式
+	 *
+	 * @param name
+	 * @param tablePrefix
+	 * @return
+	 */
+	public static String removePrefixAndCamel(String name, String[] tablePrefix) {
+		return underlineToCamel(removePrefix(name, tablePrefix));
+	}
+
+	/**
+	 * 实体首字母大写
+	 *
+	 * @param name
+	 *            待转换的字符串
+	 * @return 转换后的字符串
+	 */
+	public static String capitalFirst(String name) {
+		if (StringUtils.isNotEmpty(name)) {
+			return name.substring(0, 1).toUpperCase() + name.substring(1);
+			/*char[] array = name.toCharArray();
+			array[0] -= 32;
+			return String.valueOf(array);*/
+		}
+		return "";
+	}
+
+}

+ 134 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/rules/QuerySQL.java

@@ -0,0 +1,134 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.baomidou.mybatisplus.generator.config.rules;
+
+/**
+ * <p>
+ * 表数据查询
+ * </p>
+ *
+ * @author hubin, tangguo
+ * @since 2016-04-25
+ */
+public enum QuerySQL {
+	MYSQL("mysql", "show tables", "show table status", "show full fields from %s", "NAME", "COMMENT", "FIELD", "TYPE",
+			"COMMENT", "KEY"),
+
+	ORACLE("oracle", "SELECT * FROM USER_TABLES", "SELECT * FROM USER_TAB_COMMENTS",
+			"SELECT A.COLUMN_NAME, CASE WHEN A.DATA_TYPE='NUMBER' THEN "
+					+ "(CASE WHEN A.DATA_PRECISION IS NULL THEN A.DATA_TYPE "
+					+ "WHEN NVL(A.DATA_SCALE, 0) > 0 THEN A.DATA_TYPE||'('||A.DATA_PRECISION||','||A.DATA_SCALE||')' "
+					+ "ELSE A.DATA_TYPE||'('||A.DATA_PRECISION||')' END) "
+					+ "ELSE A.DATA_TYPE END DATA_TYPE, B.COMMENTS,DECODE(C.POSITION, '1', 'PRI') KEY "
+					+ "FROM USER_TAB_COLUMNS A INNER JOIN USER_COL_COMMENTS B ON A.TABLE_NAME = B.TABLE_NAME"
+					+ " AND A.COLUMN_NAME = B.COLUMN_NAME LEFT JOIN USER_CONSTRAINTS D "
+					+ "ON D.TABLE_NAME = A.TABLE_NAME AND D.CONSTRAINT_TYPE = 'P' "
+					+ "LEFT JOIN USER_CONS_COLUMNS C ON C.CONSTRAINT_NAME = D.CONSTRAINT_NAME "
+					+ "AND C.COLUMN_NAME=A.COLUMN_NAME WHERE A.TABLE_NAME = '%s' ",
+			"TABLE_NAME", "COMMENTS", "COLUMN_NAME", "DATA_TYPE", "COMMENTS", "KEY"),
+
+	SQL_SERVER("sql_server",
+			"select cast(name as varchar(500)) as TABLE_NAME from sysObjects where xtype='U' order by name",
+			"select name as TABLE_NAME,(select cast(value as varchar(500)) from sys.extended_properties where major_id=id and minor_id = 0) as COMMENTS from sysobjects where xtype='U'",
+			"SELECT  cast(a.name as varchar(500)) AS TABLE_NAME, cast(b.name as varchar(500)) AS COLUMN_NAME, "
+					+ "cast(c.value as varchar(500)) AS COMMENTS,cast(sys.types.name as varchar(500)) as DATA_TYPE,"
+					+ "(" + " SELECT case count(1) when 1 then 'PRI' else '' end"
+					+ " FROM syscolumns,sysobjects,sysindexes,sysindexkeys,systypes "
+					+ " WHERE syscolumns.xusertype = systypes.xusertype and syscolumns.id = object_id(A.name) AND sysobjects.xtype = 'PK'"
+					+ " AND sysobjects.parent_obj = syscolumns.id " + " AND sysindexes.id = syscolumns.id "
+					+ " AND sysobjects.name = sysindexes.name AND sysindexkeys.id = syscolumns.id "
+					+ " AND sysindexkeys.indid = sysindexes.indid "
+					+ " AND syscolumns.colid = sysindexkeys.colid and syscolumns.name = B.name) as 'KEY'"
+					+ " FROM sys.tables a " + " INNER JOIN sys.columns b ON b.object_id = a.object_id"
+					+ " left join sys.types on b.system_type_id=sys.types.system_type_id   "
+					+ " LEFT JOIN sys.extended_properties c ON c.major_id = b.object_id AND c.minor_id = b.column_id "
+					+ " WHERE a.name = '%s'",
+			"TABLE_NAME", "COMMENTS", "COLUMN_NAME", "DATA_TYPE", "COMMENTS", "KEY"),
+
+	POSTGRE_SQL("postgre_sql", "select tablename from pg_tables where schemaname='public' ORDER BY tablename",
+			"SELECT A.tablename, obj_description(relfilenode, 'pg_class') AS comments FROM pg_tables A, pg_class B WHERE A.schemaname='public' AND A.tablename = B.relname",
+			"SELECT A.attname AS name,format_type(A.atttypid,A.atttypmod) AS type,col_description(A.attrelid,A.attnum) AS comment,(CASE C.contype WHEN 'p' THEN 'PRI' ELSE '' END) AS key"
+					+ " FROM pg_attribute A INNER JOIN pg_class B ON A.attrelid = B.oid"
+					+ " LEFT JOIN pg_constraint C ON A.attnum = C.conkey[1] WHERE B.relname = '%s' AND A.attnum>0",
+			"tablename", "comments", "name", "type", "comment", "key");
+
+	private final String dbType;
+	private final String tablesSql;
+	private final String tableCommentsSql;
+	private final String tableFieldsSql;
+	private final String tableName;
+	private final String tableComment;
+	private final String fieldName;
+	private final String fieldType;
+	private final String fieldComment;
+	private final String fieldKey;
+
+	QuerySQL(final String dbType, final String tablesSql, final String tableCommentsSql, final String tableFieldsSql,
+			final String tableName, final String tableComment, final String fieldName, final String fieldType,
+			final String fieldComment, final String fieldKey) {
+		this.dbType = dbType;
+		this.tablesSql = tablesSql;
+		this.tableCommentsSql = tableCommentsSql;
+		this.tableFieldsSql = tableFieldsSql;
+		this.tableName = tableName;
+		this.tableComment = tableComment;
+		this.fieldName = fieldName;
+		this.fieldType = fieldType;
+		this.fieldComment = fieldComment;
+		this.fieldKey = fieldKey;
+	}
+
+	public String getDbType() {
+		return dbType;
+	}
+
+	public String getTablesSql() {
+		return tablesSql;
+	}
+
+	public String getTableCommentsSql() {
+		return tableCommentsSql;
+	}
+
+	public String getTableFieldsSql() {
+		return tableFieldsSql;
+	}
+
+	public String getTableName() {
+		return tableName;
+	}
+
+	public String getTableComment() {
+		return tableComment;
+	}
+
+	public String getFieldName() {
+		return fieldName;
+	}
+
+	public String getFieldType() {
+		return fieldType;
+	}
+
+	public String getFieldComment() {
+		return fieldComment;
+	}
+
+	public String getFieldKey() {
+		return fieldKey;
+	}
+
+}

+ 4 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/config/rules/package-info.java

@@ -0,0 +1,4 @@
+/**
+ * 代码生成器,规则相关类
+ */
+package com.baomidou.mybatisplus.generator.config.rules;

+ 1 - 1
mybatis-plus/src/main/java/com/baomidou/mybatisplus/generator/package-info.java

@@ -1,4 +1,4 @@
 /**
- * 自动生成代码相关类
+ * 代码生成器相关类
  */
 package com.baomidou.mybatisplus.generator;

文件差異過大導致無法顯示
+ 521 - 283
mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/AutoSqlInjector.java


+ 100 - 92
mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/BaseMapper.java

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2011-2014, hubin (jobob@qq.com).
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
  *
  * 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
@@ -15,7 +15,9 @@
  */
 package com.baomidou.mybatisplus.mapper;
 
+import java.io.Serializable;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.session.RowBounds;
@@ -31,193 +33,199 @@ import org.apache.ibatis.session.RowBounds;
  * @author hubin
  * @Date 2016-01-23
  */
-public interface BaseMapper<T, I> {
+public interface BaseMapper<T> {
 
 	/**
 	 * <p>
 	 * 插入一条记录
 	 * </p>
+	 * 
 	 * @param entity
-	 * 				实体对象
+	 *            实体对象
 	 * @return int
 	 */
-	int insert( T entity );
-	
-	/**
-	 * <p>
-	 * 插入一条记录(选择字段, null 字段不插入)
-	 * </p>
-	 * @param entity
-	 * 				实体对象
-	 * @return int
-	 */
-	int insertSelective( T entity );
-
+	Integer insert(T entity);
 
 	/**
 	 * <p>
-	 * 插入(批量)
+	 * 根据 ID 删除
 	 * </p>
-	 * @param entityList
-	 * 				实体对象列表
+	 * 
+	 * @param id
+	 *            主键ID
 	 * @return int
 	 */
-	int insertBatch( List<T> entityList );
-
+	Integer deleteById(Serializable id);
 
 	/**
 	 * <p>
-	 * 根据 ID 删除
+	 * 根据 columnMap 条件,删除记录
 	 * </p>
-	 * @param id
-	 * 			主键ID
+	 * 
+	 * @param columnMap
+	 *            表字段 map 对象
 	 * @return int
 	 */
-	int deleteById( I id );
-
+	Integer deleteByMap(@Param("cm") Map<String, Object> columnMap);
 
 	/**
 	 * <p>
 	 * 根据 entity 条件,删除记录
 	 * </p>
-	 * @param entity
-	 * 				实体对象
+	 * 
+	 * @param wrapper
+	 *            实体对象封装操作类(可以为 null)
 	 * @return int
 	 */
-	int deleteSelective( @Param("ew" ) T entity);
-
+	Integer delete(@Param("ew") Wrapper<T> wrapper);
 
 	/**
 	 * <p>
 	 * 删除(根据ID 批量删除)
 	 * </p>
+	 * 
 	 * @param idList
-	 * 				主键ID列表
+	 *            主键ID列表
 	 * @return int
 	 */
-	int deleteBatchIds( List<I> idList );
-
+	Integer deleteBatchIds(List<? extends Serializable> idList);
 
 	/**
 	 * <p>
 	 * 根据 ID 修改
 	 * </p>
+	 * 
 	 * @param entity
-	 * 				实体对象
+	 *            实体对象
 	 * @return int
 	 */
-	int updateById( @Param("et" ) T entity);
-
+	Integer updateById(T entity);
 
 	/**
 	 * <p>
-	 * 根据 ID 选择修改
+	 * 根据 whereEntity 条件,更新记录
 	 * </p>
+	 * 
 	 * @param entity
-	 * 				实体对象
+	 *            实体对象
+	 * @param wrapper
+	 *            实体对象封装操作类(可以为 null)
+	 * @return
 	 */
-	int updateSelectiveById( @Param("et" ) T entity);
-
+	Integer update(@Param("et") T entity, @Param("ew") Wrapper<T> wrapper);
 
 	/**
 	 * <p>
-	 * 根据 whereEntity 条件,更新记录
+	 * 根据 ID 查询
 	 * </p>
-	 * @param entity
-	 * 				实体对象
-	 * @return whereEntity
-	 * 				实体查询条件(可以为 null)
+	 * 
+	 * @param id
+	 *            主键ID
+	 * @return T
 	 */
-	int update( @Param("et" ) T entity, @Param("ew") T whereEntity);
-
+	T selectById(Serializable id);
 
 	/**
 	 * <p>
-	 * 根据 whereEntity 条件,选择更新记录
+	 * 查询(根据ID 批量查询)
 	 * </p>
-	 * @param entity
-	 * 				实体对象
-	 * @return whereEntity(可以为 null)
-	 * 				实体查询条件
+	 * 
+	 * @param idList
+	 *            主键ID列表
+	 * @return List<T>
 	 */
-	int updateSelective( @Param("et" ) T entity, @Param("ew") T whereEntity);
-
+	List<T> selectBatchIds(List<? extends Serializable> idList);
 
 	/**
 	 * <p>
-	 * 根据ID 批量更新
+	 * 查询(根据 columnMap 条件)
 	 * </p>
-	 * @param entityList
-	 * 				实体对象列表
-	 * @return int
+	 * 
+	 * @param columnMap
+	 *            表字段 map 对象
+	 * @return List<T>
 	 */
-	int updateBatchById( List<T> entityList );
-
+	List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);
 
 	/**
 	 * <p>
-	 * 根据 ID 查询
+	 * 根据 entity 条件,查询一条记录
 	 * </p>
-	 * @param id
-	 * 			主键ID
+	 * 
+	 * @param entity
+	 *            实体对象
 	 * @return T
 	 */
-	T selectById( I id );
+	T selectOne(@Param("ew") T entity);
 
+	/**
+	 * <p>
+	 * 根据 Wrapper 条件,查询总记录数
+	 * </p>
+	 * 
+	 * @param wrapper
+	 *            实体对象
+	 * @return int
+	 */
+	Integer selectCount(@Param("ew") Wrapper<T> wrapper);
 
 	/**
 	 * <p>
-	 * 查询(根据ID 批量查询)
+	 * 根据 entity 条件,查询全部记录
 	 * </p>
-	 * @param idList
-	 * 				主键ID列表
+	 * 
+	 * @param wrapper
+	 *            实体对象封装操作类(可以为 null)
 	 * @return List<T>
 	 */
-	List<T> selectBatchIds( List<I> idList );
-
+	List<T> selectList(@Param("ew") Wrapper<T> wrapper);
 
 	/**
 	 * <p>
-	 * 根据 entity 条件,查询一条记录
+	 * 根据 Wrapper 条件,查询全部记录
 	 * </p>
-	 * @param entity
-	 * 				实体对象
-	 * @return T
+	 *
+	 * @param wrapper
+	 *            实体对象封装操作类(可以为 null)
+	 * @return List<T>
 	 */
-	T selectOne( @Param("ew" ) T entity);
-	
-	
+	List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> wrapper);
+
 	/**
 	 * <p>
-	 * 根据 entity 条件,查询总记录数
+	 * 根据 Wrapper 条件,查询全部记录
 	 * </p>
-	 * @param entity
-	 * 				实体对象
-	 * @return int
+	 *
+	 * @param wrapper
+	 *            实体对象封装操作类(可以为 null)
+	 * @return List<Object>
 	 */
-	int selectCount( @Param("ew" ) T entity);
-
+	List<Object> selectObjs(@Param("ew") Wrapper<T> wrapper);
 
 	/**
 	 * <p>
-	 * 根据 entity 条件,查询全部记录
+	 * 根据 entity 条件,查询全部记录(并翻页)
 	 * </p>
-	 * @param entityWrapper
-	 * 					实体对象封装操作类(可以为 null)
+	 * 
+	 * @param rowBounds
+	 *            分页查询条件(可以为 RowBounds.DEFAULT)
+	 * @param wrapper
+	 *            实体对象封装操作类(可以为 null)
 	 * @return List<T>
 	 */
-	List<T> selectList( @Param("ew" ) EntityWrapper<T> entityWrapper);
-	
+	List<T> selectPage(RowBounds rowBounds, @Param("ew") Wrapper<T> wrapper);
+
 	/**
 	 * <p>
-	 * 根据 entity 条件,查询全部记录(并翻页)
+	 * 根据 Wrapper 条件,查询全部记录(并翻页)
 	 * </p>
+	 *
 	 * @param rowBounds
-	 * 					分页查询条件(可以为 RowBounds.DEFAULT)
-	 * @param entityWrapper
-	 * 					实体对象封装操作类(可以为 null)
-	 * @return List<T>
+	 *            分页查询条件(可以为 RowBounds.DEFAULT)
+	 * @param wrapper
+	 *            实体对象封装操作类
+	 * @return List<Map<String, Object>>
 	 */
-	List<T> selectPage( RowBounds rowBounds, @Param("ew" ) EntityWrapper<T> entityWrapper);
+	List<Map<String, Object>> selectMapsPage(RowBounds rowBounds, @Param("ew") Wrapper<T> wrapper);
 
 }

+ 61 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/Condition.java

@@ -0,0 +1,61 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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 EntityWrapperS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.baomidou.mybatisplus.mapper;
+
+import com.baomidou.mybatisplus.toolkit.StringUtils;
+
+/**
+ * <p>
+ * 条件查询构造器
+ * </p>
+ *
+ * @author hubin Caratacus
+ * @date 2016-11-7
+ */
+@SuppressWarnings({ "rawtypes", "serial" })
+public class Condition extends Wrapper {
+
+	/**
+	 * 构建一个Empty条件构造 避免传递参数使用null
+	 */
+	public static Condition Empty() {
+		return Condition.instance();
+	}
+
+	/**
+	 * 获取实例
+	 */
+	public static Condition instance() {
+		return new Condition();
+	}
+
+	/**
+	 * SQL 片段
+	 */
+	@Override
+	public String getSqlSegment() {
+		/*
+		 * 无条件
+		 */
+		String sqlWhere = sql.toString();
+		if (StringUtils.isEmpty(sqlWhere)) {
+			return null;
+		}
+
+		return sqlWhere;
+	}
+
+}

+ 81 - 50
mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/EntityWrapper.java

@@ -1,12 +1,12 @@
 /**
  * Copyright (c) 2011-2014, hubin (jobob@qq.com).
- *
+ * <p>
  * 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
- *
+ * <p>
  * http://www.apache.org/licenses/LICENSE-2.0
- *
+ * <p>
  * 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
@@ -15,81 +15,112 @@
  */
 package com.baomidou.mybatisplus.mapper;
 
-import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
+import com.baomidou.mybatisplus.toolkit.ReflectionKit;
+import com.baomidou.mybatisplus.toolkit.StringUtils;
 
 /**
  * <p>
- * Entity 对象封装操作类
+ * Entity 对象封装操作类,定义T-SQL语法
  * </p>
- * 
- * @author hubin
- * @Date 2016-03-15
+ *
+ * @author hubin , yanghu , Dyang , Caratacus
+ * @Date 2016-11-7
  */
-public class EntityWrapper<T> {
+@SuppressWarnings("serial")
+public class EntityWrapper<T> extends Wrapper<T> {
 
 	/**
-	 * 数据库表映射实体类
+	 * 拼接WHERE后应该是AND还是OR
 	 */
-	private T entity = null;
-
+	private String AND_OR = "AND";
 	/**
-	 * <p>SQL 排序 ORDER BY 字段,例如: id DESC(根据id倒序查询)</p>
-	 * <p>
-	 *  DESC 表示按倒序排序(即:从大到小排序)<br> ACS  表示按正序排序(即:从小到大排序)
-	 * </p>
+	 * 数据库表映射实体类
 	 */
-	private String orderByField = null;
+	protected T entity = null;
 
-
-	protected EntityWrapper() {
-		/* 保护 */
+	public EntityWrapper() {
+		/* 注意,传入查询参数 */
 	}
 
-
-	public EntityWrapper( T entity) {
-		this.setEntity(entity);
-	}
-	
-	
-	public EntityWrapper( T entity, String orderByField ) {
-		this.setEntity(entity);
-		this.setOrderByField(orderByField);
+	public EntityWrapper(T entity) {
+		this.entity = entity;
 	}
 
+	public EntityWrapper(T entity, String sqlSelect) {
+		this.entity = entity;
+		this.sqlSelect = sqlSelect;
+	}
 
 	public T getEntity() {
 		return entity;
 	}
 
-
-	public void setEntity( T entity ) {
+	public void setEntity(T entity) {
 		this.entity = entity;
 	}
 
-
-	public String getOrderByField() {
-		if ( this.orderByField != null ) {
-			StringBuffer ob = new StringBuffer(" ORDER BY ");
-			ob.append(this.orderByField);
-			return ob.toString();
+	/**
+	 * <p>
+	 * 添加OR条件
+	 * </p>
+	 *
+	 * @param sqlOr
+	 *            or 条件语句
+	 * @param params
+	 *            参数集
+	 * @return this
+	 */
+	@Override
+	public Wrapper<T> or(String sqlOr, Object... params) {
+		if (StringUtils.isEmpty(sql.toString())) {
+			AND_OR = "OR";
 		}
-		return null;
+		super.or(sqlOr, params);
+		return this;
 	}
 
+	/**
+	 * <p>
+	 * 使用OR换行,并添加一个带()的新的条件
+	 * </p>
+	 * <p>
+	 * eg: ew.where("name='zhangsan'").and("id=11").orNew("statu=1"); 输出: WHERE
+	 * (name='zhangsan' AND id=11) OR (statu=1)
+	 * </p>
+	 *
+	 * @param sqlOr
+	 *            AND 条件语句
+	 * @param params
+	 *            参数值
+	 * @return this
+	 */
+	@Override
+	public Wrapper<T> orNew(String sqlOr, Object... params) {
+		if (StringUtils.isEmpty(sql.toString())) {
+			AND_OR = "OR";
+		}
+		super.orNew(sqlOr, params);
+		return this;
+	}
 
-	public void setOrderByField( String orderByField ) {
-		if ( orderByField != null && !"".equals(orderByField) ) {
-			/**
-			 * 判断是否存在 SQL 注入
-			 */
-			String ob = orderByField.toUpperCase();
-			if ( ob.contains("INSERT") || ob.contains("DELETE") 
-					|| ob.contains("UPDATE") || ob.contains("SELECT") ) {
-				throw new MybatisPlusException(" orderBy=[" + orderByField + "], There may be SQL injection");
-			} else {
-				this.orderByField = orderByField;
-			}
+	/**
+	 * SQL 片段
+	 */
+	@Override
+	public String getSqlSegment() {
+		/*
+		 * 无条件
+		 */
+		String sqlWhere = sql.toString();
+		if (StringUtils.isEmpty(sqlWhere)) {
+			return null;
 		}
+
+		/*
+		 * 根据当前实体判断是否需要将WHERE替换成 AND 增加实体不为空但所有属性为空的情况
+		 */
+		sqlWhere = ReflectionKit.checkFieldValueNotNull(entity) ? sqlWhere.replaceFirst("WHERE", AND_OR) : sqlWhere;
+		return sqlWhere;
 	}
 
 }

+ 41 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/IMetaObjectHandler.java

@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.mapper;
+
+import org.apache.ibatis.reflection.MetaObject;
+
+/**
+ * <p>
+ * 元对象字段填充控制器抽象类,实现公共字段自动写入
+ * </p>
+ * 
+ * @author hubin
+ * @Date 2016-08-28
+ */
+public interface IMetaObjectHandler {
+
+	/**
+	 * <p>
+	 * 插入元对象字段填充
+	 * </p>
+	 * 
+	 * @param metaObject
+	 *            元对象
+	 * @return
+	 */
+	void insertFill(MetaObject metaObject);
+
+}

+ 55 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/ISqlInjector.java

@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2011-2016, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.mapper;
+
+import org.apache.ibatis.builder.MapperBuilderAssistant;
+import org.apache.ibatis.session.Configuration;
+
+/**
+ * <p>
+ * SQL 自动注入器接口
+ * </p>
+ * 
+ * @author hubin
+ * @Date 2016-07-24
+ */
+public interface ISqlInjector {
+
+	/**
+	 * 根据mapperClass注入SQL
+	 * 
+	 * @param builderAssistant
+	 * @param mapperClass
+	 */
+	void inject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass);
+
+	/**
+	 * 检查SQL是否注入(已经注入过不再注入)
+	 * 
+	 * @param builderAssistant
+	 * @param mapperClass
+	 */
+	void inspectInject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass);
+
+	/**
+	 * 注入SqlRunner相关
+	 * 
+	 * @param configuration
+	 * @see com.baomidou.mybatisplus.mapper.SqlRunner
+	 */
+	void injectSqlRunner(Configuration configuration);
+
+}

+ 178 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/SqlHelper.java

@@ -0,0 +1,178 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.mapper;
+
+import com.baomidou.mybatisplus.entity.GlobalConfiguration;
+import com.baomidou.mybatisplus.entity.TableInfo;
+import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
+import com.baomidou.mybatisplus.plugins.Page;
+import com.baomidou.mybatisplus.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.toolkit.TableInfoHelper;
+import org.apache.ibatis.logging.Log;
+import org.apache.ibatis.logging.LogFactory;
+import org.apache.ibatis.session.Configuration;
+import org.apache.ibatis.session.ExecutorType;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+
+import java.util.List;
+
+/**
+ * <p>
+ * SQL 辅助类
+ * </p>
+ *
+ * @author hubin
+ * @Date 2016-11-06
+ */
+public class SqlHelper {
+
+	private static final Log logger = LogFactory.getLog(SqlHelper.class);
+
+	/**
+	 * 获取Session 默认自动提交
+	 * <p>
+	 * 特别说明:这里获取SqlSession时这里虽然设置了自动提交但是如果事务托管了的话 是不起作用的 切记!!
+	 * <p/>
+	 *
+	 * @return SqlSession
+	 */
+	public static SqlSession sqlSession(Class<?> clazz) {
+		return sqlSession(clazz, true);
+	}
+
+	/**
+	 * <p>
+	 * 批量操作 SqlSession
+	 * </p>
+	 *
+	 * @param clazz
+	 *            实体类
+	 * @return SqlSession
+	 */
+	public static SqlSession sqlSessionBatch(Class<?> clazz) {
+		SqlSession sqlSession = getSqlSession(clazz, true);
+		return (sqlSession != null) ? sqlSession : GlobalConfiguration.currentSessionFactory(clazz).openSession(
+				ExecutorType.BATCH, false);
+	}
+
+	/**
+	 * 获取sqlSessionå
+	 *
+	 * @param clazz
+	 * @param isBatch
+	 * @return
+	 */
+	private static SqlSession getSqlSession(Class<?> clazz, boolean isBatch) {
+		SqlSession session = null;
+		try {
+			SqlSessionFactory sqlSessionFactory = GlobalConfiguration.currentSessionFactory(clazz);
+			Configuration configuration = sqlSessionFactory.getConfiguration();
+			GlobalConfiguration globalConfiguration = GlobalConfiguration.getGlobalConfig(configuration);
+			session = isBatch ? globalConfiguration.getSqlsessionBatch() : globalConfiguration.getSqlSession();
+		} catch (Exception e) {
+			// ignored
+		}
+		return session;
+	}
+
+	/**
+	 * <p>
+	 * 获取Session
+	 * </p>
+	 *
+	 * @param clazz
+	 *            实体类
+	 * @param autoCommit
+	 *            true自动提交false则相反
+	 * @return SqlSession
+	 */
+	public static SqlSession sqlSession(Class<?> clazz, boolean autoCommit) {
+		SqlSession sqlSession = getSqlSession(clazz, false);
+		return (sqlSession != null) ? sqlSession : GlobalConfiguration.currentSessionFactory(clazz).openSession(autoCommit);
+	}
+
+	/**
+	 * 获取TableInfo
+	 *
+	 * @return TableInfo
+	 */
+	public static TableInfo table(Class<?> clazz) {
+		TableInfo tableInfo = TableInfoHelper.getTableInfo(clazz);
+		if (null == tableInfo) {
+			throw new MybatisPlusException("Error: Cannot execute table Method, ClassGenricType not found .");
+		}
+		return tableInfo;
+	}
+
+	/**
+	 * <p>
+	 * 判断数据库操作是否成功
+	 * </p>
+	 *
+	 * @param result
+	 *            数据库操作返回影响条数
+	 * @return boolean
+	 */
+	public static boolean retBool(Integer result) {
+		return (null == result) ? false : result >= 1;
+	}
+
+	/**
+	 * <p>
+	 * 返回SelectCount执行结果
+	 * </p>
+	 *
+	 * @param result
+	 * @return int
+	 */
+	public static int retCount(Integer result) {
+		return (null == result) ? 0 : result;
+	}
+
+	/**
+	 * <p>
+	 * 从list中取第一条数据返回对应List中泛型的单个结果
+	 * </p>
+	 *
+	 * @param list
+	 * @param <E>
+	 * @return
+	 */
+	public static <E> E getObject(List<E> list) {
+		if (CollectionUtils.isNotEmpty(list)) {
+			int size = list.size();
+			if (size > 1) {
+				logger.warn(String.format("Warn: execute Method There are  %s results.", size));
+			}
+			return list.get(0);
+		}
+		return null;
+	}
+
+	/**
+	 * 填充Wrapper
+	 *
+	 * @param page
+	 * @param wrapper
+	 */
+	public static void fillWrapper(Page<?> page, Wrapper<?> wrapper) {
+		if (null != wrapper) {
+			wrapper.orderBy(page.getOrderByField(), page.isAsc());
+			wrapper.allEq(page.getCondition());
+		}
+	}
+}

+ 312 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/SqlPlus.java

@@ -0,0 +1,312 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.baomidou.mybatisplus.mapper;
+
+import com.baomidou.mybatisplus.MybatisAbstractSQL;
+import com.baomidou.mybatisplus.enums.SqlLike;
+import com.baomidou.mybatisplus.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.toolkit.StringUtils;
+
+import java.util.Collection;
+
+/**
+ * <p>
+ * 实现AbstractSQL ,实现WHERE条件自定义
+ * </p>
+ *
+ * @author yanghu , Caratacus
+ * @Date 2016-08-22
+ */
+@SuppressWarnings("serial")
+public class SqlPlus extends MybatisAbstractSQL<SqlPlus> {
+
+	private final String IS_NOT_NULL = " IS NOT NULL";
+	private final String IS_NULL = " IS NULL";
+	private final String SQL_LIKE = " LIKE {0}";
+	private final String SQL_BETWEEN_AND = " BETWEEN {0} AND {1}";
+
+	@Override
+	public SqlPlus getSelf() {
+		return this;
+	}
+
+	/**
+	 * 将LIKE语句添加到WHERE条件中
+	 *
+	 * @param column
+	 *            字段名
+	 * @param value
+	 *            like值,无需前后%
+	 * @param type
+	 *            like值,无需前后%
+	 * @return
+	 */
+	public SqlPlus LIKE(String column, String value, SqlLike type) {
+		handerLike(column, value, type, false);
+		return this;
+	}
+
+	/**
+	 * 将LIKE语句添加到WHERE条件中
+	 *
+	 * @param column
+	 *            字段名
+	 * @param value
+	 *            like值,无需前后%
+	 * @param type
+	 * @return
+	 */
+	public SqlPlus NOT_LIKE(String column, String value, SqlLike type) {
+		handerLike(column, value, type, true);
+		return this;
+	}
+
+	/**
+	 * IS NOT NULL查询
+	 *
+	 * @param columns
+	 *            以逗号分隔的字段名称
+	 * @return this
+	 */
+	public SqlPlus IS_NOT_NULL(String columns) {
+		handerNull(columns, IS_NOT_NULL);
+		return this;
+	}
+
+	/**
+	 * IS NULL查询
+	 *
+	 * @param columns
+	 *            以逗号分隔的字段名称
+	 * @return
+	 */
+	public SqlPlus IS_NULL(String columns) {
+		handerNull(columns, IS_NULL);
+		return this;
+	}
+
+	/**
+	 * 处理LIKE操作
+	 *
+	 * @param column
+	 *            字段名称
+	 * @param value
+	 *            like匹配值
+	 * @param isNot
+	 *            是否为NOT LIKE操作
+	 */
+	private void handerLike(String column, String value, SqlLike type, boolean isNot) {
+		if (StringUtils.isNotEmpty(column) && StringUtils.isNotEmpty(value)) {
+			StringBuilder inSql = new StringBuilder();
+			inSql.append(column);
+			if (isNot) {
+				inSql.append(" NOT");
+			}
+			inSql.append(StringUtils.sqlArgsFill(SQL_LIKE, StringUtils.concatLike(value, type)));
+			WHERE(inSql.toString());
+		}
+	}
+
+	/**
+	 * 将IN语句添加到WHERE条件中
+	 *
+	 * @param column
+	 *            字段名
+	 * @param value
+	 *            List集合
+	 * @return
+	 */
+	public SqlPlus IN(String column, Collection<?> value) {
+		handerIn(column, value, false);
+		return this;
+	}
+
+	/**
+	 * 将IN语句添加到WHERE条件中
+	 *
+	 * @param column
+	 *            字段名
+	 * @param value
+	 *            List集合
+	 * @return
+	 */
+	public SqlPlus NOT_IN(String column, Collection<?> value) {
+		handerIn(column, value, true);
+		return this;
+	}
+
+	/**
+	 * 将IN语句添加到WHERE条件中
+	 *
+	 * @param column
+	 *            字段名
+	 * @param value
+	 *            逗号拼接的字符串
+	 * @return
+	 */
+	public SqlPlus IN(String column, String value) {
+		handerIn(column, value, false);
+		return this;
+	}
+
+	/**
+	 * 将IN语句添加到WHERE条件中
+	 *
+	 * @param column
+	 *            字段名
+	 * @param value
+	 *            逗号拼接的字符串
+	 * @return
+	 */
+	public SqlPlus NOT_IN(String column, String value) {
+		handerIn(column, value, true);
+		return this;
+	}
+
+	/**
+	 * 将EXISTS语句添加到WHERE条件中
+	 *
+	 * @param value
+	 * @return
+	 */
+	public SqlPlus EXISTS(String value) {
+		handerExists(value, false);
+		return this;
+	}
+
+	/**
+	 * 处理EXISTS操作
+	 *
+	 * @param value
+	 * @param isNot
+	 *            是否为NOT EXISTS操作
+	 */
+	private void handerExists(String value, boolean isNot) {
+		if (StringUtils.isNotEmpty(value)) {
+			StringBuilder inSql = new StringBuilder();
+			if (isNot) {
+				inSql.append(" NOT");
+			}
+			inSql.append(" EXISTS (").append(value).append(")");
+			WHERE(inSql.toString());
+		}
+	}
+
+	/**
+	 * 将NOT_EXISTS语句添加到WHERE条件中
+	 *
+	 * @param value
+	 * @return
+	 */
+	public SqlPlus NOT_EXISTS(String value) {
+		handerExists(value, true);
+		return this;
+	}
+
+	/**
+	 * 处理IN操作
+	 *
+	 * @param column
+	 *            字段名称
+	 * @param value
+	 *            集合List
+	 * @param isNot
+	 *            是否为NOT IN操作
+	 */
+	private void handerIn(String column, Collection<?> value, boolean isNot) {
+		if (StringUtils.isNotEmpty(column) && CollectionUtils.isNotEmpty(value)) {
+			StringBuilder inSql = new StringBuilder();
+			inSql.append(column);
+			if (isNot) {
+				inSql.append(" NOT");
+			}
+			inSql.append(" IN ");
+			inSql.append(StringUtils.quotaMarkList(value));
+			WHERE(inSql.toString());
+		}
+	}
+
+	/**
+	 * 处理IN操作
+	 *
+	 * @param column
+	 *            字段名称
+	 * @param value
+	 *            逗号拼接的字符串
+	 * @param isNot
+	 *            是否为NOT IN操作
+	 */
+	private void handerIn(String column, String value, boolean isNot) {
+		if (StringUtils.isNotEmpty(column) && StringUtils.isNotEmpty(value)) {
+			StringBuilder inSql = new StringBuilder();
+			inSql.append(column);
+			if (isNot) {
+				inSql.append(" NOT");
+			}
+			inSql.append(" IN (").append(value).append(")");
+			WHERE(inSql.toString());
+		}
+	}
+
+	/**
+	 * 处理BETWEEN_AND操作
+	 *
+	 * @param column
+	 *            字段名称
+	 * @param val1
+	 * @param val2
+	 */
+	public SqlPlus BETWEEN_AND(String column, String val1, String val2) {
+		between(column, val1, val2);
+		return this;
+	}
+
+	/**
+	 * 处理BETWEEN_AND操作
+	 *
+	 * @param column
+	 *            字段名称
+	 * @param val1
+	 * @param val2
+	 */
+	private void between(String column, String val1, String val2) {
+		if (StringUtils.isNotEmpty(column) && StringUtils.isNotEmpty(val1) && StringUtils.isNotEmpty(val2)) {
+			StringBuilder betweenSql = new StringBuilder();
+			betweenSql.append(column);
+			betweenSql.append(StringUtils.sqlArgsFill(SQL_BETWEEN_AND, StringUtils.quotaMark(val1), StringUtils.quotaMark(val2)));
+			WHERE(betweenSql.toString());
+		}
+	}
+
+	/**
+	 * 以相同的方式处理null和notnull
+	 *
+	 * @param columns
+	 *            以逗号分隔的字段名称
+	 * @param sqlPart
+	 *            SQL部分
+	 */
+	private void handerNull(String columns, String sqlPart) {
+		if (StringUtils.isNotEmpty(columns)) {
+			String[] cols = columns.split(",");
+			for (String col : cols) {
+				if (StringUtils.isNotEmpty(col.trim())) {
+					WHERE(col + sqlPart);
+				}
+			}
+		}
+	}
+}

+ 142 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/SqlRunner.java

@@ -0,0 +1,142 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.mapper;
+
+import com.baomidou.mybatisplus.entity.GlobalConfiguration;
+import com.baomidou.mybatisplus.plugins.Page;
+import com.baomidou.mybatisplus.toolkit.StringUtils;
+import org.apache.ibatis.session.SqlSession;
+import org.apache.ibatis.session.SqlSessionFactory;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * SqlRunner 执行 SQL
+ * </p>
+ *
+ * @author Caratacus
+ * @Date 2016-12-11
+ */
+public class SqlRunner {
+
+	// 默认FACTORY
+	public static SqlSessionFactory FACTORY;
+
+	public static final String INSERT = "com.baomidou.mybatisplus.mapper.SqlRunner.Insert";
+	public static final String DELETE = "com.baomidou.mybatisplus.mapper.SqlRunner.Delete";
+	public static final String UPDATE = "com.baomidou.mybatisplus.mapper.SqlRunner.Update";
+	public static final String SELECT = "com.baomidou.mybatisplus.mapper.SqlRunner.Select";
+	public static final String COUNT = "com.baomidou.mybatisplus.mapper.SqlRunner.Count";
+	public static final String SQLScript = "${sql}";
+	public static final String SQL = "sql";
+
+	// 单例Query
+	public static final SqlRunner DEFAULT = new SqlRunner();
+
+	private SqlSessionFactory sqlSessionFactory;
+
+	private Class<?> clazz;
+
+	public SqlRunner() {
+		this.sqlSessionFactory = FACTORY;
+	}
+
+	public SqlRunner(Class<?> clazz) {
+		this.clazz = clazz;
+	}
+
+	public boolean insert(String sql, Object... args) {
+		return SqlHelper.retBool(sqlSession().insert(INSERT, sqlMap(sql, args)));
+	}
+
+	public boolean delete(String sql, Object... args) {
+		return SqlHelper.retBool(sqlSession().delete(DELETE, sqlMap(sql, args)));
+	}
+
+	/**
+	 * 获取sqlMap参数
+	 * 
+	 * @param sql
+	 * @param args
+	 * @return
+	 */
+	private Map<String, String> sqlMap(String sql, Object... args) {
+		Map<String, String> sqlMap = new HashMap<String, String>();
+		sqlMap.put(SQL, StringUtils.sqlArgsFill(sql, args));
+		return sqlMap;
+	}
+
+	public boolean update(String sql, Object... args) {
+		return SqlHelper.retBool(sqlSession().update(UPDATE, sqlMap(sql, args)));
+	}
+
+	public List<Map<String, Object>> selectList(String sql, Object... args) {
+		return sqlSession().selectList(SELECT, sqlMap(sql, args));
+	}
+
+	public int selectCount(String sql, Object... args) {
+		return SqlHelper.retCount(sqlSession().<Integer> selectOne(COUNT, sqlMap(sql, args)));
+	}
+
+	public Map<String, Object> selectOne(String sql, Object... args) {
+		return SqlHelper.getObject(selectList(sql, args));
+	}
+
+	@SuppressWarnings({ "unchecked", "rawtypes" })
+	public Page<Map<String, Object>> selectPage(Page page, String sql, Object... args) {
+		if (null == page) {
+			return null;
+		}
+		page.setRecords(sqlSession().selectList(SELECT, sqlMap(sql, args), page));
+		return page;
+	}
+
+	/**
+	 * 获取默认的SqlQuery(适用于单库)
+	 * 
+	 * @return
+	 */
+	public static SqlRunner db() {
+		// 初始化的静态变量 还是有前后加载的问题 该判断只会执行一次
+		if (DEFAULT.sqlSessionFactory == null) {
+			DEFAULT.sqlSessionFactory = FACTORY;
+		}
+		return DEFAULT;
+	}
+
+	/**
+	 * 根据当前class对象获取SqlQuery(适用于多库)
+	 * 
+	 * @param clazz
+	 * @return
+	 */
+	public static SqlRunner db(Class<?> clazz) {
+		return new SqlRunner(clazz);
+	}
+
+	/**
+	 * <p>
+	 * 获取Session 默认自动提交
+	 * <p/>
+	 */
+	private SqlSession sqlSession() {
+		return clazz != null ? SqlHelper.sqlSession(clazz) : GlobalConfiguration.getSqlSession(FACTORY.getConfiguration());
+	}
+
+}

+ 643 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/Wrapper.java

@@ -0,0 +1,643 @@
+/**
+ * Copyright (c) 2011-2014, hubin (jobob@qq.com).
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.baomidou.mybatisplus.mapper;
+
+import com.baomidou.mybatisplus.enums.SqlLike;
+import com.baomidou.mybatisplus.toolkit.MapUtils;
+import com.baomidou.mybatisplus.toolkit.StringUtils;
+
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Map;
+
+
+/**
+ * <p>
+ * 条件构造抽象类,定义T-SQL语法
+ * </p>
+ *
+ * @author hubin , yanghu , Dyang , Caratacus
+ * @Date 2016-11-7
+ */
+@SuppressWarnings("serial")
+public abstract class Wrapper<T> implements Serializable {
+
+    /**
+     * SQL 查询字段内容,例如:id,name,age
+     */
+    protected String sqlSelect = null;
+
+    /**
+     * 实现了TSQL语法的SQL实体
+     */
+    protected SqlPlus sql = new SqlPlus();
+
+    /**
+     * 兼容EntityWrapper
+     *
+     * @return
+     */
+    public T getEntity() {
+        return null;
+    }
+
+    public String getSqlSelect() {
+        if (StringUtils.isEmpty(sqlSelect)) {
+            return null;
+        }
+        return stripSqlInjection(sqlSelect);
+    }
+
+    public Wrapper<T> setSqlSelect(String sqlSelect) {
+        if (StringUtils.isNotEmpty(sqlSelect)) {
+            this.sqlSelect = sqlSelect;
+        }
+        return this;
+    }
+
+    /**
+     * SQL 片段 (子类实现)
+     */
+    public abstract String getSqlSegment();
+
+    public String toString() {
+        return getSqlSegment();
+    }
+
+    /**
+     * <p>
+     * SQL中WHERE关键字跟的条件语句
+     * </p>
+     * <p>
+     * eg: ew.where("name='zhangsan'").where("id={0}","123");
+     * <p>
+     * 输出: WHERE (NAME='zhangsan' AND id=123)
+     * </p>
+     *
+     * @param sqlWhere
+     *            where语句
+     * @param params
+     *            参数集
+     * @return this
+     */
+    public Wrapper<T> where(String sqlWhere, Object... params) {
+        sql.WHERE(formatSql(sqlWhere, params));
+        return this;
+    }
+
+    /**
+     * <p>
+     * 等同于SQL的"field=value"表达式
+     * </p>
+     *
+     * @param column
+     * @param params
+     * @return
+     */
+    public Wrapper<T> eq(String column, Object params) {
+        sql.WHERE(formatSql(String.format("%s = {0}", column), params));
+        return this;
+    }
+
+    /**
+     * <p>
+     * 等同于SQL的"field <> value"表达式
+     * </p>
+     *
+     * @param column
+     * @param params
+     * @return
+     */
+    public Wrapper<T> ne(String column, Object params) {
+        sql.WHERE(formatSql(String.format("%s <> {0}", column), params));
+        return this;
+    }
+
+    /**
+     * <p>
+     * 等同于SQL的"field=value"表达式
+     * </p>
+     *
+     * @param params
+     * @return
+     */
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    public Wrapper<T> allEq(Map<String, Object> params) {
+        if (MapUtils.isNotEmpty(params)) {
+			Iterator iterator = params.entrySet().iterator();
+            while (iterator.hasNext()) {
+				Map.Entry<String,Object> entry = (Map.Entry<String,Object>) iterator.next();
+                Object value = entry.getValue();
+                if(StringUtils.checkValNotNull(value)){
+                    sql.WHERE(formatSql(String.format("%s = {0}", entry.getKey()), entry.getValue()));
+                }
+
+            }
+
+        }
+        return this;
+    }
+
+    /**
+     * <p>
+     * 等同于SQL的"field>value"表达式
+     * </p>
+     *
+     * @param column
+     * @param params
+     * @return
+     */
+    public Wrapper<T> gt(String column, Object params) {
+        sql.WHERE(formatSql(String.format("%s > {0}", column), params));
+        return this;
+    }
+
+    /**
+     * <p>
+     * 等同于SQL的"field>=value"表达式
+     * </p>
+     *
+     * @param column
+     * @param params
+     * @return
+     */
+    public Wrapper<T> ge(String column, Object params) {
+        sql.WHERE(formatSql(String.format("%s >= {0}", column), params));
+        return this;
+    }
+
+    /**
+     * <p>
+     * 等同于SQL的"field<value"表达式
+     * </p>
+     *
+     * @param column
+     * @param params
+     * @return
+     */
+    public Wrapper<T> lt(String column, Object params) {
+        sql.WHERE(formatSql(String.format("%s < {0}", column), params));
+        return this;
+    }
+
+    /**
+     * <p>
+     * 等同于SQL的"field<=value"表达式
+     * </p>
+     *
+     * @param column
+     * @param params
+     * @return
+     */
+    public Wrapper<T> le(String column, Object params) {
+        sql.WHERE(formatSql(String.format("%s <= {0}", column), params));
+        return this;
+    }
+
+    /**
+     * <p>
+     * AND 连接后续条件
+     * </p>
+     *
+     * @param sqlAnd
+     *            and条件语句
+     * @param params
+     *            参数集
+     * @return this
+     */
+    public Wrapper<T> and(String sqlAnd, Object... params) {
+        sql.AND().WHERE(formatSql(sqlAnd, params));
+        return this;
+    }
+
+    /**
+     * <p>
+     * 使用AND连接并换行
+     * </p>
+     * <p>
+     * eg: ew.where("name='zhangsan'").and("id=11").andNew("statu=1"); 输出: WHERE
+     * (name='zhangsan' AND id=11) AND (statu=1)
+     * </p>
+     *
+     * @param sqlAnd
+     *            AND 条件语句
+     * @param params
+     *            参数值
+     * @return this
+     */
+    public Wrapper<T> andNew(String sqlAnd, Object... params) {
+        sql.AND_NEW().WHERE(formatSql(sqlAnd, params));
+        return this;
+    }
+
+    /**
+     * <p>
+     * 添加OR条件
+     * </p>
+     *
+     * @param sqlOr
+     *            or 条件语句
+     * @param params
+     *            参数集
+     * @return this
+     */
+    public Wrapper<T> or(String sqlOr, Object... params) {
+        sql.OR().WHERE(formatSql(sqlOr, params));
+        return this;
+    }
+
+    /**
+     * <p>
+     * 使用OR换行,并添加一个带()的新的条件
+     * </p>
+     * <p>
+     * eg: ew.where("name='zhangsan'").and("id=11").orNew("statu=1"); 输出: WHERE
+     * (name='zhangsan' AND id=11) OR (statu=1)
+     * </p>
+     *
+     * @param sqlOr
+     *            AND 条件语句
+     * @param params
+     *            参数值
+     * @return this
+     */
+    public Wrapper<T> orNew(String sqlOr, Object... params) {
+        sql.OR_NEW().WHERE(formatSql(sqlOr, params));
+        return this;
+    }
+
+    /**
+     * <p>
+     * SQL中groupBy关键字跟的条件语句
+     * </p>
+     * <p>
+     * eg: ew.where("name='zhangsan'").groupBy("id,name")
+     * </p>
+     *
+     * @param columns
+     *            SQL 中的 Group by 语句,无需输入 Group By 关键字
+     * @return this
+     */
+    public Wrapper<T> groupBy(String columns) {
+        sql.GROUP_BY(columns);
+        return this;
+    }
+
+    /**
+     * <p>
+     * SQL中having关键字跟的条件语句
+     * </p>
+     * <p>
+     * eg: ew.groupBy("id,name").having("id={0}",22).and("password is not null")
+     * </p>
+     *
+     * @param sqlHaving
+     *            having关键字后面跟随的语句
+     * @param params
+     *            参数集
+     * @return EntityWrapper<T>
+     */
+    public Wrapper<T> having(String sqlHaving, Object... params) {
+        sql.HAVING(formatSql(sqlHaving, params));
+        return this;
+    }
+
+    /**
+     * <p>
+     * SQL中orderby关键字跟的条件语句
+     * </p>
+     * <p>
+     * eg: ew.groupBy("id,name").having("id={0}",22).and("password is not null"
+     * ).orderBy("id,name")
+     * </p>
+     *
+     * @param columns
+     *            SQL 中的 order by 语句,无需输入 Order By 关键字
+     * @return this
+     */
+    public Wrapper<T> orderBy(String columns) {
+        sql.ORDER_BY(columns);
+        return this;
+    }
+
+    /**
+     * <p>
+     * SQL中orderby关键字跟的条件语句,可根据变更动态排序
+     * </p>
+     *
+     * @param columns
+     *            SQL 中的 order by 语句,无需输入 Order By 关键字
+     * @param isAsc
+     *            是否为升序
+     * @return this
+     */
+    public Wrapper<T> orderBy(String columns, boolean isAsc) {
+        if (StringUtils.isNotEmpty(columns)) {
+            sql.ORDER_BY(columns + (isAsc ? " ASC" : " DESC"));
+        }
+        return this;
+    }
+
+    /**
+     * LIKE条件语句,value中无需前后%
+     *
+     * @param column
+     *            字段名称
+     * @param value
+     *            匹配值
+     * @return this
+     */
+    public Wrapper<T> like(String column, String value) {
+        sql.LIKE(column, value, SqlLike.DEFAULT);
+        return this;
+    }
+
+    /**
+     * NOT LIKE条件语句,value中无需前后%
+     *
+     * @param column
+     *            字段名称
+     * @param value
+     *            匹配值
+     * @return this
+     */
+    public Wrapper<T> notLike(String column, String value) {
+        sql.NOT_LIKE(column, value, SqlLike.DEFAULT);
+        return this;
+    }
+    /**
+     * LIKE条件语句,value中无需前后%
+     *
+     * @param column
+     *            字段名称
+     * @param value
+     *            匹配值
+     * @param type
+     * @return this
+     */
+    public Wrapper<T> like(String column, String value, SqlLike type) {
+        sql.LIKE(column, value,type);
+        return this;
+    }
+
+    /**
+     * NOT LIKE条件语句,value中无需前后%
+     *
+     * @param column
+     *            字段名称
+     * @param value
+     *            匹配值
+     * @param type
+     * @return this
+     */
+    public Wrapper<T> notLike(String column, String value, SqlLike type) {
+        sql.NOT_LIKE(column, value,type);
+        return this;
+    }
+
+    /**
+     * is not null 条件
+     *
+     * @param columns
+     *            字段名称。多个字段以逗号分隔。
+     * @return this
+     */
+    public Wrapper<T> isNotNull(String columns) {
+        sql.IS_NOT_NULL(columns);
+        return this;
+    }
+
+    /**
+     * is not null 条件
+     *
+     * @param columns
+     *            字段名称。多个字段以逗号分隔。
+     * @return this
+     */
+    public Wrapper<T> isNull(String columns) {
+        sql.IS_NULL(columns);
+        return this;
+    }
+
+    /**
+     * EXISTS 条件语句,目前适配mysql及oracle
+     *
+     * @param value
+     *            匹配值
+     * @return this
+     */
+    public Wrapper<T> exists(String value) {
+        sql.EXISTS(value);
+        return this;
+    }
+
+    /**
+     * NOT EXISTS条件语句
+     *
+     * @param value
+     *            匹配值
+     * @return this
+     */
+    public Wrapper<T> notExists(String value) {
+        sql.NOT_EXISTS(value);
+        return this;
+    }
+
+    /**
+     * IN 条件语句,目前适配mysql及oracle
+     *
+     * @param column
+     *            字段名称
+     * @param value
+     *            逗号拼接的字符串
+     * @return this
+     */
+    public Wrapper<T> in(String column, String value) {
+        sql.IN(column, value);
+        return this;
+    }
+
+    /**
+     * NOT IN条件语句
+     *
+     * @param column
+     *            字段名称
+     * @param value
+     *            逗号拼接的字符串
+     * @return this
+     */
+    public Wrapper<T> notIn(String column, String value) {
+        sql.NOT_IN(column, value);
+        return this;
+    }
+
+    /**
+     * IN 条件语句,目前适配mysql及oracle
+     *
+     * @param column
+     *            字段名称
+     * @param value
+     *            匹配值 List集合
+     * @return this
+     */
+    public Wrapper<T> in(String column, Collection<?> value) {
+        sql.IN(column, value);
+        return this;
+    }
+
+    /**
+     * NOT IN 条件语句,目前适配mysql及oracle
+     *
+     * @param column
+     *            字段名称
+     * @param value
+     *            匹配值 List集合
+     * @return this
+     */
+    public Wrapper<T> notIn(String column, Collection<?> value) {
+        sql.NOT_IN(column, value);
+        return this;
+    }
+
+    /**
+     * IN 条件语句,目前适配mysql及oracle
+     *
+     * @param column
+     *            字段名称
+     * @param value
+     *            匹配值 object数组
+     * @return this
+     */
+    public Wrapper<T> in(String column, Object[] value) {
+        sql.IN(column, Arrays.asList(value));
+        return this;
+    }
+
+    /**
+     * NOT IN 条件语句,目前适配mysql及oracle
+     *
+     * @param column
+     *            字段名称
+     * @param value
+     *            匹配值 object数组
+     * @return this
+     */
+    public Wrapper<T> notIn(String column, Object... value) {
+        sql.NOT_IN(column, Arrays.asList(value));
+        return this;
+    }
+
+    /**
+     * betwwee 条件语句
+     *
+     * @param column
+     *            字段名称
+     * @param val1
+     * @param val2
+     * @return this
+     */
+    public Wrapper<T> between(String column, String val1, String val2) {
+        sql.BETWEEN_AND(column, val1, val2);
+        return this;
+    }
+
+    /**
+     * 为了兼容之前的版本,可使用where()或and()替代
+     *
+     * @param sqlWhere
+     *            where sql部分
+     * @param params
+     *            参数集
+     * @return this
+     */
+    public Wrapper<T> addFilter(String sqlWhere, Object... params) {
+        return and(sqlWhere, params);
+    }
+
+    /**
+     * <p>
+     * 根据判断条件来添加条件语句部分 使用 andIf() 替代
+     * </p>
+     * <p>
+     * eg: ew.filterIfNeed(false,"name='zhangsan'").where("name='zhangsan'")
+     * .filterIfNeed(true,"id={0}",22)
+     * <p>
+     * 输出: WHERE (name='zhangsan' AND id=22)
+     * </p>
+     *
+     * @param need
+     *            是否需要添加该条件
+     * @param sqlWhere
+     *            条件语句
+     * @param params
+     *            参数集
+     * @return this
+     */
+    public Wrapper<T> addFilterIfNeed(boolean need, String sqlWhere, Object... params) {
+        return need ? where(sqlWhere, params) : this;
+    }
+
+    /**
+     * <p>
+     * SQL注入内容剥离
+     * </p>
+     *
+     * @param value
+     *            待处理内容
+     * @return this
+     */
+    protected String stripSqlInjection(String value) {
+        return value.replaceAll("('.+--)|(--)|(\\|)|(%7C)", "");
+    }
+
+    /**
+     * <p>
+     * 格式化SQL
+     * </p>
+     *
+     * @param sqlStr
+     *            SQL语句部分
+     * @param params
+     *            参数集
+     * @return this
+     */
+    protected String formatSql(String sqlStr, Object... params) {
+        return formatSqlIfNeed(true, sqlStr, params);
+    }
+
+    /**
+     * <p>
+     * 根据需要格式化SQL
+     * </p>
+     *
+     * @param need
+     *            是否需要格式化
+     * @param sqlStr
+     *            SQL语句部分
+     * @param params
+     *            参数集
+     * @return this
+     */
+    protected String formatSqlIfNeed(boolean need, String sqlStr, Object... params) {
+        if (!need || StringUtils.isEmpty(sqlStr)) {
+            return null;
+        }
+        return StringUtils.sqlArgsFill(sqlStr, params);
+    }
+
+}

+ 27 - 11
mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/Page.java

@@ -1,12 +1,12 @@
 /**
  * Copyright (c) 2011-2014, hubin (jobob@qq.com).
- *
+ * <p>
  * 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
- *
+ * <p>
  * http://www.apache.org/licenses/LICENSE-2.0
- *
+ * <p>
  * 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
@@ -17,6 +17,8 @@ package com.baomidou.mybatisplus.plugins;
 
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 import com.baomidou.mybatisplus.plugins.pagination.Pagination;
 
@@ -24,7 +26,7 @@ import com.baomidou.mybatisplus.plugins.pagination.Pagination;
  * <p>
  * 实现分页辅助类
  * </p>
- * 
+ *
  * @author hubin
  * @Date 2016-03-01
  */
@@ -37,36 +39,50 @@ public class Page<T> extends Pagination {
 	 */
 	private List<T> records = Collections.emptyList();
 
+	/**
+	 * 查询参数
+	 */
+	private Map<String, Object> condition = new ConcurrentHashMap<String, Object>();
 
-	protected Page() {
-		/* 保护 */
+	public Page() {
+		/* 注意,传入翻页参数 */
 	}
 
-
-	public Page( int current, int size ) {
+	public Page(int current, int size) {
 		super(current, size);
 	}
 
+	public Page(int current, int size, String orderByField) {
+		super(current, size);
+		this.setOrderByField(orderByField);
+	}
 
 	public List<T> getRecords() {
 		return records;
 	}
 
-
-	public void setRecords( List<T> records ) {
+	public void setRecords(List<T> records) {
 		this.records = records;
 	}
 
+	public Map<String, Object> getCondition() {
+		return condition;
+	}
+
+	public void setCondition(Map<String, Object> condition) {
+		this.condition = condition;
+	}
 
 	@Override
 	public String toString() {
 		StringBuffer pg = new StringBuffer();
 		pg.append(" Page:{ [").append(super.toString()).append("], ");
-		if ( records != null ) {
+		if (records != null) {
 			pg.append("records-size:").append(records.size());
 		} else {
 			pg.append("records is null");
 		}
 		return pg.append(" }").toString();
 	}
+
 }

+ 113 - 77
mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/PaginationInterceptor.java

@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2011-2014, hubin (jobob@qq.com).
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
  *
  * 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
@@ -15,13 +15,14 @@
  */
 package com.baomidou.mybatisplus.plugins;
 
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.Properties;
-
-import org.apache.ibatis.executor.parameter.ParameterHandler;
+import com.baomidou.mybatisplus.MybatisDefaultParameterHandler;
+import com.baomidou.mybatisplus.entity.CountOptimize;
+import com.baomidou.mybatisplus.plugins.pagination.DialectFactory;
+import com.baomidou.mybatisplus.plugins.pagination.Pagination;
+import com.baomidou.mybatisplus.toolkit.IOUtils;
+import com.baomidou.mybatisplus.toolkit.SqlUtils;
+import com.baomidou.mybatisplus.toolkit.StringUtils;
+import org.apache.ibatis.executor.Executor;
 import org.apache.ibatis.executor.statement.StatementHandler;
 import org.apache.ibatis.mapping.BoundSql;
 import org.apache.ibatis.mapping.MappedStatement;
@@ -33,70 +34,50 @@ import org.apache.ibatis.plugin.Signature;
 import org.apache.ibatis.reflection.MetaObject;
 import org.apache.ibatis.reflection.SystemMetaObject;
 import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
+import org.apache.ibatis.session.ResultHandler;
 import org.apache.ibatis.session.RowBounds;
 
-import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
-import com.baomidou.mybatisplus.plugins.pagination.DialectFactory;
-import com.baomidou.mybatisplus.plugins.pagination.IDialect;
-import com.baomidou.mybatisplus.plugins.pagination.Pagination;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.Properties;
 
 /**
  * <p>
  * 分页拦截器
  * </p>
- * 
+ *
  * @author hubin
  * @Date 2016-01-23
  */
-@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class, Integer.class }) })
+@Intercepts({@Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class }),
+		@Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class, Integer.class }) })
 public class PaginationInterceptor implements Interceptor {
-	
+
+	/* 溢出总页数,设置第一页 */
+	private boolean overflowCurrent = false;
+	/* Count优化方式 */
+	private String optimizeType = "default";
 	/* 方言类型 */
 	private String dialectType;
-	
 	/* 方言实现类 */
 	private String dialectClazz;
 
 	public Object intercept(Invocation invocation) throws Throwable {
+
 		Object target = invocation.getTarget();
 		if (target instanceof StatementHandler) {
 			StatementHandler statementHandler = (StatementHandler) target;
 			MetaObject metaStatementHandler = SystemMetaObject.forObject(statementHandler);
 			RowBounds rowBounds = (RowBounds) metaStatementHandler.getValue("delegate.rowBounds");
-			
+
 			/* 不需要分页的场合 */
 			if (rowBounds == null || rowBounds == RowBounds.DEFAULT) {
 				return invocation.proceed();
 			}
-			
-			/* 定义数据库方言 */
-			IDialect dialect = null;
-			if (dialectType != null && !"".equals(dialectType)) {
-				dialect = DialectFactory.getDialectByDbtype(dialectType);
-			} else {
-				if (dialectClazz != null && !"".equals(dialectClazz)) {
-					try {
-						Class<?> clazz = Class.forName(dialectClazz);
-						if (IDialect.class.isAssignableFrom(clazz)) {
-							dialect = (IDialect) clazz.newInstance();
-						}
-					} catch (ClassNotFoundException e) {
-						throw new MybatisPlusException("Class :" + dialectClazz + " is not found");
-					}
-				}
-			}
-			
-			/* 未配置方言则抛出异常 */
-			if (dialect == null) {
-				throw new MybatisPlusException("The value of the dialect property in mybatis configuration.xml is not defined.");
-			}
 
 			/*
-			 * <p>
-			 * 禁用内存分页
-			 * </p>
-			 * <p>
-			 * 内存分页会查询所有结果出来处理(这个很吓人的),如果结果变化频繁这个数据还会不准。
+			 * <p> 禁用内存分页 </p> <p> 内存分页会查询所有结果出来处理(这个很吓人的),如果结果变化频繁这个数据还会不准。
 			 * </p>
 			 */
 			BoundSql boundSql = (BoundSql) metaStatementHandler.getValue("delegate.boundSql");
@@ -113,47 +94,97 @@ public class PaginationInterceptor implements Interceptor {
 			 * </p>
 			 */
 			if (rowBounds instanceof Pagination) {
-				MappedStatement mappedStatement = (MappedStatement) metaStatementHandler.getValue("delegate.mappedStatement");
-				Connection connection = (Connection) invocation.getArgs()[0];
-				Pagination page = this.count(originalSql, connection, mappedStatement, boundSql, (Pagination) rowBounds);
-				originalSql = dialect.buildPaginationSql(originalSql, page.getOffsetCurrent(), page.getSize());
+				Pagination page = (Pagination) rowBounds;
+				boolean orderBy = true;
+				if (page.isSearchCount()) {
+					/*
+					 * COUNT 查询,去掉 ORDER BY 优化执行 SQL
+					 */
+					CountOptimize countOptimize = SqlUtils.getCountOptimize(originalSql, optimizeType, dialectType,
+							page.isOptimizeCount());
+					orderBy = countOptimize.isOrderBy();
+				}
+
+				/* 执行 SQL */
+				String buildSql = SqlUtils.concatOrderBy(originalSql, page, orderBy);
+				originalSql = DialectFactory.buildPaginationSql(page, buildSql, dialectType, dialectClazz);
 			}
 
 			/**
 			 * 查询 SQL 设置
 			 */
 			metaStatementHandler.setValue("delegate.boundSql.sql", originalSql);
+		} else {
+			MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
+			Object parameterObject = null;
+			RowBounds rowBounds = null;
+			if (invocation.getArgs().length > 1) {
+				parameterObject = invocation.getArgs()[1];
+				rowBounds = (RowBounds) invocation.getArgs()[2];
+			}
+			/* 不需要分页的场合 */
+			if (rowBounds == null || rowBounds == RowBounds.DEFAULT) {
+				return invocation.proceed();
+			}
+
+			BoundSql boundSql = mappedStatement.getBoundSql(parameterObject);
+			/*
+			 * <p> 禁用内存分页 </p> <p> 内存分页会查询所有结果出来处理(这个很吓人的),如果结果变化频繁这个数据还会不准。
+			 * </p>
+			 */
+			String originalSql = (String) boundSql.getSql();
+
+			/**
+			 * <p>
+			 * 分页逻辑
+			 * </p>
+			 * <p>
+			 * 查询总记录数 count
+			 * </p>
+			 */
+			if (rowBounds instanceof Pagination) {
+				Connection connection = null;
+				try {
+					Pagination page = (Pagination) rowBounds;
+					if (page.isSearchCount()) {
+						connection = mappedStatement.getConfiguration().getEnvironment().getDataSource().getConnection();
+						/*
+						 * COUNT 查询,去掉 ORDER BY 优化执行 SQL
+						 */
+						CountOptimize countOptimize = SqlUtils.getCountOptimize(originalSql, optimizeType, dialectType,
+								page.isOptimizeCount());
+						page = this.count(countOptimize.getCountSQL(), connection, mappedStatement, boundSql, page);
+						/** 总数 0 跳出执行 */
+						if (page.getTotal() <= 0) {
+							return invocation.proceed();
+						}
+					}
+				} finally {
+					IOUtils.closeQuietly(connection);
+				}
+			}
 		}
 
 		return invocation.proceed();
+
 	}
 
 	/**
 	 * 查询总记录条数
-	 * 
+	 *
 	 * @param sql
 	 * @param connection
 	 * @param mappedStatement
 	 * @param boundSql
 	 * @param page
 	 */
-	public Pagination count(String sql, Connection connection, MappedStatement mappedStatement, BoundSql boundSql,
-			Pagination page) {
-		String sqlUse = sql;
-		int order_by = sql.toUpperCase().lastIndexOf("ORDER BY");
-		if ( order_by > -1 ) {
-			sqlUse = sql.substring(0, order_by);
-		}
-		StringBuffer countSql = new StringBuffer("SELECT COUNT(1) AS TOTAL FROM (");
-		countSql.append(sqlUse).append(") A");
+	public Pagination count(String sql, Connection connection, MappedStatement mappedStatement, BoundSql boundSql, Pagination page) {
 		PreparedStatement pstmt = null;
 		ResultSet rs = null;
 		try {
-			pstmt = connection.prepareStatement(countSql.toString());
-			BoundSql countBS = new BoundSql(mappedStatement.getConfiguration(), countSql.toString(),
-					boundSql.getParameterMappings(), boundSql.getParameterObject());
-			ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement,
-					boundSql.getParameterObject(), countBS);
+			pstmt = connection.prepareStatement(sql);
+			DefaultParameterHandler parameterHandler = new MybatisDefaultParameterHandler(mappedStatement,
+					boundSql.getParameterObject(), boundSql);
 			parameterHandler.setParameters(pstmt);
 			rs = pstmt.executeQuery();
 			int total = 0;
@@ -161,27 +192,25 @@ public class PaginationInterceptor implements Interceptor {
 				total = rs.getInt(1);
 			}
 			page.setTotal(total);
-			/**
-			 * 当前页大于总页数,当前页设置为第一页
+			/*
+			 * 溢出总页数,设置第一页
 			 */
-			if(page.getCurrent() > page.getPages()){
+			if (overflowCurrent && (page.getCurrent() > page.getPages())) {
 				page = new Pagination(1, page.getSize());
 				page.setTotal(total);
 			}
-		} catch (SQLException e) {
-			e.printStackTrace();
+		} catch (Exception e) {
+			// ignored
 		} finally {
-			try {
-				rs.close();
-				pstmt.close();
-			} catch (SQLException e) {
-				e.printStackTrace();
-			}
+			IOUtils.closeQuietly(pstmt, rs);
 		}
 		return page;
 	}
 
 	public Object plugin(Object target) {
+		if (target instanceof Executor) {
+			return Plugin.wrap(target, this);
+		}
 		if (target instanceof StatementHandler) {
 			return Plugin.wrap(target, this);
 		}
@@ -191,10 +220,10 @@ public class PaginationInterceptor implements Interceptor {
 	public void setProperties(Properties prop) {
 		String dialectType = prop.getProperty("dialectType");
 		String dialectClazz = prop.getProperty("dialectClazz");
-		if (dialectType != null && !"".equals(dialectType)) {
+		if (StringUtils.isNotEmpty(dialectType)) {
 			this.dialectType = dialectType;
 		}
-		if (dialectClazz != null && !"".equals(dialectClazz)) {
+		if (StringUtils.isNotEmpty(dialectClazz)) {
 			this.dialectClazz = dialectClazz;
 		}
 	}
@@ -207,4 +236,11 @@ public class PaginationInterceptor implements Interceptor {
 		this.dialectClazz = dialectClazz;
 	}
 
-}
+	public void setOverflowCurrent(boolean overflowCurrent) {
+		this.overflowCurrent = overflowCurrent;
+	}
+
+	public void setOptimizeType(String optimizeType) {
+		this.optimizeType = optimizeType;
+	}
+}

+ 141 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/PerformanceInterceptor.java

@@ -0,0 +1,141 @@
+/**
+ * Copyright (c) 2011-2014, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.plugins;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.mapping.BoundSql;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.mapping.ParameterMapping;
+import org.apache.ibatis.mapping.ParameterMode;
+import org.apache.ibatis.plugin.Interceptor;
+import org.apache.ibatis.plugin.Intercepts;
+import org.apache.ibatis.plugin.Invocation;
+import org.apache.ibatis.plugin.Plugin;
+import org.apache.ibatis.plugin.Signature;
+import org.apache.ibatis.reflection.MetaObject;
+import org.apache.ibatis.session.Configuration;
+import org.apache.ibatis.session.ResultHandler;
+import org.apache.ibatis.session.RowBounds;
+import org.apache.ibatis.type.TypeHandlerRegistry;
+
+import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
+import com.baomidou.mybatisplus.toolkit.SqlUtils;
+import com.baomidou.mybatisplus.toolkit.StringUtils;
+import com.baomidou.mybatisplus.toolkit.SystemClock;
+
+/**
+ * <p>
+ * 性能分析拦截器,用于输出每条 SQL 语句及其执行时间
+ * </p>
+ * 
+ * @author hubin
+ * @Date 2016-07-07
+ */
+@Intercepts({@Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class }),
+		@Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
+public class PerformanceInterceptor implements Interceptor {
+
+	/**
+	 * SQL 执行最大时长,超过自动停止运行,有助于发现问题。
+	 */
+	private long maxTime = 0;
+
+	private boolean format = false;
+
+	public Object intercept(Invocation invocation) throws Throwable {
+		MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
+		Object parameterObject = null;
+		if (invocation.getArgs().length > 1) {
+			parameterObject = invocation.getArgs()[1];
+		}
+
+		String statementId = mappedStatement.getId();
+		BoundSql boundSql = mappedStatement.getBoundSql(parameterObject);
+		Configuration configuration = mappedStatement.getConfiguration();
+		String sql = SqlUtils.sqlFormat(boundSql.getSql(), format);
+
+		List<String> params = getParams(boundSql, parameterObject, configuration);
+
+		long start = SystemClock.now();
+		Object result = invocation.proceed();
+		long end = SystemClock.now();
+		long timing = end - start;
+		System.err.println(" Time:" + timing + " ms" + " - ID:" + statementId + "\n SQL Params:" + params.toString()
+				+ "\n Execute SQL:" + sql + "\n");
+		if (maxTime >= 1 && timing > maxTime) {
+			throw new MybatisPlusException(" The SQL execution time is too large, please optimize ! ");
+		}
+		return result;
+	}
+
+	public Object plugin(Object target) {
+		if (target instanceof Executor) {
+			return Plugin.wrap(target, this);
+		}
+		return target;
+	}
+
+	public void setProperties(Properties prop) {
+		// TODO
+	}
+
+	private List<String> getParams(BoundSql boundSql, Object parameterObject, Configuration configuration) {
+		List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
+		TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
+		List<String> params = new ArrayList<String>();
+		if (parameterMappings != null) {
+			for (int i = 0; i < parameterMappings.size(); i++) {
+				ParameterMapping parameterMapping = parameterMappings.get(i);
+				if (parameterMapping.getMode() != ParameterMode.OUT) {
+					Object value;
+					String propertyName = parameterMapping.getProperty();
+					if (boundSql.hasAdditionalParameter(propertyName)) {
+						value = boundSql.getAdditionalParameter(propertyName);
+					} else if (parameterObject == null) {
+						value = null;
+					} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
+						value = parameterObject;
+					} else {
+						MetaObject metaObject = configuration.newMetaObject(parameterObject);
+						value = metaObject.getValue(propertyName);
+					}
+					params.add(StringUtils.sqlParam(value));
+				}
+			}
+		}
+		return params;
+	}
+
+	public long getMaxTime() {
+		return maxTime;
+	}
+
+	public void setMaxTime(long maxTime) {
+		this.maxTime = maxTime;
+	}
+
+	public boolean isFormat() {
+		return format;
+	}
+
+	public void setFormat(boolean format) {
+		this.format = format;
+	}
+}

+ 159 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/SqlExplainInterceptor.java

@@ -0,0 +1,159 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.plugins;
+
+import com.baomidou.mybatisplus.entity.GlobalConfiguration;
+import com.baomidou.mybatisplus.enums.DBType;
+import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
+import com.baomidou.mybatisplus.toolkit.IOUtils;
+import com.baomidou.mybatisplus.toolkit.VersionUtils;
+import org.apache.ibatis.builder.StaticSqlSource;
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.logging.Log;
+import org.apache.ibatis.logging.LogFactory;
+import org.apache.ibatis.mapping.BoundSql;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.mapping.SqlCommandType;
+import org.apache.ibatis.plugin.Interceptor;
+import org.apache.ibatis.plugin.Intercepts;
+import org.apache.ibatis.plugin.Invocation;
+import org.apache.ibatis.plugin.Plugin;
+import org.apache.ibatis.plugin.Signature;
+import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
+import org.apache.ibatis.session.Configuration;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.Properties;
+
+/**
+ * <p>
+ * SQL 执行分析拦截器【 目前只支持 MYSQL-5.6.3 以上版本 】
+ * </p>
+ * 
+ * @author hubin
+ * @Date 2016-08-16
+ */
+@Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
+public class SqlExplainInterceptor implements Interceptor {
+
+	private static final Log logger = LogFactory.getLog(SqlExplainInterceptor.class);
+
+	/**
+	 * 发现执行全表 delete update 语句是否停止执行
+	 */
+	private boolean stopProceed = false;
+	/**
+	 * Mysql支持分析SQL的最小版本
+	 */
+	private String minMySQLVersion = "5.6.3";
+
+	public Object intercept(Invocation invocation) throws Throwable {
+		/**
+		 * 处理 DELETE UPDATE 语句
+		 */
+		MappedStatement ms = (MappedStatement) invocation.getArgs()[0];
+		if (ms.getSqlCommandType() == SqlCommandType.DELETE || ms.getSqlCommandType() == SqlCommandType.UPDATE) {
+			Configuration configuration = ms.getConfiguration();
+			Object parameter = invocation.getArgs()[1];
+			BoundSql boundSql = ms.getBoundSql(parameter);
+			Connection connection = configuration.getEnvironment().getDataSource().getConnection();
+			String databaseVersion = connection.getMetaData().getDatabaseProductVersion();
+			if (GlobalConfiguration.getDbType(configuration).equals(DBType.MYSQL)
+					&& VersionUtils.compare(minMySQLVersion, databaseVersion)) {
+				logger.warn("Warn: Your mysql version needs to be greater than '5.6.3' to execute of Sql Explain!");
+				IOUtils.closeQuietly(connection);
+				return invocation.proceed();
+			}
+			/**
+			 * 执行 SQL 分析
+			 */
+			sqlExplain(configuration, ms, boundSql, connection, parameter);
+		}
+		return invocation.proceed();
+	}
+
+	/**
+	 * <p>
+	 * 判断是否执行 SQL
+	 * </p>
+	 * 
+	 * @param configuration
+	 * @param mappedStatement
+	 * @param boundSql
+	 * @param connection
+	 * @param parameter
+	 * @return
+	 * @throws Exception
+	 */
+	@SuppressWarnings("resource")
+	protected void sqlExplain(Configuration configuration, MappedStatement mappedStatement, BoundSql boundSql,
+			Connection connection, Object parameter) {
+		PreparedStatement stmt = null;
+		ResultSet rs = null;
+		try {
+			StringBuilder explain = new StringBuilder("EXPLAIN ");
+			explain.append(boundSql.getSql());
+			String sqlExplain = explain.toString();
+			StaticSqlSource sqlsource = new StaticSqlSource(configuration, sqlExplain, boundSql.getParameterMappings());
+			MappedStatement.Builder builder = new MappedStatement.Builder(configuration, "explain_sql", sqlsource,
+					SqlCommandType.SELECT);
+			builder.resultMaps(mappedStatement.getResultMaps()).resultSetType(mappedStatement.getResultSetType())
+					.statementType(mappedStatement.getStatementType());
+			MappedStatement query_statement = builder.build();
+			DefaultParameterHandler handler = new DefaultParameterHandler(query_statement, parameter, boundSql);
+			stmt = connection.prepareStatement(sqlExplain);
+			handler.setParameters(stmt);
+			rs = stmt.executeQuery();
+			while (rs.next()) {
+				if (!"Using where".equals(rs.getString("Extra"))) {
+					String tip = " Full table operation is prohibited. SQL: " + boundSql.getSql();
+					if (this.isStopProceed()) {
+						throw new MybatisPlusException(tip);
+					}
+					logger.error(tip);
+					break;
+				}
+			}
+
+		} catch (Exception e) {
+			throw new MybatisPlusException(e);
+		} finally {
+			IOUtils.closeQuietly(rs, stmt, connection);
+		}
+	}
+
+	public Object plugin(Object target) {
+		if (target instanceof Executor) {
+			return Plugin.wrap(target, this);
+		}
+		return target;
+	}
+
+	public void setProperties(Properties prop) {
+		// TODO
+	}
+
+	public boolean isStopProceed() {
+		return stopProceed;
+	}
+
+	public void setStopProceed(boolean stopProceed) {
+		this.stopProceed = stopProceed;
+	}
+
+}

+ 88 - 14
mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/pagination/DialectFactory.java

@@ -15,12 +15,18 @@
  */
 package com.baomidou.mybatisplus.plugins.pagination;
 
+import com.baomidou.mybatisplus.enums.DBType;
+import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
+import com.baomidou.mybatisplus.plugins.pagination.dialects.DB2Dialect;
+import com.baomidou.mybatisplus.plugins.pagination.dialects.H2Dialect;
 import com.baomidou.mybatisplus.plugins.pagination.dialects.HSQLDialect;
 import com.baomidou.mybatisplus.plugins.pagination.dialects.MySqlDialect;
 import com.baomidou.mybatisplus.plugins.pagination.dialects.OracleDialect;
 import com.baomidou.mybatisplus.plugins.pagination.dialects.PostgreDialect;
+import com.baomidou.mybatisplus.plugins.pagination.dialects.SQLServer2005Dialect;
 import com.baomidou.mybatisplus.plugins.pagination.dialects.SQLServerDialect;
 import com.baomidou.mybatisplus.plugins.pagination.dialects.SQLiteDialect;
+import com.baomidou.mybatisplus.toolkit.StringUtils;
 
 /**
  * <p>
@@ -32,6 +38,67 @@ import com.baomidou.mybatisplus.plugins.pagination.dialects.SQLiteDialect;
  */
 public class DialectFactory {
 
+	// 数据库方言
+	private static IDialect dialect = null;
+
+	/**
+	 * <p>
+	 * 生成翻页执行 SQL
+	 * </p>
+	 * 
+	 * @param page
+	 *            翻页对象
+	 * @param buildSql
+	 *            执行 SQL
+	 * @param dialectType
+	 *            方言类型
+	 * @param dialectClazz
+	 *            自定义方言实现类
+	 * @return
+	 * @throws Exception
+	 */
+	public static String buildPaginationSql(Pagination page, String buildSql, String dialectType, String dialectClazz)
+			throws Exception {
+		if (null == dialect) {
+			dialect = getiDialect(dialectType, dialectClazz);
+		}
+		return dialect.buildPaginationSql(buildSql, page.getOffset(), page.getLimit());
+	}
+
+	/**
+	 * <p>
+	 * 获取数据库方言
+	 * </p>
+	 * 
+	 * @param dialectType
+	 *            方言类型
+	 * @param dialectClazz
+	 *            自定义方言实现类
+	 * @return
+	 * @throws Exception
+	 */
+	private static IDialect getiDialect(String dialectType, String dialectClazz) throws Exception {
+		if (StringUtils.isNotEmpty(dialectType)) {
+			dialect = getDialectByDbtype(dialectType);
+		} else {
+			if (StringUtils.isNotEmpty(dialectClazz)) {
+				try {
+					Class<?> clazz = Class.forName(dialectClazz);
+					if (IDialect.class.isAssignableFrom(clazz)) {
+						dialect = (IDialect) clazz.newInstance();
+					}
+				} catch (ClassNotFoundException e) {
+					throw new MybatisPlusException("Class :" + dialectClazz + " is not found");
+				}
+			}
+		}
+		/* 未配置方言则抛出异常 */
+		if (dialect == null) {
+			throw new MybatisPlusException("The value of the dialect property in mybatis configuration.xml is not defined.");
+		}
+		return dialect;
+	}
+
 	/**
 	 * <p>
 	 * 根据数据库类型选择不同分页方言
@@ -42,22 +109,29 @@ public class DialectFactory {
 	 * @return
 	 * @throws Exception
 	 */
-	public static IDialect getDialectByDbtype( String dbtype ) throws Exception {
-		if ( "mysql".equalsIgnoreCase(dbtype) ) {
-			return new MySqlDialect();
-		} else if ( "oracle".equalsIgnoreCase(dbtype) ) {
-			return new OracleDialect();
-		} else if ( "hsql".equalsIgnoreCase(dbtype) ) {
-			return new HSQLDialect();
-		} else if ( "sqlite".equalsIgnoreCase(dbtype) ) {
-			return new SQLiteDialect();
-		} else if ( "postgre".equalsIgnoreCase(dbtype) ) {
-			return new PostgreDialect();
-		} else if ( "sqlserver".equalsIgnoreCase(dbtype) ) {
-			return new SQLServerDialect();
+	private static IDialect getDialectByDbtype(String dbtype) throws Exception {
+		if (DBType.MYSQL.getDb().equalsIgnoreCase(dbtype)) {
+			dialect = new MySqlDialect();
+		} else if (DBType.ORACLE.getDb().equalsIgnoreCase(dbtype)) {
+			dialect = new OracleDialect();
+		} else if (DBType.DB2.getDb().equalsIgnoreCase(dbtype)) {
+			dialect = new DB2Dialect();
+		} else if (DBType.H2.getDb().equalsIgnoreCase(dbtype)) {
+			dialect = new H2Dialect();
+		} else if (DBType.SQLSERVER.getDb().equalsIgnoreCase(dbtype)) {
+			dialect = new SQLServerDialect();
+		} else if (DBType.SQLSERVER2005.getDb().equalsIgnoreCase(dbtype)) {
+			dialect = new SQLServer2005Dialect();
+		} else if (DBType.POSTGRE.getDb().equalsIgnoreCase(dbtype)) {
+			dialect = new PostgreDialect();
+		} else if (DBType.HSQL.getDb().equalsIgnoreCase(dbtype)) {
+			dialect = new HSQLDialect();
+		} else if (DBType.SQLITE.getDb().equalsIgnoreCase(dbtype)) {
+			dialect = new SQLiteDialect();
 		} else {
-			return null;
+			throw new MybatisPlusException("The database is not supported!dbtype:" + dbtype);
 		}
+		return dialect;
 	}
 
 }

+ 89 - 28
mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/pagination/Pagination.java

@@ -15,10 +15,11 @@
  */
 package com.baomidou.mybatisplus.plugins.pagination;
 
-import java.io.Serializable;
-
+import com.baomidou.mybatisplus.toolkit.StringUtils;
 import org.apache.ibatis.session.RowBounds;
 
+import java.io.Serializable;
+
 /**
  * <p>
  * 简单分页模型
@@ -36,8 +37,8 @@ public class Pagination extends RowBounds implements Serializable {
 	/* 总数 */
 	private int total;
 
-	/* 每页显示条数 */
-	private int size;
+	/* 每页显示条数,默认 10 */
+	private int size = 10;
 
 	/* 总页数 */
 	private int pages;
@@ -45,12 +46,37 @@ public class Pagination extends RowBounds implements Serializable {
 	/* 当前页 */
 	private int current = 1;
 
+	/* 查询总记录数(默认 true) */
+	private boolean searchCount = true;
+
+	/**
+	 * 查询总数优化(默认 false 该属性只针对于Optimize.DEFAULT有效)
+	 * 
+	 * @see com.baomidou.mybatisplus.enums.Optimize
+	 *
+	 */
+	private boolean optimizeCount = false;
+
+	/**
+	 * <p>
+	 * SQL 排序 ORDER BY 字段,例如: id DESC(根据id倒序查询)
+	 * </p>
+	 * <p>
+	 * DESC 表示按倒序排序(即:从大到小排序)<br>
+	 * ASC 表示按正序排序(即:从小到大排序)
+	 * </p>
+	 */
+	private String orderByField;
+
+	/**
+	 * 是否为升序 ASC( 默认: true )
+	 */
+	private boolean isAsc = true;
 
 	public Pagination() {
 		super();
 	}
 
-
 	/**
 	 * <p>
 	 * 分页构造函数
@@ -61,75 +87,110 @@ public class Pagination extends RowBounds implements Serializable {
 	 * @param size
 	 *            每页显示条数
 	 */
-	public Pagination( int current, int size ) {
+	public Pagination(int current, int size) {
+		this(current, size, true);
+	}
+
+	public Pagination(int current, int size, boolean searchCount) {
 		super(offsetCurrent(current, size), size);
-		if ( current > 1 ) {
+		if (current > 1) {
 			this.current = current;
 		}
 		this.size = size;
+		this.searchCount = searchCount;
 	}
 
-
-	protected static int offsetCurrent( int current, int size ) {
-		if ( current > 0 ) {
+	protected static int offsetCurrent(int current, int size) {
+		if (current > 0) {
 			return (current - 1) * size;
 		}
 		return 0;
 	}
 
-
 	public int getOffsetCurrent() {
 		return offsetCurrent(this.current, this.size);
 	}
 
-
 	public boolean hasPrevious() {
 		return this.current > 1;
 	}
 
-
 	public boolean hasNext() {
 		return this.current < this.pages;
 	}
 
-
 	public int getTotal() {
 		return total;
 	}
 
-
-	public void setTotal( int total ) {
+	public void setTotal(int total) {
 		this.total = total;
-		this.pages = this.total / this.size;
-		if ( this.total % this.size != 0 ) {
-			this.pages++;
-		}
-		if ( this.current > this.pages ) {
-			/**
-			 * 当前页大于总页数,当前页设置为第一页
-			 */
-			this.current = 1;
-		}
 	}
 
-
 	public int getSize() {
 		return size;
 	}
 
+	public void setSize(int size) {
+		this.size = size;
+	}
 
 	public int getPages() {
-		return pages;
+		if (this.size == 0) {
+			return 0;
+		}
+		this.pages = this.total / this.size;
+		if (this.total % this.size != 0) {
+			this.pages++;
+		}
+		return this.pages;
 	}
 
+	public void setCurrent(int current) {
+		this.current = current;
+	}
 
 	public int getCurrent() {
 		return current;
 	}
 
+	public boolean isSearchCount() {
+		return searchCount;
+	}
+
+	public void setSearchCount(boolean searchCount) {
+		this.searchCount = searchCount;
+	}
+
+	public boolean isOptimizeCount() {
+		return optimizeCount;
+	}
+
+	public void setOptimizeCount(boolean optimizeCount) {
+		this.optimizeCount = optimizeCount;
+	}
+
+	public String getOrderByField() {
+		return orderByField;
+	}
+
+	public void setOrderByField(String orderByField) {
+		if (StringUtils.isNotEmpty(orderByField)) {
+			this.orderByField = orderByField;
+		}
+	}
+
+	public boolean isAsc() {
+		return isAsc;
+	}
+
+	public void setAsc(boolean isAsc) {
+		this.isAsc = isAsc;
+	}
 
 	@Override
 	public String toString() {
 		return "Pagination { total=" + total + " ,size=" + size + " ,pages=" + pages + " ,current=" + current + " }";
 	}
+
 }

+ 69 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/pagination/dialects/DB2Dialect.java

@@ -0,0 +1,69 @@
+/**
+ * Copyright &copy; 2015-2015  Jeedcp All rights reserved.
+ */
+/**
+ * Copyright (c) 2011-2014, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.plugins.pagination.dialects;
+
+import com.baomidou.mybatisplus.plugins.pagination.IDialect;
+
+/**
+ * <p>
+ * DB2 数据库分页方言
+ * </p>
+ * 
+ * @author hubin
+ * @Date 2016-11-10
+ */
+public class DB2Dialect implements IDialect {
+
+	private static String getRowNumber(String originalSql) {
+		StringBuilder rownumber = new StringBuilder(50).append("rownumber() over(");
+		int orderByIndex = originalSql.toLowerCase().indexOf("order by");
+		if (orderByIndex > 0 && !hasDistinct(originalSql)) {
+			rownumber.append(originalSql.substring(orderByIndex));
+		}
+		rownumber.append(") as rownumber_,");
+		return rownumber.toString();
+	}
+
+	private static boolean hasDistinct(String originalSql) {
+		return originalSql.toLowerCase().contains("select distinct");
+	}
+
+	public String buildPaginationSql(String originalSql, int offset, int limit) {
+		int startOfSelect = originalSql.toLowerCase().indexOf("select");
+		StringBuilder pagingSelect = new StringBuilder(originalSql.length() + 100)
+				.append(originalSql.substring(0, startOfSelect)).append("select * from ( select ")
+				.append(getRowNumber(originalSql));
+		if (hasDistinct(originalSql)) {
+			pagingSelect.append(" row_.* from ( ").append(originalSql.substring(startOfSelect)).append(" ) as row_");
+		} else {
+			pagingSelect.append(originalSql.substring(startOfSelect + 6));
+		}
+		pagingSelect.append(" ) as temp_ where rownumber_ ");
+
+		// add the restriction to the outer select
+		if (offset > 0) {
+			String endString = offset + "+" + limit;
+			pagingSelect.append("between ").append(offset).append("+1 and ").append(endString);
+		} else {
+			pagingSelect.append("<= ").append(limit);
+		}
+		return null;
+	}
+
+}

+ 39 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/pagination/dialects/H2Dialect.java

@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2011-2014, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.plugins.pagination.dialects;
+
+import com.baomidou.mybatisplus.plugins.pagination.IDialect;
+
+/**
+ * <p>
+ * H2 数据库分页方言
+ * </p>
+ * 
+ * @author hubin
+ * @Date 2016-11-10
+ */
+public class H2Dialect implements IDialect {
+
+	public String buildPaginationSql(String originalSql, int offset, int limit) {
+		StringBuffer sql = new StringBuffer(originalSql);
+		sql.append(" limit ").append(limit);
+		if (offset > 0) {
+			sql.append(" offset ").append(offset);
+		}
+		return sql.toString();
+	}
+
+}

+ 2 - 2
mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/pagination/dialects/OracleDialect.java

@@ -27,10 +27,10 @@ import com.baomidou.mybatisplus.plugins.pagination.IDialect;
  */
 public class OracleDialect implements IDialect {
 
-	public String buildPaginationSql( String originalSql, int offset, int limit ) {
+	public String buildPaginationSql(String originalSql, int offset, int limit) {
 		StringBuilder sql = new StringBuilder();
 		sql.append("SELECT * FROM ( SELECT TMP.*, ROWNUM ROW_ID FROM ( ");
-		sql.append(originalSql).append(" ) TMP WHERE ROWNUM <=").append((offset >=1)?(offset*limit):limit);
+		sql.append(originalSql).append(" ) TMP WHERE ROWNUM <=").append((offset >= 1) ? (offset + limit) : limit);
 		sql.append(") WHERE ROW_ID > ").append(offset);
 		return sql.toString();
 	}

+ 71 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/plugins/pagination/dialects/SQLServer2005Dialect.java

@@ -0,0 +1,71 @@
+/**
+ * Copyright (c) 2011-2014, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.plugins.pagination.dialects;
+
+import com.baomidou.mybatisplus.plugins.pagination.IDialect;
+import com.baomidou.mybatisplus.toolkit.StringUtils;
+
+/**
+ * <p>
+ * SQLServer 2005 数据库分页方言
+ * </p>
+ * 
+ * @author hubin
+ * @Date 2016-11-10
+ */
+public class SQLServer2005Dialect implements IDialect {
+
+	private static String getOrderByPart(String sql) {
+		String loweredString = sql.toLowerCase();
+		int orderByIndex = loweredString.indexOf("order by");
+		if (orderByIndex != -1) {
+			return sql.substring(orderByIndex);
+		} else {
+			return "";
+		}
+	}
+
+	public String buildPaginationSql(String originalSql, int offset, int limit) {
+		StringBuilder pagingBuilder = new StringBuilder();
+		String orderby = getOrderByPart(originalSql);
+		String distinctStr = "";
+
+		String loweredString = originalSql.toLowerCase();
+		String sqlPartString = originalSql;
+		if (loweredString.trim().startsWith("select")) {
+			int index = 6;
+			if (loweredString.startsWith("select distinct")) {
+				distinctStr = "DISTINCT ";
+				index = 15;
+			}
+			sqlPartString = sqlPartString.substring(index);
+		}
+		pagingBuilder.append(sqlPartString);
+
+		// if no ORDER BY is specified use fake ORDER BY field to avoid errors
+		if (StringUtils.isEmpty(orderby)) {
+			orderby = "ORDER BY CURRENT_TIMESTAMP";
+		}
+
+		StringBuilder sql = new StringBuilder();
+		sql.append("WITH query AS (SELECT ").append(distinctStr).append("TOP 100 PERCENT ")
+				.append(" ROW_NUMBER() OVER (").append(orderby).append(") as __row_number__, ").append(pagingBuilder)
+				.append(") SELECT * FROM query WHERE __row_number__ BETWEEN ").append(offset).append(" AND ")
+				.append(offset + limit).append(" ORDER BY __row_number__");
+		return sql.toString();
+	}
+
+}

+ 332 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/service/IService.java

@@ -0,0 +1,332 @@
+/**
+ * Copyright (c) 2011-2016, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.service;
+
+import com.baomidou.mybatisplus.mapper.Wrapper;
+import com.baomidou.mybatisplus.plugins.Page;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * 顶级 Service
+ * </p>
+ *
+ * @author hubin
+ * @Date 2016-04-20
+ */
+public interface IService<T> {
+
+	/**
+	 * <p>
+	 * 插入一条记录
+	 * </p>
+	 *
+	 * @param entity
+	 *            实体对象
+	 * @return boolean
+	 */
+	boolean insert(T entity);
+
+	/**
+	 * <p>
+	 * 插入(批量)
+	 * </p>
+	 *
+	 * @param entityList
+	 *            实体对象列表
+	 * @return boolean
+	 */
+	boolean insertBatch(List<T> entityList);
+
+	/**
+	 * <p>
+	 * 插入(批量)
+	 * </p>
+	 *
+	 * @param entityList
+	 *            实体对象列表
+	 * @param batchSize
+	 *
+	 * @return boolean
+	 */
+	boolean insertBatch(List<T> entityList, int batchSize);
+
+	/**
+	 * <p>
+	 * 批量修改插入
+	 * </p>
+	 *
+	 * @param entityList
+	 *            实体对象列表
+	 * @return boolean
+	 */
+	boolean insertOrUpdateBatch(List<T> entityList);
+
+	/**
+	 * <p>
+	 * 批量修改插入
+	 * </p>
+	 *
+	 * @param entityList
+	 *            实体对象列表
+	 * @param batchSize
+	 *
+	 * @return boolean
+	 */
+	boolean insertOrUpdateBatch(List<T> entityList, int batchSize);
+
+	/**
+	 * <p>
+	 * 根据 ID 删除
+	 * </p>
+	 *
+	 * @param id
+	 *            主键ID
+	 * @return boolean
+	 */
+	boolean deleteById(Serializable id);
+
+	/**
+	 * <p>
+	 * 根据 columnMap 条件,删除记录
+	 * </p>
+	 *
+	 * @param columnMap
+	 *            表字段 map 对象
+	 * @return boolean
+	 */
+	boolean deleteByMap(Map<String, Object> columnMap);
+
+	/**
+	 * <p>
+	 * 根据 entity 条件,删除记录
+	 * </p>
+	 *
+	 * @param wrapper
+	 *            实体包装类 {@link Wrapper}
+	 * @return boolean
+	 */
+	boolean delete(Wrapper<T> wrapper);
+
+	/**
+	 * <p>
+	 * 删除(根据ID 批量删除)
+	 * </p>
+	 *
+	 * @param idList
+	 *            主键ID列表
+	 * @return boolean
+	 */
+	boolean deleteBatchIds(List<? extends Serializable> idList);
+
+	/**
+	 * <p>
+	 * 根据 ID 修改
+	 * </p>
+	 *
+	 * @param entity
+	 *            实体对象
+	 * @return boolean
+	 */
+	boolean updateById(T entity);
+
+	/**
+	 * <p>
+	 * 根据 whereEntity 条件,更新记录
+	 * </p>
+	 *
+	 * @param entity
+	 *            实体对象
+	 * @param wrapper
+	 *            实体包装类 {@link Wrapper}
+	 * @return boolean
+	 */
+	boolean update(T entity, Wrapper<T> wrapper);
+
+	/**
+	 * <p>
+	 * 根据ID 批量更新
+	 * </p>
+	 *
+	 * @param entityList
+	 *            实体对象列表
+	 * @return boolean
+	 */
+	boolean updateBatchById(List<T> entityList);
+
+	/**
+	 * <p>
+	 * TableId 注解存在更新记录,否插入一条记录
+	 * </p>
+	 *
+	 * @param entity
+	 *            实体对象
+	 * @return boolean
+	 */
+	boolean insertOrUpdate(T entity);
+
+	/**
+	 * <p>
+	 * 根据 ID 查询
+	 * </p>
+	 *
+	 * @param id
+	 *            主键ID
+	 * @return T
+	 */
+	T selectById(Serializable id);
+
+	/**
+	 * <p>
+	 * 查询(根据ID 批量查询)
+	 * </p>
+	 *
+	 * @param idList
+	 *            主键ID列表
+	 * @return List<T>
+	 */
+	List<T> selectBatchIds(List<? extends Serializable> idList);
+
+	/**
+	 * <p>
+	 * 查询(根据 columnMap 条件)
+	 * </p>
+	 *
+	 * @param columnMap
+	 *            表字段 map 对象
+	 * @return List<T>
+	 */
+	List<T> selectByMap(Map<String, Object> columnMap);
+
+	/**
+	 * <p>
+	 * 根据 Wrapper,查询一条记录
+	 * </p>
+	 *
+	 * @param wrapper
+	 *            实体对象
+	 * @return T
+	 */
+	T selectOne(Wrapper<T> wrapper);
+
+	/**
+	 * <p>
+	 * 根据 Wrapper,查询一条记录
+	 * </p>
+	 *
+	 * @param wrapper
+	 *            {@link Wrapper}
+	 * @return Map<String,Object>
+	 */
+	Map<String, Object> selectMap(Wrapper<T> wrapper);
+
+	/**
+	 * <p>
+	 * 根据 Wrapper,查询一条记录
+	 * </p>
+	 *
+	 * @param wrapper
+	 *            {@link Wrapper}
+	 * @return Object
+	 */
+	Object selectObj(Wrapper<T> wrapper);
+
+	/**
+	 * <p>
+	 * 根据 Wrapper 条件,查询总记录数
+	 * </p>
+	 *
+	 * @param wrapper
+	 *            实体对象
+	 * @return int
+	 */
+	int selectCount(Wrapper<T> wrapper);
+
+	/**
+	 * <p>
+	 * 查询列表
+	 * </p>
+	 *
+	 * @param wrapper
+	 *            实体包装类 {@link Wrapper}
+	 * @return
+	 */
+	List<T> selectList(Wrapper<T> wrapper);
+
+	/**
+	 * <p>
+	 * 翻页查询
+	 * </p>
+	 *
+	 * @param page
+	 *            翻页对象
+	 * @return
+	 */
+	Page<T> selectPage(Page<T> page);
+
+	/**
+	 * <p>
+	 * 查询列表
+	 * </p>
+	 *
+	 * @param wrapper
+	 *            {@link Wrapper}
+	 * @return
+	 */
+	List<Map<String, Object>> selectMaps(Wrapper<T> wrapper);
+
+	/**
+	 * <p>
+	 * 根据 Wrapper 条件,查询全部记录
+	 * </p>
+	 *
+	 * @param wrapper
+	 *            实体对象封装操作类(可以为 null)
+	 * @return List<Object>
+	 */
+	List<Object> selectObjs(Wrapper<T> wrapper);
+
+	/**
+	 * <p>
+	 * 翻页查询
+	 * </p>
+	 *
+	 * @param page
+	 *            翻页对象
+	 * @param wrapper
+	 *            {@link Wrapper}
+	 * @return
+	 */
+	@SuppressWarnings("rawtypes")
+	Page<Map<String, Object>> selectMapsPage(Page page, Wrapper<T> wrapper);
+
+	/**
+	 * <p>
+	 * 翻页查询
+	 * </p>
+	 *
+	 * @param page
+	 *            翻页对象
+	 * @param wrapper
+	 *            实体包装类 {@link Wrapper}
+	 * @return
+	 */
+	Page<T> selectPage(Page<T> page, Wrapper<T> wrapper);
+
+}

+ 297 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/service/impl/ServiceImpl.java

@@ -0,0 +1,297 @@
+/**
+ * Copyright (c) 2011-2016, hubin (jobob@qq.com).
+ * <p>
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.baomidou.mybatisplus.service.impl;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.ibatis.logging.Log;
+import org.apache.ibatis.logging.LogFactory;
+import org.apache.ibatis.session.SqlSession;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.baomidou.mybatisplus.entity.TableInfo;
+import com.baomidou.mybatisplus.enums.SqlMethod;
+import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
+import com.baomidou.mybatisplus.mapper.BaseMapper;
+import com.baomidou.mybatisplus.mapper.SqlHelper;
+import com.baomidou.mybatisplus.mapper.Wrapper;
+import com.baomidou.mybatisplus.plugins.Page;
+import com.baomidou.mybatisplus.service.IService;
+import com.baomidou.mybatisplus.toolkit.CollectionUtils;
+import com.baomidou.mybatisplus.toolkit.MapUtils;
+import com.baomidou.mybatisplus.toolkit.ReflectionKit;
+import com.baomidou.mybatisplus.toolkit.StringUtils;
+import com.baomidou.mybatisplus.toolkit.TableInfoHelper;
+
+/**
+ * <p>
+ * IService 实现类( 泛型:M 是 mapper 对象,T 是实体 , PK 是主键泛型 )
+ * </p>
+ *
+ * @author hubin
+ * @Date 2016-04-20
+ */
+public class ServiceImpl<M extends BaseMapper<T>, T> implements IService<T> {
+
+	private static final Log logger = LogFactory.getLog(ServiceImpl.class);
+
+	@Autowired
+	protected M baseMapper;
+
+	@SuppressWarnings("unchecked")
+	protected Class<T> currentModleClass() {
+		return ReflectionKit.getSuperClassGenricType(getClass(), 1);
+	}
+
+	/**
+	 * <p>
+	 * 批量操作 SqlSession
+	 * </p>
+	 */
+	protected SqlSession sqlSessionBatch() {
+		return SqlHelper.sqlSessionBatch(currentModleClass());
+	}
+
+	/**
+	 * 获取SqlStatement
+	 *
+	 * @param sqlMethod
+	 * @return
+	 */
+	protected String sqlStatement(SqlMethod sqlMethod) {
+		return SqlHelper.table(currentModleClass()).getSqlStatement(sqlMethod.getMethod());
+	}
+
+	/**
+	 * <p>
+	 * 判断数据库操作是否成功
+	 * </p>
+	 * <p>
+	 * 注意!! 该方法为 Integer 判断,不可传入 int 基本类型
+	 * </p>
+	 *
+	 * @param result
+	 *            数据库操作返回影响条数
+	 * @return boolean
+	 */
+	protected static boolean retBool(Integer result) {
+		return SqlHelper.retBool(result);
+	}
+
+	/**
+	 * <p>
+	 * TableId 注解存在更新记录,否插入一条记录
+	 * </p>
+	 *
+	 * @param entity
+	 *            实体对象
+	 * @return boolean
+	 */
+	public boolean insertOrUpdate(T entity) {
+		if (null != entity) {
+			Class<?> cls = entity.getClass();
+			TableInfo tableInfo = TableInfoHelper.getTableInfo(cls);
+			if (null != tableInfo && StringUtils.isNotEmpty(tableInfo.getKeyProperty())) {
+				Object idVal = ReflectionKit.getMethodValue(cls, entity, tableInfo.getKeyProperty());
+				if (StringUtils.checkValNull(idVal)) {
+					return insert(entity);
+				} else {
+					/*
+					 * 更新成功直接返回,失败执行插入逻辑
+					 */
+					boolean rlt = updateById(entity);
+					if (!rlt) {
+						return insert(entity);
+					}
+					return rlt;
+				}
+			} else {
+				throw new MybatisPlusException("Error:  Can not execute. Could not find @TableId.");
+			}
+		}
+		return false;
+	}
+
+	public boolean insert(T entity) {
+		return retBool(baseMapper.insert(entity));
+	}
+
+	public boolean insertBatch(List<T> entityList) {
+		return insertBatch(entityList, 30);
+	}
+
+	public boolean insertOrUpdateBatch(List<T> entityList) {
+		return insertOrUpdateBatch(entityList, 30);
+	}
+
+	public boolean insertOrUpdateBatch(List<T> entityList, int batchSize) {
+		if (CollectionUtils.isEmpty(entityList)) {
+			throw new IllegalArgumentException("Error: entityList must not be empty");
+		}
+		try {
+			SqlSession batchSqlSession = sqlSessionBatch();
+			int size = entityList.size();
+			for (int i = 0; i < size; i++) {
+				insertOrUpdate(entityList.get(i));
+				if (i % batchSize == 0) {
+					batchSqlSession.flushStatements();
+				}
+			}
+			batchSqlSession.flushStatements();
+		} catch (Exception e) {
+			logger.warn("Error: Cannot execute insertOrUpdateBatch Method. Cause:" + e);
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * 批量插入
+	 *
+	 * @param entityList
+	 * @param batchSize
+	 * @return
+	 */
+	public boolean insertBatch(List<T> entityList, int batchSize) {
+		if (CollectionUtils.isEmpty(entityList)) {
+			throw new IllegalArgumentException("Error: entityList must not be empty");
+		}
+		SqlSession batchSqlSession = sqlSessionBatch();
+		try {
+			int size = entityList.size();
+			for (int i = 0; i < size; i++) {
+				batchSqlSession.insert(sqlStatement(SqlMethod.INSERT_ONE), entityList.get(i));
+				if (i % batchSize == 0) {
+					batchSqlSession.flushStatements();
+				}
+			}
+			batchSqlSession.flushStatements();
+		} catch (Exception e) {
+			logger.warn("Error: Cannot execute insertBatch Method. Cause:" + e);
+			return false;
+		}
+		return true;
+
+	}
+
+	public boolean deleteById(Serializable id) {
+		return retBool(baseMapper.deleteById(id));
+	}
+
+	public boolean deleteByMap(Map<String, Object> columnMap) {
+		if (MapUtils.isEmpty(columnMap)) {
+			throw new MybatisPlusException("deleteByMap columnMap is empty.");
+		}
+		return retBool(baseMapper.deleteByMap(columnMap));
+	}
+
+	public boolean delete(Wrapper<T> wrapper) {
+		return retBool(baseMapper.delete(wrapper));
+	}
+
+	public boolean deleteBatchIds(List<? extends Serializable> idList) {
+		return retBool(baseMapper.deleteBatchIds(idList));
+	}
+
+	public boolean updateById(T entity) {
+		return retBool(baseMapper.updateById(entity));
+	}
+
+	public boolean update(T entity, Wrapper<T> wrapper) {
+		return retBool(baseMapper.update(entity, wrapper));
+	}
+
+	public boolean updateBatchById(List<T> entityList) {
+		if (CollectionUtils.isEmpty(entityList)) {
+			throw new IllegalArgumentException("Error: entityList must not be empty");
+		}
+		SqlSession batchSqlSession = sqlSessionBatch();
+		try {
+			int size = entityList.size();
+			for (int i = 0; i < size; i++) {
+				batchSqlSession.update(sqlStatement(SqlMethod.UPDATE_BY_ID), entityList.get(i));
+				if (i % 30 == 0) {
+					batchSqlSession.flushStatements();
+				}
+			}
+			batchSqlSession.flushStatements();
+		} catch (Exception e) {
+			logger.warn("Error: Cannot execute insertBatch Method. Cause:" + e);
+			return false;
+		}
+		return true;
+	}
+
+	public T selectById(Serializable id) {
+		return baseMapper.selectById(id);
+	}
+
+	public List<T> selectBatchIds(List<? extends Serializable> idList) {
+		return baseMapper.selectBatchIds(idList);
+	}
+
+	public List<T> selectByMap(Map<String, Object> columnMap) {
+		return baseMapper.selectByMap(columnMap);
+	}
+
+	public T selectOne(Wrapper<T> wrapper) {
+		return SqlHelper.getObject(baseMapper.selectList(wrapper));
+	}
+
+	public Map<String, Object> selectMap(Wrapper<T> wrapper) {
+		return SqlHelper.getObject(baseMapper.selectMaps(wrapper));
+	}
+
+	public Object selectObj(Wrapper<T> wrapper) {
+		return SqlHelper.getObject(baseMapper.selectObjs(wrapper));
+	}
+
+	public int selectCount(Wrapper<T> wrapper) {
+		return SqlHelper.retCount(baseMapper.selectCount(wrapper));
+	}
+
+	public List<T> selectList(Wrapper<T> wrapper) {
+		return baseMapper.selectList(wrapper);
+	}
+
+	public Page<T> selectPage(Page<T> page) {
+		page.setRecords(baseMapper.selectPage(page, null));
+		return page;
+	}
+
+	public List<Map<String, Object>> selectMaps(Wrapper<T> wrapper) {
+		return baseMapper.selectMaps(wrapper);
+	}
+
+	public List<Object> selectObjs(Wrapper<T> wrapper) {
+		return baseMapper.selectObjs(wrapper);
+	}
+
+	@SuppressWarnings({ "rawtypes", "unchecked" })
+	public Page<Map<String, Object>> selectMapsPage(Page page, Wrapper<T> wrapper) {
+		SqlHelper.fillWrapper(page, wrapper);
+		page.setRecords(baseMapper.selectMapsPage(page, wrapper));
+		return page;
+	}
+
+	public Page<T> selectPage(Page<T> page, Wrapper<T> wrapper) {
+		SqlHelper.fillWrapper(page, wrapper);
+		page.setRecords(baseMapper.selectPage(page, wrapper));
+		return page;
+	}
+}

+ 4 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/service/impl/package-info.java

@@ -0,0 +1,4 @@
+/**
+ * service 实现类
+ */
+package com.baomidou.mybatisplus.service.impl;

+ 4 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/service/package-info.java

@@ -0,0 +1,4 @@
+/**
+ * service 超级抽象类
+ */
+package com.baomidou.mybatisplus.service;

+ 296 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/spring/MybatisMapperRefresh.java

@@ -0,0 +1,296 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.spring;
+
+import com.baomidou.mybatisplus.entity.GlobalConfiguration;
+import com.baomidou.mybatisplus.toolkit.SystemClock;
+import org.apache.ibatis.binding.MapperRegistry;
+import org.apache.ibatis.builder.xml.XMLMapperBuilder;
+import org.apache.ibatis.builder.xml.XMLMapperEntityResolver;
+import org.apache.ibatis.executor.ErrorContext;
+import org.apache.ibatis.executor.keygen.SelectKeyGenerator;
+import org.apache.ibatis.io.Resources;
+import org.apache.ibatis.logging.Log;
+import org.apache.ibatis.logging.LogFactory;
+import org.apache.ibatis.parsing.XNode;
+import org.apache.ibatis.parsing.XPathParser;
+import org.apache.ibatis.session.Configuration;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.springframework.core.NestedIOException;
+import org.springframework.core.io.FileSystemResource;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.UrlResource;
+import org.springframework.util.ResourceUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * <p>
+ * 切莫用于生产环境(后果自负)<br>
+ * Mybatis 映射文件热加载(发生变动后自动重新加载).<br>
+ * 方便开发时使用,不用每次修改xml文件后都要去重启应用.<br>
+ * </p>
+ *
+ * @author nieqiurong
+ * @Date 2016-08-25
+ */
+public class MybatisMapperRefresh implements Runnable {
+	private static final Log logger = LogFactory.getLog(MybatisMapperRefresh.class);
+	private SqlSessionFactory sqlSessionFactory;
+	private Resource[] mapperLocations;
+	private Long beforeTime = 0L;
+	private Configuration configuration;
+
+	/**
+	 * 是否开启刷新mapper
+	 */
+	private boolean enabled;
+
+	/**
+	 * xml文件目录
+	 */
+	private Set<String> fileSet;
+
+	/**
+	 * 延迟加载时间
+	 */
+	private int delaySeconds = 10;
+
+	/**
+	 * 刷新间隔时间
+	 */
+	private int sleepSeconds = 20;
+
+	/**
+	 * 记录jar包存在的mapper
+	 */
+	private static Map<String, List<Resource>> jarMapper = new HashMap<String, List<Resource>>();
+
+	public MybatisMapperRefresh(Resource[] mapperLocations, SqlSessionFactory sqlSessionFactory, int delaySeconds,
+			int sleepSeconds, boolean enabled) {
+		this.mapperLocations = mapperLocations;
+		this.sqlSessionFactory = sqlSessionFactory;
+		this.delaySeconds = delaySeconds;
+		this.enabled = enabled;
+		this.sleepSeconds = sleepSeconds;
+		this.configuration = sqlSessionFactory.getConfiguration();
+		this.run();
+	}
+
+	public MybatisMapperRefresh(Resource[] mapperLocations, SqlSessionFactory sqlSessionFactory, boolean enabled) {
+		this.mapperLocations = mapperLocations;
+		this.sqlSessionFactory = sqlSessionFactory;
+		this.enabled = enabled;
+		this.configuration = sqlSessionFactory.getConfiguration();
+		this.run();
+	}
+
+	public void run() {
+		final GlobalConfiguration globalConfig = GlobalConfiguration.getGlobalConfig(configuration);
+		/*
+		 * 启动 XML 热加载
+		 */
+		if (enabled) {
+			beforeTime = SystemClock.now();
+			final MybatisMapperRefresh runnable = this;
+			new Thread(new Runnable() {
+
+				public void run() {
+					if (fileSet == null) {
+						fileSet = new HashSet<String>();
+						for (Resource mapperLocation : mapperLocations) {
+							try {
+								if (ResourceUtils.isJarURL(mapperLocation.getURL())) {
+									String key = new UrlResource(ResourceUtils.extractJarFileURL(mapperLocation.getURL()))
+											.getFile().getPath();
+									fileSet.add(key);
+									if (jarMapper.get(key) != null) {
+										jarMapper.get(key).add(mapperLocation);
+									} else {
+										List<Resource> resourcesList = new ArrayList<Resource>();
+										resourcesList.add(mapperLocation);
+										jarMapper.put(key, resourcesList);
+									}
+								} else {
+									fileSet.add(mapperLocation.getFile().getPath());
+								}
+							} catch (IOException ioException) {
+								ioException.printStackTrace();
+							}
+						}
+					}
+					try {
+						Thread.sleep(delaySeconds * 1000);
+					} catch (InterruptedException interruptedException) {
+						interruptedException.printStackTrace();
+					}
+					while (true) {
+						try {
+							for (String filePath : fileSet) {
+								File file = new File(filePath);
+								if (file != null && file.isFile() && file.lastModified() > beforeTime) {
+									globalConfig.setRefresh(true);
+									List<Resource> removeList = jarMapper.get(filePath);
+									if (removeList != null && !removeList.isEmpty()) {// 如果是jar包中的xml,将刷新jar包中存在的所有xml,后期再修改加载jar中修改过后的xml
+										for (Resource resource : removeList) {
+											runnable.refresh(resource);
+										}
+									} else {
+										runnable.refresh(new FileSystemResource(file));
+									}
+								}
+							}
+							if (globalConfig.isRefresh()) {
+								beforeTime = SystemClock.now();
+							}
+							globalConfig.setRefresh(true);
+						} catch (Exception exception) {
+							exception.printStackTrace();
+						}
+						try {
+							Thread.sleep(sleepSeconds * 1000);
+						} catch (InterruptedException interruptedException) {
+							interruptedException.printStackTrace();
+						}
+
+					}
+				}
+			}, "mybatis-plus MapperRefresh").start();
+		}
+	}
+
+	/**
+	 * 刷新mapper
+	 *
+	 * @throws Exception
+	 */
+	@SuppressWarnings("rawtypes")
+	private void refresh(Resource resource) throws Exception {
+		this.configuration = sqlSessionFactory.getConfiguration();
+		boolean isSupper = configuration.getClass().getSuperclass() == Configuration.class;
+		try {
+			Field loadedResourcesField = isSupper ? configuration.getClass().getSuperclass().getDeclaredField("loadedResources")
+					: configuration.getClass().getDeclaredField("loadedResources");
+			loadedResourcesField.setAccessible(true);
+			Set loadedResourcesSet = ((Set) loadedResourcesField.get(configuration));
+			XPathParser xPathParser = new XPathParser(resource.getInputStream(), true, configuration.getVariables(),
+					new XMLMapperEntityResolver());
+			XNode context = xPathParser.evalNode("/mapper");
+			String namespace = context.getStringAttribute("namespace");
+			Field field = MapperRegistry.class.getDeclaredField("knownMappers");
+			field.setAccessible(true);
+			Map mapConfig = (Map) field.get(configuration.getMapperRegistry());
+			mapConfig.remove(Resources.classForName(namespace));
+			loadedResourcesSet.remove(resource.toString());
+			configuration.getCacheNames().remove(namespace);
+			cleanParameterMap(context.evalNodes("/mapper/parameterMap"), namespace);
+			cleanResultMap(context.evalNodes("/mapper/resultMap"), namespace);
+			cleanKeyGenerators(context.evalNodes("insert|update"), namespace);
+			cleanSqlElement(context.evalNodes("/mapper/sql"), namespace);
+			XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(resource.getInputStream(),
+					sqlSessionFactory.getConfiguration(), // 注入的sql先不进行处理了
+					resource.toString(), sqlSessionFactory.getConfiguration().getSqlFragments());
+			xmlMapperBuilder.parse();
+			logger.debug("refresh:" + resource + ",success!");
+		} catch (Exception e) {
+			throw new NestedIOException("Failed to parse mapping resource: '" + resource + "'", e);
+		} finally {
+			ErrorContext.instance().reset();
+		}
+	}
+
+	/**
+	 * 清理parameterMap
+	 *
+	 * @param list
+	 * @param namespace
+	 */
+	private void cleanParameterMap(List<XNode> list, String namespace) {
+		for (XNode parameterMapNode : list) {
+			String id = parameterMapNode.getStringAttribute("id");
+			configuration.getParameterMaps().remove(namespace + "." + id);
+		}
+	}
+
+	/**
+	 * 清理resultMap
+	 *
+	 * @param list
+	 * @param namespace
+	 */
+	private void cleanResultMap(List<XNode> list, String namespace) {
+		for (XNode resultMapNode : list) {
+			String id = resultMapNode.getStringAttribute("id", resultMapNode.getValueBasedIdentifier());
+			configuration.getResultMapNames().remove(id);
+			configuration.getResultMapNames().remove(namespace + "." + id);
+			clearResultMap(resultMapNode, namespace);
+		}
+	}
+
+	private void clearResultMap(XNode xNode, String namespace) {
+		for (XNode resultChild : xNode.getChildren()) {
+			if ("association".equals(resultChild.getName()) || "collection".equals(resultChild.getName())
+					|| "case".equals(resultChild.getName())) {
+				if (resultChild.getStringAttribute("select") == null) {
+					configuration.getResultMapNames().remove(
+							resultChild.getStringAttribute("id", resultChild.getValueBasedIdentifier()));
+					configuration.getResultMapNames().remove(
+							namespace + "." + resultChild.getStringAttribute("id", resultChild.getValueBasedIdentifier()));
+					if (resultChild.getChildren() != null && !resultChild.getChildren().isEmpty()) {
+						clearResultMap(resultChild, namespace);
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * 清理selectKey
+	 *
+	 * @param list
+	 * @param namespace
+	 */
+	private void cleanKeyGenerators(List<XNode> list, String namespace) {
+		for (XNode context : list) {
+			String id = context.getStringAttribute("id");
+			configuration.getKeyGeneratorNames().remove(id + SelectKeyGenerator.SELECT_KEY_SUFFIX);
+			configuration.getKeyGeneratorNames().remove(namespace + "." + id + SelectKeyGenerator.SELECT_KEY_SUFFIX);
+		}
+	}
+
+	/**
+	 * 清理sql节点缓存
+	 *
+	 * @param list
+	 * @param namespace
+	 */
+	private void cleanSqlElement(List<XNode> list, String namespace) {
+		for (XNode context : list) {
+			String id = context.getStringAttribute("id");
+			configuration.getSqlFragments().remove(id);
+			configuration.getSqlFragments().remove(namespace + "." + id);
+		}
+	}
+
+}

+ 58 - 37
mybatis-plus/src/main/java/com/baomidou/mybatisplus/spring/MybatisSqlSessionFactoryBean.java

@@ -15,19 +15,13 @@
  */
 package com.baomidou.mybatisplus.spring;
 
-import static org.springframework.util.Assert.notNull;
-import static org.springframework.util.Assert.state;
-import static org.springframework.util.ObjectUtils.isEmpty;
-import static org.springframework.util.StringUtils.hasLength;
-import static org.springframework.util.StringUtils.tokenizeToStringArray;
-
-import java.io.IOException;
-import java.sql.SQLException;
-import java.util.Properties;
-
-import javax.sql.DataSource;
-
-import org.apache.ibatis.builder.xml.XMLMapperBuilder;
+import com.baomidou.mybatisplus.MybatisConfiguration;
+import com.baomidou.mybatisplus.MybatisXMLConfigBuilder;
+import com.baomidou.mybatisplus.MybatisXMLMapperBuilder;
+import com.baomidou.mybatisplus.entity.GlobalConfiguration;
+import com.baomidou.mybatisplus.exceptions.MybatisPlusException;
+import com.baomidou.mybatisplus.mapper.SqlRunner;
+import com.baomidou.mybatisplus.toolkit.PackageHelper;
 import org.apache.ibatis.cache.Cache;
 import org.apache.ibatis.executor.ErrorContext;
 import org.apache.ibatis.io.VFS;
@@ -54,20 +48,28 @@ import org.springframework.core.NestedIOException;
 import org.springframework.core.io.Resource;
 import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
 
-import com.baomidou.mybatisplus.MybatisConfiguration;
-import com.baomidou.mybatisplus.MybatisXMLConfigBuilder;
-import com.baomidou.mybatisplus.mapper.DBType;
+import javax.sql.DataSource;
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.Properties;
+
+import static org.springframework.util.Assert.notNull;
+import static org.springframework.util.Assert.state;
+import static org.springframework.util.ObjectUtils.isEmpty;
+import static org.springframework.util.StringUtils.hasLength;
+import static org.springframework.util.StringUtils.tokenizeToStringArray;
 
 /**
  * <p>
  * 拷贝类 org.mybatis.spring.SqlSessionFactoryBean 修改方法 buildSqlSessionFactory()
  * 加载自定义 MybatisXmlConfigBuilder
  * </p>
- * 
+ *
  * @author hubin
- * @Date 2016-01-23
+ * @Date 2017-01-04
  */
-public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
+public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean,
+		ApplicationListener<ApplicationEvent> {
 
 	private static final Log LOGGER = LogFactory.getLog(MybatisSqlSessionFactoryBean.class);
 
@@ -114,10 +116,12 @@ public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFacto
 	private ObjectFactory objectFactory;
 
 	private ObjectWrapperFactory objectWrapperFactory;
-	
-	//TODO 注入数据库类型
-	public void setDbType(String dbType) {
-		MybatisConfiguration.DB_TYPE = DBType.getDBType(dbType);
+
+	private GlobalConfiguration globalConfig = GlobalConfiguration.defaults();
+
+	// TODO 注入全局配置
+	public void setGlobalConfig(GlobalConfiguration globalConfig) {
+		this.globalConfig = globalConfig;
 	}
 
 	/**
@@ -280,7 +284,7 @@ public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFacto
 
 	/**
 	 * Set a customized MyBatis configuration.
-	 * 
+	 *
 	 * @param configuration
 	 *            MyBatis configuration
 	 * @since 1.3.0
@@ -399,7 +403,6 @@ public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFacto
 		notNull(sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
 		state((configuration == null && configLocation == null) || !(configuration != null && configLocation != null),
 				"Property 'configuration' and 'configLocation' can not specified with together");
-
 		this.sqlSessionFactory = buildSqlSessionFactory();
 	}
 
@@ -419,7 +422,7 @@ public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFacto
 
 		Configuration configuration;
 
-		//TODO 加载自定义 MybatisXmlConfigBuilder
+		// TODO 加载自定义 MybatisXmlConfigBuilder
 		MybatisXMLConfigBuilder xmlConfigBuilder = null;
 		if (this.configuration != null) {
 			configuration = this.configuration;
@@ -434,12 +437,13 @@ public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFacto
 			configuration = xmlConfigBuilder.getConfiguration();
 		} else {
 			if (LOGGER.isDebugEnabled()) {
-				LOGGER.debug(
-						"Property `configuration` or 'configLocation' not specified, using default MyBatis Configuration");
+				LOGGER.debug("Property 'configuration' or 'configLocation' not specified, using default MyBatisPlus Configuration");
 			}
-			//TODO 使用自定义配置
+			// TODO 使用自定义配置
 			configuration = new MybatisConfiguration();
-			configuration.setVariables(this.configurationProperties);
+			if (this.configurationProperties != null) {
+				configuration.setVariables(this.configurationProperties);
+			}
 		}
 
 		if (this.objectFactory != null) {
@@ -455,8 +459,17 @@ public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFacto
 		}
 
 		if (hasLength(this.typeAliasesPackage)) {
-			String[] typeAliasPackageArray = tokenizeToStringArray(this.typeAliasesPackage,
-					ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
+			// TODO
+			String[] typeAliasPackageArray = null;
+			if (typeAliasesPackage.contains("*")) {
+				typeAliasPackageArray = PackageHelper.convertTypeAliasesPackage(typeAliasesPackage);
+			} else {
+				typeAliasPackageArray = tokenizeToStringArray(this.typeAliasesPackage,
+						ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
+			}
+			if (typeAliasPackageArray == null) {
+				throw new MybatisPlusException("not find typeAliasesPackage:" + typeAliasesPackage);
+			}
 			for (String packageToScan : typeAliasPackageArray) {
 				configuration.getTypeAliasRegistry().registerAliases(packageToScan,
 						typeAliasesSuperType == null ? Object.class : typeAliasesSuperType);
@@ -505,7 +518,7 @@ public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFacto
 		}
 
 		if (this.databaseIdProvider != null) {// fix #64 set databaseId before
-												// parse mapper xmls
+			// parse mapper xmls
 			try {
 				configuration.setDatabaseId(this.databaseIdProvider.getDatabaseId(this.dataSource));
 			} catch (SQLException e) {
@@ -536,6 +549,15 @@ public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFacto
 		}
 
 		configuration.setEnvironment(new Environment(this.environment, this.transactionFactory, this.dataSource));
+		// 设置元数据相关
+		GlobalConfiguration.setMetaData(dataSource, globalConfig);
+		SqlSessionFactory sqlSessionFactory = this.sqlSessionFactoryBuilder.build(configuration);
+		// TODO SqlRunner
+		SqlRunner.FACTORY = sqlSessionFactory;
+		// TODO 缓存 sqlSessionFactory
+		globalConfig.setSqlSessionFactory(sqlSessionFactory);
+		// TODO 设置全局参数属性
+		globalConfig.signGlobalConfig(sqlSessionFactory);
 
 		if (!isEmpty(this.mapperLocations)) {
 			for (Resource mapperLocation : this.mapperLocations) {
@@ -544,7 +566,8 @@ public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFacto
 				}
 
 				try {
-					XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
+					// TODO
+					MybatisXMLMapperBuilder xmlMapperBuilder = new MybatisXMLMapperBuilder(mapperLocation.getInputStream(),
 							configuration, mapperLocation.toString(), configuration.getSqlFragments());
 					xmlMapperBuilder.parse();
 				} catch (Exception e) {
@@ -562,8 +585,7 @@ public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFacto
 				LOGGER.debug("Property 'mapperLocations' was not specified or no matching resources found");
 			}
 		}
-
-		return this.sqlSessionFactoryBuilder.build(configuration);
+		return sqlSessionFactory;
 	}
 
 	/**
@@ -573,7 +595,6 @@ public class MybatisSqlSessionFactoryBean implements FactoryBean<SqlSessionFacto
 		if (this.sqlSessionFactory == null) {
 			afterPropertiesSet();
 		}
-
 		return this.sqlSessionFactory;
 	}
 

+ 4 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/spring/package-info.java

@@ -0,0 +1,4 @@
+/**
+ * Spring相关类
+ */
+package com.baomidou.mybatisplus.spring;

+ 54 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/toolkit/CollectionUtils.java

@@ -0,0 +1,54 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.toolkit;
+
+import java.util.Collection;
+
+/**
+ * <p>
+ * Collection工具类
+ * </p>
+ *
+ * @author Caratacus
+ * @Date 2016-09-19
+ */
+public class CollectionUtils {
+
+	/**
+	 * <p>
+	 * 校验集合是否为空
+	 * </p>
+	 *
+	 * @param coll
+	 * @return boolean
+	 */
+	public static boolean isEmpty(Collection<?> coll) {
+		return (coll == null || coll.isEmpty());
+	}
+
+	/**
+	 * <p>
+	 * 校验集合是否不为空
+	 * </p>
+	 *
+	 * @param coll
+	 * @return boolean
+	 */
+	public static boolean isNotEmpty(Collection<?> coll) {
+		return !isEmpty(coll);
+	}
+
+}

+ 41 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/toolkit/DruidUtils.java

@@ -0,0 +1,41 @@
+/**
+ * Copyright (c) 2011-2020, hubin (jobob@qq.com).
+ *
+ * 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.baomidou.mybatisplus.toolkit;
+
+import com.alibaba.druid.sql.PagerUtils;
+
+/**
+ * <p>
+ * DruidUtils工具类
+ * </p>
+ *
+ * @author Caratacus
+ * @Date 2016-11-30
+ */
+public class DruidUtils {
+
+	/**
+	 * 通过Druid方式获取count语句
+	 * 
+	 * @param originalSql
+	 * @param dialectType
+	 * @return
+	 */
+	public static String count(String originalSql, String dialectType) {
+		return PagerUtils.count(originalSql, dialectType);
+	}
+
+}

部分文件因文件數量過多而無法顯示