瀏覽代碼

更改包名,项目名

zhangweixin 4 年之前
當前提交
01ddee6fd9
共有 67 個文件被更改,包括 7629 次插入0 次删除
  1. 8 0
      .gitignore
  2. 7 0
      README.md
  3. 96 0
      build.gradle
  4. 70 0
      gradle.properties
  5. 8 0
      local.properties
  6. 129 0
      persagy-kotlin-base/build.gradle
  7. 31 0
      persagy-kotlin-base/src/main/kotlin/com/persagy/base/exceptions/SApplicationRuntimeException.kt
  8. 33 0
      persagy-kotlin-base/src/main/kotlin/com/persagy/base/exceptions/SBusinessException.kt
  9. 33 0
      persagy-kotlin-base/src/main/kotlin/com/persagy/base/exceptions/SFieldNotFoundException.kt
  10. 230 0
      persagy-kotlin-base/src/main/kotlin/com/persagy/base/extensions/SAnyExtension.kt
  11. 39 0
      persagy-kotlin-base/src/main/kotlin/com/persagy/base/extensions/SByteArrayExtension.kt
  12. 99 0
      persagy-kotlin-base/src/main/kotlin/com/persagy/base/extensions/SClassExtension.kt
  13. 64 0
      persagy-kotlin-base/src/main/kotlin/com/persagy/base/extensions/SDoubleExtension.kt
  14. 64 0
      persagy-kotlin-base/src/main/kotlin/com/persagy/base/extensions/SFloatExtension.kt
  15. 35 0
      persagy-kotlin-base/src/main/kotlin/com/persagy/base/extensions/SIntExtension.kt
  16. 44 0
      persagy-kotlin-base/src/main/kotlin/com/persagy/base/extensions/SStringBuilderExtension.kt
  17. 50 0
      persagy-kotlin-base/src/main/kotlin/com/persagy/base/extensions/SStringExtension.kt
  18. 39 0
      persagy-kotlin-base/src/main/kotlin/com/persagy/base/extensions/SThrowableExtension.kt
  19. 43 0
      persagy-kotlin-base/src/main/kotlin/com/persagy/base/opts/SFormat.kt
  20. 162 0
      persagy-kotlin-base/src/main/kotlin/com/persagy/base/utils/SGzipUtil.kt
  21. 543 0
      persagy-kotlin-base/src/main/kotlin/com/persagy/base/utils/SHttpUtil.kt
  22. 40 0
      persagy-kotlin-base/src/main/kotlin/com/persagy/base/utils/SJarUtil.kt
  23. 160 0
      persagy-kotlin-base/src/main/kotlin/com/persagy/base/utils/SJsonUtil.kt
  24. 22 0
      persagy-kotlin-base/src/test/kotlin/com/sybotan/base/extensions/TestSAnyExtension.kt
  25. 22 0
      persagy-kotlin-base/src/test/kotlin/com/sybotan/base/utils/TestSJsonUtil.kt
  26. 134 0
      persagy-kotlin-database/build.gradle
  27. 368 0
      persagy-kotlin-database/src/main/javacc/SSyntaxParser.jj
  28. 385 0
      persagy-kotlin-database/src/main/kotlin/com/persagy/database/SAbstractDao.kt
  29. 39 0
      persagy-kotlin-database/src/main/kotlin/com/persagy/database/SAbstractDaoFactory.kt
  30. 44 0
      persagy-kotlin-database/src/main/kotlin/com/persagy/database/SAbstractFunction.kt
  31. 321 0
      persagy-kotlin-database/src/main/kotlin/com/persagy/database/SFilter.kt
  32. 49 0
      persagy-kotlin-database/src/main/kotlin/com/persagy/database/SGroup.kt
  33. 33 0
      persagy-kotlin-database/src/main/kotlin/com/persagy/database/SOrder.kt
  34. 49 0
      persagy-kotlin-database/src/main/kotlin/com/persagy/database/SPageQueryInfo.kt
  35. 376 0
      persagy-kotlin-database/src/main/kotlin/com/persagy/database/SQueryBuilder.kt
  36. 36 0
      persagy-kotlin-database/src/main/kotlin/com/persagy/database/enums/SDatabaseType.kt
  37. 36 0
      persagy-kotlin-database/src/main/kotlin/com/persagy/database/enums/SDirection.kt
  38. 60 0
      persagy-kotlin-database/src/main/kotlin/com/persagy/database/enums/SOps.kt
  39. 82 0
      persagy-kotlin-database/src/main/kotlin/com/persagy/database/extensions/SAnyExtension.kt
  40. 63 0
      persagy-kotlin-database/src/main/kotlin/com/persagy/database/extensions/SClassExtension.kt
  41. 44 0
      persagy-kotlin-database/src/main/kotlin/com/persagy/database/functions/SLPad.kt
  42. 44 0
      persagy-kotlin-database/src/main/kotlin/com/persagy/database/functions/SLeft.kt
  43. 44 0
      persagy-kotlin-database/src/main/kotlin/com/persagy/database/functions/SLength.kt
  44. 44 0
      persagy-kotlin-database/src/main/kotlin/com/persagy/database/functions/SLower.kt
  45. 48 0
      persagy-kotlin-database/src/main/kotlin/com/persagy/database/functions/SMid.kt
  46. 44 0
      persagy-kotlin-database/src/main/kotlin/com/persagy/database/functions/SRPad.kt
  47. 44 0
      persagy-kotlin-database/src/main/kotlin/com/persagy/database/functions/SRight.kt
  48. 48 0
      persagy-kotlin-database/src/main/kotlin/com/persagy/database/functions/SSubstring.kt
  49. 44 0
      persagy-kotlin-database/src/main/kotlin/com/persagy/database/functions/SUpper.kt
  50. 33 0
      persagy-kotlin-database/src/test/kotlin/com/sybotan/database/test/SQueryBuilderTest.kt
  51. 41 0
      persagy-kotlin-database/src/test/kotlin/com/sybotan/database/test/TestMap.kt
  52. 45 0
      persagy-kotlin-database/src/test/kotlin/com/sybotan/database/test/enums/SDirectionTest.kt
  53. 45 0
      persagy-kotlin-database/src/test/kotlin/com/sybotan/database/test/enums/SOpsTest.kt
  54. 124 0
      persagy-kotlin-database/src/test/kotlin/com/sybotan/database/test/parser/SSyntaxParserTest.kt
  55. 131 0
      persagy-kotlin-mybatis/build.gradle
  56. 136 0
      persagy-kotlin-mybatis/src/main/kotlin/com/persagy/mybatis/IBaseMapper.kt
  57. 34 0
      persagy-kotlin-mybatis/src/main/kotlin/com/persagy/mybatis/IMybatisMapper.kt
  58. 625 0
      persagy-kotlin-mybatis/src/main/kotlin/com/persagy/mybatis/SAbstractDriver.kt
  59. 214 0
      persagy-kotlin-mybatis/src/main/kotlin/com/persagy/mybatis/SAbstractMybatisDao.kt
  60. 151 0
      persagy-kotlin-mybatis/src/main/kotlin/com/persagy/mybatis/SRowParser.kt
  61. 358 0
      persagy-kotlin-mybatis/src/main/kotlin/com/persagy/mybatis/SSqlProvider.kt
  62. 80 0
      persagy-kotlin-mybatis/src/main/kotlin/com/persagy/mybatis/extensions/SAnyExtension.kt
  63. 136 0
      persagy-kotlin-mysql/build.gradle
  64. 350 0
      persagy-kotlin-mysql/src/main/kotlin/com/persagy/mysql/SMySqlDriver.kt
  65. 136 0
      persagy-kotlin-postgresql/build.gradle
  66. 410 0
      persagy-kotlin-postgresql/src/main/kotlin/com/persagy/postgresql/SPostgreSqlDriver.kt
  67. 30 0
      settings.gradle

+ 8 - 0
.gitignore

@@ -0,0 +1,8 @@
+/persagy-kotlin-database/src/main/kotlin/com/persagy/database/parser
+/.idea
+/.gradle
+/.build
+build
+out
+gradlew
+gradlew.bat

+ 7 - 0
README.md

@@ -0,0 +1,7 @@
+# saga-kotlin
+#### 项目介绍
+上格云kotlin语言公共支持库。
+
+#### 软件架构
+软件架构说明
+

+ 96 - 0
build.gradle

@@ -0,0 +1,96 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+group 'com.persagy'
+version PERSAGY_KOTLIN_VERSION
+
+apply plugin: 'org.hidetake.ssh'
+
+buildscript {
+    repositories {
+        maven{ url "http://maven.aliyun.com/nexus/content/groups/public/"}
+        mavenCentral()
+        jcenter()
+    }
+    dependencies {
+        classpath group: 'org.jetbrains.kotlin', name: 'kotlin-gradle-plugin', version: KOTLIN_VERSION
+        classpath group: 'org.jetbrains.dokka', name: 'dokka-gradle-plugin', version: DOKKA_VERSION
+        classpath group: 'ca.coglinc', name: 'javacc-gradle-plugin', version: JAVACC_GRACLE_VERSION
+        classpath group: 'org.hidetake', name: 'gradle-ssh-plugin', version: GRADLE_SSH_VERSION
+    }
+}
+
+allprojects {
+    repositories {
+        maven{url MAVEN_REPO_PUBLIC_URL}
+        maven{ url "http://maven.aliyun.com/nexus/content/groups/public/"}
+        mavenCentral()
+        jcenter()
+    }
+    tasks.withType(Javadoc) {
+        options{ encoding "UTF-8"
+            charSet "UTF-8"
+            links "http://docs.oracle.com/javase/8/docs/api"
+        }
+    }
+}
+
+task dokkaAll(type: org.jetbrains.dokka.gradle.DokkaTask) {
+    jdkVersion = 8
+    outputFormat = "javadoc"
+    outputDirectory = "$buildDir/javadoc/kotlin"
+    sourceDirs = files(
+            "persagy-kotlin-base/src/main/kotlin",
+            "persagy-kotlin-database/src/main/kotlin",
+            "persagy-kotlin-mybatis/src/main/kotlin",
+            "persagy-kotlin-mysql/src/main/kotlin",
+            "persagy-kotlin-postgresql/src/main/kotlin")
+}
+
+task clean(type: Delete) {
+    delete rootProject.buildDir
+}
+
+//////////////////////////////////////////////////////
+// ssh 部署文档
+ssh.settings {
+    knownHosts = allowAnyHosts
+}
+
+remotes {
+    docserver {
+        host = "47.94.89.44"
+        port = 22
+        user = "user1"
+        password = "@)!^sagacloud"
+    }
+}
+
+task deployDoc {
+    ssh.run {
+        session(remotes.docserver) {
+            // Deploy doc
+            // put from: "$buildDir/javadoc/kotlin", into: '/opt/tomcat9/webapps/api/server'
+        }
+    }
+}

+ 70 - 0
gradle.properties

@@ -0,0 +1,70 @@
+#
+# *********************************************************************************************************************
+#
+#               iFHS7.
+#              ;BBMBMBMc                  rZMBMBR              BMB
+#              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+#     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+#     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+#      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+#     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+#     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+#     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+#         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+#     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+#      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+#         i0BM: SWKHKGO  MBDv
+#           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  ˹��̹������
+#              ,  XMW  ..
+#                  r                                                                     All rights reserved.
+#
+# *********************************************************************************************************************
+#
+
+PERSAGY_URL = http://www.persagy.com/
+PERSAGY_KOTLIN_VERSION = 1.4.111
+# android
+# SYBOTAN_KOTLIN_VERSION = 1.4.63
+
+LICENSE_NAME = The Apache Software License, Version 2.0
+LICENSE_URL = http://www.apache.org/licenses/LICENSE-2.0.txt
+
+MAVEN_REPO_PUBLIC_URL = http://dev.dp.sagacloud.cn:8082/repository/maven-public/
+MAVEN_REPO_RELEASE_URL = http://dev.dp.sagacloud.cn:8082/repository/maven-releases/
+MAVEN_REPO_SNAPSHOT_URL = http://dev.dp.sagacloud.cn:8082/repository/maven-snapshots/
+NEXUS_USERNAME = saga
+NEXUS_PASSWORD = saga
+
+DEVELOPER_ID = Andy.Sybotan
+DEVELOPER_NAME = Andy
+
+JVM_TARGET = 1.8
+JDK_VERSION = 8
+
+# https://mvnrepository.com/artifact/org.jetbrains.dokka/dokka-gradle-plugin
+DOKKA_VERSION = 0.9.16
+# https://mvnrepository.com/artifact/com.alibaba/druid
+DRUID_VERSION = 1.1.21
+# https://mvnrepository.com/artifact/com.alibaba/fastjson
+# FASTJSON_VERSION = 1.2.60
+FASTJSON_VERSION = 1.1.70.android
+# https://mvnrepository.com/artifact/org.hidetake/gradle-ssh-plugin
+GRADLE_SSH_VERSION = 2.10.1
+# https://mvnrepository.com/artifact/ca.coglinc/javacc-gradle-plugin
+JAVACC_GRACLE_VERSION = 2.4.0
+# https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-stdlib-jdk8
+KOTLIN_VERSION = 1.3.61
+# https://mvnrepository.com/artifact/org.mybatis/mybatis
+MYBATIS_VERSION = 3.5.3
+# https://mvnrepository.com/artifact/mysql/mysql-connector-java
+MYSQL_VERSION = 8.0.18
+# https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp
+OKHTTP_VERSION = 3.14.4
+# https://mvnrepository.com/artifact/javax.persistence/persistence-api
+PERSISTENCE_VERSION = 1.0.2
+# https://mvnrepository.com/artifact/org.postgresql/postgresql
+POSTGRESQL_VERSION = 42.2.9
+# https://mvnrepository.com/artifact/org.slf4j/slf4j-api
+SLF4J_VERSION = 1.7.29
+# https://mvnrepository.com/artifact/org.testng/testng
+TESTNG_VERSION = 7.0.0

+ 8 - 0
local.properties

@@ -0,0 +1,8 @@
+## This file must *NOT* be checked into Version Control Systems,
+# as it contains information specific to your local configuration.
+#
+# Location of the SDK. This is only used by Gradle.
+# For customization when using a Version Control System, please read the
+# header note.
+#Tue Aug 25 17:40:47 CST 2020
+sdk.dir=D\:\\android_space\\androidSDK

+ 129 - 0
persagy-kotlin-base/build.gradle

@@ -0,0 +1,129 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+group rootProject.group
+version rootProject.version
+
+apply plugin: "kotlin"
+apply plugin: "org.jetbrains.dokka"
+apply plugin: "maven"
+
+sourceCompatibility = JVM_TARGET
+
+compileKotlin {
+    kotlinOptions.jvmTarget = JVM_TARGET
+}
+compileTestKotlin {
+    kotlinOptions.jvmTarget = JVM_TARGET
+}
+
+dependencies {
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // kotlin 依赖
+    compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8', version: KOTLIN_VERSION
+    compile group: 'org.jetbrains.kotlin', name: 'kotlin-reflect', version: KOTLIN_VERSION
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // 单元测试
+    // https://mvnrepository.com/artifact/org.testng/testng
+    testCompile group: 'org.testng', name: 'testng', version: TESTNG_VERSION
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // http请求
+    // https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp
+    compile group: 'com.squareup.okhttp3', name: 'okhttp', version: OKHTTP_VERSION
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // JSON解析
+    // https://mvnrepository.com/artifact/com.alibaba/fastjson
+    compile group: 'com.alibaba', name: 'fastjson', version: FASTJSON_VERSION
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// 文档生成
+dokka {
+    jdkVersion = JDK_VERSION
+    outputFormat = 'javadoc'
+    outputDirectory = "$buildDir/javadoc"
+    //sourceDirs = files('src/main/kotlin')
+}
+
+// 上成上传的文档jar包
+task javadocJar(type: Jar, dependsOn: dokka) {
+    classifier = 'javadoc'
+    from dokka.outputDirectory
+}
+
+// 上成上传的文档jar包
+task sourcesJar(type: Jar) {
+    classifier = 'sources'
+    from sourceSets.main.allSource
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// maven 仓库管理
+
+// 设置上传的包,默认上传aar与pom
+artifacts {
+    // archives javadocJar
+    // archives sourcesJar
+}
+
+uploadArchives {
+    repositories {
+        mavenDeployer {
+            pom.groupId = project.group
+            pom.version = project.version
+            pom.artifactId = project.name
+            pom.project {
+                name project.name
+                packaging 'jar'
+                url PERSAGY_URL
+                description '斯伯坦机器人 Kotlin 基础支持库。'
+                licenses {
+                    license {
+                        name LICENSE_NAME
+                        url LICENSE_URL
+                    }
+                }
+                developers {
+                    developer {
+                        id DEVELOPER_ID
+                        name DEVELOPER_NAME
+                    }
+                }
+            }
+            snapshotRepository(url: MAVEN_REPO_SNAPSHOT_URL) {
+                authentication(userName: NEXUS_USERNAME, password: NEXUS_PASSWORD)
+            }
+            repository(url: MAVEN_REPO_RELEASE_URL) {
+                authentication(userName: NEXUS_USERNAME, password: NEXUS_PASSWORD)
+            }
+        }
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// 自动化测试
+test {
+    useTestNG()
+}

+ 31 - 0
persagy-kotlin-base/src/main/kotlin/com/persagy/base/exceptions/SApplicationRuntimeException.kt

@@ -0,0 +1,31 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.base.exceptions
+
+/**
+ * 应用运行时异常
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+open class SApplicationRuntimeException(message: String): RuntimeException(message)

+ 33 - 0
persagy-kotlin-base/src/main/kotlin/com/persagy/base/exceptions/SBusinessException.kt

@@ -0,0 +1,33 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.base.exceptions
+
+import com.persagy.base.exceptions.SApplicationRuntimeException
+
+/**
+ * 业务异常
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+open class SBusinessException(message: String): SApplicationRuntimeException(message)

+ 33 - 0
persagy-kotlin-base/src/main/kotlin/com/persagy/base/exceptions/SFieldNotFoundException.kt

@@ -0,0 +1,33 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.base.exceptions
+
+import com.persagy.base.exceptions.SBusinessException
+
+/**
+ * 字段未找到异常
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+open class SFieldNotFoundException(field: String): SBusinessException("字段 '$field' 未找到。")

+ 230 - 0
persagy-kotlin-base/src/main/kotlin/com/persagy/base/extensions/SAnyExtension.kt

@@ -0,0 +1,230 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.base.extensions
+
+import com.alibaba.fastjson.PropertyNamingStrategy
+import com.persagy.base.utils.SJsonUtil
+import java.lang.Exception
+import java.lang.reflect.ParameterizedType
+
+/**
+ * Any扩展。获得类的泛型类
+ *
+ * @return  类的泛型类
+ */
+fun Any.gennericClass(): Class<*>? {
+    return try {
+        (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<*>
+    } catch (e: Exception) {
+        null
+    }
+} // Fun Any.gennericClass()
+
+/**
+ * Any扩展toJson()函数。
+ *
+ * @param   namingStrategy          命名规则
+ * @return  Json字符串(属性为null不序列化)
+ */
+fun Any.toJson(namingStrategy: PropertyNamingStrategy? = null): String {
+    return SJsonUtil.toJson(this, namingStrategy)
+} // Fun Any.toJson()
+
+/**
+ * Any扩展toJson()函数。
+ *
+ * @param   namingStrategy          命名规则
+ * @return  Json字符串(属性为null序列化)
+ */
+fun Any.toJsonAll(namingStrategy: PropertyNamingStrategy? = null): String {
+    return SJsonUtil.toJsonAll(this, namingStrategy)
+} // Fun Any.toJsonAll()
+
+/**
+ * Any扩展toMap()函数。
+ *
+ * @return  Json字符串
+ */
+fun Any.toMap(): Map<String, Any?> {
+    @Suppress("UNCHECKED_CAST")
+    return SJsonUtil.fromJson(this.toJson(), Map::class.java) as Map<String, Any?>
+} // Fun Any.toMap()
+
+/**
+ * Any扩展toByte()函数。
+ *
+ * @return  将对象转换为Int类型
+ */
+fun Any.toBoolean(): Boolean? {
+    return when(this.javaClass.simpleName) {
+        "Boolean" -> this as Boolean
+        "Byte" -> (this as Byte).toBoolean()
+        "Double" -> (this as Double).toBoolean()
+        "Float" -> (this as Float).toBoolean()
+        "Int", "Integer" ->  (this as Int).toBoolean()
+        "Long" -> (this as Long).toBoolean()
+        "Short" -> (this as Short).toBoolean()
+        else -> null
+    }
+} // Fun Any.toBoolean()
+
+/**
+ * Any扩展toByte()函数。
+ *
+ * @return  将对象转换为Int类型
+ */
+fun Any.toByte(): Byte? {
+    return when(this.javaClass.simpleName) {
+        "Boolean" -> (this as Boolean).toByte()
+        "Byte" -> this as Byte
+        "Double" -> (this as Double).toByte()
+        "Float" -> (this as Float).toByte()
+        "Int", "Integer" ->  (this as Int).toByte()
+        "Long" -> (this as Long).toByte()
+        "Short" -> (this as Short).toByte()
+        else -> null
+    }
+} // Fun Any.toByte()
+
+/**
+ * Any扩展toDouble()函数。
+ *
+ * @return  将对象转换为Int类型
+ */
+fun Any.toDouble(): Double? {
+    return when(this.javaClass.simpleName) {
+        "Boolean" -> (this as Boolean).toDouble()
+        "Byte" -> (this as Byte).toDouble()
+        "Double" -> this as Double
+        "Float" -> (this as Float).toDouble()
+        "Int", "Integer" ->  (this as Int).toDouble()
+        "Long" -> (this as Long).toDouble()
+        "Short" -> (this as Short).toDouble()
+        else -> null
+    }
+} // Fun Any.toDouble()
+
+/**
+ * Any扩展toFloat()函数。
+ *
+ * @return  将对象转换为Int类型
+ */
+fun Any.toFloat(): Float? {
+    return when(this.javaClass.simpleName) {
+        "Boolean" -> (this as Boolean).toFloat()
+        "Byte" -> (this as Byte).toFloat()
+        "Double" -> (this as Double).toFloat()
+        "Float" -> this as Float
+        "Int", "Integer" ->  (this as Int).toFloat()
+        "Long" -> (this as Long).toFloat()
+        "Short" -> (this as Short).toFloat()
+        else -> null
+    }
+} // Fun Any.toFloat()
+
+/**
+ * Any扩展toInt()函数。
+ *
+ * @return  将对象转换为Int类型
+ */
+fun Any.toInt(): Int? {
+    return when(this.javaClass.simpleName) {
+        "Boolean" -> (this as Boolean).toInt()
+        "Byte" -> (this as Byte).toInt()
+        "Double" -> (this as Double).toInt()
+        "Float" -> (this as Float).toInt()
+        "Int", "Integer" ->  this as Int
+        "Long" -> (this as Long).toInt()
+        "Short" -> (this as Short).toInt()
+        "String" -> {
+            try {
+                Integer.parseInt(this as String)
+            }catch (e: Exception) {
+                0
+            }
+        }
+        else -> null
+    }
+} // Fun Any.toInt()
+
+/**
+ * Any扩展toLong()函数。
+ *
+ * @return  将对象转换为Int类型
+ */
+fun Any.toLong(): Long? {
+    return when(this.javaClass.simpleName) {
+        "Boolean" -> (this as Boolean).toLong()
+        "Byte" -> (this as Byte).toLong()
+        "Double" -> (this as Double).toLong()
+        "Float" -> (this as Float).toLong()
+        "Int", "Integer" ->  (this as Int).toLong()
+        "Long" -> this as Long
+        "Short" -> (this as Short).toLong()
+        else -> null
+    }
+} // Fun Any.toLong()
+
+/**
+ * Any扩展toShort()函数。
+ *
+ * @return  将对象转换为Int类型
+ */
+fun Any.toShort(): Short? {
+    return when(this.javaClass.simpleName) {
+        "Boolean" -> (this as Boolean).toShort()
+        "Byte" -> (this as Byte).toShort()
+        "Double" -> (this as Double). toShort()
+        "Float" -> (this as Float).toShort()
+        "Int", "Integer" ->  (this as Int).toShort()
+        "Long" -> (this as Long).toShort()
+        "Short" -> this as Short
+        else -> null
+    }
+} // Fun Any.toShort()
+
+/**
+ * Any扩展,判断是否为基本类型
+ *
+ * @return  如果是则返回true
+ */
+fun Any.isBaseType(): Boolean {
+    if (this.javaClass.isPrimitive) {
+        return true;
+    }
+
+    return  this is String ||
+            this is Boolean ||
+            this is Char ||
+            this is Byte ||
+            this is Short ||
+            this is Int ||
+            this is Long ||
+            this is Float ||
+            this is Double ||
+            this is java.sql.Date ||
+            this is java.sql.Time ||
+            this is java.sql.Timestamp ||
+            this is java.util.Date
+} // Fun Any.isBaseType()

+ 39 - 0
persagy-kotlin-base/src/main/kotlin/com/persagy/base/extensions/SByteArrayExtension.kt

@@ -0,0 +1,39 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.base.extensions
+
+/**
+ * 字节数组16进制字符串
+ *
+ * @return  16进制字符串
+ */
+fun ByteArray.toHex(): String {
+    val sb = StringBuilder("")
+    for (c in this) {
+        val stmp = String.format("%02x", c)
+        sb.append(stmp)
+        sb.append(" ")
+    }
+    return sb.toString().toUpperCase().trim()
+} // Fun String.byteArrayToHexStr()

+ 99 - 0
persagy-kotlin-base/src/main/kotlin/com/persagy/base/extensions/SClassExtension.kt

@@ -0,0 +1,99 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.base.extensions
+
+import com.alibaba.fastjson.annotation.JSONField
+import java.lang.reflect.Field
+import java.lang.reflect.Method
+
+/**
+ * Class<*>扩展。获得所有包含父对象的定义字段列表。
+ *
+ * @return  字段列表
+ */
+fun Class<*>.getAllDeclaredFields(): ArrayList<Field> {
+    val fieldList = ArrayList<Field>()
+    var clz: Class<*>? = this
+    while (clz != null) {
+        fieldList.addAll(clz.declaredFields.toList())
+        clz = clz.superclass
+    }
+    return fieldList
+} // Fun Class<*>.getAllDeclaredFields()
+
+/**
+ * Class<*>扩展。根据名称获得所有包含父对象的定义字段。
+ *
+ * @param   ignoreCase      是否忽略大小写,默认不忽略
+ * @param   jsonProperty    是否检测Json属性
+ * @return  字段
+ */
+fun Class<*>.getAllDeclaredField(name: String, ignoreCase: Boolean = false, jsonProperty: Boolean = false): Field? {
+    val list = this.getAllDeclaredFields()
+    return list.first {
+        val annName = it.getAnnotation(JSONField::class.java)?.name
+        it.name.equals(name, ignoreCase) || (jsonProperty && name.equals(annName, ignoreCase))
+    }
+} // Fun Class<*>.getAllDeclaredField()
+
+/**
+ * Class<*>扩展。获得所有包含父对象的定义方法列表。
+ *
+ * @return  方法列表
+ */
+fun Class<*>.getAllDeclaredMethods(): ArrayList<Method> {
+    val methodList = ArrayList<Method>()
+    var clz: Class<*>? = this
+    while (clz != null) {
+        methodList.addAll(clz.declaredMethods.toList())
+        clz = clz.superclass
+    }
+    return methodList
+} // Fun Class<*>.getAllDeclaredMethods()
+
+/**
+ * Class<*>扩展,判断是否为基本类型
+ *
+ * @return  如果是则返回true
+ */
+fun Class<*>.isBaseType(): Boolean {
+    if (this.isPrimitive) {
+        return true;
+    }
+
+    return  String::class.java.isAssignableFrom(this) ||
+            Boolean::class.java.isAssignableFrom(this) ||
+            Char::class.java.isAssignableFrom(this) ||
+            Byte::class.java.isAssignableFrom(this) ||
+            Short::class.java.isAssignableFrom(this) ||
+            Int::class.java.isAssignableFrom(this) ||
+            Long::class.java.isAssignableFrom(this) ||
+            Float::class.java.isAssignableFrom(this) ||
+            Double::class.java.isAssignableFrom(this) ||
+            java.sql.Date::class.java.isAssignableFrom(this) ||
+            java.sql.Time::class.java.isAssignableFrom(this) ||
+            java.sql.Timestamp::class.java.isAssignableFrom(this) ||
+            java.util.Date::class.java.isAssignableFrom(this)
+
+} // Fun Class<*>.isBaseType()

+ 64 - 0
persagy-kotlin-base/src/main/kotlin/com/persagy/base/extensions/SDoubleExtension.kt

@@ -0,0 +1,64 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.base.extensions
+
+/**
+ * Double扩展判断相等
+ *
+ * @param   other   比较的数据
+ * @return  是否相等
+ */
+fun Double.eq(other: Double): Boolean {
+    return Math.abs(this - other) < 0.000001f
+} // Fun Any.Float.eq()
+
+/**
+ * Double扩展判断相等
+ *
+ * @param   other   比较的数据
+ * @return  是否相等
+ */
+fun Double.eq(other: Float): Boolean {
+    return Math.abs(this - other) < 0.000001f
+} // Fun Any.Float.eq()
+
+/**
+ * Double扩展判断不等
+ *
+ * @param   other   比较的数据
+ * @return  是否相等
+ */
+fun Double.ne(other: Double): Boolean {
+    return Math.abs(this - other) > 0.000001f
+} // Fun Any.Float.ne()
+
+/**
+ * Double扩展判断不等
+ *
+ * @param   other   比较的数据
+ * @return  是否相等
+ */
+fun Double.ne(other: Float): Boolean {
+    return Math.abs(this - other) > 0.000001f
+} // Fun Any.Float.ne()

+ 64 - 0
persagy-kotlin-base/src/main/kotlin/com/persagy/base/extensions/SFloatExtension.kt

@@ -0,0 +1,64 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.base.extensions
+
+/**
+ * Float扩展判断相等
+ *
+ * @param   other   比较的数据
+ * @return  是否相等
+ */
+fun Float.eq(other: Double): Boolean {
+    return Math.abs(this - other) < 0.000001f
+} // Fun Any.Float.eq()
+
+/**
+ * Float扩展判断相等
+ *
+ * @param   other   比较的数据
+ * @return  是否相等
+ */
+fun Float.eq(other: Float): Boolean {
+    return Math.abs(this - other) < 0.000001f
+} // Fun Any.Float.eq()
+
+/**
+ * Float扩展判断不等
+ *
+ * @param   other   比较的数据
+ * @return  是否相等
+ */
+fun Float.ne(other: Double): Boolean {
+    return Math.abs(this - other) > 0.000001f
+} // Fun Any.Float.ne()
+
+/**
+ * Float扩展判断不等
+ *
+ * @param   other   比较的数据
+ * @return  是否相等
+ */
+fun Float.ne(other: Float): Boolean {
+    return Math.abs(this - other) > 0.000001f
+} // Fun Any.Float.ne()

+ 35 - 0
persagy-kotlin-base/src/main/kotlin/com/persagy/base/extensions/SIntExtension.kt

@@ -0,0 +1,35 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.base.extensions
+
+/**
+ * 将int类型转换成16进制数字符串,长度不够补0
+ *
+ * @param   len     转换的16进制数字符串长度
+ * @return  转换后的16进制字符串
+ */
+fun Int.toHex(len: Int): String {
+    val value = String.format("%0${len}x", this)
+    return value.substring(value.length - len)
+} // Fun String.intTo3Byte()

+ 44 - 0
persagy-kotlin-base/src/main/kotlin/com/persagy/base/extensions/SStringBuilderExtension.kt

@@ -0,0 +1,44 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.base.extensions
+
+/**
+ * StringBuilder扩展。追加n个ch字符
+ * @param   ch      追加的字符
+ * @param   n       追加多少个
+ */
+fun StringBuilder.appendChar(ch: Char, n: Int): StringBuilder {
+    for (i in 0 until n) {
+        this.append(ch)
+    }
+    return this
+} // Fun String.genSpace()
+
+/**
+ * StringBuilder扩展。追加n个空格
+ * @param   n       追加多少个
+ */
+fun StringBuilder.appendSpace(n: Int): StringBuilder {
+    return appendChar(' ', n)
+} // Fun String.genSpace()

+ 50 - 0
persagy-kotlin-base/src/main/kotlin/com/persagy/base/extensions/SStringExtension.kt

@@ -0,0 +1,50 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.base.extensions
+
+/**
+ * String扩展firstUpperCase函数。首字母转换为大写
+ *
+ * @return  转换后的字符串
+ */
+fun String.firstUpperCase(): String {
+    val ch = this.toCharArray()
+    if (ch[0] in 'a'..'z') {
+        ch[0] = (ch[0].toInt() - 32).toChar()
+    }
+    return String(ch)
+} // Fun String.firstUpperCase()
+
+/**
+ * String扩展firstUpperCase函数。首字母转换为小写
+ *
+ * @return  转换后的字符串
+ */
+fun String.firstLowerCase(): String {
+    val ch = this.toCharArray()
+    if (ch[0] in 'A'..'Z') {
+        ch[0] = (ch[0].toInt() + 32).toChar()
+    }
+    return String(ch)
+} // Fun String.firstLowerCase()

+ 39 - 0
persagy-kotlin-base/src/main/kotlin/com/persagy/base/extensions/SThrowableExtension.kt

@@ -0,0 +1,39 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.base.extensions
+
+/**
+ * 扩展异常rootCause。用于取得嵌套异常的异常信息。
+ */
+fun Throwable.rootCause(): Throwable? {
+    var root = this.cause
+    return try {
+        while (root!!.cause != null) {
+            root = root.cause
+        }
+        root
+    } catch (e: Exception) {
+        null
+    }
+} // Throwable.rootCause()

+ 43 - 0
persagy-kotlin-base/src/main/kotlin/com/persagy/base/opts/SFormat.kt

@@ -0,0 +1,43 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.base.opts
+
+/**
+ * 格式定义
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+object SFormat {
+    /** datetime类型数据格式定义 */
+    var dateTime = "yyyy-MM-dd HH:mm:ss"
+
+    /** timestamp类型数据格式定义 */
+    var timestamp = "yyyy-MM-dd HH:mm:ss"
+
+    /** date类型数据格式定义 */
+    var date = "yyyy-MM-dd"
+
+    /** time类型数据格式定义 */
+    var time = "HH:mm:ss"
+} // Object SFormat

+ 162 - 0
persagy-kotlin-base/src/main/kotlin/com/persagy/base/utils/SGzipUtil.kt

@@ -0,0 +1,162 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.base.utils
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+
+/**
+ * Gzip工具,用于完成zip压缩与解压缩
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+object SGzipUtil {
+    const val GZIP_ENCODE_UTF_8 = "UTF-8"
+    const val GZIP_ENCODE_ISO_8859_1 = "ISO-8859-1"
+
+    /**
+     * 字符串的解压
+     *
+     * @param   str         对字符串解压
+     * @return  返回解压缩后的字符串
+     */
+    @Throws(IOException::class)
+    fun unCompress(str: String): ByteArray? {
+        if (str.isEmpty()) {
+            return null
+        }
+
+        // 创建一个新的 byte 数组输出流
+        val out = ByteArrayOutputStream()
+        // 创建一个 ByteArrayInputStream,使用 buf 作为其缓冲区数组
+        val `in` = ByteArrayInputStream(str
+                .toByteArray(charset("UTF-8")))
+        // 使用默认缓冲区大小创建新的输入流
+        val gzip = GZIPInputStream(`in`)
+        val buffer = ByteArray(1024)
+        var n = gzip.read(buffer)
+        while (n >= 0) {  // 将未压缩数据读入字节数组
+            // 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此 byte数组输出流
+            out.write(buffer, 0, n)
+            n = gzip.read(buffer)
+        }
+        // 使用指定的 charsetName,通过解码字节将缓冲区内容转换为字符串
+        return buffer
+    } // Fun unCompress()
+
+    /**
+     * 字符串压缩为GZIP字节数组
+     */
+    fun compress(str: String, encoding: String): ByteArray? {
+        if (str.isEmpty()) {
+            return null
+        }
+
+        val out = ByteArrayOutputStream()
+        val gzip: GZIPOutputStream
+        try {
+            gzip = GZIPOutputStream(out)
+            gzip.write(str.toByteArray(charset(encoding)))
+            gzip.close()
+        } catch (e: IOException) {
+            println("gzip compress error: " + e.message)
+        }
+
+        return out.toByteArray()
+    } // Fun compress()
+
+    /**
+     * Gzip  byte[] 解压成字符串
+     */
+    fun uncompressToString(bytes: ByteArray): String? {
+        return uncompressToString(bytes, GZIP_ENCODE_UTF_8)
+    } // Fun uncompressToString()
+
+
+    /**
+     * Gzip  byte[] 解压成字符串
+     */
+    private fun uncompressToString(bytes: ByteArray?, encoding: String): String? {
+        if (bytes == null || bytes.size == 0) {
+            return null
+        }
+        val out = ByteArrayOutputStream()
+        val `in` = ByteArrayInputStream(bytes)
+        try {
+            val ungzip = GZIPInputStream(`in`)
+            val buffer = ByteArray(1024)
+            var n = ungzip.read(buffer)
+            while (n >= 0) {
+                out.write(buffer, 0, n)
+                n = ungzip.read(buffer)
+            }
+            return out.toString(encoding)
+        } catch (e: IOException) {
+            println("gzip compress error:" + e.message)
+        }
+
+        return null
+    } // Fun uncompressToString()
+
+//    /**
+//     * 判断byte[]是否是Gzip格式
+//     */
+//    fun isGzip(data: ByteArray): Boolean {
+//        val header = data[0] shl 8 or (data[1] and 0xff)
+//        return header == 0x1f8b
+//    } // Fun isGzip()
+
+//    /**
+//     * GZIP解压缩
+//     *
+//     * @param   zipText     GZIP压缩过的字符串
+//     * @return 解压后的字符串
+//     */
+//    @Throws(IOException::class)
+//    fun decompress(zipText: String): String {
+//        val compressed = Base64.decode(zipText, 1024)
+//        if (compressed.size > 4) {
+//            val gzipInputStream = GZIPInputStream(
+//                    ByteArrayInputStream(compressed, 4,
+//                            compressed.size - 4))
+//
+//            val baos = ByteArrayOutputStream()
+//            var value = 0
+//            while (value != -1) {
+//                value = gzipInputStream.read()
+//                if (value != -1) {
+//                    baos.write(value)
+//                }
+//            }
+//            gzipInputStream.close()
+//            baos.close()
+//            return String(baos.toByteArray(), "UTF-8")
+//        } else {
+//            return ""
+//        }
+//    }
+} // Object GzipUtil

+ 543 - 0
persagy-kotlin-base/src/main/kotlin/com/persagy/base/utils/SHttpUtil.kt

@@ -0,0 +1,543 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.base.utils
+
+import com.alibaba.fastjson.PropertyNamingStrategy
+import com.persagy.base.extensions.toJson
+import okhttp3.*
+import java.util.concurrent.TimeUnit
+
+/**
+ * Http工具类
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+object SHttpUtil {
+    /** 连接超时时间 */
+    var connectTimeout: Long = 30L
+    /** 读取超时时间 */
+    var readTimeout: Long = 30L
+    /** 写入超时时间 */
+    var writeTimeout: Long = 30L
+
+    /** http客户端 */
+    private val httpClient: OkHttpClient by lazy {
+        OkHttpClient.Builder()
+                .connectTimeout(connectTimeout, TimeUnit.SECONDS)
+                .readTimeout(readTimeout, TimeUnit.SECONDS)
+                .writeTimeout(writeTimeout, TimeUnit.SECONDS)
+                .build()
+    }
+
+    /** 媒体类型 */
+    val ALTERNATIVE     = MediaType.parse("multipart/alternative")
+    val DIGEST          = MediaType.parse("multipart/digest")
+    val FORM            = MediaType.parse("multipart/form-data")
+    val JSON            = MediaType.parse("application/json; charset=utf-8")
+    val MIXED           = MediaType.parse("multipart/mixed")
+    val PARALLEL        = MediaType.parse("multipart/parallel")
+
+    /**
+     * 根据扩展名获得Http的Content-Type
+     *
+     * @param       extensionName       文件扩展名
+     * @return      扩展名对应的Content-Type
+     */
+    fun contentType(extensionName: String): String {
+        val map = mapOf(
+                "tif"     to  "image/tiff",
+                "001"     to  "application/x-001",
+                "301"     to  "application/x-301",
+                "323"     to  "text/h323",
+                "906"     to  "application/x-906",
+                "907"     to  "drawing/907",
+                "a11"     to  "application/x-a11",
+                "acp"     to  "audio/x-mei-aac",
+                "ai"      to  "application/postscript",
+                "aif"     to  "audio/aiff",
+                "aifc"    to  "audio/aiff",
+                "aiff"    to  "audio/aiff",
+                "anv"     to  "application/x-anv",
+                "asa"     to  "text/asa",
+                "asf"     to  "video/x-ms-asf",
+                "asp"     to  "text/asp",
+                "asx"     to  "video/x-ms-asf",
+                "au"      to  "audio/basic",
+                "avi"     to  "video/avi",
+                "awf"     to  "application/vnd.adobe.workflow",
+                "biz"     to  "text/xml",
+                "bmp"     to  "application/x-bmp",
+                "bot"     to  "application/x-bot",
+                "c4t"     to  "application/x-c4t",
+                "c90"     to  "application/x-c90",
+                "cal"     to  "application/x-cals",
+                "cat"     to  "application/vnd.ms-pki.seccat",
+                "cdf"     to  "application/x-netcdf",
+                "cdr"     to  "application/x-cdr",
+                "cel"     to  "application/x-cel",
+                "cer"     to  "application/x-x509-ca-cert",
+                "cg4"     to  "application/x-g4",
+                "cgm"     to  "application/x-cgm",
+                "cit"     to  "application/x-cit",
+                "class"   to  "java/*",
+                "cml"     to  "text/xml",
+                "cmp"     to  "application/x-cmp",
+                "cmx"     to  "application/x-cmx",
+                "cot"     to  "application/x-cot",
+                "crl"     to  "application/pkix-crl",
+                "crt"     to  "application/x-x509-ca-cert",
+                "csi"     to  "application/x-csi",
+                "css"     to  "text/css",
+                "cut"     to  "application/x-cut",
+                "dbf"     to  "application/x-dbf",
+                "dbm"     to  "application/x-dbm",
+                "dbx"     to  "application/x-dbx",
+                "dcd"     to  "text/xml",
+                "dcx"     to  "application/x-dcx",
+                "der"     to  "application/x-x509-ca-cert",
+                "dgn"     to  "application/x-dgn",
+                "dib"     to  "application/x-dib",
+                "dll"     to  "application/x-msdownload",
+                "doc"     to  "application/msword",
+                "dot"     to  "application/msword",
+                "drw"     to  "application/x-drw",
+                "dtd"     to  "text/xml",
+                "dwf"     to  "Model/vnd.dwf",
+                "dwf"     to  "application/x-dwf",
+                "dwg"     to  "application/x-dwg",
+                "dxb"     to  "application/x-dxb",
+                "dxf"     to  "application/x-dxf",
+                "edn"     to  "application/vnd.adobe.edn",
+                "emf"     to  "application/x-emf",
+                "eml"     to  "message/rfc822",
+                "ent"     to  "text/xml",
+                "epi"     to  "application/x-epi",
+                "eps"     to  "application/x-ps",
+                "eps"     to  "application/postscript",
+                "etd"     to  "application/x-ebx",
+                "exe"     to  "application/x-msdownload",
+                "fax"     to  "image/fax",
+                "fdf"     to  "application/vnd.fdf",
+                "fif"     to  "application/fractals",
+                "fo"      to  "text/xml",
+                "frm"     to  "application/x-frm",
+                "g4"      to  "application/x-g4",
+                "gbr"     to  "application/x-gbr",
+                "gif"     to  "image/gif",
+                "gl2"     to  "application/x-gl2",
+                "gp4"     to  "application/x-gp4",
+                "hgl"     to  "application/x-hgl",
+                "hmr"     to  "application/x-hmr",
+                "hpg"     to  "application/x-hpgl",
+                "hpl"     to  "application/x-hpl",
+                "hqx"     to  "application/mac-binhex40",
+                "hrf"     to  "application/x-hrf",
+                "hta"     to  "application/hta",
+                "htc"     to  "text/x-component",
+                "htm"     to  "text/html",
+                "html"    to  "text/html",
+                "htt"     to  "text/webviewhtml",
+                "htx"     to  "text/html",
+                "icb"     to  "application/x-icb",
+                "ico"     to  "image/x-icon",
+                "ico"     to  "application/x-ico",
+                "iff"     to  "application/x-iff",
+                "ig4"     to  "application/x-g4",
+                "igs"     to  "application/x-igs",
+                "iii"     to  "application/x-iphone",
+                "img"     to  "application/x-img",
+                "ins"     to  "application/x-internet-signup",
+                "isp"     to  "application/x-internet-signup",
+                "ivf"     to  "video/x-ivf",
+                "java"    to  "java/*",
+                "jfif"    to  "image/jpeg",
+                "jpe"     to  "image/jpeg",
+                "jpe"     to  "application/x-jpe",
+                "jpeg"    to  "image/jpeg",
+                "jpg"     to  "image/jpeg",
+                "jpg"     to  "application/x-jpg",
+                "js"      to  "application/x-javascript",
+                "jsp"     to  "text/html",
+                "la1"     to  "audio/x-liquid-resources",
+                "lar"     to  "application/x-laplayer-reg",
+                "latex"   to  "application/x-latex",
+                "lavs"    to  "audio/x-liquid-secure",
+                "lbm"     to  "application/x-lbm",
+                "lmsff"   to  "audio/x-la-lms",
+                "ls"      to  "application/x-javascript",
+                "ltr"     to  "application/x-ltr",
+                "m1v"     to  "video/x-mpeg",
+                "m2v"     to  "video/x-mpeg",
+                "m3u"     to  "audio/mpegurl",
+                "m4e"     to  "video/mpeg4",
+                "mac"     to  "application/x-mac",
+                "man"     to  "application/x-troff-man",
+                "math"    to  "text/xml",
+                "mdb"     to  "application/msaccess",
+                "mdb"     to  "application/x-mdb",
+                "mfp"     to  "application/x-shockwave-flash",
+                "mht"     to  "message/rfc822",
+                "mhtml"   to  "message/rfc822",
+                "mi"      to  "application/x-mi",
+                "mid"     to  "audio/mid",
+                "midi"    to  "audio/mid",
+                "mil"     to  "application/x-mil",
+                "mml"     to  "text/xml",
+                "mnd"     to  "audio/x-musicnet-download",
+                "mns"     to  "audio/x-musicnet-stream",
+                "mocha"   to  "application/x-javascript",
+                "movie"   to  "video/x-sgi-movie",
+                "mp1"     to  "audio/mp1",
+                "mp2"     to  "audio/mp2",
+                "mp2v"    to  "video/mpeg",
+                "mp3"     to  "audio/mp3",
+                "mp4"     to  "video/mp4",
+                "mpa"     to  "video/x-mpg",
+                "mpd"     to  "application/vnd.ms-project",
+                "mpe"     to  "video/x-mpeg",
+                "mpeg"    to  "video/mpg",
+                "mpg"     to  "video/mpg",
+                "mpga"    to  "audio/rn-mpeg",
+                "mpp"     to  "application/vnd.ms-project",
+                "mps"     to  "video/x-mpeg",
+                "mpt"     to  "application/vnd.ms-project",
+                "mpv"     to  "video/mpg",
+                "mpv2"    to  "video/mpeg",
+                "mpw"     to  "application/vnd.ms-project",
+                "mpx"     to  "application/vnd.ms-project",
+                "mtx"     to  "text/xml",
+                "mxp"     to  "application/x-mmxp",
+                "net"     to  "image/pnetvue",
+                "nrf"     to  "application/x-nrf",
+                "nws"     to  "message/rfc822",
+                "odc"     to  "text/x-ms-odc",
+                "out"     to  "application/x-out",
+                "p10"     to  "application/pkcs10",
+                "p12"     to  "application/x-pkcs12",
+                "p7b"     to  "application/x-pkcs7-certificates",
+                "p7c"     to  "application/pkcs7-mime",
+                "p7m"     to  "application/pkcs7-mime",
+                "p7r"     to  "application/x-pkcs7-certreqresp",
+                "p7s"     to  "application/pkcs7-signature",
+                "pc5"     to  "application/x-pc5",
+                "pci"     to  "application/x-pci",
+                "pcl"     to  "application/x-pcl",
+                "pcx"     to  "application/x-pcx",
+                "pdf"     to  "application/pdf",
+                "pdx"     to  "application/vnd.adobe.pdx",
+                "pfx"     to  "application/x-pkcs12",
+                "pgl"     to  "application/x-pgl",
+                "pic"     to  "application/x-pic",
+                "pko"     to  "application/vnd.ms-pki.pko",
+                "pl"      to  "application/x-perl",
+                "plg"     to  "text/html",
+                "pls"     to  "audio/scpls",
+                "plt"     to  "application/x-plt",
+                "png"     to  "image/png",
+                "png"     to  "application/x-png",
+                "pot"     to  "application/vnd.ms-powerpoint",
+                "ppa"     to  "application/vnd.ms-powerpoint",
+                "ppm"     to  "application/x-ppm",
+                "pps"     to  "application/vnd.ms-powerpoint",
+                "ppt"     to  "application/vnd.ms-powerpoint",
+                "ppt"     to  "application/x-ppt",
+                "pr"      to  "application/x-pr",
+                "prf"     to  "application/pics-rules",
+                "prn"     to  "application/x-prn",
+                "prt"     to  "application/x-prt",
+                "ps"      to  "application/x-ps",
+                "ptn"     to  "application/x-ptn",
+                "pwz"     to  "application/vnd.ms-powerpoint",
+                "r3t"     to  "text/vnd.rn-realtext3d",
+                "ra"      to  "audio/vnd.rn-realaudio",
+                "ram"     to  "audio/x-pn-realaudio",
+                "ras"     to  "application/x-ras",
+                "rat"     to  "application/rat-resources",
+                "rdf"     to  "text/xml",
+                "rec"     to  "application/vnd.rn-recording",
+                "red"     to  "application/x-red",
+                "rgb"     to  "application/x-rgb",
+                "rjs"     to  "application/vnd.rn-realsystem-rjs",
+                "rjt"     to  "application/vnd.rn-realsystem-rjt",
+                "rlc"     to  "application/x-rlc",
+                "rle"     to  "application/x-rle",
+                "rm"      to  "application/vnd.rn-realmedia",
+                "rmf"     to  "application/vnd.adobe.rmf",
+                "rmi"     to  "audio/mid",
+                "rmj"     to  "application/vnd.rn-realsystem-rmj",
+                "rmm"     to  "audio/x-pn-realaudio",
+                "rmp"     to  "application/vnd.rn-rn_music_package",
+                "rms"     to  "application/vnd.rn-realmedia-secure",
+                "rmvb"    to  "application/vnd.rn-realmedia-vbr",
+                "rmx"     to  "application/vnd.rn-realsystem-rmx",
+                "rnx"     to  "application/vnd.rn-realplayer",
+                "rp"      to  "image/vnd.rn-realpix",
+                "rpm"     to  "audio/x-pn-realaudio-plugin",
+                "rsml"    to  "application/vnd.rn-rsml",
+                "rt"      to  "text/vnd.rn-realtext",
+                "rtf"     to  "application/msword",
+                "rtf"     to  "application/x-rtf",
+                "rv"      to  "video/vnd.rn-realvideo",
+                "sam"     to  "application/x-sam",
+                "sat"     to  "application/x-sat",
+                "sdp"     to  "application/sdp",
+                "sdw"     to  "application/x-sdw",
+                "sit"     to  "application/x-stuffit",
+                "slb"     to  "application/x-slb",
+                "sld"     to  "application/x-sld",
+                "slk"     to  "drawing/x-slk",
+                "smi"     to  "application/smil",
+                "smil"    to  "application/smil",
+                "smk"     to  "application/x-smk",
+                "snd"     to  "audio/basic",
+                "sol"     to  "text/plain",
+                "sor"     to  "text/plain",
+                "spc"     to  "application/x-pkcs7-certificates",
+                "spl"     to  "application/futuresplash",
+                "spp"     to  "text/xml",
+                "ssm"     to  "application/streamingmedia",
+                "sst"     to  "application/vnd.ms-pki.certs  tore",
+                "stl"     to  "application/vnd.ms-pki.stl",
+                "stm"     to  "text/html",
+                "sty"     to  "application/x-sty",
+                "svg"     to  "text/xml",
+                "swf"     to  "application/x-shockwave-flash",
+                "tdf"     to  "application/x-tdf",
+                "tg4"     to  "application/x-tg4",
+                "tga"     to  "application/x-tga",
+                "tif"     to  "image/tiff",
+                "tif"     to  "application/x-tif",
+                "tiff"    to  "image/tiff",
+                "tld"     to  "text/xml",
+                "top"     to  "drawing/x-top",
+                "torrent" to  "application/x-bittorrent",
+                "tsd"     to  "text/xml",
+                "txt"     to  "text/plain",
+                "uin"     to  "application/x-icq",
+                "uls"     to  "text/iuls",
+                "vcf"     to  "text/x-vcard",
+                "vda"     to  "application/x-vda",
+                "vdx"     to  "application/vnd.visio",
+                "vml"     to  "text/xml",
+                "vpg"     to  "application/x-vpeg005",
+                "vsd"     to  "application/vnd.visio",
+                "vsd"     to  "application/x-vsd",
+                "vss"     to  "application/vnd.visio",
+                "vst"     to  "application/vnd.visio",
+                "vst"     to  "application/x-vst",
+                "vsw"     to  "application/vnd.visio",
+                "vsx"     to  "application/vnd.visio",
+                "vtx"     to  "application/vnd.visio",
+                "vxml"    to  "text/xml",
+                "wav"     to  "audio/wav",
+                "wax"     to  "audio/x-ms-wax",
+                "wb1"     to  "application/x-wb1",
+                "wb2"     to  "application/x-wb2",
+                "wb3"     to  "application/x-wb3",
+                "wbmp"    to  "image/vnd.wap.wbmp",
+                "wiz"     to  "application/msword",
+                "wk3"     to  "application/x-wk3",
+                "wk4"     to  "application/x-wk4",
+                "wkq"     to  "application/x-wkq",
+                "wks"     to  "application/x-wks",
+                "wm"      to  "video/x-ms-wm",
+                "wma"     to  "audio/x-ms-wma",
+                "wmd"     to  "application/x-ms-wmd",
+                "wmf"     to  "application/x-wmf",
+                "wml"     to  "text/vnd.wap.wml",
+                "wmv"     to  "video/x-ms-wmv",
+                "wmx"     to  "video/x-ms-wmx",
+                "wmz"     to  "application/x-ms-wmz",
+                "wp6"     to  "application/x-wp6",
+                "wpd"     to  "application/x-wpd",
+                "wpg"     to  "application/x-wpg",
+                "wpl"     to  "application/vnd.ms-wpl",
+                "wq1"     to  "application/x-wq1",
+                "wr1"     to  "application/x-wr1",
+                "wri"     to  "application/x-wri",
+                "wrk"     to  "application/x-wrk",
+                "ws"      to  "application/x-ws",
+                "ws2"     to  "application/x-ws",
+                "wsc"     to  "text/scriptlet",
+                "wsdl"    to  "text/xml",
+                "wvx"     to  "video/x-ms-wvx",
+                "xdp"     to  "application/vnd.adobe.xdp",
+                "xdr"     to  "text/xml",
+                "xfd"     to  "application/vnd.adobe.xfd",
+                "xfdf"    to  "application/vnd.adobe.xfdf",
+                "xhtml"   to  "text/html",
+                "xls"     to  "application/vnd.ms-excel",
+                "xls"     to  "application/x-xls",
+                "xlw"     to  "application/x-xlw",
+                "xml"     to  "text/xml",
+                "xpl"     to  "audio/scpls",
+                "xq"      to  "text/xml",
+                "xql"     to  "text/xml",
+                "xquery"  to  "text/xml",
+                "xsd"     to  "text/xml",
+                "xsl"     to  "text/xml",
+                "xslt"    to  "text/xml",
+                "xwd"     to  "application/x-xwd",
+                "x_b"     to  "application/x-x_b",
+                "sis"     to  "application/vnd.symbian.install",
+                "sisx"    to  "application/vnd.symbian.install",
+                "x_t"     to  "application/x-x_t",
+                "ipa"     to  "application/vnd.iphone",
+                "apk"     to  "application/vnd.android.package-archive",
+                "xap"     to  "application/x-silverlight-app"
+        )
+
+        // 扩展名转换为小写
+        val key = extensionName.toLowerCase()
+
+        // 如果map包含指定的扩展名,则返回对应的Content-Type, 否则返回二进制流类型"application/octet-stream"
+        return if (map.contains(key)) {
+            map.getValue(key)
+        } else {
+            "application/octet-stream"
+        }
+    } // Fun contentType()
+
+    /**
+     * GET 请求
+     *
+     * @param   url     URL 地址
+     * @return  服务器返回的应答信息
+     */
+    @Throws(Exception::class)
+    fun getRequest(url: String): String {
+        val request = Request.Builder()
+                .url(url)
+                .get()
+                .build()
+
+        val call = httpClient.newCall(request)
+        val response = call.execute()
+        return response.body()!!.string()
+    } // Fun getRequest()
+
+    /**
+     * GET 请求(zip压缩格式)
+     *
+     * @param   url     URL地址
+     * @return  服务器返回的应答信息
+     */
+    @Throws(Exception::class)
+    fun getZipRequest(url: String): String {
+        val request = Request.Builder()
+                .url(url)
+                .get()
+                .header("Accept-Encoding", "gzip")
+                .build()
+
+        val call = httpClient.newCall(request)
+        val response = call.execute()
+
+        return SGzipUtil.uncompressToString(response.body()!!.bytes()) ?: ""
+    } // Fun getZipRequest()
+
+    /**
+     * 发送post对象请求
+     *
+     * @param   url     URL地址
+     * @param   body    请求体
+     * @return  返回应答体字符串
+     */
+    @Throws(Exception::class)
+    fun postRequest(url: String, body: String, type: MediaType = JSON!!): String {
+        val jsonBody = FormBody.create(type, body)
+        val request = createPostRequest(url, jsonBody)
+
+        val call = httpClient.newCall(request)
+        val response = call.execute()
+        return response.body()!!.string()
+    } // Fun postRequest()
+
+    /**
+     * 发送get对象请求
+     *
+     * @param   <T>                 请求的返回类型
+     * @param   url                 URL地址
+     * @param   namingStrategy      命名规则
+     * @return  接收到的请求体
+     */
+    @Throws(Exception::class)
+    inline fun <reified T> getObject(url: String, namingStrategy: PropertyNamingStrategy? = null): T {
+        val responseJson = getRequest(url)
+        return SJsonUtil.fromJson(responseJson, namingStrategy)
+    } // Fun getObject()
+
+    /**
+     * 发送post请求
+     *
+     * @param   url                 URL地址
+     * @param   <T>                 请求的返回类型
+     * @param   requestBody         发送到服务器的请求体
+     * @param   namingStrategy      命名规则
+     * @return  接收到的请求体
+     */
+    @Throws(Exception::class)
+    inline fun <reified T> postObject(url: String, requestBody: Any, namingStrategy: PropertyNamingStrategy? = null): T {
+        val responseJson = postRequest(url, requestBody.toJson(namingStrategy))
+        return SJsonUtil.fromJson(responseJson, namingStrategy)
+    } // Fun postObject()
+
+    /**
+     * 上传文件
+     *
+     * @param   url     上传地址
+     */
+//    fun uploadFile(url: String) {
+//        /*RequestBody requestBody = new MultipartBody.Builder()
+//                .setType(MultipartBody.FORM)
+//                .addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse("image/png"), file))
+//                .build();*/
+//        return
+//    } // Fun uploadFile()
+
+    /**
+     * 下载文件
+     *
+     * @param       url     文件url地址
+     */
+//    fun downloadFile(url: String) {
+//
+//    } // Fun downloadFile()
+
+    /**
+     * 创建Http post请求对象
+     *
+     * @param   url             URL地址
+     * @param   jsonBody        发送到服务器的请求体
+     */
+    private fun createPostRequest(url: String, jsonBody: RequestBody? = null): Request {
+        val builder = Request.Builder()
+                .url(url)
+        if (jsonBody!= null) {
+            builder.post(jsonBody)
+        }
+
+        return builder.build()
+    } // Fun createPostRequest()
+} // Object SHttpUtil

+ 40 - 0
persagy-kotlin-base/src/main/kotlin/com/persagy/base/utils/SJarUtil.kt

@@ -0,0 +1,40 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.base.utils
+
+/**
+ * Jar包工具类
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+object SJarUtil {
+    /**
+     *  加载jar包
+     *
+     *  @param  jarFile     jar包文件
+     */
+//    fun loadJar(jarFile: String) {
+//
+//    } // Fun loadJar()
+} // Object SJarUtil

+ 160 - 0
persagy-kotlin-base/src/main/kotlin/com/persagy/base/utils/SJsonUtil.kt

@@ -0,0 +1,160 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.base.utils
+
+import com.alibaba.fastjson.JSON
+import com.alibaba.fastjson.PropertyNamingStrategy
+import com.alibaba.fastjson.serializer.SerializeConfig
+import com.alibaba.fastjson.serializer.SerializerFeature
+import java.io.*
+import java.lang.reflect.Type
+
+/**
+ * Json工具类
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+object SJsonUtil {
+    private val TAG = SJsonUtil::class.java.name
+    /** 序列化配置 */
+    val serializeConfig = SerializeConfig()
+
+    /**
+     * 转换对象到 JSON 格式字符串
+     *
+     * @param   obj                     被转换对象
+     * @param   namingStrategy          命名规则
+     * @return  JSON 格式字符串
+     */
+    fun toJson(obj: Any, namingStrategy: PropertyNamingStrategy? = null): String {
+        return if (null == namingStrategy) {
+            JSON.toJSONString(obj, serializeConfig, SerializerFeature.DisableCircularReferenceDetect)
+        } else {
+            val config = SerializeConfig()
+            config.propertyNamingStrategy = namingStrategy
+            JSON.toJSONString(obj, config, SerializerFeature.DisableCircularReferenceDetect)
+        }
+    } // Fun toJson()
+
+    /**
+     * 转换对象到 JSON 格式字符串,包含空字符串
+     *
+     * @param   obj                     被转换对象
+     * @param   namingStrategy          首字母是否大写
+     * @return  json格式字符串
+     */
+    fun toJsonAll(obj: Any, namingStrategy: PropertyNamingStrategy? = null): String {
+        return if (null == namingStrategy) {
+            JSON.toJSONString(obj,
+                    serializeConfig,
+                    SerializerFeature.WriteMapNullValue,
+                    SerializerFeature.WriteNullListAsEmpty,
+                    SerializerFeature.DisableCircularReferenceDetect)
+        } else {
+            val config = SerializeConfig()
+            config.propertyNamingStrategy = namingStrategy
+            JSON.toJSONString(obj,
+                    config,
+                    SerializerFeature.WriteMapNullValue,
+                    SerializerFeature.WriteNullListAsEmpty,
+                    SerializerFeature.DisableCircularReferenceDetect)
+        }
+    } // Fun toJsonAll()
+
+    /**
+     * 将 JSON 数据解析成相应的映射对象
+     *
+     * @param   jsonData                要解析的JSON数据
+     * @param   type                    Java类型
+     * @return  解析结果
+     */
+    @Throws(Exception::class)
+    fun <T> fromJson(jsonData: String, type: Class<T>): T? {
+        return JSON.parseObject(jsonData, type)
+    } // Fun fromJson()
+
+    /**
+     * 将Json数据解析成相应的映射对象
+     *
+     * @param   jsonData                要解析的JSON数据
+     * @param   type                    Java类型
+     * @return  解析结果
+     */
+    @Throws(Exception::class)
+    fun fromJson(jsonData: String, type: Type): Any? {
+        return JSON.parseObject(jsonData, type)
+    } // Fun fromJson()
+
+    /**
+     * 将Json数据解析成相应的映射对象
+     *
+     * @param   input                   要解析的JSON数据输入流
+     * @param   type                    Java类型
+     * @param   namingStrategy          命名规则
+     * @return  解析结果
+     */
+    @Throws(Exception::class)
+    fun <T> fromJson(input: InputStream, type: Class<T>): T? {
+        val count = input.available()
+        val buf = ByteArray(count)
+        var readCount = 0
+        while (readCount < count) {
+            readCount += input.read(buf, readCount, count - readCount)
+        }
+
+        return fromJson(String(buf), type)
+    } // Fun fromJson()
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * 将Json数据解析成相应的映射对象
+     *
+     * @param   jsonData                要解析的JSON数据
+     * @param   namingStrategy          命名规则
+     * @return  解析结果
+     */
+    @Throws(Exception::class)
+    inline fun <reified T> fromJson(jsonData: String, namingStrategy: PropertyNamingStrategy? = null): T {
+        return JSON.parseObject(jsonData, T::class.java)
+    } // Fun parseJson()
+
+    /**
+     * 将Json数据解析成相应的映射对象
+     *
+     * @param   input                   要解析的JSON数据输入流
+     * @param   namingStrategy          命名规则
+     * @return  解析结果
+     */
+    @Throws(Exception::class)
+    inline fun <reified T> fromJson(input: InputStream, namingStrategy: PropertyNamingStrategy? = null): T {
+        val count = input.available()
+        val buf = ByteArray(count)
+        var readCount = 0
+        while (readCount < count) {
+            readCount += input.read(buf, readCount, count - readCount)
+        }
+
+        return fromJson(String(buf), namingStrategy)
+    } // Fun fromJson()
+} // Class SJsonUtil

+ 22 - 0
persagy-kotlin-base/src/test/kotlin/com/sybotan/base/extensions/TestSAnyExtension.kt

@@ -0,0 +1,22 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */

+ 22 - 0
persagy-kotlin-base/src/test/kotlin/com/sybotan/base/utils/TestSJsonUtil.kt

@@ -0,0 +1,22 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */

+ 134 - 0
persagy-kotlin-database/build.gradle

@@ -0,0 +1,134 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+group rootProject.group
+version rootProject.version
+
+apply plugin: "kotlin"
+apply plugin: "org.jetbrains.dokka"
+apply plugin: "maven"
+apply plugin: 'ca.coglinc.javacc'
+
+sourceCompatibility = JVM_TARGET
+
+compileKotlin {
+    kotlinOptions.jvmTarget = JVM_TARGET
+}
+compileTestKotlin {
+    kotlinOptions.jvmTarget = JVM_TARGET
+}
+
+compileJavacc {
+    inputDirectory = file("src/main/javacc")
+    outputDirectory = file("src/main/kotlin/com/persagy/database/parser")
+}
+
+dependencies {
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // kotlin 依赖
+    compile group: "org.jetbrains.kotlin", name: "kotlin-stdlib-jdk8", version: KOTLIN_VERSION
+    compile group: "org.jetbrains.kotlin", name: "kotlin-reflect", version: KOTLIN_VERSION
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // 单元测试
+    // https://mvnrepository.com/artifact/org.testng/testng
+    testCompile group: 'org.testng', name: 'testng', version: TESTNG_VERSION
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    compile group: "javax.persistence", name: "persistence-api", version: PERSISTENCE_VERSION
+
+    // https://mvnrepository.com/artifact/io.swagger/swagger-annotations
+    compile group: 'io.swagger', name: 'swagger-annotations', version: '1.5.22'
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // Sybotan依赖
+    compile project(':persagy-kotlin-base')
+
+//    // https://mvnrepository.com/artifact/net.java.dev.javacc/javacc
+//    compile group: 'net.java.dev.javacc', name: 'javacc', version: '6.1.2'
+
+
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// 文档生成
+dokka {
+    jdkVersion = JDK_VERSION
+    outputFormat = "javadoc"
+    outputDirectory = "$buildDir/javadoc"
+    //sourceDirs = files("src/main/kotlin")
+}
+
+// 上成上传的文档jar包
+task javadocJar(type: Jar, dependsOn: dokka) {
+    classifier = "javadoc"
+    from dokka.outputDirectory
+}
+
+// 上成上传的文档jar包
+task sourcesJar(type: Jar) {
+    classifier = 'sources'
+    from sourceSets.main.allSource
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// maven 仓库管理
+
+// 设置上传的包,默认上传aar与pom
+artifacts {
+    // archives javadocJar
+    // archives sourcesJar
+}
+
+uploadArchives {
+    repositories {
+        mavenDeployer {
+            pom.groupId = project.group
+            pom.version = project.version
+            pom.artifactId = project.name
+            pom.project {
+                name project.name
+                packaging "jar"
+                url PERSAGY_URL
+                description "斯伯坦机器人 Kotlin 数据库操作支持库。"
+                licenses {
+                    license {
+                        name LICENSE_NAME
+                        url LICENSE_URL
+                    }
+                }
+                developers {
+                    developer {
+                        id DEVELOPER_ID
+                        name DEVELOPER_NAME
+                    }
+                }
+            }
+            snapshotRepository(url: MAVEN_REPO_SNAPSHOT_URL) {
+                authentication(userName: NEXUS_USERNAME, password: NEXUS_PASSWORD)
+            }
+            repository(url: MAVEN_REPO_RELEASE_URL) {
+                authentication(userName: NEXUS_USERNAME, password: NEXUS_PASSWORD)
+            }
+        }
+    }
+}

+ 368 - 0
persagy-kotlin-database/src/main/javacc/SSyntaxParser.jj

@@ -0,0 +1,368 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+options {
+    STATIC = false;             // 成员与方法不生成为静态
+    UNICODE_INPUT = true;       // 支持中文解析
+    JDK_VERSION = "1.8";        // JDK版本为1.8
+    IGNORE_CASE = true;         // 不区分大小写
+}
+
+PARSER_BEGIN(SSyntaxParser)
+package com.persagy.database.parser;
+
+import com.persagy.database.*;
+import com.persagy.database.enums.*;
+import java.util.*;
+
+public class SSyntaxParser {
+    public List<SFilter> parserFilters() throws ParseException {
+        return parserFilterList();
+    } // Fun parserFilters()
+
+    public List<SOrder> parserOrders() throws ParseException {
+        return parserOrderList();
+    } // Fun parserOrders()
+} // Class SSyntaxParser
+
+PARSER_END(SSyntaxParser)
+
+SKIP: { <[" ", "\t", "\r", "\n"]> }
+
+TOKEN:  /* 运算符 */
+{
+      < EQ          : "=" >
+    | < NE          : "!=" >
+    | < GTE         : ">=" >
+    | < GT          : ">" >
+    | < LTE         : "<=" >
+    | < LT          : "<" >
+    | < LPAREN      : "(" >
+    | < RPAREN      : ")" >
+    | < LBRACKET    : "[" >
+    | < RBRACKET    : "]" >
+    | < LBRACES     : "{" >
+    | < RBRACES     : "}" >
+    | < COMMA       : "," >
+    | < SEMICOLON   : ";" >
+    | < DOT         : "." >
+}
+
+TOKEN:  /* 关键字 */
+{
+      < AND         : "AND" | "&&" >
+    | < ASC         : "ASC" >
+    | < CONTAIN     : "CONTAIN" >
+    | < DESC        : "DESC" >
+    | < ENDWITH     : "ENDWITH" >
+    | < FALSE       : "FALSE" >
+    | < IN          : "IN" >
+    | < ISNULL      : "ISNULL" >
+    | < NOT         : "NOT" | "!" >
+    | < NOTNULL     : "NOTNULL" >
+    | < OR          : "OR" | "||" >
+    | < STARTWITH   : "STARTWITH" >
+    | < TRUE        : "TRUE" >
+}
+
+TOKEN:  /* 标识符 */
+{
+    <PROPERTY: <IDENTIFIER>(<DOT>|<IDENTIFIER>)*>
+    | <IDENTIFIER: <LETTER>(<LETTER>|<DIGIT>)*>
+    | <STRING: ("'"(~["'"])*"'")|("\""(~["\""])*"\"")|("`"(~["`"])*"`")>
+    | <FLOAT: ("+"|"-")?(["1"-"9"](<DIGIT>)*"."(<DIGIT>)+)|"0">
+    | <INTEGER: ("+"|"-")?(["1"-"9"](<DIGIT>)*)|"0">
+    | <#LETTER: ["_","a"-"z","A"-"Z"]>
+    | <#DIGIT: ["0"-"9"]>
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// 解析过滤条件列表
+List<SFilter> parserFilterList():
+{
+    Token t;
+    ArrayList<SFilter> filterList = new ArrayList<SFilter>();
+    SFilter filter;
+}
+{
+    filter = parserFilter()
+    {
+        filterList.add(filter);
+    }
+    (
+        <SEMICOLON>
+        filter = parserFilter()
+        {
+            filterList.add(filter);
+        }
+    )*<EOF>
+    {
+        return filterList;
+    }
+}
+
+/** 解析过滤条件 */
+SFilter parserFilter():
+{
+    SFilter filter;
+}
+{
+    (
+        filter = parserOrExpression()
+    )
+    {
+        return filter;
+    }
+}
+
+/** 解析OR运算 */
+SFilter parserOrExpression():
+{
+    SFilter first;
+    SFilter second;
+}
+{
+    first = parserAndExpression()
+    (
+        <OR>
+        second = parserAndExpression()
+        {
+            first = SFilter.Companion.or(first, second);
+        }
+    )*
+    {
+        return first;
+    }
+}
+
+/** 解析AND运算 */
+SFilter parserAndExpression():
+{
+    SFilter first;
+    SFilter second;
+    SFilter temp;
+}
+{
+    first = parserPrimaryExpression()
+    (
+        <AND>
+        second = parserPrimaryExpression()
+        {
+            first = SFilter.Companion.and(first, second);
+        }
+    )*
+    {
+        return first;
+    }
+}
+
+/** 解析OR运算 */
+SFilter parserPrimaryExpression():
+{
+    SFilter filter;
+    SFilter temp;
+}
+{
+    (
+          filter = parserRelationalExpression()
+        | <LPAREN>filter = parserFilter()<RPAREN>
+        | <NOT> temp = parserFilter()
+            {
+                filter = SFilter.Companion.not(temp);
+            }
+    )
+    {
+        return filter;
+    }
+}
+
+/** 解析关系表达式 */
+SFilter parserRelationalExpression():
+{
+    Token property;
+    Object value = null;
+}
+{
+    property = <PROPERTY>
+    (
+          <EQ>
+        {return SFilter.Companion.eq(property.image, parserValue());}
+        | <NE>
+        {return SFilter.Companion.ne(property.image, parserValue());}
+        | <GT>
+        {return SFilter.Companion.gt(property.image, parserValue());}
+        | <GTE>
+        {return SFilter.Companion.gte(property.image, parserValue());}
+        | <LT>
+        {return SFilter.Companion.lt(property.image, parserValue());}
+        | <LTE>
+        {return SFilter.Companion.lte(property.image, parserValue());}
+        | <CONTAIN>
+        {return SFilter.Companion.contain(property.image, parserString());}
+        | <STARTWITH>
+        {return SFilter.Companion.startWith(property.image, parserString());}
+        | <ENDWITH>
+        {return SFilter.Companion.endWith(property.image, parserString());}
+        | <ISNULL>
+        {return SFilter.Companion.isNull(property.image);}
+        | <IN>
+        {return SFilter.Companion.inList(property.image, parserObjectList());}
+    )
+}
+
+/** 对象 */
+Object parserValue():
+{
+    Token t;
+    Object value;
+}
+{
+    (
+        value = parserFloat()
+      | value = parserInteger()
+      | value = parserString()
+      | value = parserBoolean())
+    {
+        return value;
+    }
+}
+
+/** 解析对象列表 */
+List<Object> parserObjectList():
+{
+    ArrayList<Object> list = new ArrayList<Object>();
+    Object obj = 1;
+}
+{
+    <LBRACKET>
+    obj = parserValue()
+    {  list.add(obj); }
+    (
+        <COMMA>
+        obj = parserValue()
+        {
+            if (obj.getClass() != list.get(0).getClass()) {
+                ParseException e = new ParseException();
+                throw e;
+            }
+            list.add(obj);
+        }
+    )*
+    <RBRACKET>
+    {
+        return list;
+    }
+}
+
+/** 浮点数 */
+Float parserFloat():
+{
+    Token t;
+}
+{
+    t = <FLOAT>
+    {
+        return Float.parseFloat(t.image);
+    }
+}
+
+/** 整数 */
+int parserInteger():
+{
+    Token t;
+}
+{
+    t = <INTEGER>
+    {
+        return Integer.parseInt(t.image);
+    }
+}
+
+/** 字符串 */
+String parserString():
+{
+    Token t;
+}
+{
+    t=<STRING>
+    {
+        return t.image.substring(1, t.image.length() - 1);
+    }
+}
+
+/** 布尔值 */
+Boolean parserBoolean():
+{
+    Token t;
+}
+{
+    t=<TRUE>
+    {
+        return true;
+    }
+    | t=<FALSE>
+    {
+        return false;
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// 解析排序条件
+List<SOrder> parserOrderList():
+{
+    Token t;
+    List<SOrder> orderList = new ArrayList<SOrder>();
+    SOrder order;
+}
+{
+    order = parserOrder()
+    {
+        orderList.add(order);
+    }
+    (
+        <COMMA>
+        order = parserOrder()
+        {
+            orderList.add(order);
+        }
+    )*<EOF>
+    {
+        return orderList;
+    }
+}
+
+SOrder parserOrder():
+{
+    Token property;
+    SOrder order = null;
+}
+{
+    property = <PROPERTY>
+    (
+        <DESC>
+        {
+            return new SOrder(property.image, SDirection.DESC);
+        }
+        | (<ASC>)?
+        {return new SOrder(property.image, SDirection.ASC);}
+    )
+}

+ 385 - 0
persagy-kotlin-database/src/main/kotlin/com/persagy/database/SAbstractDao.kt

@@ -0,0 +1,385 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database
+
+import com.persagy.base.exceptions.SFieldNotFoundException
+import com.persagy.base.extensions.toJson
+import com.persagy.base.extensions.*
+import com.persagy.database.extensions.filterListByKeys
+import com.persagy.database.parser.SSyntaxParser
+import java.io.ByteArrayInputStream
+import java.lang.reflect.Field
+import java.lang.reflect.ParameterizedType
+import javax.persistence.Column
+import javax.persistence.Table
+
+/**
+ * 数据访问对象基类
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+abstract class SAbstractDao<ENTITY: Any>(entityClazz: Class<ENTITY>) {
+    companion object {
+        /**
+         * 获得表名,取实体类@Table注解的名称,如果没有注解,则取实体类类名。
+         *
+         * @param   clz         mapper类类型
+         * @param   keyEsc      转义符,用于避免与数据库关键词冲突
+         * @return  表名
+         */
+        fun tableName(clz: Class<*>, keyEsc: String = ""): String {
+            val tableAnno = clz.getAnnotation(javax.persistence.Table::class.java)
+            // 如果有@Table注解,则取注解的表名;否则使用类名做为表名
+            val tableName = tableAnno?.name ?: clz.simpleName
+            val name = tableName.replace(".", "$keyEsc.$keyEsc")
+            return "$keyEsc$name$keyEsc"
+        } // Fun tableName()
+
+        /**
+         * 获得实体类属性对应的数据表字段名
+         *
+         * @param   clazz   实体类类型
+         * @param   name    属性名
+         * @return  对应的数据表字段名
+         */
+        fun columnName(clazz: Class<*>, name: String, keyEsc: String = ""): String {
+            try {
+                val field = clazz.getAllDeclaredField(name, true, true)
+                val colName = field!!.getAnnotation(Column::class.java).name
+                return "$keyEsc$colName$keyEsc"
+            } catch (e: Exception) {
+                throw SFieldNotFoundException(name)
+            }
+        } // Fun columnName()
+
+        /**
+         * 获得实体类属性名
+         *
+         * @param   clazz   实体类类型
+         * @param   name    名称
+         * @return  实体类属性名
+         */
+        fun propertyName(clazz: Class<*>, name: String): String {
+            try {
+                val field = clazz.getAllDeclaredField(name, true, true)
+                return field!!.name
+            } catch (e: Exception) {
+                throw SFieldNotFoundException(name)
+            }
+        } // Fun propertyName()
+    } // companion object
+
+    /** 实体类类型 */
+    val entityClass = entityClazz
+
+    /**
+     * 在数据库中插入实体
+     *
+     * @param   entity      插入数据库的实体
+     * @return  插入是否成功
+     */
+    abstract fun insert(entity: ENTITY): Boolean
+
+    /**
+     * 在数据库中插入/更新实体
+     *
+     * @param   entity      插入/更新数据库的实体
+     * @return  插入是否成功
+     */
+    abstract fun replace(entity: ENTITY): Boolean
+
+    /**
+     * 根据条件删除
+     *
+     * @param   args        删除条件
+     * @return  删除是否成功
+     */
+    abstract fun delete(args: List<SFilter>): Boolean
+
+    /**
+     * 删除所有记录
+     *
+     * @return  删除是否成功
+     */
+    abstract fun deleteAll(): Boolean
+
+    /**
+     * 根据条件更新
+     *
+     * @param   entity      更新的值
+     * @param   projection  将被更新的字段列表(以逗号分隔),为空表示更新所有非空字段
+     * @param   args        更新条件
+     * @return  更新是否成功
+     */
+    abstract fun update(entity: ENTITY, projection: ArrayList<String>? = null, args: List<SFilter>? = null): Boolean
+
+    /**
+     * 根据条件查询记录
+     *
+     * @param   args        查询条件
+     * @return  查询构造器
+     */
+    abstract fun select(args: List<SFilter>): SQueryBuilder<ENTITY>
+
+    /**
+     * 根据条件查询所有记录
+     *
+     * @return  查找构建器
+     */
+    abstract fun selectAll(): SQueryBuilder<ENTITY>
+
+    /**
+     * 执行查询操作
+     *
+     * @param   builder     查询查询构造器
+     * @return  查询到的记录
+     */
+    abstract fun execQuery(builder: SQueryBuilder<ENTITY>): ArrayList<ENTITY>
+
+    /**
+     * 执行统计个数操作
+     *
+     * @param   builder     查询查询构造器
+     * @return  查询到的记录数
+     */
+    abstract fun execCount(builder: SQueryBuilder<ENTITY>): Long
+
+    /**
+     * 执行分页查询操作
+     *
+     * @param   builder     查询查询构造器
+     * @param   pageNumber      第几页
+     * @param   pageSize        每页记录数
+     * @return  查询到的记录
+     */
+    fun pageQuery(builder: SQueryBuilder<ENTITY>, pageNumber: Int, pageSize: Int): SPageQueryInfo<ENTITY> {
+        val pageInfo = SPageQueryInfo<ENTITY>(pageNumber, pageSize)
+        builder.limit((pageNumber - 1) * pageSize, pageSize)
+        pageInfo.total = execCount(builder)
+        pageInfo.content = execQuery(builder)
+
+        return pageInfo
+    } // Fun pageQuery()
+
+    /**
+     * 删除实体
+     *
+     * @param   entity      被删除的实体
+     * @return  删除是否成功
+     */
+    open fun delete(entity: ENTITY): Boolean {
+        return delete(entity.filterListByKeys())
+    } // Fun delete()
+
+    /**
+     * 根据条件删除
+     *
+     * @param   args        删除条件
+     * @return  删除是否成功
+     */
+    open fun delete(vararg args: Pair<String, Any>): Boolean {
+        val filterList = ArrayList<SFilter>()
+        for (arg in args) {     // 同时取列表元素与下标
+            filterList.add(SFilter.eq(arg.first, arg.second))
+        }
+
+        return delete(filterList)
+    } // Fun delete()
+
+    /**
+     * 根据条件删除
+     *
+     * @param   args        删除条件
+     * @return  删除是否成功
+     */
+    open fun delete(vararg args: SFilter): Boolean {
+        return delete(args.toList())
+    } // Fun delete()
+
+    /**
+     * 根据条件删除
+     *
+     * @param   query       删除条件
+     * @return  删除是否成功
+     */
+    open fun delete(query: String): Boolean {
+        val parser = SSyntaxParser(ByteArrayInputStream(query.toByteArray()))
+        return delete(parser.parserFilters())
+    } // Fun delete()
+
+    /**
+     * 更新实体
+     *
+     * @param   entity      更新实体
+     * @param   projection  将被更新的字段列表(以逗号分隔),为空表示更新所有非空字段
+     * @return  更新是否成功
+     */
+    open fun update(entity: ENTITY, projection: ArrayList<String>? = null): Boolean {
+        return update(entity, projection, entity.filterListByKeys())
+    } // Fun update()
+
+    /**
+     * 根据条件更新
+     *
+     * @param   entity      更新实体内容
+     * @param   projection  将被更新的字段列表(以逗号分隔),为空表示更新所有非空字段
+     * @param   args        更新条件
+     * @return  更新是否成功
+     */
+    open fun update(entity: ENTITY, projection: ArrayList<String>? = null, vararg args: Pair<String, Any>): Boolean {
+        val filterList = ArrayList<SFilter>()
+        for (arg in args) {
+            filterList.add(SFilter.eq(arg.first, arg.second))
+        }
+
+        return update(entity, projection, filterList)
+    } // Fun update()
+
+    /**
+     * 根据条件更新
+     *
+     * @param   entity      更新实体内容
+     * @param   projection  将被更新的字段列表(以逗号分隔),为空表示更新所有非空字段
+     * @param   args        更新条件
+     * @return  更新是否成功
+     */
+    open fun update(entity: ENTITY, projection: ArrayList<String>? = null, vararg args: SFilter): Boolean {
+        return update(entity, projection, args.toList())
+    } // Fun update()
+
+    /**
+     * 根据条件更新
+     *
+     * @param   entity      更新实体内容
+     * @param   projection  将被更新的字段列表(以逗号分隔),为空表示更新所有非空字段
+     * @param   query       更新条件
+     * @return  更新是否成功
+     */
+    open fun update(entity: ENTITY, projection: ArrayList<String>? = null, query: String): Boolean {
+        val parser = SSyntaxParser(ByteArrayInputStream(query.toByteArray()))
+        return update(entity, projection, parser.parserFilters())
+    } // Fun update()
+
+    /**
+     * 根据条件查询一条记录
+     *
+     * @param   args        查询条件
+     * @return  查询构造器
+     */
+    open fun select(vararg args: Pair<String, Any>): SQueryBuilder<ENTITY> {
+        val filterList = ArrayList<SFilter>()
+        for (arg in args) {     // 同时取列表元素与下标
+            filterList.add(SFilter.eq(arg.first, arg.second))
+        }
+
+        return select(filterList)
+    } // Fun select()
+
+    /**
+     * 根据条件查询记录
+     *
+     * @param   args        查询条件
+     * @return  查询构造器
+     */
+    open fun select(vararg args: SFilter): SQueryBuilder<ENTITY> {
+        return select(args.toList())
+    } // Fun select()
+
+    /**
+     * 根据条件查询记录
+     *
+     * @param   query        查询条件
+     * @return  查询构造器
+     */
+    open fun select(query: String?): SQueryBuilder<ENTITY> {
+        // 如果查询条件为空,则执行查询所有
+        if (query == null) {
+            return selectAll()
+        }
+
+        val queryParser = SSyntaxParser(ByteArrayInputStream(query.toByteArray()))
+        val filters  = queryParser.parserFilters()
+        return select(filters)
+    } // Fun select()
+
+    /**
+     * 获得表名
+     */
+    fun tableName(): String {
+        val clz = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<*>
+        if (clz.isAnnotationPresent(Table::class.java)) {
+            val anno = clz.getAnnotation(Table::class.java)
+            return anno!!.name
+        }
+
+        return clz.simpleName
+    } // Fun tableName()
+
+    /**
+     * 实体的field转换为Pair结构
+     *
+     * @param   entity      要转换的实体对象
+     * @param   field       实体对应的域
+     */
+    protected fun fieldToPair(entity: ENTITY, field: Field):  Pair<String, Any?> {
+        // 获得field对应的数据库表字段名
+        val anno = field.getAnnotation(Column::class.java)
+        return Pair<String, Any?>(anno.name, when (field.type.simpleName) {
+            "byte", "Byte" -> field.getByte(entity)
+            "double", "Double" -> field.getDouble(entity)
+            "float", "Float" -> field.getFloat(entity)
+            "int", "Integer", "Int" -> field.getInt(entity)
+            "long", "Long" -> field.getLong(entity)
+            "short", "Short" -> field.getShort(entity)
+            "Boolean" -> field.getBoolean(entity)
+            "String" ->  field.get(entity)
+            else ->{
+                if (entity == null){
+                    null
+                }else{
+                    if (field.get(entity) == null){
+                        null
+                    }else{
+                        field.get(entity).toJson()
+                    }
+                }
+            }
+        })
+    } // Fun fieldToPair()
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // 级联操作相关
+    /**
+     * 查询级联关系
+     *
+     * @param   table       表名
+     * @param   id1         对象表ID字段名
+     * @param   id2         级联对象ID字段名
+     * @param   self        自身级联
+     * @param   filter      附加过滤条件
+     * @param   idList      对象ID列表
+     * @return  关系列表
+     */
+    abstract fun relationQuery(table: String, id1: String, id2: String, self: Boolean, filter: String, idList: ArrayList<Any>): ArrayList<HashMap<String, Any>>
+} // Class SAbstractDao

+ 39 - 0
persagy-kotlin-database/src/main/kotlin/com/persagy/database/SAbstractDaoFactory.kt

@@ -0,0 +1,39 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database
+
+/**
+ * Dao工厂
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+abstract class SAbstractDaoFactory<ENTITY: Any> {
+    /**
+     * 创建DAO对象
+     *
+     * @param   entityClazz     实体类
+     * @return  实体类的数据访问对象
+     */
+    abstract fun createDao(entityClazz: Class<ENTITY>): SAbstractDao<ENTITY>
+} // Class SDaoFactory

+ 44 - 0
persagy-kotlin-database/src/main/kotlin/com/persagy/database/SAbstractFunction.kt

@@ -0,0 +1,44 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database
+
+import com.persagy.database.enums.SDatabaseType
+
+/**
+ * 函数支持
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+abstract class SAbstractFunction (val name: String, val args: ArrayList<Any>) {
+    /** 字段名 */
+    var colName = ""
+
+    /**
+     * 转换成对应的SQL语句
+     *
+     * @param   type        数据库类型
+     * @return  对应的SQL语句
+     */
+    abstract fun toSql(type: SDatabaseType): String
+} // Class SAbstractFunction

+ 321 - 0
persagy-kotlin-database/src/main/kotlin/com/persagy/database/SFilter.kt

@@ -0,0 +1,321 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database
+
+import com.persagy.database.enums.SOps
+
+/**
+ * 过滤条件
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+class SFilter private constructor(
+        /** 第一参数,保存属性名 */
+        var first: Any?,
+        /** 第一参数,保存值 */
+        var second: Any?,
+        /** 操作符 */
+        var opt: SOps = SOps.EQ) {
+    constructor(): this(null, null)
+
+    companion object {
+        /**
+         * 过滤条件:属性 == 值
+         *
+         * @param   property        属性名
+         * @param   value           值
+         * @return  过滤条件
+         */
+        fun eq(property: String, value: Any): SFilter {
+            return SFilter(property, value, SOps.EQ)
+        } // Fun eq()
+
+        /**
+         * 过滤条件:函数 == 值
+         *
+         * @param   func            函数对象
+         * @param   value           值
+         * @return  过滤条件
+         */
+        fun eq(func: SAbstractFunction, value: Any): SFilter {
+            return SFilter(func, value, SOps.EQ)
+        } // Fun eq()
+
+        /**
+         * 过滤条件:属性 != 值
+         *
+         * @param   property        属性名
+         * @param   value           值
+         * @return  过滤条件
+         */
+        fun ne(property: String, value: Any): SFilter {
+            return SFilter(property, value, SOps.NE)
+        } // Fun ne()
+
+        /**
+         * 过滤条件:函数 != 值
+         *
+         * @param   func            函数对象
+         * @param   value           值
+         * @return  过滤条件
+         */
+        fun ne(func: SAbstractFunction, value: Any): SFilter {
+            return SFilter(func, value, SOps.NE)
+        } // Fun ne()
+
+        /**
+         * 过滤条件:属性 > 值
+         *
+         * @param   property        属性名
+         * @param   value           值
+         * @return  过滤条件
+         */
+        fun gt(property: String, value: Any): SFilter {
+            return SFilter(property, value, SOps.GT)
+        } // Fun gt()
+
+        /**
+         * 过滤条件:函数 > 值
+         *
+         * @param   func            函数对象
+         * @param   value           值
+         * @return  过滤条件
+         */
+        fun gt(func: SAbstractFunction, value: Any): SFilter {
+            return SFilter(func, value, SOps.GT)
+        } // Fun gt()
+
+        /**
+         * 过滤条件:属性 >= 值
+         *
+         * @param   property        属性名
+         * @param   value           值
+         * @return  过滤条件
+         */
+        fun gte(property: String, value: Any): SFilter {
+            return SFilter(property, value, SOps.GTE)
+        } // Fun gte()
+
+        /**
+         * 过滤条件:函数 >= 值
+         *
+         * @param   func            函数对象
+         * @param   value           值
+         * @return  过滤条件
+         */
+        fun gte(func: SAbstractFunction, value: Any): SFilter {
+            return SFilter(func, value, SOps.GTE)
+        } // Fun gte()
+
+        /**
+         * 过滤条件:属性 < 值
+         *
+         * @param   property        属性名
+         * @param   value           值
+         * @return  过滤条件
+         */
+        fun lt(property: String, value: Any): SFilter {
+            return SFilter(property, value, SOps.LT)
+        } // Fun lt()
+
+        /**
+         * 过滤条件:函数 < 值
+         *
+         * @param   func            函数对象
+         * @param   value           值
+         * @return  过滤条件
+         */
+        fun lt(func: SAbstractFunction, value: Any): SFilter {
+            return SFilter(func, value, SOps.LT)
+        } // Fun lt()
+
+        /**
+         * 过滤条件:属性 <= 值
+         *
+         * @param   property        属性名
+         * @param   value           值
+         * @return  过滤条件
+         */
+        fun lte(property: String, value: Any): SFilter {
+            return SFilter(property, value, SOps.LTE)
+        } // Fun lte()
+
+        /**
+         * 过滤条件:函数 <= 值
+         *
+         * @param   func            函数对象
+         * @param   value           值
+         * @return  过滤条件
+         */
+        fun lte(func: SAbstractFunction, value: Any): SFilter {
+            return SFilter(func, value, SOps.LTE)
+        } // Fun lte()
+
+        /**
+         * 过滤条件:包含
+         *
+         * @param   property        属性名
+         * @param   value           被包含的值
+         * @return  过滤条件
+         */
+        fun contain(property: String, value: String): SFilter {
+            return SFilter(property, value, SOps.CONTAIN)
+        } // Fun contain()
+
+        /**
+         * 过滤条件:包含
+         *
+         * @param   func            函数对象
+         * @param   value           被包含的值
+         * @return  过滤条件
+         */
+        fun contain(func: SAbstractFunction, value: String): SFilter {
+            return SFilter(func, value, SOps.CONTAIN)
+        } // Fun contain()
+
+        /**
+         * 过滤条件:以指定字符串开始
+         *
+         * @param   property        属性名
+         * @param   value           指定字符串开始
+         * @return  过滤条件
+         */
+        fun startWith(property: String, value: String): SFilter {
+            return SFilter(property, value, SOps.STARTWITH)
+        } // Fun contain()
+
+        /**
+         * 过滤条件:以指定字符串开始
+         *
+         * @param   func            函数对象
+         * @param   value           指定字符串开始
+         * @return  过滤条件
+         */
+        fun startWith(func: SAbstractFunction, value: String): SFilter {
+            return SFilter(func, value, SOps.STARTWITH)
+        } // Fun contain()
+
+        /**
+         * 过滤条件:以指定字符串结尾
+         *
+         * @param   property        属性名
+         * @param   value           指定字符串开始
+         * @return  过滤条件
+         */
+        fun endWith(property: String, value: String): SFilter {
+            return SFilter(property, value, SOps.ENDWITH)
+        } // Fun endWith()
+
+        /**
+         * 过滤条件:以指定字符串结尾
+         *
+         * @param   func            函数对象
+         * @param   value           指定字符串开始
+         * @return  过滤条件
+         */
+        fun endWith(func: SAbstractFunction, value: String): SFilter {
+            return SFilter(func, value, SOps.ENDWITH)
+        } // Fun endWith()
+
+        /**
+         * 过滤条件:属性为空
+         *
+         * @param   property        属性名
+         * @return  过滤条件
+         */
+        fun isNull(property: String): SFilter {
+            return SFilter(property, null, SOps.ISNULL)
+        } // Fun isNull()
+
+        /**
+         * 过滤条件:属性为空
+         *
+         * @param   func            函数对象
+         * @return  过滤条件
+         */
+        fun isNull(func: SAbstractFunction): SFilter {
+            return SFilter(func, null, SOps.ISNULL)
+        } // Fun isNull()
+
+        /**
+         * 过滤条件:属性在值列表中
+         *
+         * @param   property        属性名
+         * @param   valueList       值列表
+         * @return  过滤条件
+         */
+        fun inList(property: String, valueList: List<Any>): SFilter {
+            return SFilter(property, valueList, SOps.IN)
+        } // Fun inList()
+
+        /**
+         * 过滤条件:属性在值列表中
+         *
+         * @param   func            函数对象
+         * @param   valueList       值列表
+         * @return  过滤条件
+         */
+        fun inList(func: SAbstractFunction, valueList: List<Any>): SFilter {
+            return SFilter(func, valueList, SOps.IN)
+        } // Fun inList()
+
+        /**
+         * 过滤条件:逻辑非
+         *
+         * @param   filter          属性名
+         * @return  过滤条件
+         */
+        fun not(filter: SFilter): SFilter {
+            return SFilter(filter, null, SOps.NOT)
+        } // Fun not()
+
+        /**
+         * 过滤条件:逻辑与
+         *
+         * @param   filterList      过滤条件列表
+         * @return  过滤条件
+         */
+        fun and(vararg filterList: SFilter): SFilter {
+            var filter = filterList[0]
+            for (i in 1 until filterList.size) {
+                filter = SFilter(filter, filterList[i], SOps.AND)
+            }
+            return filter
+        } // Fun not()
+
+        /**
+         * 过滤条件:逻辑或
+         *
+         * @param   filterList      过滤条件列表
+         * @return  过滤条件
+         */
+        fun or(vararg filterList: SFilter): SFilter {
+            var filter = filterList[0]
+            for (i in 1 until filterList.size) {
+                filter = SFilter(filter, filterList[i], SOps.OR)
+            }
+            return filter
+        } // Fun not()
+    } // companion object
+} // Class SFilter

+ 49 - 0
persagy-kotlin-database/src/main/kotlin/com/persagy/database/SGroup.kt

@@ -0,0 +1,49 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database
+
+/**
+ * 查询统计分组
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+class SGroup {
+    /** 分组属性名 */
+    var nameList = ArrayList<String>()
+
+    /** 统计个数 */
+    var count: Boolean? = null
+
+    /** 需计算最大数属性列表 */
+    var maxList = ArrayList<String>()
+
+    /** 需计算最小数属性列表 */
+    var minList = ArrayList<String>()
+
+    /** 需求和数属性列表 */
+    var sumList = ArrayList<String>()
+
+    /** 需计算平均值属性列表 */
+    var avgList = ArrayList<String>()
+} // class SGroup

+ 33 - 0
persagy-kotlin-database/src/main/kotlin/com/persagy/database/SOrder.kt

@@ -0,0 +1,33 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database
+
+import com.persagy.database.enums.SDirection
+
+/**
+ * 排序条件
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+class SOrder(val name: String, var direction: SDirection = SDirection.ASC)

+ 49 - 0
persagy-kotlin-database/src/main/kotlin/com/persagy/database/SPageQueryInfo.kt

@@ -0,0 +1,49 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database
+
+/**
+ * 分页查询信息
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+open class SPageQueryInfo<ENTITY: Any>(pageNumber: Int, pageSize: Int) {
+        /** 符合条件的总记录数 */
+    var total: Long? = null
+
+    /** 第几页(从 1 开始) */
+    var pageNumber: Int? = null
+
+    /** 每页记录数 */
+    var pageSize: Int? = null
+
+    /** 查询到的数据列表 */
+    var content: ArrayList<ENTITY>? = null
+
+    /** 初始化 */
+    init {
+        this.pageNumber = pageNumber
+        this.pageSize = pageSize
+    } // Init
+} // Class SPageQueryInfo

+ 376 - 0
persagy-kotlin-database/src/main/kotlin/com/persagy/database/SQueryBuilder.kt

@@ -0,0 +1,376 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database
+
+import com.persagy.base.exceptions.SFieldNotFoundException
+import com.persagy.base.extensions.getAllDeclaredField
+import com.persagy.base.opts.SFormat
+import com.persagy.database.enums.SDirection
+import com.persagy.database.parser.SSyntaxParser
+import java.io.ByteArrayInputStream
+import java.text.SimpleDateFormat
+import java.util.*
+import kotlin.collections.ArrayList
+
+/**
+ * 查询条件生成器
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+class SQueryBuilder<ENTITY: Any>(
+        private val baseDao: SAbstractDao<ENTITY>,
+        val filterList: ArrayList<SFilter>) {
+
+    init {
+        // 转换数据类型
+        for (item in filterList) {
+            convertType(baseDao.entityClass, item)
+        }
+    } // Init
+
+    /** 表名 */
+    var tableName: String? = null
+    /** 映射字段列表 */
+    var fieldList = ArrayList<String>()
+    /** 排序条件 */
+    var orderArgs = ArrayList<SOrder>()
+    /** 是否去除重复记录 */
+    var isDistinct = false
+    /** 偏移量 */
+    var offset = 0
+        set(value) {
+            field = value
+            if (field < 0) {
+                field = 0
+            }
+        }
+
+    /** 记录数 */
+    var count:Int? = null
+//        set(value) {
+//            field = value
+//            if (field < 1) {
+//                field = 1
+//            }
+//        }
+
+    /** 分组 */
+    var group = SGroup()
+
+    /**
+     * 执行查询
+     *
+     * @return  返回查询到的记录
+     */
+    fun exec(): ArrayList<ENTITY> {
+        return baseDao.execQuery(this)
+    } // Fun exec()
+
+    /**
+     * 统计查询个数
+     *
+     * @return  返回查询到的记录个数
+     */
+    fun execCount(): Long {
+        return baseDao.execCount(this)
+    } // Fun execCount()
+
+    /**
+     * 执行查询,并返回第一条记录
+     *
+     * @return  返回查询到的第一条记录
+     */
+    fun entity(): ENTITY? {
+        count = 1
+        val list = exec()
+        return if (list.size > 0) {
+            list[0]
+        } else {
+            null
+        }
+    } // Fun entity()
+
+    /**
+     * 执行分页查询
+     *
+     * @param   pageNumber      第几页
+     * @param   pageSize        每页记录数
+     * @return  分页找到的数据
+     */
+    fun pageQuery(pageNumber: Int, pageSize: Int): SPageQueryInfo<ENTITY> {
+        return baseDao.pageQuery(this, pageNumber, pageSize)
+    } // Fun pageQuery()
+
+    /**
+     * 数据库表
+     *
+     * @param   name    表名
+     * @return  查询构建器
+     */
+    fun table(name: String): SQueryBuilder<ENTITY> {
+        tableName = name
+        return this
+    } // Fun tableName
+
+    /**
+     * 字段映射
+     *
+     * @param   fields      字段列表
+     * @return  查询构建器
+     */
+    fun projection(fields: List<String>): SQueryBuilder<ENTITY> {
+        for (name in fields) {
+            fieldList.add(propertyName(name.trim()))
+        }
+        return this
+    } // Fun projection()
+
+    /**
+     * 字段映射
+     *
+     * @param   fields      字段列表
+     * @return  查询构建器
+     */
+    fun projection(fields: String): SQueryBuilder<ENTITY> {
+        return projection(fields.split(","))
+    } // Fun projection()
+
+    /**
+     * 添加过滤条件
+     *
+     * @param   filterList      过滤条件
+     * @return  查询构建器
+     */
+    fun filter(vararg filterList: SFilter): SQueryBuilder<ENTITY> {
+        for (item in filterList) {
+            convertType(baseDao.entityClass, item)
+            this.filterList.add(item)
+        }
+        return this
+    } // Fun filter()
+
+    /**
+     * 添加过滤条件
+     *
+     * @param   filterList      过滤条件
+     * @return  查询构建器
+     */
+    fun filter(vararg filterList: Pair<String, Any>): SQueryBuilder<ENTITY> {
+        for (item in filterList) {
+            val filter = SFilter.eq(item.first, item.second)
+            convertType(baseDao.entityClass, filter)
+            this.filterList.add(filter)
+        }
+        return this
+    } // Fun filter()
+
+    /**
+     * 添加排序条件
+     *
+     * @param   name    排序属性名
+     * @param   dir     排序方向
+     * @return  查询构建器
+     */
+    fun order(name: String, dir: SDirection): SQueryBuilder<ENTITY> {
+        orderArgs.add(SOrder(propertyName(name.trim()), dir))
+        return this
+    } // Fun order()
+
+    /**
+     * 添加排序条件
+     *
+     * @param   orderList   排序条件
+     * @return  查询构建器
+     */
+    fun order(vararg orderList: SOrder): SQueryBuilder<ENTITY> {
+        for (order in orderList) {
+            order(order.name, order.direction)
+        }
+        return this
+    } // Fun order()
+
+    /**
+     * 添加排序条件
+     *
+     * @param   orderStr    排序条件
+     * @return  查询构建器
+     */
+    fun order(orderStr: String): SQueryBuilder<ENTITY> {
+        val parser = SSyntaxParser(ByteArrayInputStream(orderStr.toByteArray()))
+        val orderList = parser.parserOrders()
+        order(*orderList.toTypedArray())
+        return this
+    } // Fun order()
+
+    /**
+     * 去除重复记录
+     *
+     * @return  查询构建器
+     */
+    fun distinct(): SQueryBuilder<ENTITY> {
+        isDistinct = true
+        return this
+    } // Fun distinct()
+
+    /**
+     * 限定取得的记录数
+     *
+     * @param   count   取得的记录数
+     * @return  查询构建器
+     */
+    fun limit(count: Int): SQueryBuilder<ENTITY> {
+        limit(0, count)
+        return this
+    } // Fun limit()
+
+    /**
+     * 限定从指定位置取得的记录数
+     *
+     * @param   offset  指定位置(默认从0开始)
+     * @param   count   取得的记录数
+     * @return  查询构建器
+     */
+    fun limit(offset: Int, count: Int): SQueryBuilder<ENTITY> {
+        this.offset = offset
+        this.count = count
+        return this
+    } // Fun limit()
+
+    /**
+     * 添加分组
+     *
+     * @param   nameList    名称列表
+     * @return  查询构建器
+     */
+    fun group(vararg nameList: String): SQueryBuilder<ENTITY> {
+        for (name in nameList) {
+            group.nameList.add(propertyName(name.trim()))
+        }
+        return this
+    } // Fun group()
+
+    /**
+     * 是否统计记录个数
+     */
+    fun count(value: Boolean): SQueryBuilder<ENTITY>{
+        group.count = value
+        return this
+    } // Fun count()
+    /**
+     * 统计最大数
+     *
+     * @param   nameList    统计的属性名称
+     * @return  查询构建器
+     */
+    fun max(vararg nameList: String): SQueryBuilder<ENTITY> {
+        for (name in nameList) {
+            group.maxList.add(propertyName(name.trim()))
+        }
+        return this
+    } // Fun max()
+
+
+    /**
+     * 统计最小数
+     *
+     * @param   nameList    统计的属性名称
+     * @return  查询构建器
+     */
+    fun min(vararg nameList: String): SQueryBuilder<ENTITY> {
+        for (name in nameList) {
+            group.minList.add(propertyName(name.trim()))
+        }
+        return this
+    } // Fun min()
+
+    /**
+     * 统计求和
+     *
+     * @param   nameList    统计的属性名称
+     * @return  查询构建器
+     */
+    fun sum(vararg nameList: String): SQueryBuilder<ENTITY> {
+        for (name in nameList) {
+            group.sumList.add(propertyName(name.trim()))
+        }
+        return this
+    } // Fun sum()
+
+    /**
+     * 统计求平均数
+     *
+     * @param   nameList    统计的属性名称
+     * @return  查询构建器
+     */
+    fun avg(vararg nameList: String): SQueryBuilder<ENTITY> {
+        for (name in nameList) {
+            group.avgList.add(propertyName(name.trim()))
+        }
+        return this
+    } // Fun avg()
+
+    /**
+     * 获得属性名
+     *
+     * @param   name    输入名称
+     * @return  属性名
+     */
+    private fun propertyName(name: String): String {
+        try {
+            val clz = baseDao.entityClass
+            return clz.getAllDeclaredField(name, ignoreCase = true, jsonProperty = true)?.name!!
+        } catch (e: Exception) {
+            e.printStackTrace()
+            throw SFieldNotFoundException(name)
+        }
+    } // Fun propertyName()
+
+    /**
+     * 转换数据类型
+     *
+     * @param   entityClass 实体类类型
+     * @param   filter      过滤条件
+     */
+    private fun convertType(entityClass: Class<*>, filter: SFilter) {
+        if (filter.first is SFilter) {
+            convertType(entityClass, filter.first as SFilter)
+        }
+        if (filter.second is SFilter) {
+            convertType(entityClass, filter.second as SFilter)
+        }
+
+        if (filter.first is String) {
+            val name = filter.first as String
+            if (name.indexOf(".") < 0) {
+                val field = entityClass.getAllDeclaredField(filter.first as String, ignoreCase = true, jsonProperty = true)
+                        ?: return
+                // 如果数据类型为日期型
+                if (Date::class.java.isAssignableFrom(field.type)) {
+                    val ft = SimpleDateFormat(SFormat.dateTime)
+                    filter.second = ft.parse(filter.second as String)
+                }
+            }
+        }
+    } // Fun convertType()
+} // Class SQueryBuilder

+ 36 - 0
persagy-kotlin-database/src/main/kotlin/com/persagy/database/enums/SDatabaseType.kt

@@ -0,0 +1,36 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database.enums
+
+/**
+ * 框架支持的数据库类型
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+enum class SDatabaseType {
+    MySQL,
+    Oracle,
+    PostgreSQL,
+    SQLServer
+} // Enum SDatabaseType

+ 36 - 0
persagy-kotlin-database/src/main/kotlin/com/persagy/database/enums/SDirection.kt

@@ -0,0 +1,36 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database.enums
+
+/**
+ * 排序方式
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+enum class SDirection {
+    /** 升级 */
+    ASC,
+    /**  降序 */
+    DESC
+} // Enum Order

+ 60 - 0
persagy-kotlin-database/src/main/kotlin/com/persagy/database/enums/SOps.kt

@@ -0,0 +1,60 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database.enums
+
+/**
+ * 过滤操作运算符
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+enum class SOps {
+    /** 等于 */
+    EQ,
+    /** 不等于 */
+    NE,
+    /** 大于 */
+    GT,
+    /** 大于等于 */
+    GTE,
+    /** 小于 */
+    LT,
+    /** 小于等于 */
+    LTE,
+    /** 包含 */
+    CONTAIN,
+    /** 开始 */
+    STARTWITH,
+    /** 结尾 */
+    ENDWITH,
+    /** 为空 */
+    ISNULL,
+    /** 包含在列表中 */
+    IN,
+    /** 逻辑非 */
+    NOT,
+    /** 逻辑与 */
+    AND,
+    /** 逻辑或 */
+    OR
+} // Enum Ops

+ 82 - 0
persagy-kotlin-database/src/main/kotlin/com/persagy/database/extensions/SAnyExtension.kt

@@ -0,0 +1,82 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database.extensions
+
+import com.persagy.base.extensions.getAllDeclaredFields
+import com.persagy.database.SFilter
+import javax.persistence.Id
+
+/**
+ * 取得主键字段值
+ *
+ * @return  Id字段值
+ */
+fun Any.keyValue(property: String = "id"): Any? {
+    /** 依次取id列表中的键值 */
+    javaClass.keyFieldList().forEach {
+        if (it.name == property) {
+            val accessible = it.isAccessible   //canAccess(this)
+            it.isAccessible = true
+            val id = it.get(this)
+            it.isAccessible = accessible
+            return id
+        }
+    }
+    return null
+} // Fun Serializable.keyValue()
+
+/**
+ * 取得主键与值的映射
+ *
+ * @return  主键映射。key为属性名
+ */
+fun Any.keyMap(): HashMap<String, Any> {
+    val map = HashMap<String, Any>()
+    val clz = this::class.java
+    for (field in clz.getAllDeclaredFields()) {
+        // val anno = field.getAnnotation(Column::class.java)
+        if (field.getAnnotation(Id::class.java) != null)
+        {
+            val accessible = field.isAccessible  //canAccess(this)
+            field.isAccessible = true
+            map[field.name] = field.get(this)
+            field.isAccessible = accessible
+        }
+    }
+
+    return map
+} // Fun Serializable.keyMap()
+
+/**
+ * 获得主键的过滤条件
+ *
+ * @return  主键的过滤条件
+ */
+fun Any.filterListByKeys(): ArrayList<SFilter> {
+    val filterList = ArrayList<SFilter>()
+    this.keyMap().forEach {
+        filterList.add(SFilter.eq(it.key, it.value))
+    }
+    return filterList
+} // Fun Serializable.filterListByKeys()

+ 63 - 0
persagy-kotlin-database/src/main/kotlin/com/persagy/database/extensions/SClassExtension.kt

@@ -0,0 +1,63 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database.extensions
+
+import com.persagy.base.extensions.getAllDeclaredFields
+import com.persagy.database.SFilter
+import java.lang.reflect.Field
+import javax.persistence.Column
+import javax.persistence.Id
+
+/**
+ * 取得主键列表
+ *
+ * @return  主键列表
+ */
+fun Class<*>.keyFieldList(): ArrayList<Field> {
+    val keyList = ArrayList<Field>()
+    for (field in this.getAllDeclaredFields()) {
+        if (field.getAnnotation(Id::class.java) != null )
+        {
+            keyList.add(field)
+        }
+    }
+    return keyList
+} // Fun Serializable.keyFieldList()
+
+/**
+ * 取得主键字段列表
+ *
+ * @return  主键字段列表
+ */
+fun Class<*>.keyColumnList(): ArrayList<String> {
+    val columnList = ArrayList<String>()
+    for (field in this.getAllDeclaredFields()) {
+        val anno = field.getAnnotation(Column::class.java)
+        if (field.getAnnotation(Id::class.java) != null && anno !=null)
+        {
+            columnList.add(anno.name)
+        }
+    }
+    return columnList
+} // Fun keyColumnList()

+ 44 - 0
persagy-kotlin-database/src/main/kotlin/com/persagy/database/functions/SLPad.kt

@@ -0,0 +1,44 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database.functions
+
+import com.persagy.database.SAbstractFunction
+import com.persagy.database.enums.SDatabaseType
+
+/**
+ * SQL:左填充字符串函数
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+class SLPad(name: String, len: Int, padString: String) : SAbstractFunction(name, arrayListOf(len, padString)) {
+    /**
+     * 转换成对应的SQL语句
+     *
+     * @param   type        数据库类型
+     * @return  对应的SQL语句
+     */
+    override fun toSql(type: SDatabaseType): String {
+        return "lpad($colName, ${args[0]}, '${args[1]}')"
+    } // Fun toSql()
+} // Class SLPad

+ 44 - 0
persagy-kotlin-database/src/main/kotlin/com/persagy/database/functions/SLeft.kt

@@ -0,0 +1,44 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database.functions
+
+import com.persagy.database.SAbstractFunction
+import com.persagy.database.enums.SDatabaseType
+
+/**
+ * SQL:左截取函数
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+class SLeft(name: String, len: Int) : SAbstractFunction(name, arrayListOf(len)) {
+    /**
+     * 转换成对应的SQL语句
+     *
+     * @param   type        数据库类型
+     * @return  对应的SQL语句
+     */
+    override fun toSql(type: SDatabaseType): String {
+        return "left($colName, ${args[0]})"
+    } // Fun toSql()
+} // Class SLeft

+ 44 - 0
persagy-kotlin-database/src/main/kotlin/com/persagy/database/functions/SLength.kt

@@ -0,0 +1,44 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database.functions
+
+import com.persagy.database.SAbstractFunction
+import com.persagy.database.enums.SDatabaseType
+
+/**
+ * SQL:取长度函数
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+class SLength(name: String) : SAbstractFunction(name, arrayListOf()) {
+    /**
+     * 转换成对应的SQL语句
+     *
+     * @param   type        数据库类型
+     * @return  对应的SQL语句
+     */
+    override fun toSql(type: SDatabaseType): String {
+        return "length($colName)"
+    } // Fun toSql()
+} // Class SLength

+ 44 - 0
persagy-kotlin-database/src/main/kotlin/com/persagy/database/functions/SLower.kt

@@ -0,0 +1,44 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database.functions
+
+import com.persagy.database.SAbstractFunction
+import com.persagy.database.enums.SDatabaseType
+
+/**
+ * SQL:字符串转换为小写
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+class SLower(name: String) : SAbstractFunction(name, arrayListOf()) {
+    /**
+     * 转换成对应的SQL语句
+     *
+     * @param   type        数据库类型
+     * @return  对应的SQL语句
+     */
+    override fun toSql(type: SDatabaseType): String {
+        return "lower($colName)"
+    } // Fun toSql()
+} // Class SLower

+ 48 - 0
persagy-kotlin-database/src/main/kotlin/com/persagy/database/functions/SMid.kt

@@ -0,0 +1,48 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database.functions
+
+import com.persagy.database.SAbstractFunction
+import com.persagy.database.enums.SDatabaseType
+
+/**
+ * SQL:从指定位置截取批暄长度字符串函数
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+class SMid(name: String, pos: Int, len: Int) : SAbstractFunction(name, arrayListOf(pos, len)) {
+    /**
+     * 转换成对应的SQL语句
+     *
+     * @param   type        数据库类型
+     * @return  对应的SQL语句
+     */
+    override fun toSql(type: SDatabaseType): String {
+        return if (args.size == 2) {
+            "substring($colName, ${args[0]}, ${args[1]})"
+        } else {
+            "substring($colName, ${args[0]})"
+        }
+    } // Fun toSql()
+} // Class SMid

+ 44 - 0
persagy-kotlin-database/src/main/kotlin/com/persagy/database/functions/SRPad.kt

@@ -0,0 +1,44 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database.functions
+
+import com.persagy.database.SAbstractFunction
+import com.persagy.database.enums.SDatabaseType
+
+/**
+ * SQL:右填充字符串函数
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+class SRPad(name: String, len: Int, padString: String) : SAbstractFunction(name, arrayListOf(len, padString)) {
+    /**
+     * 转换成对应的SQL语句
+     *
+     * @param   type        数据库类型
+     * @return  对应的SQL语句
+     */
+    override fun toSql(type: SDatabaseType): String {
+        return "rpad($colName, ${args[0]}, '${args[1]}')"
+    } // Fun toSql()
+} // Class SRPad

+ 44 - 0
persagy-kotlin-database/src/main/kotlin/com/persagy/database/functions/SRight.kt

@@ -0,0 +1,44 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database.functions
+
+import com.persagy.database.SAbstractFunction
+import com.persagy.database.enums.SDatabaseType
+
+/**
+ * SQL:右截取函数
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+class SRight(name: String, len: Int) : SAbstractFunction(name, arrayListOf(len)) {
+    /**
+     * 转换成对应的SQL语句
+     *
+     * @param   type        数据库类型
+     * @return  对应的SQL语句
+     */
+    override fun toSql(type: SDatabaseType): String {
+        return "right($colName, ${args[0]})"
+    } // Fun toSql()
+} // Class SRight

+ 48 - 0
persagy-kotlin-database/src/main/kotlin/com/persagy/database/functions/SSubstring.kt

@@ -0,0 +1,48 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database.functions
+
+import com.persagy.database.SAbstractFunction
+import com.persagy.database.enums.SDatabaseType
+
+/**
+ * SQL:从指定位置截取批暄长度字符串函数
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+class SSubstring(name: String, pos: Int, len: Int) : SAbstractFunction(name, arrayListOf(pos, len)) {
+    /**
+     * 转换成对应的SQL语句
+     *
+     * @param   type        数据库类型
+     * @return  对应的SQL语句
+     */
+    override fun toSql(type: SDatabaseType): String {
+        return if (args.size == 2) {
+            "substring($colName, ${args[0]}, ${args[1]})"
+        } else {
+            "substring($colName, ${args[0]})"
+        }
+    } // Fun toSql()
+} // Class SSubstring

+ 44 - 0
persagy-kotlin-database/src/main/kotlin/com/persagy/database/functions/SUpper.kt

@@ -0,0 +1,44 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database.functions
+
+import com.persagy.database.SAbstractFunction
+import com.persagy.database.enums.SDatabaseType
+
+/**
+ * SQL:字符串转换为大写
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+class SUpper(name: String) : SAbstractFunction(name, arrayListOf()) {
+    /**
+     * 转换成对应的SQL语句
+     *
+     * @param   type        数据库类型
+     * @return  对应的SQL语句
+     */
+    override fun toSql(type: SDatabaseType): String {
+        return "upper($colName)"
+    } // Fun toSql()
+} // Class SUpper

+ 33 - 0
persagy-kotlin-database/src/test/kotlin/com/sybotan/database/test/SQueryBuilderTest.kt

@@ -0,0 +1,33 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database.test
+
+/**
+ * SQL构造器-测试类
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+class SQueryBuilderTest {
+
+} // Class SQueryBuilderTest

+ 41 - 0
persagy-kotlin-database/src/test/kotlin/com/sybotan/database/test/TestMap.kt

@@ -0,0 +1,41 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database.test
+
+import org.testng.Assert
+import org.testng.annotations.Test
+
+class TestMap {
+    /**
+     * 测试枚举元素列表
+     */
+    @Test
+    fun enumItemTest() {
+        //Assert.assertEquals(SDirection.values().toJson(), "[\"ASC\",\"DESC\"]")
+        val abc: Any? = null//HashMap<String, Any?>()
+
+        println(abc is Map<*,*>)
+        return
+    } // Fun enumItemTest()
+}

+ 45 - 0
persagy-kotlin-database/src/test/kotlin/com/sybotan/database/test/enums/SDirectionTest.kt

@@ -0,0 +1,45 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database.test.enums
+
+import com.persagy.base.extensions.toJson
+import com.persagy.database.enums.SDirection
+import org.testng.Assert
+import org.testng.annotations.Test
+
+/**
+ * 排序方向枚举类-测试类
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+class SDirectionTest {
+    /**
+     * 测试枚举元素列表
+     */
+    @Test
+    fun enumItemTest() {
+        Assert.assertEquals(SDirection.values().toJson(), "[\"ASC\",\"DESC\"]")
+        return
+    } // Fun enumItemTest()
+} // Class SQueryBuilderTest

+ 45 - 0
persagy-kotlin-database/src/test/kotlin/com/sybotan/database/test/enums/SOpsTest.kt

@@ -0,0 +1,45 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database.test.enums
+
+import com.persagy.base.extensions.toJson
+import com.persagy.database.enums.SOps
+import org.testng.Assert
+import org.testng.annotations.Test
+
+/**
+ * 排序方向枚举类-测试类
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+class SOpsTest {
+    /**
+     * 测试枚举元素列表
+     */
+    @Test
+    fun enumItemTest() {
+        Assert.assertEquals(SOps.values().toJson(), "[\"EQ\",\"NE\",\"GT\",\"GTE\",\"LT\",\"LTE\",\"CONTAIN\",\"STARTWITH\",\"ENDWITH\",\"ISNULL\",\"IN\",\"NOT\",\"AND\",\"OR\"]")
+        return
+    } // Fun enumItemTest()
+} // Class SOpsTest

+ 124 - 0
persagy-kotlin-database/src/test/kotlin/com/sybotan/database/test/parser/SSyntaxParserTest.kt

@@ -0,0 +1,124 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.database.test.parser
+
+import org.testng.annotations.DataProvider
+import org.testng.annotations.Test
+
+/**
+ * 语法解析器-测试类
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+class SSyntaxParserTest {
+
+    /**
+     * 提供正确过滤条件测试数据
+     *
+     * @param   filter      过滤条件
+     * @param   result      预期结果
+     */
+    @DataProvider(name="filter")
+    fun goodFilterDataProvider(): Array<Array<String>> {
+        return arrayOf(
+                // 关系
+                arrayOf("id = 1", "[{\"first\":\"id\",\"second\":1,\"opt\":\"EQ\"}]"),
+                arrayOf("id = '2'", "[{\"first\":\"id\",\"second\":\"2\",\"opt\":\"EQ\"}]"),
+                arrayOf("id > '2'", "[{\"first\":\"id\",\"second\":\"2\",\"opt\":\"GT\"}]"),
+                arrayOf(" id >= '2' ", "[{\"first\":\"id\",\"second\":\"2\",\"opt\":\"GTE\"}]"),
+                arrayOf(" id < '2' ", "[{\"first\":\"id\",\"second\":\"2\",\"opt\":\"LT\"}]"),
+                arrayOf(" id <= '2' ", "[{\"first\":\"id\",\"second\":\"2\",\"opt\":\"LTE\"}]"),
+                arrayOf(" id != '2' ", "[{\"first\":\"id\",\"second\":\"2\",\"opt\":\"NE\"}]"),
+                // 包含
+                arrayOf(" id CONTAIN '2' ", "[{\"first\":\"id\",\"second\":\"2\",\"opt\":\"CONTAIN\"}]"),
+                arrayOf(" id contain '2' ", "[{\"first\":\"id\",\"second\":\"2\",\"opt\":\"CONTAIN\"}]"),
+                arrayOf(" id ContaiN '2' ", "[{\"first\":\"id\",\"second\":\"2\",\"opt\":\"CONTAIN\"}]"),
+                arrayOf(" id CoNTaIN '2' ", "[{\"first\":\"id\",\"second\":\"2\",\"opt\":\"CONTAIN\"}]"),
+                // 以XXX开始
+                arrayOf(" id STARTWITH '2' ", "[{\"first\":\"id\",\"second\":\"2\",\"opt\":\"STARTWITH\"}]"),
+                arrayOf(" id startwith '2' ", "[{\"first\":\"id\",\"second\":\"2\",\"opt\":\"STARTWITH\"}]"),
+                arrayOf(" id STarTWiTH '2' ", "[{\"first\":\"id\",\"second\":\"2\",\"opt\":\"STARTWITH\"}]"),
+                // 以XXX结束
+                arrayOf(" id ENDWITH '2' ", "[{\"first\":\"id\",\"second\":\"2\",\"opt\":\"ENDWITH\"}]"),
+                arrayOf(" id endwith '2' ", "[{\"first\":\"id\",\"second\":\"2\",\"opt\":\"ENDWITH\"}]"),
+                arrayOf(" id EndWiTH '2' ", "[{\"first\":\"id\",\"second\":\"2\",\"opt\":\"ENDWITH\"}]"),
+                // 为空
+                arrayOf(" id ISNULL ", "[{\"first\":\"id\",\"opt\":\"ISNULL\"}]"),
+                arrayOf(" id isnull ", "[{\"first\":\"id\",\"opt\":\"ISNULL\"}]"),
+                arrayOf(" id IsNull ", "[{\"first\":\"id\",\"opt\":\"ISNULL\"}]"),
+                // 不为空
+                arrayOf(" id NOTNULL ", "[{\"first\":\"id\",\"opt\":\"NOTNULL\"}]"),
+                arrayOf(" id notnull ", "[{\"first\":\"id\",\"opt\":\"NOTNULL\"}]"),
+                arrayOf(" id NotNULL ", "[{\"first\":\"id\",\"opt\":\"NOTNULL\"}]"),
+                // 数据类型
+                arrayOf(" used = true", "[{\"first\":\"used\",\"second\":true,\"opt\":\"EQ\"}]"),
+                arrayOf(" used != TRUE", "[{\"first\":\"used\",\"second\":true,\"opt\":\"NE\"}]"),
+                arrayOf(" used = TruE", "[{\"first\":\"used\",\"second\":true,\"opt\":\"EQ\"}]"),
+                arrayOf(" used = false", "[{\"first\":\"used\",\"second\":false,\"opt\":\"EQ\"}]"),
+                arrayOf(" used != FALSE", "[{\"first\":\"used\",\"second\":false,\"opt\":\"NE\"}]"),
+                arrayOf(" used = FaLse", "[{\"first\":\"used\",\"second\":false,\"opt\":\"EQ\"}]"),
+                arrayOf(" age = 18", "[{\"first\":\"age\",\"second\":18,\"opt\":\"EQ\"}]"),
+                arrayOf(" width = 18.15", "[{\"first\":\"width\",\"second\":18.15,\"opt\":\"EQ\"}]"),
+                // 括号表达式
+                arrayOf(" (  width = 18.15 )", "[{\"first\":\"width\",\"second\":18.15,\"opt\":\"EQ\"}]"),
+                // NOT
+                arrayOf(" not width = 18.15", "[{\"first\":{\"first\":\"width\",\"second\":18.15,\"opt\":\"EQ\"},\"opt\":\"NOT\"}]"),
+                arrayOf(" NOT width = 18.15", "[{\"first\":{\"first\":\"width\",\"second\":18.15,\"opt\":\"EQ\"},\"opt\":\"NOT\"}]"),
+                arrayOf(" Not width = 18.15", "[{\"first\":{\"first\":\"width\",\"second\":18.15,\"opt\":\"EQ\"},\"opt\":\"NOT\"}]"),
+                arrayOf(" !width = 18.15 ", "[{\"first\":{\"first\":\"width\",\"second\":18.15,\"opt\":\"EQ\"},\"opt\":\"NOT\"}]"),
+                arrayOf(" !(width = 18.15)", "[{\"first\":{\"first\":\"width\",\"second\":18.15,\"opt\":\"EQ\"},\"opt\":\"NOT\"}]"),
+                // OR
+                arrayOf(" (id = '1') or (width>=2)", "[{\"first\":{\"first\":\"id\",\"second\":\"1\",\"opt\":\"EQ\"},\"second\":{\"first\":\"width\",\"second\":2,\"opt\":\"GTE\"},\"opt\":\"OR\"}]"),
+                arrayOf(" (id = '1') OR (width>=2)", "[{\"first\":{\"first\":\"id\",\"second\":\"1\",\"opt\":\"EQ\"},\"second\":{\"first\":\"width\",\"second\":2,\"opt\":\"GTE\"},\"opt\":\"OR\"}]"),
+                arrayOf(" (id = '1') || (width>=2)", "[{\"first\":{\"first\":\"id\",\"second\":\"1\",\"opt\":\"EQ\"},\"second\":{\"first\":\"width\",\"second\":2,\"opt\":\"GTE\"},\"opt\":\"OR\"}]"),
+                arrayOf(" (id = '1') or (width>=2) || height > 3", "[{\"first\":{\"first\":{\"first\":\"id\",\"second\":\"1\",\"opt\":\"EQ\"},\"second\":{\"first\":\"width\",\"second\":2,\"opt\":\"GTE\"},\"opt\":\"OR\"},\"second\":{\"first\":\"height\",\"second\":3,\"opt\":\"GT\"},\"opt\":\"OR\"}]"),
+                // AND
+                arrayOf(" (id = '1') and (width>=2)", "[{\"first\":{\"first\":\"id\",\"second\":\"1\",\"opt\":\"EQ\"},\"second\":{\"first\":\"width\",\"second\":2,\"opt\":\"GTE\"},\"opt\":\"AND\"}]"),
+                arrayOf(" (id = '1') AND (width>=2)", "[{\"first\":{\"first\":\"id\",\"second\":\"1\",\"opt\":\"EQ\"},\"second\":{\"first\":\"width\",\"second\":2,\"opt\":\"GTE\"},\"opt\":\"AND\"}]"),
+                arrayOf(" (id = '1') && (width>=2)", "[{\"first\":{\"first\":\"id\",\"second\":\"1\",\"opt\":\"EQ\"},\"second\":{\"first\":\"width\",\"second\":2,\"opt\":\"GTE\"},\"opt\":\"AND\"}]"),
+                arrayOf(" (id = '1') anD (width>=2) && height > 3", "[{\"first\":{\"first\":{\"first\":\"id\",\"second\":\"1\",\"opt\":\"EQ\"},\"second\":{\"first\":\"width\",\"second\":2,\"opt\":\"GTE\"},\"opt\":\"AND\"},\"second\":{\"first\":\"height\",\"second\":3,\"opt\":\"GT\"},\"opt\":\"AND\"}]"),
+                // 逻辑混合
+                arrayOf(" (id = '1') and (width>=2) || height > 3", "[{\"first\":{\"first\":{\"first\":\"id\",\"second\":\"1\",\"opt\":\"EQ\"},\"second\":{\"first\":\"width\",\"second\":2,\"opt\":\"GTE\"},\"opt\":\"AND\"},\"second\":{\"first\":\"height\",\"second\":3,\"opt\":\"GT\"},\"opt\":\"OR\"}]"),
+                arrayOf(" (id = '1') || (width>=2) && height > 3", "[{\"first\":{\"first\":\"id\",\"second\":\"1\",\"opt\":\"EQ\"},\"second\":{\"first\":{\"first\":\"width\",\"second\":2,\"opt\":\"GTE\"},\"second\":{\"first\":\"height\",\"second\":3,\"opt\":\"GT\"},\"opt\":\"AND\"},\"opt\":\"OR\"}]"),
+                arrayOf(" (id = '1') and (width>=2 || height > 3)", "[{\"first\":{\"first\":\"id\",\"second\":\"1\",\"opt\":\"EQ\"},\"second\":{\"first\":{\"first\":\"width\",\"second\":2,\"opt\":\"GTE\"},\"second\":{\"first\":\"height\",\"second\":3,\"opt\":\"GT\"},\"opt\":\"OR\"},\"opt\":\"AND\"}]"),
+                // 条件列表
+                arrayOf(" width <= 18.15; age>18; name='abc'", "[{\"first\":\"width\",\"second\":18.15,\"opt\":\"LTE\"},{\"first\":\"age\",\"second\":18,\"opt\":\"GT\"},{\"first\":\"name\",\"second\":\"abc\",\"opt\":\"EQ\"}]")
+        )
+    } // Fun goodFilterDataProvider()
+
+    /**
+     * 正确过滤条件测试
+     *
+     * @param   filter      过滤条件
+     * @param   expected    预期结果
+     */
+    @Test(dataProvider="filter")
+    fun goodFilterTest(filter: String, expected: String) {
+//        val queryParser = SSyntaxParser(ByteArrayInputStream(filter.toByteArray()))
+//        val filters  = queryParser.parserFilters()
+//        Assert.assertEquals(filters.toJson(), expected)
+        return
+    } // Fun goodFilterTest()
+
+} // Class SSyntaxParserTest

+ 131 - 0
persagy-kotlin-mybatis/build.gradle

@@ -0,0 +1,131 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+group rootProject.group
+version rootProject.version
+
+apply plugin: "kotlin"
+apply plugin: "org.jetbrains.dokka"
+apply plugin: "maven"
+apply plugin: 'ca.coglinc.javacc'
+
+sourceCompatibility = JVM_TARGET
+
+compileKotlin {
+    kotlinOptions.jvmTarget = JVM_TARGET
+}
+compileTestKotlin {
+    kotlinOptions.jvmTarget = JVM_TARGET
+}
+
+compileJavacc {
+    inputDirectory = file("src/main/javacc")
+    outputDirectory = file("src/main/kotlin/com/sybotan/database/parser")
+}
+
+dependencies {
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // kotlin 依赖
+    compile group: "org.jetbrains.kotlin", name: "kotlin-stdlib-jdk8", version: KOTLIN_VERSION
+    compile group: "org.jetbrains.kotlin", name: "kotlin-reflect", version: KOTLIN_VERSION
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // alibaba数据库连接池
+    // https://mvnrepository.com/artifact/com.alibaba/druid
+    compile group: 'com.alibaba', name: 'druid', version: DRUID_VERSION
+    // https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-starter
+    compile group: "com.alibaba", name: "druid-spring-boot-starter", version: DRUID_VERSION
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // MyBatis支持
+    // https://mvnrepository.com/artifact/org.mybatis/mybatis
+    compile group: 'org.mybatis', name: 'mybatis', version: '3.5.0'
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // Sybotan依赖
+    implementation project(':persagy-kotlin-base')
+    implementation project(':persagy-kotlin-database')
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// 文档生成
+dokka {
+    jdkVersion = JDK_VERSION
+    outputFormat = "javadoc"
+    outputDirectory = "$buildDir/javadoc"
+    //sourceDirs = files("src/main/kotlin")
+}
+
+// 上成上传的文档jar包
+task javadocJar(type: Jar, dependsOn: dokka) {
+    classifier = "javadoc"
+    from dokka.outputDirectory
+}
+
+// 上成上传的文档jar包
+task sourcesJar(type: Jar) {
+    classifier = 'sources'
+    from sourceSets.main.allSource
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// maven 仓库管理
+
+// 设置上传的包,默认上传aar与pom
+artifacts {
+    // archives javadocJar
+    // archives sourcesJar
+}
+
+uploadArchives {
+    repositories {
+        mavenDeployer {
+            pom.groupId = project.group
+            pom.version = project.version
+            pom.artifactId = project.name
+            pom.project {
+                name project.name
+                packaging "jar"
+                url PERSAGY_URL
+                description "斯伯坦机器人 Kotlin 数据库操作支持库。"
+                licenses {
+                    license {
+                        name LICENSE_NAME
+                        url LICENSE_URL
+                    }
+                }
+                developers {
+                    developer {
+                        id DEVELOPER_ID
+                        name DEVELOPER_NAME
+                    }
+                }
+            }
+            snapshotRepository(url: MAVEN_REPO_SNAPSHOT_URL) {
+                authentication(userName: NEXUS_USERNAME, password: NEXUS_PASSWORD)
+            }
+            repository(url: MAVEN_REPO_RELEASE_URL) {
+                authentication(userName: NEXUS_USERNAME, password: NEXUS_PASSWORD)
+            }
+        }
+    }
+}

+ 136 - 0
persagy-kotlin-mybatis/src/main/kotlin/com/persagy/mybatis/IBaseMapper.kt

@@ -0,0 +1,136 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.mybatis
+
+import com.persagy.database.SFilter
+import com.persagy.database.SGroup
+import com.persagy.database.SQueryBuilder
+import org.apache.ibatis.annotations.*
+
+/**
+ * 基础数据库操作影射器
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+interface IBaseMapper<ENTITY: Any> {
+    /**
+     * 根据条件删除
+     *
+     * @param   filterArgs      过滤条件
+     * @param   whereArgs       whereArgs参数值,由SQlProvider填充
+     */
+    @DeleteProvider(type = SSqlProvider::class, method = "delete")
+    fun delete(@Param("entityClass")entityClass: Class<*>,
+               @Param("filterArgs")filterArgs: List<SFilter>,
+               @Param("whereArgs")whereArgs: Map<String, Any>): Boolean
+
+    /**
+     * 删除所有记录
+     */
+    @DeleteProvider(type = SSqlProvider::class, method = "deleteAll")
+    fun deleteAll(@Param("entityClass")entityClass: Class<*>): Boolean
+
+    /**
+     * 在数据库中插入实体
+     *
+     * @param   entity      插入数据库的实体
+     * @return  插入是否成功
+     */
+    @InsertProvider(type = SSqlProvider::class, method = "insert")
+    @Options(useGeneratedKeys = true, keyProperty = "entity._id")
+    fun insert(@Param("entityClass")entityClass: Class<*>,
+               @Param("entity")entity: Map<String, Any?>): Boolean
+
+    /**
+     * 在数据库中插入实体
+     *
+     * @param   entity      插入数据库的实体
+     * @return  插入是否成功
+     */
+    @InsertProvider(type = SSqlProvider::class, method = "replace")
+    fun replace(@Param("entityClass")entityClass: Class<*>,
+                @Param("entity")entity: Map<String, Any?>,
+                @Param("keyColumnList")keyColumnList: ArrayList<String>): Boolean
+
+    /**
+     * 根据条件更新
+     *
+     * @param   entity          更新值
+     * @param   projection      字段映射
+     * @param   filterArgs      过滤条件
+     * @param   whereArgs       whereArgs参数值,由SQlProvider填充
+     */
+    @UpdateProvider(type = SSqlProvider::class, method = "update")
+    fun update(@Param("entityClass")entityClass: Class<*>,
+               @Param("entity")entity: Map<String, Any?>,
+               @Param("projection")projection: ArrayList<String>?,
+               @Param("filterArgs")filterArgs: List<SFilter>?,
+               @Param("whereArgs")whereArgs: Map<String, Any>): Boolean
+
+    /**
+     * 执行查询操作
+     *
+     * @param   builder         查询查询构造器
+     * @param   whereArgs       whereArgs参数值,由SQlProvider填充
+     * @return  查询到的记录
+     */
+    @SelectProvider(type = SSqlProvider::class, method = "execQuery")
+    fun execQuery(@Param("entityClass")entityClass: Class<*>,
+                  @Param("builder")builder: SQueryBuilder<ENTITY>,
+                  @Param("whereArgs")whereArgs: Map<String, Any>): ArrayList<Map<String, Any?>>
+
+    /**
+     * 执行查询操作
+     *
+     * @param   builder         查询查询构造器
+     * @param   whereArgs       whereArgs参数值,由SQlProvider填充
+     * @return  查询到的记录
+     */
+    @SelectProvider(type = SSqlProvider::class, method = "execCount")
+    fun execCount(@Param("entityClass")entityClass: Class<*>,
+                  @Param("builder")builder: SQueryBuilder<ENTITY>,
+                  @Param("whereArgs")whereArgs: Map<String, Any>): ArrayList<Long>
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // 级联操作相关
+    /**
+     * 查询级联关系
+     *
+     * @param   table       表名
+     * @param   id1         对象表ID字段名
+     * @param   id2         级联对象ID字段名
+     * @param   self        自身级联
+     * @param   filter      附加过滤条件
+     * @param   idList      对象ID列表
+     * @return  关系列表
+     */
+    @SelectProvider(type = SSqlProvider::class, method = "relationQuery")
+    fun relationQuery(@Param("table")table: String,
+                      @Param("id1")id1: String,
+                      @Param("id2")id2: String,
+                      @Param("self")self: Boolean,
+                      @Param("filter")filter: String,
+                      @Param("idList")idList: ArrayList<Any>,
+                      @Param("whereArgs")whereArgs: Map<String, Any>): ArrayList<HashMap<String, Any>>
+} // Interface IBaseMapper

+ 34 - 0
persagy-kotlin-mybatis/src/main/kotlin/com/persagy/mybatis/IMybatisMapper.kt

@@ -0,0 +1,34 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.mybatis
+
+import org.apache.ibatis.annotations.Mapper
+
+/**
+ * 默认数据库操作影射器
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+@Mapper
+interface IMybatisMapper : IBaseMapper<HashMap<String, Any?>>

+ 625 - 0
persagy-kotlin-mybatis/src/main/kotlin/com/persagy/mybatis/SAbstractDriver.kt

@@ -0,0 +1,625 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.mybatis
+
+import com.persagy.base.extensions.getAllDeclaredFields
+import com.persagy.database.SAbstractDao
+import com.persagy.database.SAbstractFunction
+import com.persagy.database.SFilter
+import com.persagy.database.SQueryBuilder
+import com.persagy.database.enums.SOps
+import org.apache.ibatis.jdbc.SQL
+import org.slf4j.LoggerFactory
+import javax.persistence.Column
+
+/**
+ * 数据库驱动
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+abstract class SAbstractDriver {
+    /** 静态对象 */
+    companion object {
+        /** 日志记录器 */
+        private val logger = LoggerFactory.getLogger(SAbstractDriver::class.java)
+    }
+
+    /**
+     * 在数据库中插入实体
+     *
+     * @param   argsMap         注入参数
+     * @return  插入SQL语句
+     */
+    abstract fun insert(argsMap: Map<String, Any?>): String
+
+    /**
+     * 在数据库中替换实体
+     *
+     * @param   argsMap         注入参数
+     * @param   insertSql       插入SQL语句
+     * @return  替换SQL语句
+     */
+    abstract fun replace(argsMap: Map<String, Any?>, insertSql: String): String
+
+    /**
+     * 根据条件删除
+     *
+     * @param   argsMap         注入参数
+     * @return  删除SQL语句
+     */
+    abstract fun delete(argsMap: Map<String, Any?>): String
+
+    /**
+     * 删除所有记录
+     *
+     * @return  删除SQL语句
+     */
+    abstract fun deleteAll(argsMap: Map<String, Any?>): String
+
+    /**
+     * 根据条件更新
+     *
+     * @param   argsMap         注入参数
+     * @return  更新SQL语句
+     */
+    @Suppress("UNCHECKED_CAST")
+    open fun update(argsMap: Map<String, Any?>): String {
+        val entityClass = argsMap["entityClass"] as Class<*>
+        val entity = argsMap["entity"] as HashMap<String, Any?>
+        val filterArgs = argsMap["filterArgs"] as List<SFilter>
+        val whereArgs = argsMap["whereArgs"] as HashMap<String, Any>
+        val fieldList = ArrayList<String>()
+
+        if (argsMap.containsKey("projection")) {
+            val fields = argsMap["projection"] as ArrayList<String>?
+            // 转换属性名
+            fields?.forEach {
+                try {
+                    val colName = SAbstractDao.columnName(entityClass, it.trim())
+                    fieldList.add(colName)
+                } catch (e: Exception) {
+                    e.printStackTrace()
+                }
+            }
+        }
+
+        val updateNull = fieldList.size > 0
+        val clause = buildWhereArgList(entityClass, filterArgs, whereArgs)
+
+        val sql = object: SQL() {
+            init {
+                UPDATE(SSqlProvider.driver.tableName(entityClass))
+
+                for ((key, value) in entity) {
+                    if (fieldList.size > 0 && !fieldList.contains(key)) {
+                        continue
+                    }
+                    if (value == null && updateNull) {
+                        // PostgreSQL使用参数更新,为空更新不成功。必须使用sql直接设置
+                        SET("${SSqlProvider.driver.escName(key)} = null")
+                    }
+                    if (value != null) {
+                        if (value is Map<*,*>) {
+                            SET("${SSqlProvider.driver.escName(key)} = ${SSqlProvider.driver.updateJson(key, value)}")
+                        } else {
+                            SET("${SSqlProvider.driver.escName(key)} = ${SSqlProvider.driver.entityValue(entity, key)}")
+                        }
+//                        if (value::class.java.isPrimitive) {
+//                            SET("${driver.keyEsc}$key${driver.keyEsc} = ${driver.entityValue(entity, key)}")
+//                        } else {
+//                            SET("${driver.keyEsc}$key${driver.keyEsc} = ${driver.updateJson(key, value)}")
+//                        }
+                    }
+                }
+                if (clause.isNotEmpty()) {
+                    WHERE(clause)
+                }
+            }
+        }.toString()
+
+        logger.debug("SQL= $sql")
+
+        return sql
+    } // Fun update()
+
+    /**
+     * 执行查询操作
+     *
+     * @param   argsMap         注入参数
+     * @return  查询SQL语句
+     */
+    @Suppress("UNCHECKED_CAST")
+    fun execQuery(argsMap: Map<String, Any?>): String {
+        val entityClass = argsMap["entityClass"] as Class<*>
+        val builder = argsMap["builder"] as SQueryBuilder<*>
+        val whereArgs = argsMap["whereArgs"] as HashMap<String, Any>
+
+        val clause = buildWhereArgList(entityClass, builder.filterList, whereArgs)
+
+        var sql = object: SQL() {
+            init {
+                // 如果选择去重
+                if (builder.isDistinct) {
+                    SELECT_DISTINCT(buildColumns(entityClass, builder.fieldList))
+                } else {
+                    SELECT(buildColumns(entityClass, builder.fieldList))
+                }
+
+                // 如果查询构建器朱指定了表名
+                if (builder.tableName.isNullOrEmpty()) {
+                    FROM(SSqlProvider.driver.tableName(entityClass))
+                } else {
+                    FROM(builder.tableName!!)
+                }
+
+                // 过滤条件
+                if (clause.isNotEmpty()) {
+                    WHERE(clause)
+                }
+
+                // 排序条件
+                for (col in builder.orderArgs) {
+                    var path: String? = null
+                    var propertyName = col.name
+                    val pos = propertyName.indexOf(".")
+                    if (pos > 0) {
+                        path = propertyName.substring(pos + 1)
+                        propertyName = propertyName.substring(0, pos)
+                    }
+                    val colName = SAbstractDao.columnName(entityClass, SAbstractDao.propertyName(entityClass, propertyName))
+
+                    ORDER_BY("${SSqlProvider.driver.columnName(colName, path)} ${col.direction}")
+                }
+
+                // 分组
+                if (!builder.group.nameList.isNullOrEmpty()) {
+                    for (name in builder.group.nameList) {
+                        val colName = SAbstractDao.columnName(entityClass, name)
+                        GROUP_BY(SSqlProvider.driver.escName(colName))
+                    }
+
+                    if (builder.group.count !=null && builder.group.count!!) {
+                        SELECT("count(1) as _statistics_count")
+                    }
+
+                    if (!builder.group.sumList.isNullOrEmpty()) {
+                        for (name in builder.group.sumList) {
+                            val colName = SAbstractDao.columnName(entityClass, SAbstractDao.propertyName(entityClass, name))
+                            SELECT("sum(${SSqlProvider.driver.columnName(colName, null)}) as _statistics_sum_$name")
+                        }
+                    }
+
+                    if (!builder.group.avgList.isNullOrEmpty()) {
+                        for (name in builder.group.sumList) {
+                            val colName = SAbstractDao.columnName(entityClass, SAbstractDao.propertyName(entityClass, name))
+                            SELECT("avg(${SSqlProvider.driver.columnName(colName, null)}) as _statistics_avg_$name")
+                        }
+                    }
+
+                    if (!builder.group.maxList.isNullOrEmpty()) {
+                        for (name in builder.group.sumList) {
+                            val colName = SAbstractDao.columnName(entityClass, SAbstractDao.propertyName(entityClass, name))
+                            SELECT("max(${SSqlProvider.driver.columnName(colName, null)}) as _statistics_max_$name")
+                        }
+                    }
+
+                    if (!builder.group.minList.isNullOrEmpty()) {
+                        for (name in builder.group.sumList) {
+                            val colName = SAbstractDao.columnName(entityClass, SAbstractDao.propertyName(entityClass, name))
+                            SELECT("min(${SSqlProvider.driver.columnName(colName, null)}) as _statistics_min_$name")
+                        }
+                    }
+                }
+            }
+        }.toString()
+
+        if (builder.count != null) {
+            sql += SSqlProvider.driver.limit(builder.offset, builder.count)
+        }
+
+        logger.debug("SQL= $sql")
+        return sql
+    } // Fun execQuery()
+
+    /**
+     * 执行查询操作
+     *
+     * @param   argsMap         注入参数
+     * @return  查询SQL语句
+     */
+    @Suppress("UNCHECKED_CAST")
+    fun execCount(argsMap: Map<String, Any?>): String {
+        val entityClass = argsMap["entityClass"] as Class<*>
+        val builder = argsMap["builder"] as SQueryBuilder<*>
+        val whereArgs = argsMap["whereArgs"] as HashMap<String, Any>
+
+        val clause = buildWhereArgList(entityClass, builder.filterList, whereArgs)
+
+        val sql = object: SQL() {
+            init {
+                SELECT("count(1) AS total")
+
+                // 如果查询构建器指定了表名
+                if (builder.tableName.isNullOrEmpty()) {
+                    FROM(SSqlProvider.driver.tableName(entityClass))
+                } else {
+                    FROM(builder.tableName!!)
+                }
+
+                // 过滤条件
+                if (clause.isNotEmpty()) {
+                    WHERE(clause)
+                }
+
+                // 分组
+                if (!builder.group.nameList.isNullOrEmpty()) {
+                    for (name in builder.group.nameList) {
+                        val colName = SAbstractDao.columnName(entityClass, name)
+                        GROUP_BY(SSqlProvider.driver.escName(colName))
+                    }
+                }
+            }
+        }.toString()
+        logger.debug("SQL= $sql")
+        return sql
+    } // Fun execQuery()
+
+    /**
+     * 获得表名,取实体类@Table注解的名称,如果没有注解,则取实体类类名。
+     *
+     * @param   clz         mapper类类型
+     * @return  表名
+     */
+    abstract fun tableName(clz: Class<*>): String
+
+    /**
+     * 将 name 加上引用符号
+     *
+     * @param   name        名称
+     * @return  加上引用符号的名称
+     */
+    abstract fun escName(name: String): String
+
+    /**
+     * 实体类的值,如果不是基本类型,则转换为json
+     *
+     * @param   entity      实体类
+     * @param   name        名称
+     * @return  加上引用符号的名称
+     */
+    abstract fun entityValue(entity: HashMap<String, Any?>, name: String): String
+
+    /**
+     * 生成limit语句
+     *
+     * @param   offset      偏移位置
+     * @param   count       取得的记录数
+     * @return  LIMIT子句
+     */
+    abstract fun limit(offset: Int?, count: Int?): String
+
+//    /**
+//     * 删除所有记录
+//     *
+//     * @return  删除SQL语句
+//     */
+//    abstract fun deleteAll(argsMap: Map<String, Any?>): String
+//
+//    /**
+//     * 在数据库中插入实体
+//     *
+//     * @param   argsMap         注入参数
+//     * @return  插入SQL语句
+//     */
+//    abstract fun insert(argsMap: Map<String, Any?>): String
+//
+//    /**
+//     * 在数据库中插入实体
+//     *
+//     * @param   argsMap         注入参数
+//     * @return  插入SQL语句
+//     */
+//    abstract fun replace(argsMap: Map<String, Any?>): String
+//
+//    /**
+//     * 根据条件更新
+//     *
+//     * @param   argsMap         注入参数
+//     * @return  更新SQL语句
+//     */
+//    abstract fun update(argsMap: Map<String, Any?>): String
+//
+//    /**
+//     * 执行查询操作
+//     *
+//     * @param   argsMap         注入参数
+//     * @return  查询SQL语句
+//     */
+//    abstract fun execQuery(argsMap: Map<String, Any?>): String
+//
+//    /**
+//     * 执行查询操作
+//     *
+//     * @param   argsMap         注入参数
+//     * @return  查询SQL语句
+//     */
+//    abstract fun execCount(argsMap: Map<String, Any?>): String
+//
+//    /**
+//     * 查询级联关系
+//     *
+//     * @param   argsMap         注入参数
+//     * @return  查询SQL语句
+//     */
+//    abstract fun relationQuery(argsMap: Map<String, Any?>): String
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    //
+    /**
+     * 转换where字句参数
+     *
+     * @param   argName     参数名
+     * @param   argValue    参数值
+     * @param   ops         运算符
+     * @return  转换后的SQL
+     */
+    abstract fun whereArg(argName: String, argValue: String, ops: SOps): String
+
+
+    /**
+     * 转换参数名SQL语句
+     *
+     * @param   name        字段名
+     * @param   path        json路径。如果不是json对象,则该值为空
+     * @return  转换后的SQL
+     */
+    abstract fun argName(name: String, path: String?): String
+
+    /**
+     * 转换参数值SQL语句
+     *
+     * @param   argName     参数名
+     * @param   isJson      是否Json对象
+     * @return  转换后的SQL
+     */
+    abstract fun argValue(argName: String, isJson: Boolean): String
+
+    /**
+     * 转换IN条件表达式
+     *
+     * @param   name        字段名
+     * @param   path        json路径,如果字段不为json,则path为null
+     * @param   inArg       in操作参数
+     * @return  转换后的SQL
+     */
+    abstract fun inArg(name: String, path: String?, inArg: String): String
+
+    /**
+     * 将名称及json路径转换为SQL
+     *
+     * @param   name        字段名
+     * @param   path        json路径,如果字段不为json,则path为null
+     * @return   转换后的SQL
+     */
+    abstract fun columnName(name: String, path: String?): String
+
+    /**
+     * 将参数值转换为SQL语句
+     *
+     * @param   value       值
+     * @param   isJson      值是否转换为json格式
+     * @return  转换后的SQL
+     */
+    abstract fun argValueToJson(value: String, isJson: Boolean): String
+
+    /**
+     * 更新Json类型字段
+     *
+     * @param   name        字段名
+     * @param   value       值
+     * @return  更新SQL字符串
+     */
+    abstract fun updateJson(name: String, value: Any): String
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // 函数
+    /**
+     * 处理函数支持
+     *
+     * @param   func        函数对象
+     * @param   colName     字段名
+     * @return  生成的SQL语句
+     */
+    abstract fun processFunction(func: SAbstractFunction, colName: String): String;
+
+    /**
+     * 构造where子句参数
+     *
+     * @param   filterList      过滤条件
+     * @param   values          子句参数列表
+     * @return  返回where子句
+     */
+    protected fun buildWhereArgList(clazz: Class<*>, filterList: List<SFilter>, values: HashMap<String, Any>): String {
+        val builder = StringBuilder()
+
+        for (filter in filterList) {
+            val where = buildWhereArg(clazz, filter, values)
+            if (builder.isNotEmpty()) {
+                builder.append(" AND ")
+            }
+            builder.append(where)
+        }
+
+        val sql = builder.toString()
+        logger.debug("buildWhereArgList = $sql")
+        return sql
+    } // Fun buildWhereArgList()
+
+    /**
+     * 构造where子句参数
+     *
+     * @param   clazz           对应的实体类类型
+     * @param   filter          过滤条件
+     * @param   values          子句参数列表
+     * @return  返回where子句
+     */
+    protected fun buildWhereArg(clazz: Class<*>, filter: SFilter, values: HashMap<String, Any>): String {
+        val builder = StringBuilder()
+        val argName = "arg${values.size}"
+        when (filter.opt) {
+            SOps.EQ,            // 等于
+            SOps.NE,            // 不等于
+            SOps.GT,            // 大于
+            SOps.GTE,           // 大于等于
+            SOps.LT,            // 小于
+            SOps.LTE,           // 小于等于
+            SOps.CONTAIN,       // 包含
+            SOps.STARTWITH,     // 以指定字符串开始
+            SOps.ENDWITH,       // 以指定字符串结束
+            SOps.ISNULL         // 为空
+            -> {
+                var path: String? = null
+                var propertyName = if (filter.first is SAbstractFunction) {
+                    (filter.first!! as SAbstractFunction).name
+                } else {
+                    filter.first as String
+                }
+                val pos = propertyName.indexOf(".")
+                if (pos > 0) {
+                    path = propertyName.substring(pos + 1)
+                    propertyName = propertyName.substring(0, pos)
+                }
+                val colName = SAbstractDao.columnName(clazz, propertyName)
+                try {
+                    values[argName] = filter.second!!
+                } catch (e: Exception) {
+                    // DO NOTHING
+                }
+
+                val isJson = if (filter.opt == SOps.CONTAIN || filter.opt == SOps.STARTWITH || filter.opt == SOps.ENDWITH) {
+                    false
+                } else {
+                    path != null
+                }
+
+                return if (filter.first is SAbstractFunction) {
+                    SSqlProvider.driver.whereArg(SSqlProvider.driver.processFunction(filter.first!! as SAbstractFunction, SSqlProvider.driver.argName(colName, path)), SSqlProvider.driver.argValue(argName, isJson), filter.opt)
+                } else {
+                    SSqlProvider.driver.whereArg(SSqlProvider.driver.argName(colName, path), SSqlProvider.driver.argValue(argName, isJson), filter.opt)
+                }
+            }
+            SOps.IN -> {         // 在列表内
+                // 如果列表不为空,则添加IN子句
+                if (filter.second !=null && List::class.java.isAssignableFrom(filter.second!!.javaClass) &&
+                        (filter.second as List<Any?>).size > 0) {
+                    var path: String? = null
+                    val inArg = buildInArgs(filter, values, argName)
+
+                    if (filter.first is SAbstractFunction) {
+                        val colName = SAbstractDao.columnName(clazz, (filter.first as SAbstractFunction).name)
+                        val col = SSqlProvider.driver.processFunction(filter.first!! as SAbstractFunction, SSqlProvider.driver.argName(colName, path))
+                        builder.append("$col IN ($inArg)")
+                    } else {
+                        var propertyName = filter.first!!.toString()
+                        val pos = propertyName.indexOf(".")
+                        if (pos > 0) {
+                            path = propertyName.substring(pos + 1)
+                            propertyName = propertyName.substring(0, pos)
+                        }
+                        val colName = SAbstractDao.columnName(clazz, propertyName)
+                        builder.append(SSqlProvider.driver.inArg(colName, path, inArg))
+                    }
+                    //"${driver.keyEsc}$colName${driver.keyEsc} IN ($inArg)"
+                }
+            }
+            SOps.NOT -> {        // 逻辑非
+                builder.append("NOT (${buildWhereArg(clazz, filter.first as SFilter, values)})")
+            }
+            SOps.AND -> {        // 逻辑与
+                builder.append("(${buildWhereArg(clazz, filter.first as SFilter, values)}) AND (${buildWhereArg(clazz, filter.second as SFilter, values)})")
+            }
+            SOps.OR -> {         // 逻辑或
+                builder.append("((${buildWhereArg(clazz, filter.first as SFilter, values)}) OR (${buildWhereArg(clazz, filter.second as SFilter, values)}))")
+            }
+            else -> {
+            }
+        }
+
+        return builder.toString()
+    } // Fun buildWhereArgList()
+
+    /**
+     * 生成IN操作参数
+     */
+    @Suppress("UNCHECKED_CAST")
+    protected fun buildInArgs(filter: SFilter, values: HashMap<String, Any>, argName: String): String {
+        val builder = StringBuilder()
+        val argList = filter.second!! as List<Any>
+        val property = filter.first?.toString()
+        val isJson = if (filter.first is SAbstractFunction) {
+            false
+        } else {
+            property?.indexOf(".") != -1
+        }
+
+        for ((index, item) in argList.withIndex()) {
+            if (index > 0) {
+                builder.append(", ")
+            }
+            builder.append(SSqlProvider.driver.argValueToJson("#{whereArgs.${argName}_$index}", isJson))
+            values["${argName}_$index"] = item
+        }
+
+        return builder.toString()
+    } // Fun buildInArgs()
+
+    /**
+     * 构建columns值。如果不指定字段列表,则查所有记录
+     *
+     * @param   clazz       实体类类型
+     * @param   fieldList   属性映射列表
+     * @return  values列表
+     */
+    protected fun buildColumns(clazz: Class<*>, fieldList: ArrayList<String>?): String {
+        // 如果不指定字段列表,则查所有记录
+        if (fieldList == null || fieldList.size <= 0) {
+            return "*"
+        }
+
+        val builder = StringBuilder()
+        for (field in clazz.getAllDeclaredFields()) {
+            if (!fieldList.contains(field.name)) {
+                continue
+            }
+            val anna = field.getAnnotation(Column::class.java) ?: continue
+
+            if (builder.isNotEmpty()) {
+                builder.append(", ")
+            }
+
+            builder.append(SSqlProvider.driver.escName(anna.name))
+        }
+        return builder.toString()
+    } // Fun buildColumns()
+} // Class SAbstractDriver

+ 214 - 0
persagy-kotlin-mybatis/src/main/kotlin/com/persagy/mybatis/SAbstractMybatisDao.kt

@@ -0,0 +1,214 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.mybatis
+
+import com.persagy.base.extensions.toJson
+import com.persagy.database.*
+import com.persagy.database.extensions.keyColumnList
+import com.persagy.database.extensions.keyFieldList
+import com.persagy.mybatis.extensions.toInsertRow
+import com.persagy.mybatis.extensions.toUpdateRow
+import org.slf4j.LoggerFactory
+
+/**
+     * Mybatis基础Dao操作
+ *
+ * @author 庞利祥 <sybotan@126.com>
+ */
+abstract class SAbstractMybatisDao<ENTITY: Any>(entityClazz: Class<ENTITY>) : SAbstractDao<ENTITY>(entityClazz) {
+    /** 静态对象 */
+    companion object {
+        /** 日志记录器 */
+        private val logger = LoggerFactory.getLogger(SAbstractMybatisDao::class.java)
+    } // companion object
+
+    /** sql映射对象*/
+    abstract val mapper: IBaseMapper<ENTITY>
+
+    /** 读取记录行解析器 */
+    private val rowParser = SRowParser(entityClazz)
+
+    /**
+     * 在数据库中插入实体
+     *
+     * @param   entity      插入数据库的实体
+     * @return  手入是否成功
+     */
+    override fun insert(entity: ENTITY): Boolean {
+        val entityMap = entity.toInsertRow()
+        val result = mapper.insert(entityClass, entityMap)
+        try {
+            if (entityMap.containsKey("_id")) {
+                val id = entityMap["_id"]
+                val keyField = entity::class.java.keyFieldList()[0]
+                val accessible = keyField.isAccessible //canAccess(entity)
+                keyField.isAccessible = true
+                keyField.set(entity, id)
+                keyField.isAccessible = accessible
+            }
+        } catch (e: Exception) {
+            // DO NOTHING
+        }
+
+        return result
+    } // Fun insert()
+
+    /**
+     * 在数据库中插入实体
+     *
+     * @param   entity      插入数据库的实体
+     * @return  手入是否成功
+     */
+    override fun replace(entity: ENTITY): Boolean {
+        return try {
+            mapper.replace(entityClass, entity.toInsertRow(), entity.javaClass.keyColumnList())
+        } catch (e: Exception) {
+            e.printStackTrace()
+            false
+        }
+    } // Fun replace()
+
+    /**
+     * 根据条件删除
+     *
+     * @param   args        删除条件
+     * @return  删除是否成功
+     */
+    override fun delete(args: List<SFilter>): Boolean {
+        return try {
+            mapper.delete(entityClass, args, HashMap())
+        } catch (e: Exception) {
+            e.printStackTrace()
+            false
+        }
+    } // Fun delete()
+
+    /**
+     * 删除所有记录
+     *
+     * @return  删除是否成功
+     */
+    override fun deleteAll(): Boolean {
+        return try {
+            mapper.deleteAll(entityClass)
+        } catch (e: Exception) {
+            e.printStackTrace()
+            false
+        }
+    } // Fun deleteAll()
+
+    /**
+     * 根据条件更新
+     *
+     * @param   projection  将被更新的字段列表(以逗号分隔),为空表示更新所有非空字段
+     * @param   args        删除条件
+     * @return  更新是否成功
+     */
+    override fun update(entity: ENTITY, projection: ArrayList<String>?, args: List<SFilter>?): Boolean {
+        return try {
+            mapper.update(entityClass, entity.toUpdateRow(), projection, args, HashMap())
+        } catch (e: Exception) {
+            e.printStackTrace()
+            false
+        }
+    } // Fun update()
+
+    /**
+     * 根据条件查询记录
+     *
+     * @param   args        查询条件
+     * @return  查询构造器
+     */
+    override fun select(args: List<SFilter>): SQueryBuilder<ENTITY> {
+        // 以下循环解决 “SingletonList cannot be cast to java.util.ArrayList” 错误。
+        val filterList = ArrayList<SFilter>()
+        args.forEach {
+            filterList.add(it)
+        }
+        return SQueryBuilder(this, filterList)
+    } // Fun select()
+
+    /**
+     * 根据条件查询所有记录
+     *
+     * @return  查找的记录
+     */
+    override fun selectAll(): SQueryBuilder<ENTITY> {
+        val sQueryBuilder = SQueryBuilder(this, ArrayList())
+//        sQueryBuilder.count = 999999999
+        sQueryBuilder.limit(999999999)
+        logger.debug("查询记录:${sQueryBuilder.toJson()}")
+        return sQueryBuilder
+    } // Fun selectAll()
+
+    /**
+     * 执行查询操作
+     *
+     * @param   builder     查询查询构造器
+     * @return  查询到的记录
+     */
+    override fun execQuery(builder: SQueryBuilder<ENTITY>): ArrayList<ENTITY> {
+        val result = ArrayList<ENTITY>()
+        for (row in mapper.execQuery(entityClass, builder, HashMap())) {
+            try {
+                result.add(rowParser.parseRow(row))
+            } catch (e: Exception) {
+                // DO NOTHING
+            }
+        }
+
+        return result
+    } // Fun exec()
+
+    /**
+     * 执行统计个数操作
+     *
+     * @param   builder     查询查询构造器
+     * @return  查询到的记录
+     */
+    override fun execCount(builder: SQueryBuilder<ENTITY>): Long {
+        val list = mapper.execCount(entityClass, builder, HashMap())
+        if (list.size == 1) {
+            return list[0]
+        }
+        return list.size.toLong()
+    } // Fun execCount()
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // 级联操作相关
+    /**
+     * 查询级联关系
+     *
+     * @param   table       表名
+     * @param   id1         对象表ID字段名
+     * @param   id2         级联对象ID字段名
+     * @param   self        自身级联
+     * @param   filter      附加过滤条件
+     * @param   idList      对象ID列表
+     * @return  关系列表
+     */
+    override fun relationQuery(table: String, id1: String, id2: String, self: Boolean, filter: String, idList: ArrayList<Any>): ArrayList<HashMap<String, Any>> {
+        return mapper.relationQuery(table, id1, id2, self, filter, idList, HashMap());
+    } // Fun cascadeIdList()
+} // Class SAbstractMybatisDao

+ 151 - 0
persagy-kotlin-mybatis/src/main/kotlin/com/persagy/mybatis/SRowParser.kt

@@ -0,0 +1,151 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.mybatis
+
+import com.alibaba.fastjson.PropertyNamingStrategy
+import com.persagy.base.extensions.*
+import com.persagy.base.utils.SJsonUtil
+import org.slf4j.LoggerFactory
+import javax.persistence.Column
+
+/**
+ * 记录解析器
+ *
+ * @author  庞利祥(庞利祥)
+ */
+open class SRowParser<ENTITY: Any>(entityClazz: Class<ENTITY>) {
+    companion object {
+        /** 日志记录器 */
+        private val logger = LoggerFactory.getLogger(SRowParser::class.java)
+    }
+    /** 实体类类型 */
+    private val entityClass = entityClazz
+
+    /**
+     * 解析记录行
+     *
+     * @param   columns     字段映射
+     * @return  实体类
+     */
+    open fun parseRow(columns: Map<String, Any?>): ENTITY {
+        val entity = entityClass.getDeclaredConstructor().newInstance()
+        for (field in entityClass.getAllDeclaredFields()) {
+            val accessible = field.isAccessible    // canAccess(entity)
+            field.isAccessible = true
+
+            // 处理统计信息
+            if (field.name == "statistics") {
+                field.set(entity, groupStatistics(columns))
+                continue
+            }
+            val anno = field.getAnnotation(Column::class.java) ?: continue
+
+            val value = columns[anno.name] ?: continue
+            try {
+                when {
+                    field.type.isBaseType() -> {
+                        field.set(entity, value)
+                    }
+                    Map::class.java.isAssignableFrom(field.type) -> {
+                        field.set(entity, SJsonUtil.fromJson(value.toString(), HashMap::class.java))
+                    }
+                    List::class.java.isAssignableFrom(field.type) -> {
+                        try {
+                            val genericType = field.genericType
+                            val v1 = SJsonUtil.fromJson(value.toString(), genericType!!)
+                            field.set(entity, v1)
+                        } catch (e: Exception) {
+                            // DO NOTHING
+                        }
+                    }
+                    else -> {
+                        // field.set(entity, SJsonUtil.fromJson(value.toString(), field.type))
+                        field.set(entity, SJsonUtil.fromJson(value.toString(), field.type))
+                    }
+                }
+            } catch (e: Exception) {
+                e.printStackTrace()
+            }
+            field.isAccessible = accessible
+        }
+
+        return entity as ENTITY
+    } // Fun parseRow()
+
+    /**
+     * 获得分组统计信息
+     *
+     * @param   columns     字段列表
+     * @return  分组统计信息
+     */
+    private fun groupStatistics(columns: Map<String, Any?>): HashMap<String, Any?>? {
+        var statistics: HashMap<String, Any?>?
+        statistics = HashMap()
+        for (col in columns) {
+            if (!col.key.startsWith("_statistics_")) {
+                continue
+            }
+            if (null == statistics) {
+                statistics = HashMap()
+            }
+
+            when {
+                col.key.startsWith("_statistics_count") ->
+                    statistics[statisticName("Count", "")] = col.value
+                col.key.startsWith("_statistics_avg_") ->
+                    statistics[statisticName("Avg", col.key)] = col.value
+                col.key.startsWith("_statistics_sum_") ->
+                    statistics[statisticName("Sum", col.key)] = col.value
+                col.key.startsWith("_statistics_max_") ->
+                    statistics[statisticName("Max", col.key)] = col.value
+                col.key.startsWith("_statistics_min_") ->
+                    statistics[statisticName("Min", col.key)] = col.value
+            }
+        }
+
+        return statistics
+    } // Fun groupStatistics()
+
+    /**
+     * 统记字段名称
+     *
+     * @param   type        统计类型
+     * @param   name        统计字段名
+     * @return  字段名
+     */
+    private fun statisticName(type: String, name: String): String {
+        val col = if (name.startsWith("_statistics_")) {
+            name.substring(16)
+        } else {
+            ""
+        }
+
+        val str = "$col$type"
+        return if (PropertyNamingStrategy.PascalCase == SJsonUtil.serializeConfig.propertyNamingStrategy) {
+            str.firstUpperCase();
+        } else {
+            str.firstLowerCase();
+        }
+    } // Fun statisticName()
+} // SRowParser

+ 358 - 0
persagy-kotlin-mybatis/src/main/kotlin/com/persagy/mybatis/SSqlProvider.kt

@@ -0,0 +1,358 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.mybatis
+
+import org.apache.ibatis.jdbc.SQL
+import org.slf4j.LoggerFactory
+import kotlin.collections.ArrayList
+import kotlin.collections.HashMap
+
+/**
+ * SQL构造器
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+open class SSqlProvider {
+    /** 静态对象 */
+    companion object {
+        /** 日志记录器 */
+        private val logger = LoggerFactory.getLogger(SSqlProvider::class.java)
+
+        /** 驱动 */
+        lateinit var driver: SAbstractDriver;
+    } // companion object
+
+    /**
+     * 在数据库中插入实体
+     *
+     * @param   argsMap         注入参数
+     * @return  插入SQL语句
+     */
+    @Suppress("UNCHECKED_CAST")
+    open fun insert(argsMap: Map<String, Any?>): String {
+        return driver.insert(argsMap)
+    } // Fun insert()
+
+    /**
+     * 在数据库中替换实体
+     *
+     * @param   argsMap         注入参数
+     * @return  替换SQL语句
+     */
+    @Suppress("UNCHECKED_CAST")
+    open fun replace(argsMap: Map<String, Any?>): String {
+        val insertSql = insert(argsMap)
+        return driver.replace(argsMap, insertSql)
+    } // Fun replace()
+
+    /**
+     * 根据条件删除
+     *
+     * @param   argsMap         注入参数
+     * @return  删除SQL语句
+     */
+    @Suppress("UNCHECKED_CAST")
+    open fun delete(argsMap: Map<String, Any?>): String {
+        return driver.delete(argsMap)
+    } // Fun delete()
+
+    /**
+     * 删除所有记录
+     *
+     * @return  删除SQL语句
+     */
+    open fun deleteAll(argsMap: Map<String, Any?>): String {
+        return driver.deleteAll(argsMap)
+    } // Fun deleteAll()
+
+    /**
+     * 根据条件更新
+     *
+     * @param   argsMap         注入参数
+     * @return  更新SQL语句
+     */
+    @Suppress("UNCHECKED_CAST")
+    open fun update(argsMap: Map<String, Any?>): String {
+        return driver.update(argsMap)
+    } // Fun update()
+
+    /**
+     * 执行查询操作
+     *
+     * @param   argsMap         注入参数
+     * @return  查询SQL语句
+     */
+    @Suppress("UNCHECKED_CAST")
+    fun execQuery(argsMap: Map<String, Any?>): String {
+        return driver.execQuery(argsMap)
+    } // Fun execQuery()
+
+    /**
+     * 执行查询操作
+     *
+     * @param   argsMap         注入参数
+     * @return  查询SQL语句
+     */
+    @Suppress("UNCHECKED_CAST")
+    fun execCount(argsMap: Map<String, Any?>): String {
+        return driver.execCount(argsMap)
+    } // Fun execQuery()
+
+//    /**
+//     * 构造where子句参数
+//     *
+//     * @param   filterList      过滤条件
+//     * @param   values          子句参数列表
+//     * @return  返回where子句
+//     */
+//    private fun buildWhereArgList(clazz: Class<*>, filterList: List<SFilter>, values: HashMap<String, Any>): String {
+//        val builder = StringBuilder()
+//
+//        for (filter in filterList) {
+//            val where = buildWhereArg(clazz, filter, values)
+//            if (builder.isNotEmpty()) {
+//                builder.append(" AND ")
+//            }
+//            builder.append(where)
+//        }
+//
+//        val sql = builder.toString()
+//        logger.debug("buildWhereArgList = $sql")
+//        return sql
+//    } // Fun buildWhereArgList()
+//
+//    /**
+//     * 构造where子句参数
+//     *
+//     * @param   clazz           对应的实体类类型
+//     * @param   filter          过滤条件
+//     * @param   values          子句参数列表
+//     * @return  返回where子句
+//     */
+//    private fun buildWhereArg(clazz: Class<*>, filter: SFilter, values: HashMap<String, Any>): String {
+//        val builder = StringBuilder()
+//        val argName = "arg${values.size}"
+//        when (filter.opt) {
+//            SOps.EQ,            // 等于
+//            SOps.NE,            // 不等于
+//            SOps.GT,            // 大于
+//            SOps.GTE,           // 大于等于
+//            SOps.LT,            // 小于
+//            SOps.LTE,           // 小于等于
+//            SOps.CONTAIN,       // 包含
+//            SOps.STARTWITH,     // 以指定字符串开始
+//            SOps.ENDWITH,       // 以指定字符串结束
+//            SOps.ISNULL         // 为空
+//            -> {
+//                var path: String? = null
+//                var propertyName = if (filter.first is SAbstractFunction) {
+//                    (filter.first!! as SAbstractFunction).name
+//                } else {
+//                    filter.first as String
+//                }
+//                val pos = propertyName.indexOf(".")
+//                if (pos > 0) {
+//                    path = propertyName.substring(pos + 1)
+//                    propertyName = propertyName.substring(0, pos)
+//                }
+//                val colName = SAbstractDao.columnName(clazz, propertyName)
+//                try {
+//                    values[argName] = filter.second!!
+//                } catch (e: Exception) {
+//                    // DO NOTHING
+//                }
+//
+//                val isJson = if (filter.opt == SOps.CONTAIN || filter.opt == SOps.STARTWITH || filter.opt == SOps.ENDWITH) {
+//                    false
+//                } else {
+//                    path != null
+//                }
+//
+//                return if (filter.first is SAbstractFunction) {
+//                    driver.whereArg(driver.processFunction(filter.first!! as SAbstractFunction, driver.argName(colName, path)), driver.argValue(argName, isJson), filter.opt)
+//                } else {
+//                    driver.whereArg(driver.argName(colName, path), driver.argValue(argName, isJson), filter.opt)
+//                }
+//            }
+//            SOps.IN -> {         // 在列表内
+//                // 如果列表不为空,则添加IN子句
+//                if (filter.second !=null && List::class.java.isAssignableFrom(filter.second!!.javaClass) &&
+//                        (filter.second as List<Any?>).size > 0) {
+//                    var path: String? = null
+//                    val inArg = buildInArgs(filter, values, argName)
+//
+//                    if (filter.first is SAbstractFunction) {
+//                        val colName = SAbstractDao.columnName(clazz, (filter.first as SAbstractFunction).name)
+//                        val col = driver.processFunction(filter.first!! as SAbstractFunction, driver.argName(colName, path))
+//                        builder.append("$col IN ($inArg)")
+//                    } else {
+//                        var propertyName = filter.first!!.toString()
+//                        val pos = propertyName.indexOf(".")
+//                        if (pos > 0) {
+//                            path = propertyName.substring(pos + 1)
+//                            propertyName = propertyName.substring(0, pos)
+//                        }
+//                        val colName = SAbstractDao.columnName(clazz, propertyName)
+//                        builder.append(driver.inArg(colName, path, inArg))
+//                    }
+//                    //"${driver.keyEsc}$colName${driver.keyEsc} IN ($inArg)"
+//                }
+//            }
+//            SOps.NOT -> {        // 逻辑非
+//                builder.append("NOT (${buildWhereArg(clazz, filter.first as SFilter, values)})")
+//            }
+//            SOps.AND -> {        // 逻辑与
+//                builder.append("(${buildWhereArg(clazz, filter.first as SFilter, values)}) AND (${buildWhereArg(clazz, filter.second as SFilter, values)})")
+//            }
+//            SOps.OR -> {         // 逻辑或
+//                builder.append("((${buildWhereArg(clazz, filter.first as SFilter, values)}) OR (${buildWhereArg(clazz, filter.second as SFilter, values)}))")
+//            }
+//            else -> {
+//            }
+//        }
+//
+//        return builder.toString()
+//    } // Fun buildWhereArgList()
+//
+//    /**
+//     * 生成IN操作参数
+//     */
+//    @Suppress("UNCHECKED_CAST")
+//    private fun buildInArgs(filter: SFilter, values: HashMap<String, Any>, argName: String): String {
+//        val builder = StringBuilder()
+//        val argList = filter.second!! as List<Any>
+//        val property = filter.first?.toString()
+//        val isJson = if (filter.first is SAbstractFunction) {
+//            false
+//        } else {
+//            property?.indexOf(".") != -1
+//        }
+//
+//        for ((index, item) in argList.withIndex()) {
+//            if (index > 0) {
+//                builder.append(", ")
+//            }
+//            builder.append(driver.argValueToJson("#{whereArgs.${argName}_$index}", isJson))
+//            values["${argName}_$index"] = item
+//        }
+//
+//        return builder.toString()
+//    } // Fun buildInArgs()
+//
+//    /**
+//     * 构建columns值。如果不指定字段列表,则查所有记录
+//     *
+//     * @param   clazz       实体类类型
+//     * @param   fieldList   属性映射列表
+//     * @return  values列表
+//     */
+//    protected fun buildColumns(clazz: Class<*>, fieldList: ArrayList<String>?): String {
+//        // 如果不指定字段列表,则查所有记录
+//        if (fieldList == null || fieldList.size <= 0) {
+//            return "*"
+//        }
+//
+//        val builder = StringBuilder()
+//        for (field in clazz.getAllDeclaredFields()) {
+//            if (!fieldList.contains(field.name)) {
+//                continue
+//            }
+//            val anna = field.getAnnotation(Column::class.java) ?: continue
+//
+//            if (builder.isNotEmpty()) {
+//                builder.append(", ")
+//            }
+//
+//            builder.append(driver.escName(anna.name))
+//        }
+//        return builder.toString()
+//    } // Fun buildColumns()
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // 级联操作相关
+    /**
+     * 查询级联关系
+     *
+     * @param   argsMap         注入参数
+     * @return  查询SQL语句
+     */
+    @Suppress("UNCHECKED_CAST")
+    fun relationQuery(argsMap: Map<String, Any?>): String {
+        val table = argsMap["table"] as String
+        val id1 = argsMap["id1"] as String
+        val id2 = argsMap["id2"] as String
+        val self = argsMap["self"] as Boolean
+        val filter = argsMap["filter"] as String
+        val idList = argsMap["idList"] as ArrayList<Any>
+        val whereArgs = argsMap["whereArgs"] as HashMap<String, Any>
+
+        var sql = object: SQL() {
+            init {
+                SELECT("${driver.escName(id1)} as id1, ${driver.escName(id2)} as id2")
+                FROM(table)
+
+                val builder = StringBuilder()
+                for ((index, item) in idList.withIndex()) {
+                    if (index > 0) {
+                        builder.append(", ")
+                    }
+                    builder.append("#{whereArgs.args_$index}")
+                    whereArgs["args_$index"] = item
+                }
+                if (filter != "") {
+                    WHERE(filter)
+                }
+                WHERE("${driver.escName(id1)} IN (${builder.toString()})")
+            }
+        }.toString()
+
+        // 如果是关联自身(比如楼层连通关系,两个ID都是楼层)
+        if (self) {
+            val sql1 = object: SQL() {
+                init {
+                    SELECT("${driver.escName(id2)} as id1, ${driver.escName(id1)} as id2")
+                    FROM(table)
+
+                    val builder = StringBuilder()
+                    for ((index, item) in idList.withIndex()) {
+                        if (index > 0) {
+                            builder.append(", ")
+                        }
+                        builder.append("#{whereArgs.args_$index}")
+                        whereArgs["args_$index"] = item
+                    }
+                    if (filter != "") {
+                        WHERE(filter)
+                    }
+                    WHERE("${driver.escName(id2)} IN (${builder.toString()})")
+                }
+            }.toString()
+
+            sql = "$sql \n UNION \n $sql1"
+        }
+
+        logger.debug("SQL= $sql")
+        return sql
+    } // Fun relationQuery()
+} // Class SSqlProvider

+ 80 - 0
persagy-kotlin-mybatis/src/main/kotlin/com/persagy/mybatis/extensions/SAnyExtension.kt

@@ -0,0 +1,80 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.mybatis.extensions
+
+import com.persagy.base.extensions.getAllDeclaredFields
+import java.lang.reflect.Field
+import javax.persistence.Column
+
+/**
+ * Any扩展。获得类的泛型类
+ *
+ * @return  类的泛型类
+ */
+fun Any.toInsertRow():  HashMap<String, Any?> {
+    val row = HashMap<String, Any?>()
+    val clz = this::class.java
+    for (field in clz.getAllDeclaredFields()) {
+        val anno = field.getAnnotation(Column::class.java) ?: continue
+        if (!anno.insertable) {
+            continue
+        }
+
+        row[anno.name] = fieldValue(this, field)
+    }
+    return row
+} // Fun Serializable.toInsertRow()
+
+/**
+ * 转换实体到更新行
+ *
+ * @return  更新行
+ */
+fun Any.toUpdateRow(): HashMap<String, Any?> {
+    val row = HashMap<String, Any?>()
+    val clz = this::class.java
+    for (field in clz.getAllDeclaredFields()) {
+        val anno = field.getAnnotation(Column::class.java) ?: continue
+        if (!anno.updatable) {
+            continue
+        }
+
+        row[anno.name] = fieldValue(this, field)
+    }
+
+    return row
+} // Fun toUpdateRow()
+
+/**
+ * 构建values值
+ *
+ * @return  values列表
+ */
+private fun fieldValue(obj: Any, field: Field):  Any? {
+    val accessible = field.isAccessible     //canAccess(obj)
+    field.isAccessible = true
+    val value = field.get(obj)
+    field.isAccessible = accessible
+    return value
+} // Fun fieldValue()

+ 136 - 0
persagy-kotlin-mysql/build.gradle

@@ -0,0 +1,136 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+group rootProject.group
+version rootProject.version
+
+apply plugin: "kotlin"
+apply plugin: "org.jetbrains.dokka"
+apply plugin: "maven"
+apply plugin: 'ca.coglinc.javacc'
+
+sourceCompatibility = JVM_TARGET
+
+compileKotlin {
+    kotlinOptions.jvmTarget = JVM_TARGET
+}
+compileTestKotlin {
+    kotlinOptions.jvmTarget = JVM_TARGET
+}
+
+compileJavacc {
+    inputDirectory = file("src/main/javacc")
+    outputDirectory = file("src/main/kotlin/com/sybotan/database/parser")
+}
+
+dependencies {
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // kotlin 依赖
+    compile group: "org.jetbrains.kotlin", name: "kotlin-stdlib-jdk8", version: KOTLIN_VERSION
+    compile group: "org.jetbrains.kotlin", name: "kotlin-reflect", version: KOTLIN_VERSION
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // 单元测试
+    // https://mvnrepository.com/artifact/org.testng/testng
+    testCompile group: 'org.testng', name: 'testng', version: TESTNG_VERSION
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    compile group: "javax.persistence", name: "persistence-api", version: PERSISTENCE_VERSION
+
+    // https://mvnrepository.com/artifact/io.swagger/swagger-annotations
+    compile group: 'io.swagger', name: 'swagger-annotations', version: '1.5.22'
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // MySQL
+    // https://mvnrepository.com/artifact/mysql/mysql-connector-java
+    compile group: 'mysql', name: 'mysql-connector-java', version: MYSQL_VERSION
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // Sybotan依赖
+    compile project(':persagy-kotlin-base')
+    compile project(':persagy-kotlin-database')
+    compile project(':persagy-kotlin-mybatis')
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// 文档生成
+dokka {
+    jdkVersion = JDK_VERSION
+    outputFormat = "javadoc"
+    outputDirectory = "$buildDir/javadoc"
+    //sourceDirs = files("src/main/kotlin")
+}
+
+// 上成上传的文档jar包
+task javadocJar(type: Jar, dependsOn: dokka) {
+    classifier = "javadoc"
+    from dokka.outputDirectory
+}
+
+// 上成上传的文档jar包
+task sourcesJar(type: Jar) {
+    classifier = 'sources'
+    from sourceSets.main.allSource
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// maven 仓库管理
+
+// 设置上传的包,默认上传aar与pom
+artifacts {
+    // archives javadocJar
+    // archives sourcesJar
+}
+
+uploadArchives {
+    repositories {
+        mavenDeployer {
+            pom.groupId = project.group
+            pom.version = project.version
+            pom.artifactId = project.name
+            pom.project {
+                name project.name
+                packaging "jar"
+                url PERSAGY_URL
+                description "斯伯坦机器人 Kotlin MySQL数据库操作支持库。"
+                licenses {
+                    license {
+                        name LICENSE_NAME
+                        url LICENSE_URL
+                    }
+                }
+                developers {
+                    developer {
+                        id DEVELOPER_ID
+                        name DEVELOPER_NAME
+                    }
+                }
+            }
+            snapshotRepository(url: MAVEN_REPO_SNAPSHOT_URL) {
+                authentication(userName: NEXUS_USERNAME, password: NEXUS_PASSWORD)
+            }
+            repository(url: MAVEN_REPO_RELEASE_URL) {
+                authentication(userName: NEXUS_USERNAME, password: NEXUS_PASSWORD)
+            }
+        }
+    }
+}

+ 350 - 0
persagy-kotlin-mysql/src/main/kotlin/com/persagy/mysql/SMySqlDriver.kt

@@ -0,0 +1,350 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.mysql
+
+import com.persagy.base.extensions.isBaseType
+import com.persagy.base.extensions.toJson
+import com.persagy.base.extensions.toJsonAll
+import com.persagy.database.SAbstractFunction
+import com.persagy.database.SFilter
+import com.persagy.database.enums.SDatabaseType
+import com.persagy.database.enums.SOps
+import com.persagy.mybatis.SAbstractDriver
+import com.persagy.mybatis.SSqlProvider
+import org.apache.ibatis.jdbc.SQL
+import org.slf4j.LoggerFactory
+
+/**
+ * MySQL驱动
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+class SMySqlDriver : SAbstractDriver() {
+    /** 静态对象 */
+    companion object {
+        /** 日志记录器 */
+        private val logger = LoggerFactory.getLogger(SMySqlDriver::class.java)
+    } // companion object
+
+    /**
+     * 在数据库中插入实体
+     *
+     * @param   argsMap         注入参数
+     * @return  插入SQL语句
+     */
+    @Suppress("UNCHECKED_CAST")
+    override fun insert(argsMap: Map<String, Any?>): String {
+        val entityClass = argsMap["entityClass"] as Class<*>
+        val entity = argsMap["entity"] as HashMap<String, Any?>
+        val sql = object: SQL() {
+            init {
+                INSERT_INTO(SSqlProvider.driver.tableName(entityClass))
+                for ((key, value) in entity) {
+                    if (value != null) {
+                        if (value is Map<*,*>) {
+                            VALUES(SSqlProvider.driver.escName(key), "'${value.toJsonAll().replace("'", "''")}'")
+                        } else {
+                            VALUES(SSqlProvider.driver.escName(key), SSqlProvider.driver.entityValue(entity, key))
+                        }
+//                        if (value::class.java.isPrimitive) {
+//                            VALUES(driver.escName(key), driver.entityValue(entity, key))
+//                        } else {
+//                            VALUES(driver.escName(key), "'${value.toJsonAll()}'")
+//                        }
+                    }
+                }
+            }
+        }.toString()
+
+        logger.debug("INSERT SQL= $sql")
+
+        return sql
+    } // Fun insert()
+
+    /**
+     * 在数据库中替换实体
+     *
+     * @param   argsMap         注入参数
+     * @param   insertSql       插入SQL语句
+     * @return  替换SQL语句
+     */
+    override fun replace(argsMap: Map<String, Any?>, insertSql: String): String {
+        val sql = insertSql.replace("INSERT INTO", "REPLACE INTO")
+        logger.debug("REPLACE SQL= $sql")
+        return sql
+    } // Fun replace()
+
+    /**
+     * 根据条件删除
+     *
+     * @param   argsMap         注入参数
+     * @return  删除SQL语句
+     */
+    @Suppress("UNCHECKED_CAST")
+    override fun delete(argsMap: Map<String, Any?>): String {
+        val entityClass = argsMap["entityClass"] as Class<*>
+        // 从入参中获得过虑条件
+        val filterArgs = argsMap["filterArgs"] as List<SFilter>
+        // 转换后的where语句参数
+        val whereArgs = argsMap["whereArgs"] as HashMap<String, Any>
+        val clause = buildWhereArgList(entityClass, filterArgs, whereArgs)
+
+        val sql = object: SQL() {
+            init {
+                DELETE_FROM(SSqlProvider.driver.tableName(entityClass))
+                if (clause.isNotEmpty()) {
+                    WHERE(clause)
+                }
+            }
+        }.toString()
+
+        logger.debug("SQL= $sql")
+        return sql
+    } // Fun delete()
+
+    /**
+     * 删除所有记录
+     *
+     * @return  删除SQL语句
+     */
+    @Suppress("UNCHECKED_CAST")
+    override fun deleteAll(argsMap: Map<String, Any?>): String {
+        val entityClass = argsMap["entityClass"] as Class<*>
+        val sql = object: SQL() {
+            init {
+                DELETE_FROM(SSqlProvider.driver.tableName(entityClass))
+            }
+        }.toString()
+
+        logger.debug("SQL= $sql")
+        return sql
+    } // Fun deleteAll()
+
+    /**
+     * 获得表名,取实体类@Table注解的名称,如果没有注解,则取实体类类名。
+     *
+     * @param   clz         mapper类类型
+     * @return  表名
+     */
+    override fun tableName(clz: Class<*>): String {
+        val tableAnno = clz.getAnnotation(javax.persistence.Table::class.java)
+        // 如果有@Table注解,则取注解的表名;否则使用类名做为表名
+        val tableName = tableAnno?.name ?: clz.simpleName
+        val name = tableName.replace(".", "`.`")
+        return "`$name`"
+    } // Fun tableName()
+
+    /**
+     * 将 name 加上引用符号
+     *
+     * @param   name    名称
+     * @return  加上引用符号的名称
+     */
+    override fun escName(name: String): String {
+        return "`$name`"
+    } // Fun escName()
+
+    /**
+     * 实体类的值,如果不是基本类型,则转换为json
+     *
+     * @param   entity      实体类
+     * @param   name        名称
+     * @return  加上引用符号的名称
+     */
+    override fun entityValue(entity: HashMap<String, Any?>, name: String): String {
+        val value = entity[name] ?: return "null"
+        if (value.isBaseType()) {
+            return "#{entity.$name}"
+        }
+        return "'${value.toJson()}'"
+    } // Fun entityValue()
+
+    /**
+     * 生成limit语句
+     *
+     * @param   offset      偏移位置
+     * @param   count       取得的记录数
+     * @return  LIMIT子句
+     */
+    override fun limit(offset: Int?, count: Int?): String {
+        return " LIMIT ${offset ?: 0}, ${count ?: 1}"
+    } // Fun limit()
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // 函数
+    /**
+     * 处理函数支持
+     *
+     * @param   func        函数对象
+     * @param   colName     字段名
+     * @return  生成的SQL语句
+     */
+    override fun processFunction(func: SAbstractFunction, colName: String): String {
+        func.colName = colName
+        return func.toSql(SDatabaseType.MySQL)
+    } // Fun processFunction()
+//----------------------------------------------------------------------------------------------------------------------
+    /**
+     * 转换where字句参数
+     *
+     * @param   argName     参数名
+     * @param   argValue    参数值
+     * @param   ops         运算符
+     * @return  转换后的SQL
+     */
+    override fun whereArg(argName: String, argValue: String, ops: SOps): String {
+//        var name = obj as String
+//
+//        val colName: String
+//        val argValue: String
+//        if (path == null) {
+//            colName = "`$name`"
+//            argValue = "#{whereArgs.$argName}"
+//        } else {
+//            colName = "JSON_EXTRACT(`$name`, '\$.$path')"
+//            argValue = "#{whereArgs.$argName}"
+//        }
+
+        when (ops) {
+            SOps.EQ -> {     // 等于
+                return "$argName = $argValue"
+            }
+            SOps.NE -> {     // 不等于
+                return "$argName <> $argValue"
+            }
+            SOps.GT -> {     // 大于
+                return "$argName > $argValue"
+            }
+            SOps.GTE -> {    // 大于等于
+                return "$argName >= $argValue"
+            }
+            SOps.LT -> {     // 小于
+                return "$argName < $argValue"
+            }
+            SOps.LTE -> {    // 小于等行
+                return "$argName <= $argValue"
+            }
+            SOps.CONTAIN -> {    // 包含
+                return "$argName LIKE CONCAT(\"%\" , $argValue, \"%\")"
+            }
+            SOps.STARTWITH -> {    // 以指定字符串开始
+                return "$argName LIKE CONCAT($argValue, \"%\")"
+            }
+            SOps.ENDWITH -> {    // 以指定字符串结束
+                return "$argName LIKE CONCAT(\"%\" , $argValue)"
+            }
+            SOps.ISNULL -> {     // 为空
+                return "ISNULL($argName)"
+            }
+            else -> {
+            }
+        }
+        return ""
+    } // Fun whereArg()
+
+    /**
+     * 转换参数名SQL语句
+     *
+     * @param   name        字段名
+     * @param   path        json路径。如果不是json对象,则该值为空
+     * @return  转换后的SQL
+     */
+    override fun argName(name: String, path: String?): String {
+        return if (path == null) {
+            "`$name`"
+        } else {
+            "JSON_EXTRACT(`$name`, '\$.$path')"
+        }
+    } // Fun argName()
+
+    /**
+     * 转换参数值SQL语句
+     *
+     * @param   argName     参数名
+     * @param   isJson      是否Json对象
+     * @return  转换后的SQL
+     */
+    override fun argValue(argName: String, isJson: Boolean): String {
+        return if (isJson) {
+            "#{whereArgs.$argName}"
+        } else {
+            "#{whereArgs.$argName}"
+        }
+    } // Fun argValue()
+
+    /**
+     * 转换IN条件表达式
+     *
+     * @param   name        字段名
+     * @param   path        json路径,如果字段不为json,则path为null
+     * @param   inArg       in操作参数
+     * @return  转换后的SQL
+     */
+    override fun inArg(name: String, path: String?, inArg: String): String {
+        return if (path == null) {
+            "`$name` IN ($inArg)"
+        } else {
+            "JSON_EXTRACT(`$name`,'\$.$path') IN ($inArg)"
+        }
+    } // Fun inArg()
+
+    /**
+     * 将名称及json路径转换为SQL
+     *
+     * @param   name        字段名
+     * @param   path        json路径,如果字段不为json,则path为null
+     * @return   转换后的SQL
+     */
+    override fun columnName(name: String, path: String?): String {
+        return if (path == null) {
+            "`$name`"
+        } else {
+            "JSON_EXTRACT(`$name`, '\$.$path')"
+        }
+    }
+
+    /**
+     * 将参数值转换为SQL语句
+     *
+     * @param   value       值
+     * @param   isJson      值是否转换为json格式
+     * @return  转换后的SQL
+     */
+    override fun argValueToJson(value: String, isJson: Boolean): String {
+        return value
+    } // Fun argValueToJson()
+
+    /**
+     * 更新Json类型字段
+     *
+     * @param   name        字段名
+     * @param   value       值
+     * @return  更新SQL字符串
+     */
+    override fun updateJson(name: String, value: Any): String {
+        return "JSON_MERGE(IFNULL(`$name`,'{}'), '${value.toJsonAll()}')"
+    } // Fun updateJson()
+
+
+} // Class SMySqlDriver

+ 136 - 0
persagy-kotlin-postgresql/build.gradle

@@ -0,0 +1,136 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+group rootProject.group
+version rootProject.version
+
+apply plugin: "kotlin"
+apply plugin: "org.jetbrains.dokka"
+apply plugin: "maven"
+apply plugin: 'ca.coglinc.javacc'
+
+sourceCompatibility = JVM_TARGET
+
+compileKotlin {
+    kotlinOptions.jvmTarget = JVM_TARGET
+}
+compileTestKotlin {
+    kotlinOptions.jvmTarget = JVM_TARGET
+}
+
+compileJavacc {
+    inputDirectory = file("src/main/javacc")
+    outputDirectory = file("src/main/kotlin/com/sybotan/database/parser")
+}
+
+dependencies {
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // kotlin 依赖
+    compile group: "org.jetbrains.kotlin", name: "kotlin-stdlib-jdk8", version: KOTLIN_VERSION
+    compile group: "org.jetbrains.kotlin", name: "kotlin-reflect", version: KOTLIN_VERSION
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // 单元测试
+    // https://mvnrepository.com/artifact/org.testng/testng
+    testCompile group: 'org.testng', name: 'testng', version: TESTNG_VERSION
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    compile group: "javax.persistence", name: "persistence-api", version: PERSISTENCE_VERSION
+
+    // https://mvnrepository.com/artifact/io.swagger/swagger-annotations
+    compile group: 'io.swagger', name: 'swagger-annotations', version: '1.5.22'
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // PostgreSQL
+    // https://mvnrepository.com/artifact/org.postgresql/postgresql
+    compile group: 'org.postgresql',    name: 'postgresql',     version: POSTGRESQL_VERSION
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // Sybotan依赖
+    compile project(':persagy-kotlin-base')
+    compile project(':persagy-kotlin-database')
+    compile project(':persagy-kotlin-mybatis')
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// 文档生成
+dokka {
+    jdkVersion = JDK_VERSION
+    outputFormat = "javadoc"
+    outputDirectory = "$buildDir/javadoc"
+    //sourceDirs = files("src/main/kotlin")
+}
+
+// 上成上传的文档jar包
+task javadocJar(type: Jar, dependsOn: dokka) {
+    classifier = "javadoc"
+    from dokka.outputDirectory
+}
+
+// 上成上传的文档jar包
+task sourcesJar(type: Jar) {
+    classifier = 'sources'
+    from sourceSets.main.allSource
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// maven 仓库管理
+
+// 设置上传的包,默认上传aar与pom
+artifacts {
+    // archives javadocJar
+    // archives sourcesJar
+}
+
+uploadArchives {
+    repositories {
+        mavenDeployer {
+            pom.groupId = project.group
+            pom.version = project.version
+            pom.artifactId = project.name
+            pom.project {
+                name project.name
+                packaging "jar"
+                url PERSAGY_URL
+                description "斯伯坦机器人 Kotlin PostgreSQL数据库操作支持库。"
+                licenses {
+                    license {
+                        name LICENSE_NAME
+                        url LICENSE_URL
+                    }
+                }
+                developers {
+                    developer {
+                        id DEVELOPER_ID
+                        name DEVELOPER_NAME
+                    }
+                }
+            }
+            snapshotRepository(url: MAVEN_REPO_SNAPSHOT_URL) {
+                authentication(userName: NEXUS_USERNAME, password: NEXUS_PASSWORD)
+            }
+            repository(url: MAVEN_REPO_RELEASE_URL) {
+                authentication(userName: NEXUS_USERNAME, password: NEXUS_PASSWORD)
+            }
+        }
+    }
+}

+ 410 - 0
persagy-kotlin-postgresql/src/main/kotlin/com/persagy/postgresql/SPostgreSqlDriver.kt

@@ -0,0 +1,410 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+package com.persagy.postgresql
+
+import com.persagy.base.extensions.isBaseType
+import com.persagy.base.extensions.toJson
+import com.persagy.base.extensions.toJsonAll
+import com.persagy.database.SAbstractFunction
+import com.persagy.database.SFilter
+import com.persagy.database.enums.SDatabaseType
+import com.persagy.database.enums.SOps
+import com.persagy.mybatis.SAbstractDriver
+import com.persagy.mybatis.SSqlProvider
+import org.apache.ibatis.jdbc.SQL
+import org.slf4j.LoggerFactory
+
+/**
+ * PostgreSQL驱动
+ *
+ * @author  庞利祥 <sybotan@126.com>
+ */
+class SPostgreSqlDriver : SAbstractDriver() {
+
+    /** 静态对象 */
+    companion object {
+        /** 日志记录器 */
+        private val logger = LoggerFactory.getLogger(SPostgreSqlDriver::class.java)
+    } // companion object
+
+    /**
+     * 在数据库中插入实体
+     *
+     * @param   argsMap         注入参数
+     * @return  插入SQL语句
+     */
+    @Suppress("UNCHECKED_CAST")
+    override fun insert(argsMap: Map<String, Any?>): String {
+        val entityClass = argsMap["entityClass"] as Class<*>
+        val entity = argsMap["entity"] as HashMap<String, Any?>
+        val sql = object: SQL() {
+            init {
+                INSERT_INTO(SSqlProvider.driver.tableName(entityClass))
+                for ((key, value) in entity) {
+                    if (value != null) {
+                        if (value is Map<*,*>) {
+                            VALUES(SSqlProvider.driver.escName(key), "'${value.toJsonAll().replace("'", "''")}'")
+                        } else if (value is List<*>) {
+                            VALUES(SSqlProvider.driver.escName(key), "'${value.toJsonAll().replace("'", "''")}'")
+                        } else {
+                            VALUES(SSqlProvider.driver.escName(key), SSqlProvider.driver.entityValue(entity, key))
+                        }
+//                        if (value::class.java.isPrimitive) {
+//                            VALUES(driver.escName(key), driver.entityValue(entity, key))
+//                        } else {
+//                            VALUES(driver.escName(key), "'${value.toJsonAll()}'")
+//                        }
+                    }
+                }
+            }
+        }.toString()
+
+        logger.debug("INSERT SQL= $sql")
+
+        return sql
+    } // Fun insert()
+
+    /**
+     * 在数据库中替换实体
+     *
+     * @param   argsMap         注入参数
+     * @param   insertSql       插入SQL语句
+     * @return  替换SQL语句
+     */
+    @Suppress("UNCHECKED_CAST")
+    override fun replace(argsMap: Map<String, Any?>, insertSql: String): String {
+        val sql: String
+        val entity = argsMap["entity"] as Map<String, Any?>
+        val keyColumnList = argsMap["keyColumnList"] as ArrayList<String>
+
+        val upSqlBuilder = StringBuilder()
+        logger.debug("entity=${entity.toJson()}")
+        for ((key, value) in entity) {
+            if (value != null) {
+                if (upSqlBuilder.length > 1) {
+                    upSqlBuilder.append(",")
+                }
+                if (value is Map<*,*>) {
+                    upSqlBuilder.append("${escName(key)} = '${value.toJsonAll().replace("'", "''")}'")
+                } else if (value is List<*>) {
+                    upSqlBuilder.append("${escName(key)} = '${value.toJsonAll().replace("'", "''")}'")
+                } else {
+                    upSqlBuilder.append("${escName(key)} = #{entity.$key}")
+                }
+//                    if (value::class.java.isPrimitive) {
+//                        upSqlBuilder.append("${escName(key)} = #{entity.$key}")
+//                    } else {
+//                        upSqlBuilder.append("${escName(key)} = '${value.toJsonAll()}'")
+//                    }
+            } else {
+                // 维新有特殊要求
+//                    if (upSqlBuilder.length > 1) {
+//                        upSqlBuilder.append(",")
+//                    }
+//                    upSqlBuilder.append("${driver.keyEsc}$key${driver.keyEsc} = null")
+            }
+        }
+
+        val confict = StringBuilder()
+        keyColumnList.forEach {
+            if (confict.length > 1) {
+                confict.append(",")
+            }
+            confict.append("\"$it\"")
+        }
+
+        sql = "$insertSql ON conflict ( $confict ) DO UPDATE SET $upSqlBuilder"
+        logger.debug("REPLACE SQL= $sql")
+        return sql
+    } // Fun replace()
+
+    /**
+     * 根据条件删除
+     *
+     * @param   argsMap         注入参数
+     * @return  删除SQL语句
+     */
+    @Suppress("UNCHECKED_CAST")
+    override fun delete(argsMap: Map<String, Any?>): String {
+        val entityClass = argsMap["entityClass"] as Class<*>
+        // 从入参中获得过虑条件
+        val filterArgs = argsMap["filterArgs"] as List<SFilter>
+        // 转换后的where语句参数
+        val whereArgs = argsMap["whereArgs"] as HashMap<String, Any>
+        val clause = buildWhereArgList(entityClass, filterArgs, whereArgs)
+
+        val sql = object: SQL() {
+            init {
+                DELETE_FROM(SSqlProvider.driver.tableName(entityClass))
+                if (clause.isNotEmpty()) {
+                    WHERE(clause)
+                }
+            }
+        }.toString()
+
+        logger.debug("SQL= $sql")
+        return sql
+    } // Fun delete()
+
+    /**
+     * 删除所有记录
+     *
+     * @return  删除SQL语句
+     */
+    @Suppress("UNCHECKED_CAST")
+    override fun deleteAll(argsMap: Map<String, Any?>): String {
+        val entityClass = argsMap["entityClass"] as Class<*>
+        val sql = object: SQL() {
+            init {
+                DELETE_FROM(SSqlProvider.driver.tableName(entityClass))
+            }
+        }.toString()
+
+        logger.debug("SQL= $sql")
+        return sql
+    } // Fun deleteAll()
+
+    /**
+     * 获得表名,取实体类@Table注解的名称,如果没有注解,则取实体类类名。
+     *
+     * @param   clz         mapper类类型
+     * @return  表名
+     */
+    override fun tableName(clz: Class<*>): String {
+        val tableAnno = clz.getAnnotation(javax.persistence.Table::class.java)
+        // 如果有@Table注解,则取注解的表名;否则使用类名做为表名
+        val tableName = tableAnno?.name ?: clz.simpleName
+        val name = tableName.replace(".", "\".\"")
+        return "\"$name\""
+    } // Fun tableName()
+
+    /**
+     * 将 name 加上引用符号
+     *
+     * @param   name    名称
+     * @return  加上引用符号的名称
+     */
+    override fun escName(name: String): String {
+        return "\"$name\""
+    } // Fun escName()
+
+    /**
+     * 实体类的值,如果不是基本类型,则转换为json
+     *
+     * @param   entity      实体类
+     * @param   name        名称
+     * @return  加上引用符号的名称
+     */
+    override fun entityValue(entity: HashMap<String, Any?>, name: String): String {
+        val value = entity[name] ?: return "null"
+        if (value.isBaseType()) {
+            return "#{entity.$name}"
+        }
+        return "'${value.toJson()}'"
+    } // Fun entityValue()
+
+    /**
+     * 生成limit语句
+     *
+     * @param   offset      偏移位置
+     * @param   count       取得的记录数
+     * @return  LIMIT子句
+     */
+    override fun limit(offset: Int?, count: Int?): String {
+        if (count == null){
+            return " OFFSET ${offset ?: 0} LIMIT ${count ?: 1}"
+        }else if (offset!=null&&count!=null){
+            return " OFFSET ${offset ?: 0} LIMIT ${count ?: 1}"
+        }else{
+            return " OFFSET ${offset ?: 0} LIMIT ${count ?: 1}"
+        }
+//        return " OFFSET ${offset ?: 0} LIMIT ${count ?: 1}"
+    } // Fun limit()
+
+    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+    // 函数
+    /**
+     * 处理函数支持
+     *
+     * @param   func        函数对象
+     * @param   colName     字段名
+     * @return  生成的SQL语句
+     */
+    override fun processFunction(func: SAbstractFunction, colName: String): String {
+        func.colName = colName
+        return func.toSql(SDatabaseType.PostgreSQL)
+    } // Fun processFunction()
+
+//----------------------------------------------------------------------------------------------------------------------
+    /**
+     * 转换where字句参数
+     *
+     * @param   argName     参数名
+     * @param   argValue    参数值
+     * @param   ops         运算符
+     * @return  转换后的SQL
+     */
+    override fun whereArg(argName: String, argValue: String, ops: SOps): String {
+
+        when (ops) {
+            SOps.EQ -> {     // 等于
+                return "$argName = $argValue"
+            }
+            SOps.NE -> {     // 不等于
+                return "$argName <> $argValue"
+            }
+            SOps.GT -> {     // 大于
+                return "$argName > $argValue"
+            }
+            SOps.GTE -> {    // 大于等于
+                return "$argName >= $argValue"
+            }
+            SOps.LT -> {     // 小于
+                return "$argName < $argValue"
+            }
+            SOps.LTE -> {    // 小于等行
+                return "$argName <= $argValue"
+            }
+            SOps.CONTAIN -> {    // 包含
+                return if (argName.indexOf("#") > 0) {
+                    "($argName)::TEXT LIKE ('%' || $argValue || '%')"
+                } else {
+                    "$argName LIKE ('%' || $argValue || '%')"
+                }
+            }
+            SOps.STARTWITH -> {    // 以指定字符串开始
+                return if (argName.indexOf("#") > 0) {
+                    "($argName)::TEXT LIKE ($argValue || '%')"
+                } else {
+                    "$argName LIKE ($argValue || '%')"
+                }
+            }
+            SOps.ENDWITH -> {    // 以指定字符串结束
+                return if (argName.indexOf("#") > 0) {
+                    "($argName)::TEXT LIKE ('%' || $argValue)"
+                } else {
+                    "$argName LIKE ('%' || $argValue)"
+                }
+            }
+            SOps.ISNULL -> {     // 为空
+                return "$argName ISNULL"
+            }
+            else -> {
+            }
+        }
+        return ""
+    } // Fun whereArg()
+
+    /**
+     * 转换参数名SQL语句
+     *
+     * @param   name        字段名
+     * @param   path        json路径。如果不是json对象,则该值为空
+     * @return  转换后的SQL
+     */
+    override fun argName(name: String, path: String?): String {
+        return if (path == null) {
+            "\"$name\""
+        } else {
+            val p = path.replace(".", ",")
+            "\"$name\"#>'{$p}'"
+        }
+    } // Fun argName()
+
+    /**
+     * 转换参数值SQL语句
+     *
+     * @param   argName     参数名
+     * @param   isJson      是否Json对象
+     * @return  转换后的SQL
+     */
+    override fun argValue(argName: String, isJson: Boolean): String {
+        return if (isJson) {
+            "to_jsonb(#{whereArgs.$argName})"
+        } else {
+            "#{whereArgs.$argName}"
+        }
+    } // Fun argValue()
+
+    /**
+     * 转换IN条件表达式
+     *
+     * @param   name        字段名
+     * @param   path        json路径,如果字段不为json,则path为null
+     * @param   inArg       in操作参数
+     * @return  转换后的SQL
+     */
+    override fun inArg(name: String, path: String?, inArg: String): String {
+        return if (path == null) {
+            "\"$name\" IN ($inArg)"
+        } else {
+            val p = path.replace(".", ",")
+            "\"$name\"#>'{$p}' IN ($inArg)"
+        }
+    } // Fun inArg()
+
+    /**
+     * 将名称及json路径转换为SQL
+     *
+     * @param   name        字段名
+     * @param   path        json路径,如果字段不为json,则path为null
+     * @return   转换后的SQL
+     */
+    override fun columnName(name: String, path: String?): String {
+        return if (path == null) {
+            "\"$name\""
+        } else {
+            val p = path.replace(".", ",")
+            "\"$name\"#>'{$p}'"
+        }
+    }
+
+    /**
+     * 将参数值转换为SQL语句
+     *
+     * @param   value       值
+     * @param   isJson      值是否转换为json格式
+     * @return  转换后的SQL
+     */
+    override fun argValueToJson(value: String, isJson: Boolean): String {
+        return if (isJson) {
+            "to_jsonb($value)"
+        } else {
+            value
+        }
+    } // Fun argValueToJson()
+
+    /**
+     * 更新Json类型字段
+     *
+     * @param   name        字段名
+     * @param   value       值
+     * @return  更新SQL字符串
+     */
+    override fun updateJson(name: String, value: Any): String {
+        return "COALESCE(\"$name\", '{}') || '${value.toJsonAll().replace("'", "''")}'"
+    } // Fun updateJson()
+
+
+} // Class SMySqlDriver

+ 30 - 0
settings.gradle

@@ -0,0 +1,30 @@
+/*
+ * ********************************************************************************************************************
+ *
+ *               iFHS7.
+ *              ;BBMBMBMc                  rZMBMBR              BMB
+ *              MBEr:;PBM,               7MBMMEOBB:             BBB                       RBW
+ *     XK:      BO     SB.     :SZ       MBM.       c;;     ir  BBM :FFr       :SSF:    ;xBMB:r   iuGXv.    i:. iF2;
+ *     DBBM0r.  :D     S7   ;XMBMB       GMBMu.     MBM:   BMB  MBMBBBMBMS   WMBMBMBBK  MBMBMBM  BMBRBMBW  .MBMBMBMBB
+ *      :JMRMMD  ..    ,  1MMRM1;         ;MBMBBR:   MBM  ;MB:  BMB:   MBM. RMBr   sBMH   BM0         UMB,  BMB.  KMBv
+ *     ;.   XOW  B1; :uM: 1RE,   i           .2BMBs  rMB. MBO   MBO    JMB; MBB     MBM   BBS    7MBMBOBM:  MBW   :BMc
+ *     OBRJ.SEE  MRDOWOR, 3DE:7OBM       .     ;BMB   RMR7BM    BMB    MBB. BMB    ,BMR  .BBZ   MMB   rMB,  BMM   rMB7
+ *     :FBRO0D0  RKXSXPR. JOKOOMPi       BMBSSWBMB;    BMBB:    MBMB0ZMBMS  .BMBOXRBMB    MBMDE RBM2;SMBM;  MBB   xBM2
+ *         iZGE  O0SHSPO. uGZ7.          sBMBMBDL      :BMO     OZu:BMBK,     rRBMB0;     ,EBMB  xBMBr:ER.  RDU   :OO;
+ *     ,BZ, 1D0  RPSFHXR. xWZ .SMr                  . .BBB
+ *      :0BMRDG  RESSSKR. 2WOMBW;                   BMBMR
+ *         i0BM: SWKHKGO  MBDv
+ *           .UB  OOGDM. MK,                                          Copyright (c) 2015-2019.  斯伯坦机器人
+ *              ,  XMW  ..
+ *                  r                                                                     All rights reserved.
+ *
+ * ********************************************************************************************************************
+ */
+
+rootProject.name = 'persagy-kotlin'
+
+include 'persagy-kotlin-base'
+include 'persagy-kotlin-database'
+include 'persagy-kotlin-mybatis'
+include 'persagy-kotlin-mysql'
+include 'persagy-kotlin-postgresql'