wangming 1 سال پیش
کامیت
84ba6901e4
100فایلهای تغییر یافته به همراه12789 افزوده شده و 0 حذف شده
  1. 202 0
      LICENSE
  2. 252 0
      README-zh.md
  3. 243 0
      README.md
  4. 206 0
      common/pom.xml
  5. 103 0
      common/src/main/java/com/xc/common/api/ResponseVO.java
  6. 146 0
      common/src/main/java/com/xc/common/config/redis/RedisCacheService.java
  7. 74 0
      common/src/main/java/com/xc/common/config/redis/RedisConfig.java
  8. 134 0
      common/src/main/java/com/xc/common/config/redis/RedisQueueService.java
  9. 81 0
      common/src/main/java/com/xc/common/config/swagger/SwaggerConfig.java
  10. 69 0
      common/src/main/java/com/xc/common/constant/SysConstant.java
  11. 118 0
      common/src/main/java/com/xc/common/exception/InterfaceRequestErrorAndPerformanceLog.java
  12. 12 0
      common/src/main/java/com/xc/common/exception/ServiceException.java
  13. 40 0
      common/src/main/java/com/xc/common/utils/JsonUtil.java
  14. 27 0
      common/src/test/resources/templates/myServiceImpl.java.vm
  15. 53 0
      luckysheet-db/pom.xml
  16. 223 0
      luckysheet-db/src/main/java/com/xc/luckysheet/JfGridConfigModel.java
  17. 35 0
      luckysheet-db/src/main/java/com/xc/luckysheet/Test.java
  18. 34 0
      luckysheet-db/src/main/java/com/xc/luckysheet/db/IRecordDataInsertHandle.java
  19. 154 0
      luckysheet-db/src/main/java/com/xc/luckysheet/db/IRecordDataUpdataHandle.java
  20. 37 0
      luckysheet-db/src/main/java/com/xc/luckysheet/db/IRecordDelHandle.java
  21. 115 0
      luckysheet-db/src/main/java/com/xc/luckysheet/db/IRecordSelectHandle.java
  22. 57 0
      luckysheet-db/src/main/java/com/xc/luckysheet/entity/GridRecordDataModel.java
  23. 370 0
      luckysheet-db/src/main/java/com/xc/luckysheet/util/JfGridFileUtil.java
  24. 87 0
      luckysheet-db/src/main/java/com/xc/luckysheet/util/SnowFlake.java
  25. 86 0
      luckysheet-mongo/README-zh.md
  26. 69 0
      luckysheet-mongo/pom.xml
  27. 245 0
      luckysheet-mongo/src/main/java/com/xc/luckysheet/mongo/impl/BaseHandle.java
  28. 72 0
      luckysheet-mongo/src/main/java/com/xc/luckysheet/mongo/impl/RecordDataInsertHandle.java
  29. 439 0
      luckysheet-mongo/src/main/java/com/xc/luckysheet/mongo/impl/RecordDataUpdataHandle.java
  30. 85 0
      luckysheet-mongo/src/main/java/com/xc/luckysheet/mongo/impl/RecordDelHandle.java
  31. 376 0
      luckysheet-mongo/src/main/java/com/xc/luckysheet/mongo/impl/RecordSelectHandle.java
  32. 93 0
      luckysheet-mysql/README-zh.md
  33. 81 0
      luckysheet-mysql/pom.xml
  34. BIN
      luckysheet-mysql/src/.DS_Store
  35. BIN
      luckysheet-mysql/src/main/.DS_Store
  36. BIN
      luckysheet-mysql/src/main/java/.DS_Store
  37. BIN
      luckysheet-mysql/src/main/java/com/.DS_Store
  38. BIN
      luckysheet-mysql/src/main/java/com/xc/.DS_Store
  39. BIN
      luckysheet-mysql/src/main/java/com/xc/luckysheet/.DS_Store
  40. BIN
      luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/.DS_Store
  41. 35 0
      luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/datasource/DataSourceConfig.java
  42. 30 0
      luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/datasource/JdbcTempleConfig.java
  43. 49 0
      luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/datasource/ProfiledemoApplication.java
  44. 72 0
      luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/impl/BaseHandle.java
  45. 134 0
      luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/impl/RecordDataInsertHandle.java
  46. 561 0
      luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/impl/RecordDataUpdataHandle.java
  47. 83 0
      luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/impl/RecordDelHandle.java
  48. 397 0
      luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/impl/RecordSelectHandle.java
  49. 138 0
      luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/test/TestTransaction1.java
  50. 58 0
      luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/test/TestTransaction2.java
  51. 53 0
      luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/test/TestTransaction3.java
  52. 54 0
      luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/test/TestTransaction4.java
  53. 42 0
      luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/test/TestTransaction51.java
  54. 30 0
      luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/test/TestTransaction52.java
  55. 6 0
      luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/testinvocationhandler/test1/People.java
  56. 14 0
      luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/testinvocationhandler/test1/Student.java
  57. 41 0
      luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/testinvocationhandler/test1/Test.java
  58. 37 0
      luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/testinvocationhandler/test1/WorkHandler.java
  59. 40 0
      luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/testinvocationhandler/test1/WorkHandler2.java
  60. BIN
      luckysheet-mysql/src/test/.DS_Store
  61. 82 0
      luckysheet-postgre/pom.xml
  62. 35 0
      luckysheet-postgre/src/main/java/com/xc/luckysheet/postgres/datasource/DataSourceConfig.java
  63. 30 0
      luckysheet-postgre/src/main/java/com/xc/luckysheet/postgres/datasource/JdbcTempleConfig.java
  64. 49 0
      luckysheet-postgre/src/main/java/com/xc/luckysheet/postgres/datasource/ProfiledemoApplication.java
  65. 16 0
      luckysheet-postgre/src/main/java/com/xc/luckysheet/postgres/impl/BaseHandle.java
  66. 161 0
      luckysheet-postgre/src/main/java/com/xc/luckysheet/postgres/impl/RecordDataInsertHandle.java
  67. 523 0
      luckysheet-postgre/src/main/java/com/xc/luckysheet/postgres/impl/RecordDataUpdataHandle.java
  68. 84 0
      luckysheet-postgre/src/main/java/com/xc/luckysheet/postgres/impl/RecordDelHandle.java
  69. 416 0
      luckysheet-postgre/src/main/java/com/xc/luckysheet/postgres/impl/RecordSelectHandle.java
  70. 199 0
      luckysheet/pom.xml
  71. 63 0
      luckysheet/read.txt
  72. 50 0
      luckysheet/src/main/java/com/xc/luckysheet/WebApplication.java
  73. 202 0
      luckysheet/src/main/java/com/xc/luckysheet/controller/JfGridFileController.java
  74. 207 0
      luckysheet/src/main/java/com/xc/luckysheet/controller/TestController.java
  75. 223 0
      luckysheet/src/main/java/com/xc/luckysheet/db/server/JfGridFileGetService.java
  76. 2316 0
      luckysheet/src/main/java/com/xc/luckysheet/db/server/JfGridUpdateService.java
  77. 19 0
      luckysheet/src/main/java/com/xc/luckysheet/entity/BaseModel.java
  78. 41 0
      luckysheet/src/main/java/com/xc/luckysheet/entity/BaseOperationModel.java
  79. 102 0
      luckysheet/src/main/java/com/xc/luckysheet/entity/ConfigMergeModel.java
  80. 28 0
      luckysheet/src/main/java/com/xc/luckysheet/entity/LuckySheetGridModel.java
  81. 9 0
      luckysheet/src/main/java/com/xc/luckysheet/entity/Test.java
  82. 42 0
      luckysheet/src/main/java/com/xc/luckysheet/entity/enummodel/DisabledTypeEnum.java
  83. 73 0
      luckysheet/src/main/java/com/xc/luckysheet/entity/enummodel/ExcelCenterStyleEnum.java
  84. 17 0
      luckysheet/src/main/java/com/xc/luckysheet/entity/enummodel/OperationTypeEnum.java
  85. 44 0
      luckysheet/src/main/java/com/xc/luckysheet/entity/enummodel/SheetOperationEnum.java
  86. 46 0
      luckysheet/src/main/java/com/xc/luckysheet/entity/project/AssembleCellParam.java
  87. 41 0
      luckysheet/src/main/java/com/xc/luckysheet/entity/project/ProjectSummaryParamExcelDto.java
  88. 38 0
      luckysheet/src/main/java/com/xc/luckysheet/entity/project/SheetConfigResultDto.java
  89. 23 0
      luckysheet/src/main/java/com/xc/luckysheet/entity/project/SheetInfoParam.java
  90. 33 0
      luckysheet/src/main/java/com/xc/luckysheet/mapper/TestDao.java
  91. 119 0
      luckysheet/src/main/java/com/xc/luckysheet/redisserver/GridFileRedisCacheService.java
  92. 179 0
      luckysheet/src/main/java/com/xc/luckysheet/redisserver/RedisLock.java
  93. 47 0
      luckysheet/src/main/java/com/xc/luckysheet/redisserver/RedisMessageListener.java
  94. 61 0
      luckysheet/src/main/java/com/xc/luckysheet/redisserver/RedisMessageModel.java
  95. 42 0
      luckysheet/src/main/java/com/xc/luckysheet/redisserver/RedisMessagePublish.java
  96. 38 0
      luckysheet/src/main/java/com/xc/luckysheet/service/ConfigerService.java
  97. 38 0
      luckysheet/src/main/java/com/xc/luckysheet/service/ScheduleService.java
  98. 87 0
      luckysheet/src/main/java/com/xc/luckysheet/utils/GzipHandle.java
  99. 674 0
      luckysheet/src/main/java/com/xc/luckysheet/utils/LuckySheet4SummaryHelp.java
  100. 0 0
      luckysheet/src/main/java/com/xc/luckysheet/utils/MyStringUtil.java

+ 202 - 0
LICENSE

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

+ 252 - 0
README-zh.md

@@ -0,0 +1,252 @@
+# Luckysheet Server
+
+简体中文 | [English](./README.md)
+
+## 介绍
+💻[Luckysheet](https://gitee.com/mengshukeji/Luckysheet/) 官方Java版本后台。
+
+## 演示
+- [协同编辑Demo](http://luckysheet.lashuju.com/demo/)(注意:请大家别操作频繁,防止搞崩服务器)
+
+## 部署
+- [LuckysheetServer Starter](https://github.com/mengshukeji/LuckysheetServerStarter)
+
+## 环境
+
+jdk >= 1.8
+
+postgre >= 10 (支持jsonb的版本)
+- [Docker部署postgre](https://www.cnblogs.com/xuchen0117/p/13863509.html)
+- [postgre中jsonb字段处理](https://www.cnblogs.com/xuchen0117/p/13890710.html)
+
+redis >= 3
+- [Docker部署Redis](https://www.cnblogs.com/xuchen0117/p/12183399.html)
+- [Docker部署Redis集群](https://www.cnblogs.com/xuchen0117/p/11678931.html)
+
+
+nginx >= 1.12
+- [Docker部署Nginx](https://www.cnblogs.com/xuchen0117/p/11934202.html)
+
+maven >= 3.6 
+
+IntelliJ IDEA >= 12 (非必须)
+
+## 数据库初始化
+
+创建数据库
+```
+CREATE DATABASE luckysheetdb
+```
+创建序列
+```
+DROP SEQUENCE IF EXISTS "public"."luckysheet_id_seq";
+CREATE SEQUENCE "public"."luckysheet_id_seq"
+INCREMENT 1
+MINVALUE  1
+MAXVALUE 9999999999999
+START 1
+CACHE 10;
+```
+创建表
+```
+DROP TABLE IF EXISTS "public"."luckysheet";
+CREATE TABLE "luckysheet" (
+  "id" int8 NOT NULL,
+  "block_id" varchar(200) COLLATE "pg_catalog"."default" NOT NULL,
+  "row_col" varchar(50),
+  "index" varchar(200) COLLATE "pg_catalog"."default" NOT NULL,
+  "list_id" varchar(200) COLLATE "pg_catalog"."default" NOT NULL,
+  "status" int2 NOT NULL,
+  "json_data" jsonb,
+  "order" int2,
+  "is_delete" int2
+);
+CREATE INDEX "block_id" ON "public"."luckysheet" USING btree (
+  "block_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
+  "list_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
+);
+CREATE INDEX "index" ON "public"."luckysheet" USING btree (
+  "index" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
+  "list_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
+);
+CREATE INDEX "is_delete" ON "public"."luckysheet" USING btree (
+  "is_delete" "pg_catalog"."int2_ops" ASC NULLS LAST
+);
+CREATE INDEX "list_id" ON "public"."luckysheet" USING btree (
+  "list_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
+);
+CREATE INDEX "order" ON "public"."luckysheet" USING btree (
+  "list_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
+  "order" "pg_catalog"."int2_ops" ASC NULLS LAST
+);
+CREATE INDEX "status" ON "public"."luckysheet" USING btree (
+  "list_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
+  "status" "pg_catalog"."int2_ops" ASC NULLS LAST
+);
+ALTER TABLE "public"."luckysheet" ADD CONSTRAINT "luckysheet_pkey" PRIMARY KEY ("id");
+```
+
+插入初始化语句
+```
+INSERT INTO "public"."luckysheet" VALUES (nextval('luckysheet_id_seq'), 'fblock', '', '1', '1079500#-8803#7c45f52b7d01486d88bc53cb17dcd2c3', 1, '{"row":84,"name":"Sheet1","chart":[],"color":"","index":"1","order":0,"column":60,"config":{},"status":0,"celldata":[],"ch_width":4748,"rowsplit":[],"rh_height":1790,"scrollTop":0,"scrollLeft":0,"visibledatarow":[],"visibledatacolumn":[],"jfgird_select_save":[],"jfgrid_selection_range":{}}', 0, 0);
+INSERT INTO "public"."luckysheet" VALUES (nextval('luckysheet_id_seq'), 'fblock', '', '2', '1079500#-8803#7c45f52b7d01486d88bc53cb17dcd2c3', 0, '{"row":84,"name":"Sheet2","chart":[],"color":"","index":"2","order":1,"column":60,"config":{},"status":0,"celldata":[],"ch_width":4748,"rowsplit":[],"rh_height":1790,"scrollTop":0,"scrollLeft":0,"visibledatarow":[],"visibledatacolumn":[],"jfgird_select_save":[],"jfgrid_selection_range":{}}', 1, 0);
+INSERT INTO "public"."luckysheet" VALUES (nextval('luckysheet_id_seq'), 'fblock', '', '3', '1079500#-8803#7c45f52b7d01486d88bc53cb17dcd2c3', 0, '{"row":84,"name":"Sheet3","chart":[],"color":"","index":"3","order":2,"column":60,"config":{},"status":0,"celldata":[],"ch_width":4748,"rowsplit":[],"rh_height":1790,"scrollTop":0,"scrollLeft":0,"visibledatarow":[],"visibledatacolumn":[],"jfgird_select_save":[],"jfgrid_selection_range":{}}', 2, 0);
+```
+
+## nginx配置 
+http块配置
+```
+#websocket配置
+map $http_upgrade $connection_upgrade {
+    default upgrade;
+    ''      close;
+}
+
+upstream ws_dataluckysheet {
+      server 项目的ip:端口;
+}    
+```
+server块配置
+```
+#websocket配置
+location /luckysheet/websocket/luckysheet {
+    proxy_pass http://ws_dataluckysheet/luckysheet/websocket/luckysheet;
+
+    proxy_set_header Host $host;
+    proxy_set_header X-real-ip $remote_addr;
+    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+
+    #websocket
+    proxy_http_version 1.1;
+    proxy_set_header Upgrade $http_upgrade;
+    proxy_set_header Connection "upgrade";
+}       
+
+#动态资源配置
+location /luckysheet/ {
+    proxy_pass http://ws_dataluckysheet;
+}
+
+#静态资源配置,Luckysheet前端代码目录
+location / {
+    root   /usr/share/nginx/html; # 可修改为自己的资源路径
+    index  index.html index.htm;
+}
+```
+
+### 访问测试
+
+- 通过`项目的ip:端口`访问静态主页
+- 通过`项目的ip:端口?share`访问协同编辑主页
+
+## 项目用法 
+application.yml 项目配置
+```
+server:
+  port: 项目端口
+  servlet:
+    context-path: /项目路径
+redis.channel: redis通道名称
+row_size: 表格中行数 默认500
+col_size: 表格中列数 默认500
+pgSetUp: 是否启用pgsql作为存储数据(0为是,1为否)目前只能设置为0
+```
+application-dev.yml 数据库配置
+```
+spring:
+  redis:
+    host: ip地址
+    port: 端口
+    password: 密码
+    
+db:
+  postgre:
+    druid:
+      url: jdbc:postgresql://ip地址:端口/luckysheetdb?useSSL=false
+      driverClassName: org.postgresql.Driver
+      username: 用户名
+      password: 密码    
+```
+logback-spring.xml 日志配置
+```
+ <property name="log.path" value="日志输出目录"/>
+```
+## 项目说明
+
+### Luckysheet模块主要类说明
+com.xc.luckysheet.WebApplication 项目启动类
+
+com.xc.luckysheet.controller
+```
+JfGridFileController 表格数据加载类
+TestController  postgre redis 测试类 
+```
+com.xc.luckysheet.entity
+```
+SheetOperationEnum 表格操作类型
+JfGridConfigModel 表格块对象
+LuckySheetGridModel 表格数据库对象
+PgGridDataModel 表格sheet数据库对象
+```
+com.xc.luckysheet.postgre
+```
+PostgresGridFileDao postgre数据库操作
+PostgresGridFileGetService 记录操作
+PostgresJfGridUpdateService 更新处理
+```
+com.xc.luckysheet.redisserver
+```
+RedisLock redis锁
+RedisMessageListener 管道监听类
+RedisMessagePublish 管道发布类
+```
+com.xc.luckysheet.service
+```
+ConfigerService 配置类
+ScheduleService 对定时数据库初始化
+```
+com.xc.luckysheet.utils
+```
+GzipHandle 信息压缩
+Pako_GzipUtils WebSocket信息压缩
+```
+com.xc.luckysheet.websocket
+```
+IpAndPortUtil 获取当前服务的ip与端口
+MyWebSocketHandler Socket处理器(包括发送信息,接收信息,信息错误等方法。)
+MyWebSocketInterceptor Socket建立连接(握手)和断开
+WebSocketConfig 注册WebSocket,设置WebSocket的地址
+WSUserModel WebSocket对象
+```
+
+### common模块主要类说明
+```
+com.xc.common.config.datasource.DataSourceConfig 数据源配置类
+com.xc.common.config.redis.RedisConfig redis配置类
+```
+
+### websocket 返回数据格式
+```
+{
+    createTime: 命令发送时间
+    data:{} 修改的命令
+    id: "7a"   websocket的id
+    returnMessage: "success"
+    status: "0"  0告诉前端需要根据data的命令修改  1无意义
+    type: 0:连接成功,1:发送给当前连接的用户,2:发送信息给其他用户,3:发送选区位置信息,999:用户连接断开
+    username: 用户名
+}
+```
+
+## 相关链接
+- [Luckysheet官方文档](https://mengshukeji.gitee.io/LuckysheetDocs/)
+- [Luckysheet如何把表格里的数据保存到数据库](https://www.cnblogs.com/DuShuSir/p/13857874.html)
+
+## 贡献者和感谢
+
+### 团队
+- [@iamxuchen800117](https://github.com/iamxuchen800117)
+- [@wpxp123456](https://github.com/wpxp123456)
+
+## 版权信息
+有关详细信息,请查阅附件的[LICENSE](./LICENSE)文件。原始作者保留Apache 2.0许可未明确授予的所有权利。

+ 243 - 0
README.md

@@ -0,0 +1,243 @@
+# Luckysheet Server
+
+English| [简体中文](./README-zh.md)
+
+## Introduction
+💻[Luckysheet](https://github.com/mengshukeji/Luckysheet/) official Java version backend.
+
+## Demo
+- [Cooperative editing demo](http://luckysheet.lashuju.com/demo/)(Note: Please do not operate frequently to prevent the server from crashing)
+
+## Development
+
+[Use MySQL Tutorial for Beginners](https://github.com/mengshukeji/LuckysheetServer/wiki/Use-MySQL-Tutorial-for-Beginners)
+
+## Deploy
+- [LuckysheetServer Starter](https://github.com/mengshukeji/LuckysheetServerStarter)
+
+## Requirements
+
+jdk >= 1.8
+
+postgre >= 10 (Support jsonb version)
+- [Docker deploys postgre](https://www.cnblogs.com/xuchen0117/p/13863509.html)
+- [Jsonb field processing in postgre](https://www.cnblogs.com/xuchen0117/p/13890710.html)
+
+redis >= 3
+- [Docker deploys Redis](https://www.cnblogs.com/xuchen0117/p/12183399.html)
+- [Docker deploys Redis cluster](https://www.cnblogs.com/xuchen0117/p/11678931.html)
+
+
+nginx >= 1.12
+- [Docker deploys Nginx](https://www.cnblogs.com/xuchen0117/p/11934202.html)
+
+maven >= 3.6 
+
+IntelliJ IDEA >= 12 (not necessary)
+
+## Database initialization
+
+Create database
+```
+CREATE DATABASE luckysheetdb
+```
+Create sequence
+```
+DROP SEQUENCE IF EXISTS "public"."luckysheet_id_seq";
+CREATE SEQUENCE "public"."luckysheet_id_seq"
+INCREMENT 1
+MINVALUE  1
+MAXVALUE 9999999999999
+START 1
+CACHE 10;
+```
+Create table
+```
+DROP TABLE IF EXISTS "public"."luckysheet";
+CREATE TABLE "luckysheet" (
+  "id" int8 NOT NULL,
+  "block_id" varchar(200) COLLATE "pg_catalog"."default" NOT NULL,
+  "row_col" varchar(50),
+  "index" varchar(200) COLLATE "pg_catalog"."default" NOT NULL,
+  "list_id" varchar(200) COLLATE "pg_catalog"."default" NOT NULL,
+  "status" int2 NOT NULL,
+  "json_data" jsonb,
+  "order" int2,
+  "is_delete" int2
+);
+CREATE INDEX "block_id" ON "public"."luckysheet" USING btree (
+  "block_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
+  "list_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
+);
+CREATE INDEX "index" ON "public"."luckysheet" USING btree (
+  "index" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
+  "list_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
+);
+CREATE INDEX "is_delete" ON "public"."luckysheet" USING btree (
+  "is_delete" "pg_catalog"."int2_ops" ASC NULLS LAST
+);
+CREATE INDEX "list_id" ON "public"."luckysheet" USING btree (
+  "list_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
+);
+CREATE INDEX "order" ON "public"."luckysheet" USING btree (
+  "list_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
+  "order" "pg_catalog"."int2_ops" ASC NULLS LAST
+);
+CREATE INDEX "status" ON "public"."luckysheet" USING btree (
+  "list_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
+  "status" "pg_catalog"."int2_ops" ASC NULLS LAST
+);
+ALTER TABLE "public"."luckysheet" ADD CONSTRAINT "luckysheet_pkey" PRIMARY KEY ("id");
+```
+
+Insert initialization statement
+```
+INSERT INTO "public"."luckysheet" VALUES (nextval('luckysheet_id_seq'), 'fblock', '', '1', '1079500#-8803#7c45f52b7d01486d88bc53cb17dcd2c3', 1, '{"row":84,"name":"Sheet1","chart":[],"color":"","index":"1","order":0,"column":60,"config":{},"status":0,"celldata":[],"ch_width":4748,"rowsplit":[],"rh_height":1790,"scrollTop":0,"scrollLeft":0,"visibledatarow":[],"visibledatacolumn":[],"jfgird_select_save":[],"jfgrid_selection_range":{}}', 0, 0);
+INSERT INTO "public"."luckysheet" VALUES (nextval('luckysheet_id_seq'), 'fblock', '', '2', '1079500#-8803#7c45f52b7d01486d88bc53cb17dcd2c3', 0, '{"row":84,"name":"Sheet2","chart":[],"color":"","index":"2","order":1,"column":60,"config":{},"status":0,"celldata":[],"ch_width":4748,"rowsplit":[],"rh_height":1790,"scrollTop":0,"scrollLeft":0,"visibledatarow":[],"visibledatacolumn":[],"jfgird_select_save":[],"jfgrid_selection_range":{}}', 1, 0);
+INSERT INTO "public"."luckysheet" VALUES (nextval('luckysheet_id_seq'), 'fblock', '', '3', '1079500#-8803#7c45f52b7d01486d88bc53cb17dcd2c3', 0, '{"row":84,"name":"Sheet3","chart":[],"color":"","index":"3","order":2,"column":60,"config":{},"status":0,"celldata":[],"ch_width":4748,"rowsplit":[],"rh_height":1790,"scrollTop":0,"scrollLeft":0,"visibledatarow":[],"visibledatacolumn":[],"jfgird_select_save":[],"jfgrid_selection_range":{}}', 2, 0);
+```
+
+## nginx configuration 
+http block configuration
+```
+#websocket configuration
+map $http_upgrade $connection_upgrade {
+    default upgrade;
+    ''      close;
+}
+
+upstream ws_dataluckysheet {
+      server [Project ip]: [port];
+}    
+```
+server block configuration
+```
+#websocket configuration
+location /luckysheet/websocket/luckysheet {
+    proxy_pass http://ws_dataluckysheet/luckysheet/websocket/luckysheet;
+
+    proxy_set_header Host $host;
+    proxy_set_header X-real-ip $remote_addr;
+    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+
+    #websocket
+    proxy_http_version 1.1;
+    proxy_set_header Upgrade $http_upgrade;
+    proxy_set_header Connection "upgrade";
+}       
+
+#Dynamic resource configuration
+location /luckysheet/ {
+    proxy_pass http://ws_dataluckysheet;
+}
+
+#Static resource configuration
+location /luckysheet/demo/ {
+    root /usr/share/nginx/html;
+    index  index.html index.htm;
+}
+```
+
+### Access test
+
+- Access the static homepage through `[project ip]:[port]`
+- Access the collaborative editing homepage through `[project ip]:[port]?share`
+
+## Project usage 
+application.yml Project configuration
+```
+server:
+  port: [Project port]
+  servlet:
+    context-path: /[Project path]
+redis.channel: [redis channel name]
+row_size: [The number of rows in the table, default 500]
+col_size: [Number of columns in the table, default 500]
+pgSetUp: [Whether to enable pgsql as storage data (0 for yes, 1 for no), currently can only be set to 0]
+```
+application-dev.yml Database configuration
+```
+spring:
+  redis:
+    host: [ip address]
+    port: [port]
+    password: [password]
+    
+db:
+  postgre:
+    druid:
+      url: jdbc:postgresql://[ip address]: [port]/luckysheetdb?useSSL=false
+      driverClassName: org.postgresql.Driver
+      username: [username]
+      password: [password]    
+```
+logback-spring.xml Log configuration
+```
+ <property name="log.path" value="[Log output directory]"/>
+```
+## project instruction
+
+### Luckysheet module main class description
+com.xc.luckysheet.WebApplication Project startup
+
+com.xc.luckysheet.controller
+```
+JfGridFileController Table data loading class
+TestController  postgre redis Test class 
+```
+com.xc.luckysheet.entity
+```
+SheetOperationEnum Table operation type
+JfGridConfigModel Table block object
+LuckySheetGridModel Tabular database objects
+PgGridDataModel Table database object
+```
+com.xc.luckysheet.postgre
+```
+PostgresGridFileDao postgre database operation
+PostgresGridFileGetService Record operation
+PostgresJfGridUpdateService Update processing
+```
+com.xc.luckysheet.redisserver
+```
+RedisLock redis lock
+RedisMessageListener Pipeline monitoring class
+RedisMessagePublish Pipeline release class
+```
+com.xc.luckysheet.service
+```
+ConfigerService Configuration class
+ScheduleService Initialize the timing database
+```
+com.xc.luckysheet.utils
+```
+GzipHandle Information compression
+Pako_GzipUtils WebSocket information compression
+```
+com.xc.luckysheet.websocket
+```
+IpAndPortUtil Get the IP and port of the current service
+MyWebSocketHandler Socket processor (including methods for sending information, receiving information, and information errors.)
+MyWebSocketInterceptor Socket connection (handshake) and disconnection
+WebSocketConfig Register WebSocket, Set the address of WebSocket
+WSUserModel WebSocket object
+```
+
+### Main class description of common module
+```
+com.xc.common.config.datasource.DataSourceConfig Data source configuration class
+com.xc.common.config.redis.RedisConfig redis configuration class
+```
+
+## Links
+- [Luckysheet Documentation](https://mengshukeji.github.io/LuckysheetDocs/)
+- [How Luckysheet saves the data in the table to the database](https://www.cnblogs.com/DuShuSir/p/13857874.html)
+
+## Authors and acknowledgment
+
+### Team
+- [@iamxuchen800117](https://github.com/iamxuchen800117)
+- [@wpxp123456](https://github.com/wpxp123456)
+
+## License
+Please consult the attached [LICENSE](./LICENSE) file for details. All rights not explicitly granted by the Apache 2.0 License are reserved by the Original Author.

+ 206 - 0
common/pom.xml

@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>luckySheetServer</artifactId>
+        <groupId>com.xc</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.xc</groupId>
+    <artifactId>common</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <packaging>jar</packaging>
+    <name>common</name>
+    <description>公共核心核心包</description>
+
+    <dependencies>
+        <!--自动生成set get方法-->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>false</optional>
+        </dependency>
+        <!-- 工具包 -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.8.1</version>
+        </dependency>
+
+        <!-- 热部署开发工具 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-web</artifactId>
+            <version>5.1.6.RELEASE</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-webmvc</artifactId>
+            <version>5.1.6.RELEASE</version>
+        </dependency>
+
+        <!--GSON  -->
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+            <version>2.2.4</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.tomcat.embed</groupId>
+            <artifactId>tomcat-embed-core</artifactId>
+        </dependency>
+
+        <!--阿里的druid数据源-->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid</artifactId>
+            <version>1.1.20</version>
+        </dependency>
+        <!-- mybatis -->
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+            <version>3.3.0</version>
+        </dependency>
+        <!-- mybatis 代码自动生成 <optional>true</optional>只在当前jar生效-->
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-generator</artifactId>
+            <version>3.3.0</version>
+            <optional>true</optional>
+        </dependency>
+        <!-- 添加 模板引擎 依赖,MyBatis-Plus 支持 Velocity(默认) -->
+        <dependency>
+            <groupId>org.apache.velocity</groupId>
+            <artifactId>velocity-engine-core</artifactId>
+            <version>2.1</version>
+            <optional>true</optional>
+        </dependency>
+        <!-- mysql -->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+        <!-- postgresql  -->
+        <dependency>
+            <groupId>org.postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+            <version>42.1.1</version><!--$NO-MVN-MAN-VER$-->
+        </dependency>
+
+        <!-- xml start -->
+        <dependency>
+            <groupId>com.thoughtworks.xstream</groupId>
+            <artifactId>xstream</artifactId>
+            <version>1.4.9</version>
+        </dependency>
+        <dependency>
+            <groupId>joda-time</groupId>
+            <artifactId>joda-time</artifactId>
+            <version>2.9.7</version>
+        </dependency>
+        <dependency>
+            <groupId>org.dom4j</groupId>
+            <artifactId>dom4j</artifactId>
+            <version>2.1.1</version>
+        </dependency>
+        <!-- xml end -->
+
+
+        <!-- swagger -->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+            <version>2.9.2</version>
+        </dependency>
+        <!-- swagger-ui -->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+            <version>2.9.2</version>
+        </dependency>
+        <!--整合Knife4j-->
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>knife4j-spring-boot-starter</artifactId>
+            <version>2.0.4</version>
+        </dependency>
+
+        <!-- jackson相关依赖 -->
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>2.5.4</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml</groupId>
+            <artifactId>classmate</artifactId>
+            <version>1.2.0</version>
+        </dependency>
+
+
+        <!-- 解决maven打包 错误: 程序包com.sun.istack.internal不存在 - BBSMAX -->
+        <dependency>
+            <groupId>com.sun.xml.bind</groupId>
+            <artifactId>jaxb-impl</artifactId>
+            <version>2.2.11</version>
+        </dependency>
+        <dependency>
+            <groupId>org.jetbrains</groupId>
+            <artifactId>annotations</artifactId>
+            <version>13.0</version>
+        </dependency>
+        <!-- 解决maven打包 错误: 程序包com.sun.istack.internal不存在 - BBSMAX -->
+
+        <!-- redis -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+        <!-- 给redis集群用的Lettuce的连接池 -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-pool2</artifactId>
+        </dependency>
+
+        <!-- 邮件 -->
+        <dependency>
+            <groupId>javax.mail</groupId>
+            <artifactId>mail</artifactId>
+            <version>1.4.7</version>
+        </dependency>
+
+
+        <!--JWT-->
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt</artifactId>
+            <version>0.9.0</version>
+        </dependency>
+
+        <!--引入AOP依赖-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>javax.validation</groupId>
+            <artifactId>validation-api</artifactId>
+        </dependency>
+
+
+    </dependencies>
+
+
+</project>

+ 103 - 0
common/src/main/java/com/xc/common/api/ResponseVO.java

@@ -0,0 +1,103 @@
+package com.xc.common.api;
+
+
+import com.xc.common.constant.SysConstant;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.NotNull;
+
+import java.io.Serializable;
+
+/**
+ * 返回对象
+ * @author Administrator
+ */
+@Data
+@ApiModel(value = "请求返回类",description = "请求响应参数")
+public class ResponseVO implements Serializable {
+
+    private static final long serialVersionUID = 1l;
+
+
+    /**
+     * 消息状态
+     */
+    @NotNull
+    @ApiModelProperty(value = "status",example = StringUtils.EMPTY)
+    private String status = StringUtils.EMPTY;
+
+    /**
+     * 交互结果消息描述
+     */
+    @NotNull
+    @ApiModelProperty(value = "msg",example = StringUtils.EMPTY)
+    private String msg = StringUtils.EMPTY;
+
+    /**
+     * 消息体
+     */
+    @NotNull
+    @ApiModelProperty(value = "data",example = "{}")
+    private Object data;
+
+    /**
+     * 消息代码
+     */
+    @NotNull
+    @ApiModelProperty(value = "code",example = StringUtils.EMPTY)
+    private String code = StringUtils.EMPTY;
+
+    /**
+     * 成功默认消息
+     * @return
+     */
+    private ResponseVO() {
+        this.status = SysConstant.STATUS.Valid;
+        this.msg = SysConstant.MSG.SUCCESS;
+        this.code = SysConstant.SYS_CODE.STATUS_SUCCESS;
+        this.data="{}";
+    }
+
+    /**
+     * 成功默认消息
+     * @return
+     */
+    public static ResponseVO successInstance() {
+        return new ResponseVO();
+    }
+
+    /**
+     * 成功-返回数据
+     * @param data
+     * @return
+     */
+    public static ResponseVO successInstance(Object data) {
+        if(data==null){
+            data="";
+        }
+        ResponseVO res = successInstance();
+        res.setData(data);
+        return res;
+    }
+
+
+    /**
+     * 失败错误消息
+     * @param msg
+     * @return
+     */
+    public static ResponseVO errorInstance(String msg) {
+        ResponseVO res = successInstance();
+
+        res.setStatus(SysConstant.STATUS.Invalid);
+        res.setCode(SysConstant.SYS_CODE.STATUS_ERROR);
+        res.setMsg(StringUtils.isBlank(msg) ? SysConstant.MSG.ERROR : msg);
+
+        return res;
+    }
+
+
+
+}

+ 146 - 0
common/src/main/java/com/xc/common/config/redis/RedisCacheService.java

@@ -0,0 +1,146 @@
+package com.xc.common.config.redis;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author Administrator
+ */
+@Slf4j
+@Service
+public class RedisCacheService {
+
+    @Resource
+    private RedisTemplate<String,Object> redisTemplate;
+
+    /**
+     * 获取值
+     * @param name
+     * @param key
+     * @return
+     */
+    public Object getMapCache(String name,String key){
+        log.info("获取Map {},{}",name,key);
+        return redisTemplate.opsForHash().get(name,key);
+    }
+
+    /**
+     * 保存值
+     * @param key
+     * @param name
+     * @param value
+     */
+    public void setMapCache(String name,String key,Object value){
+        log.info("保存Map {},{},{}",name,key,value);
+        redisTemplate.opsForHash().put(name,key,value);
+    }
+    /**
+     * 删除值
+     * @param name
+     * @param key
+     */
+    public void delMapCache(String name,String key){
+        log.info("删除Map {},{}",name,key);
+        redisTemplate.opsForHash().delete(name,key);
+    }
+
+    /**
+     * 数据更新时间 默认30分钟
+     * @param key
+     * @param val
+     */
+    public void addCache(String key,Object val){
+        addCache(key,val,30);
+    }
+    /**
+     * 数据更新时间
+     * @param key
+     * @param val
+     * @param time 过期时间 以分钟为单位
+     */
+    public void addCache(String key,Object val,long time) {
+        ValueOperations opsForValue=redisTemplate.opsForValue();
+        opsForValue.set(key,val,time,TimeUnit.MINUTES);
+    }
+
+    /**
+     * 根据key查询对应缓存值
+     * @param key
+     * @return
+     */
+    public Object getCache(String key){
+        return redisTemplate.opsForValue().get(key);
+    }
+
+
+
+    /**
+     * 根据前缀批量删除redisKey
+     * @param prex 前缀
+     * @return 删除条数
+     */
+    public int deleteCaches(String prex){
+        String key=prex+"*";
+        Set<String> keys = redisTemplate.keys(key);
+        if(keys!=null && keys.size()>0){
+            redisTemplate.delete(keys);
+            return keys.size();
+        }
+        return 0;
+    }
+
+    /**
+     * 删除单条
+     * @param key 删除的key
+     * @return
+     */
+    public int deleteCacheByKey(String key){
+        Set<String> keys = redisTemplate.keys(key);
+        if(keys!=null && keys.size()>0){
+            redisTemplate.delete(keys);
+            return keys.size();
+        }
+        return 0;
+    }
+
+    /**
+     * 按数量获取
+     * @param key
+     * @param size
+     * @return
+     */
+    public List getListBySize(String key, long size){
+        List liststr=redisTemplate.opsForList().range(key, 0, size);
+        return liststr;
+    }
+    /**
+     * 从头部删除指定数量的key
+     * @param key
+     * @param size
+     */
+    public void delList(String key,int size){
+        for(int x=0;x<size;x++){
+            try{
+                redisTemplate.opsForList().leftPop(key);
+            }catch(Exception ex){
+
+            }
+        }
+    }
+    /**
+     * 添加队列(位置尾部)
+     * @param key
+     * @param val
+     * @return  返回val所在队列的序号
+     */
+    public long addList(String key,Object val){
+        return redisTemplate.opsForList().rightPush(key, val);
+    }
+}

+ 74 - 0
common/src/main/java/com/xc/common/config/redis/RedisConfig.java

@@ -0,0 +1,74 @@
+package com.xc.common.config.redis;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+@Slf4j
+@Configuration
+public class RedisConfig {
+    /**
+     * 配置自定义redisTemplate
+     * @return
+     */
+    @Bean
+    RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
+
+        log.info("start to config redisTemplate.");
+
+        RedisTemplate<String, Object> template = new RedisTemplate<>();
+        template.setConnectionFactory(redisConnectionFactory);
+
+        //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
+        Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
+
+        ObjectMapper mapper = new ObjectMapper();
+        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+        mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
+        serializer.setObjectMapper(mapper);
+
+        template.setValueSerializer(serializer);
+        //使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(serializer);
+        template.afterPropertiesSet();
+
+        log.info("Config redisTemplate end.");
+        return template;
+    }
+
+}
+
+/*
+
+集群配置
+spring:
+  #RedisProperties配置spring data redis
+  redis:
+    timeout: 6000ms
+    password: 1qaz2wsx
+    lettuce:
+      pool:
+        max-active: 1000 #连接池最大连接数(使用负值表示没有限制)
+        max-idle: 10 # 连接池中的最大空闲连接
+        min-idle: 5 # 连接池中的最小空闲连接
+        max-wait: 30 # 连接池最大阻塞等待时间(使用负值表示没有限制)
+    cluster:
+      nodes:
+        - 47.103.218.34:7001
+        - 47.103.218.34:7002
+        - 47.103.218.34:7003
+        - 47.103.218.34:7004
+        - 47.103.218.34:7005
+        - 47.103.218.34:7006
+      maxRedirects: 3 # 获取失败 最大重定向次数
+
+ */

+ 134 - 0
common/src/main/java/com/xc/common/config/redis/RedisQueueService.java

@@ -0,0 +1,134 @@
+package com.xc.common.config.redis;
+
+
+import com.xc.common.constant.SysConstant;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * redis 队列(左头右尾) 服务
+ * @author Administrator
+ */
+@Slf4j
+@Service
+public class RedisQueueService {
+
+    @Autowired
+    RedisTemplate<String, Object> redisTemplate;
+
+    /**
+     * 往队列尾加入一个值
+     *
+     * @param key
+     * @param val
+     */
+    public Long push(String key, Object val) {
+        return redisTemplate.opsForList().rightPush(key, val);
+    }
+
+    /**
+     * 从队列头部移出并获得值
+     *
+     * @param key
+     * @return
+     */
+    public Object pop(String key) {
+        return redisTemplate.opsForList().leftPop(key);
+    }
+
+    /**
+     * 从队列头部移出并获得值,x秒无数据断开
+     *
+     * @param key
+     * @param times
+     * @return
+     */
+    public Object pop(String key, int times) {
+        return redisTemplate.opsForList().leftPop(key, times, TimeUnit.SECONDS);
+    }
+
+    public void clear() {
+
+        redisTemplate.delete(SysConstant.Editor.editorQueue);
+    }
+
+    /**
+     * 获取list的数量
+     *
+     * @param key
+     * @return
+     */
+    public long getListNumber(String key) {
+        return redisTemplate.opsForList().size(key);
+    }
+
+    /**
+     * 往队列尾加入一个新数组
+     *
+     * @param key
+     * @param val
+     */
+    public Long pushList(String key, Object val) {
+        return redisTemplate.opsForList().rightPushAll(key, val);
+    }
+
+    /**
+     * 获取当前队列所有数据并删除数据
+     *
+     * @param key
+     * @return
+     */
+    public List popList(String key) {
+        long size = getListNumber(key);
+        List list = new ArrayList();
+        for (int i = 0; i < size; i++) {
+            Object obj = redisTemplate.opsForList().leftPop(key);
+            list.add(obj);
+        }
+        return list;
+    }
+
+    public void del(String key) {
+        redisTemplate.delete(key);
+    }
+
+    /**
+     * 读取redis数据数组中所有数据,不删除数据
+     * @param key
+     * @return
+     */
+    public List range(String key) {
+        long size = getListNumber(key);
+        return redisTemplate.opsForList().range(key, 0, size);
+    }
+
+    /**
+     * 从队列的左边获取数据,并删除已取出的数据
+     * @param key
+     * @param T
+     * @param count
+     * @param <T>
+     * @return
+     */
+    public <T> List<T> popList(String key,Class<T> T,int count){
+        List<T> _list=new ArrayList<T>();
+        try{
+            for(int x=0;x<count;x++){
+                Object obj=pop(key);
+                if(obj==null){
+                    break;
+                }
+                _list.add((T)obj);
+            }
+        }catch (Exception ex){
+            log.error(ex.getMessage());
+        }
+        return _list;
+    }
+}

+ 81 - 0
common/src/main/java/com/xc/common/config/swagger/SwaggerConfig.java

@@ -0,0 +1,81 @@
+package com.xc.common.config.swagger;
+
+import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.bind.annotation.RestController;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Contact;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+/**
+ * @author Administrator
+ */
+@Configuration
+@EnableSwagger2
+@EnableKnife4j
+public class SwaggerConfig {
+    @Bean
+    public Docket createRestApi() {
+        return new Docket(DocumentationType.SWAGGER_2)
+                .apiInfo(apiInfo())
+                .select()
+                //为当前包路径
+                //.apis(RequestHandlerSelectors.basePackage("com.template.controller"))
+                .apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
+                .paths(PathSelectors.any())
+                .build();
+//        return new Docket(DocumentationType.SWAGGER_2).select().apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)).build();
+    }
+
+    /**
+     * 构建 api文档的详细信息函数,注意这里的注解引用的是哪个
+     * @return
+     */
+    private ApiInfo apiInfo() {
+        return new ApiInfoBuilder()
+                //页面标题
+                .title("SpringBoot 使用 Swagger2 构建RESTful API")
+                //创建人
+                .contact(new Contact("Test", "http://www.test.co/", "test@qq.com"))
+                //版本号
+                .version("1.0")
+                //描述
+                .description("API帮助文档")
+                .build();
+    }
+}
+
+
+/*
+
+ swagger 访问地址
+ http://localhost:9001/web/swagger-ui.html
+ Knife4j 访问地址
+ http://localhost:9001/web/doc.html#/home
+
+ 1、pom.xml 文件
+<!--整合Knife4j-->
+<dependency>
+    <groupId>com.github.xiaoymin</groupId>
+    <artifactId>knife4j-spring-boot-starter</artifactId>
+    <version>2.0.4</version>
+</dependency>
+
+2、Swagger2Config中增加一个@EnableKnife4j注解,
+@Configuration
+@EnableSwagger2
+@EnableKnife4j
+public class Swagger2Config {
+
+}
+参考地址
+https://www.toutiao.com/i6851744784730554891/
+
+
+ */

+ 69 - 0
common/src/main/java/com/xc/common/constant/SysConstant.java

@@ -0,0 +1,69 @@
+package com.xc.common.constant;
+
+
+/**
+ * @author Administrator
+ */
+public interface SysConstant {
+
+    interface MSG{
+        /**
+         * 操作成功
+         */
+        String SUCCESS = "操作成功";
+
+        /**
+         * 系统错误,请联系管理员
+         */
+        String ERROR = "系统错误,请联系管理员";
+    }
+
+    /**
+     * 状态
+     */
+    public interface STATUS {
+        /**
+         * 有效/成功
+         */
+        String Valid = "1";
+
+        /**
+         * 失效/失败
+         */
+        String Invalid = "0";
+
+
+    }
+
+    /**
+     * 系统消息代码
+     */
+    public interface SYS_CODE {
+        /**
+         * 消息代码前缀
+         */
+        String SYS = "SYS";
+        /**
+         * 成功
+         */
+        String STATUS_SUCCESS = SYS + "1";
+
+        /**
+         * 失败
+         */
+        String STATUS_ERROR = SYS + "0";
+
+    }
+
+    interface Editor {
+        /**
+         * 原子保存队列名字
+         */
+        String editorQueue = "redis_editor_queue";
+    }
+
+
+
+
+
+}

+ 118 - 0
common/src/main/java/com/xc/common/exception/InterfaceRequestErrorAndPerformanceLog.java

@@ -0,0 +1,118 @@
+package com.xc.common.exception;
+
+import com.xc.common.api.ResponseVO;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.Signature;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.stereotype.Component;
+
+import javax.validation.ConstraintViolationException;
+import java.lang.reflect.Method;
+
+/**
+ * 切面切在controller上捕获全局异常并处理
+ * @author Administrator
+ */
+@Component
+@Aspect
+@Slf4j
+public class InterfaceRequestErrorAndPerformanceLog {
+    /**
+     * 切入到controller层的包和所有子包里的任意类的任意方法的执行
+     */
+    @Pointcut("execution(* com.xc.*.controller..*.*(..))")
+    public void pointCut() {
+    }
+
+
+    @Around("pointCut()")
+    public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable {
+        long startTm = System.currentTimeMillis();
+        Object res;
+        try {
+            //处理入参特殊字符和sql注入攻击
+            checkRequestParam(pjp);
+            //Signature s = pjp.getSignature();
+            //执行访问接口操作
+            res = pjp.proceed(pjp.getArgs());
+            Long consumeTime = System.currentTimeMillis() - startTm;
+            log.info("耗时:" + consumeTime + "(毫秒).");
+            //当接口请求时间大于3秒时,标记为异常调用时间,并记录入库
+            if (consumeTime > 3000) {
+                log.warn("{" + pjp.getSignature() + "的执行时间超过三秒" + "}");
+            }
+        } catch (Exception throwable) {
+            res = handlerException(pjp, throwable);
+        }
+        return res;
+    }
+
+    /**
+     * 处理接口调用异常
+     *
+     * @param pjp
+     * @param e
+     * @return
+     */
+    private ResponseVO handlerException(ProceedingJoinPoint pjp, Throwable e) {
+        //获取方法签名
+        Signature signature = pjp.getSignature();
+        //获取目标类
+        Object controller = pjp.getTarget();
+        //获取入参数
+        Object[] args = pjp.getArgs();
+        Class<?>[] parameterTypes = new Class<?>[args.length];
+        try {
+            for (int j = 0; j < args.length; j++) {
+                Object arg = args[j];
+                parameterTypes[j] = arg.getClass();
+            }
+
+            Method method = controller.getClass().getDeclaredMethod(signature.getName(), parameterTypes);
+            Class<?> returnType = method.getReturnType();
+            if (!returnType.equals(ResponseVO.class)) {
+                return null;
+            }
+        } catch (Exception ex) {
+            //TODO:出现空指针可能是get入参有问题
+            log.error(ex.getMessage());
+        }
+        ResponseVO apiResponse;
+        if (e.getClass().isAssignableFrom(ServiceException.class)) {
+            apiResponse = ResponseVO.errorInstance(e.getMessage());
+        } else if (e instanceof ConstraintViolationException) {
+            //利用校验框架的验证异常
+            String s = e.getMessage();
+            String msg = s.substring(s.indexOf(":") + 1);
+            apiResponse = ResponseVO.errorInstance(msg);
+        } else if (e instanceof RuntimeException) {
+            log.error("RuntimeException{方法:" + pjp.getSignature() + ", 参数:" + pjp.getArgs() + ",异常:" + e.getMessage() + "}", e);
+            apiResponse = ResponseVO.errorInstance(e.getMessage());
+        } else {
+            log.error("异常{方法:" + pjp.getSignature() + ", 参数:" + pjp.getArgs() + ",异常:" + e.getMessage() + "}", e);
+            apiResponse = ResponseVO.errorInstance(e.getMessage());
+        }
+        return apiResponse;
+    }
+
+    /**
+     * @Author: wzd
+     * @Description: 处理入参特殊字符和sql注入攻击
+     */
+    private void checkRequestParam(ProceedingJoinPoint pjp) {
+        String str = String.valueOf(pjp.getArgs());
+       /* if (!IllegalStrFilterUtil.sqlStrFilter(str)) {
+            logger.info("访问接口:" + pjp.getSignature() + ",输入参数存在SQL注入风险!参数为:" + Lists.newArrayList(pjp.getArgs()).toString());
+            DcErrorEntity dcErrorEntity = interfaceErrorService.processDcErrorEntity(pjp.getSignature() + "",Lists.newArrayList(pjp.getArgs()).toString(),"输入参数存在SQL注入风险!");
+            throw new DataCenterException(dcErrorEntity);
+        }
+        if (!IllegalStrFilterUtil.isIllegalStr(str)) {
+            logger.info("访问接口:" + pjp.getSignature() + ",输入参数含有非法字符!,参数为:" + Lists.newArrayList(pjp.getArgs()).toString());
+            DcErrorEntity dcErrorEntity = interfaceErrorService.processDcErrorEntity(pjp.getSignature() + "",Lists.newArrayList(pjp.getArgs()).toString(),"输入参数含有非法字符!");
+            throw new DataCenterException(dcErrorEntity);
+        }*/
+    }
+}

+ 12 - 0
common/src/main/java/com/xc/common/exception/ServiceException.java

@@ -0,0 +1,12 @@
+package com.xc.common.exception;
+
+/**
+ * @author Administrator
+ */
+public class ServiceException extends RuntimeException {
+
+    public ServiceException(String message) {
+        super(message);
+    }
+
+}

+ 40 - 0
common/src/main/java/com/xc/common/utils/JsonUtil.java

@@ -0,0 +1,40 @@
+package com.xc.common.utils;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: 5
+ * Date: 17-3-27
+ * Time: 上午9:48
+ * To change this template use File | Settings | File Templates.
+ * @author Administrator
+ */
+public class JsonUtil {
+    static final Gson GSON=new Gson();
+    static final Gson GSONData=new GsonBuilder().setDateFormat("yyyy-MM-dd").create();
+    static final Gson GSONDataTime=new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
+
+    public static String toJson(Object o){
+        return GSON.toJson(o);
+    }
+    public static String toJsonByDate(Object o){
+        return GSONData.toJson(o);
+    }
+    public static String toJsonByDateTime(Object o){
+        return GSONDataTime.toJson(o);
+    }
+
+    public static void main(String[]args){
+        String str="{\"day1\":\"2019-10-10\",\"day2\":null}";
+        Map<String,Date> map=GSONData.fromJson(str,Map.class);
+
+
+    }
+
+
+}

+ 27 - 0
common/src/test/resources/templates/myServiceImpl.java.vm

@@ -0,0 +1,27 @@
+package ${package.ServiceImpl};
+
+import ${package.Entity}.${entity};
+import ${package.Mapper}.${table.mapperName};
+import ${superServiceImplClassPackage};
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * <p>
+ * $!{table.comment} 服务实现类
+ * </p>
+ *
+ * @author ${author}
+ * @since ${date}
+ */
+@Service
+@Transactional(rollbackFor = Exception.class)
+#if(${kotlin})
+open class ${table.serviceImplName} : ${superServiceImplClass}<${table.mapperName}, ${entity}>(), ${table.serviceName} {
+
+}
+#else
+public class ${table.serviceImplName} extends ${superServiceImplClass}<${table.mapperName}, ${entity}> {
+
+}
+#end

+ 53 - 0
luckysheet-db/pom.xml

@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>luckySheetServer</artifactId>
+        <groupId>com.xc</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.xc</groupId>
+    <artifactId>luckysheet-db</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <packaging>jar</packaging>
+    <name>luckysheet-db</name>
+    <description>数据库接口</description>
+
+    <dependencies>
+        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+            <version>2.4.1</version>
+        </dependency>
+
+        <!-- 工具包 -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.8.1</version>
+        </dependency>
+        <!--自动生成set get方法-->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>false</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <scope>compile</scope>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.70</version>
+        </dependency>
+
+    </dependencies>
+
+</project>

+ 223 - 0
luckysheet-db/src/main/java/com/xc/luckysheet/JfGridConfigModel.java

@@ -0,0 +1,223 @@
+package com.xc.luckysheet;
+
+
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Administrator
+ */
+@Slf4j
+public class JfGridConfigModel {
+
+    /**
+     * 表名
+     */
+    public static final String TABLENAME="luckysheet";
+
+    /**
+     * 每一块的行、列范围
+     */
+    public static Integer row_size;
+    public static Integer col_size;
+    /**
+     * 第一块只保存二维数据以外的东西,其他“列号_行号”
+     */
+    public static final String FirstBlockID="fblock";
+
+
+    /**
+     * 默认第一块的编号
+     */
+    private static String FirstBlockId="";
+
+    static {
+        try {
+            //获取默认第一块的编号
+            FirstBlockId=JfGridConfigModel.FirstBlockID;
+        } catch (Exception e) {
+            log.error(e.getMessage());
+        }
+    }
+
+    /**
+     * 返回设置的块范围
+     * @return
+     */
+    public static String getRowCol(){
+        return row_size+"_"+col_size;
+    }
+    private static Integer getRow(String rowCol){
+        if(StringUtils.isBlank(rowCol)){
+            return row_size;
+        }
+        try{
+            return Integer.parseInt(rowCol.split("_")[0]);
+        }catch (Exception ex){
+            return row_size;
+        }
+    }
+    private static Integer getCol(String rowCol){
+        if(StringUtils.isBlank(rowCol)){
+            return col_size;
+        }
+        try{
+            return Integer.parseInt(rowCol.split("_")[1]);
+        }catch (Exception ex){
+            return col_size;
+        }
+    }
+
+
+
+    /**
+     * 获取块的范围
+     * @param r 当前行
+     * @param c 当前列
+     * @param rowSize 行范围
+     * @param colSize 列范围
+     * @return
+     */
+    public static String getRange(Integer r,Integer c,Integer rowSize,Integer colSize){
+        String _r=r/rowSize+"";
+        String _c=c/colSize+"";
+        String _result=_r+"_"+_c;
+        return _result;
+    }
+    public static String getRange(Integer r,Integer c,String rowCol){
+        return getRange(r,c,getRow(rowCol),getCol(rowCol));
+    }
+
+    /**
+     * 获取块的范围
+     * @param bson
+     * @param rowSize
+     * @param colSize
+     * @return
+     */
+    private static String getRange(JSONObject bson, Integer rowSize, Integer colSize){
+        if(bson.containsKey("r") && bson.containsKey("c")){
+            try{
+                //单元格的行号
+                Integer _r=Integer.parseInt(bson.get("r").toString());
+                //单元格的列号
+                Integer _c=Integer.parseInt(bson.get("c").toString());
+                return getRange(_r,_c,rowSize,colSize);
+            }catch (Exception ex){
+                log.error(ex.toString());
+                return null;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 单个sheet数据拆分成多个(使用默认块大小)
+     * @param sheet 一个sheet
+     */
+    public static List<JSONObject> toDataSplit(String rowCol, JSONObject sheet) {
+        return toDataSplit(getRow(rowCol),getCol(rowCol),sheet);
+    }
+
+    public static Integer getSheetCount(List<JSONObject> dbObject){
+        int i=0;
+        if(dbObject!=null && dbObject.size()>0){
+            for(JSONObject b:dbObject){
+                if(b.containsKey("block_id") && FirstBlockID.equals(b.get("block_id"))){
+                    i++;
+                }
+            }
+        }
+        return i;
+    }
+
+    /**
+     * 单个sheet数据拆分成多个
+     * @param rowSize 行数量
+     * @param colSize 列数量
+     * @param sheet 一个sheet
+     */
+    private static List<JSONObject> toDataSplit(Integer rowSize,Integer colSize,JSONObject sheet){
+        List<JSONObject> list=new ArrayList<JSONObject>();
+        if(sheet!=null && sheet.containsKey("celldata")){
+            //单元格数据
+            List<JSONObject> celldata=(List<JSONObject>)sheet.get("celldata");
+            //相同的索引
+            Object index=sheet.get("index");
+            //序号
+            Object list_id=null;
+            if(sheet.containsKey("list_id")){
+                list_id=sheet.get("list_id");
+            }
+            //Object order=sheet.get("order");//相同的位置
+
+            //k 行号+列号 v 位置_datas下标
+            Map<String,Integer> pos=new HashMap<String, Integer>();
+            //分组的数据
+            List<List<JSONObject>> datas=new ArrayList<List<JSONObject>>();
+
+            if(celldata!=null && celldata.size()>0){
+                for(JSONObject bson:celldata){
+                    //获取到位置
+                    String _pos=getRange(bson,rowSize,colSize);
+                    if(_pos!=null){
+                        //获取到数据集合
+                        List<JSONObject> _data=null;
+                        if(pos.containsKey(_pos)){
+                            //获取对应集合
+                            _data=datas.get(pos.get(_pos));
+                        }else{
+                            _data=new ArrayList<JSONObject>();
+                            //保存位置信息
+                            pos.put(_pos,datas.size());
+                            //添加集合
+                            datas.add(_data);
+                        }
+                        //添加新数据
+                        _data.add(bson);
+                    }
+                }
+            }
+
+            //替换原始的数据
+            //if(pos.containsKey(FirstBlockID)){
+            //    sheet.put("celldata",datas.get(pos.get(FirstBlockID)));
+            //}
+            if(sheet.containsKey("_id")){
+                sheet.remove("_id");
+            }
+            sheet.put("celldata",new ArrayList());
+            list.add(sheet);
+
+            for(String _pos:pos.keySet()){
+                //if(_pos.equals(FirstBlockID)){
+                //    continue;
+                //}
+                //获取对应集合
+                List<JSONObject> _data=datas.get(pos.get(_pos));
+                JSONObject _sheet=new JSONObject();
+                _sheet.put("block_id",_pos);
+                _sheet.put("celldata",_data);
+                _sheet.put("index",index);
+                if(list_id!=null){
+                    _sheet.put("list_id",list_id);
+                }
+                list.add(_sheet);
+                //_sheet.put("order",order);
+            }
+
+        }else{
+            list.add(sheet);
+        }
+        return  list;
+
+    }
+
+
+}

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 35 - 0
luckysheet-db/src/main/java/com/xc/luckysheet/Test.java


+ 34 - 0
luckysheet-db/src/main/java/com/xc/luckysheet/db/IRecordDataInsertHandle.java

@@ -0,0 +1,34 @@
+package com.xc.luckysheet.db;
+
+import com.alibaba.fastjson.JSONObject;
+import com.xc.luckysheet.entity.GridRecordDataModel;
+import org.springframework.stereotype.Repository;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 插入数据
+ * @author Administrator
+ */
+public interface IRecordDataInsertHandle {
+    /**
+     * 新增Sheet页,并返回刚刚插入的_id
+     * @param pgModel
+     * @return
+     */
+    String insert(GridRecordDataModel pgModel);
+    /**
+     * 批量添加 添加jsonb
+     * @param models
+     * @return
+     */
+    String InsertIntoBatch(List<GridRecordDataModel> models);
+
+    /**
+     * 批量添加 添加jsonb
+     * @param models
+     * @return
+     */
+    String InsertBatchDb(List<JSONObject> models);
+}

+ 154 - 0
luckysheet-db/src/main/java/com/xc/luckysheet/db/IRecordDataUpdataHandle.java

@@ -0,0 +1,154 @@
+package com.xc.luckysheet.db;
+
+import com.alibaba.fastjson.JSONObject;
+import com.xc.luckysheet.entity.GridRecordDataModel;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * json数据更新处理
+ * @author Administrator
+ */
+public interface IRecordDataUpdataHandle {
+
+    /**
+     * sheet多块更新(先删除后添加)
+     * 按IDS删除一组,然后新加处理后的
+     * @param blocks
+     * @param ids
+     * @return
+     */
+    Boolean updateMulti2(List<JSONObject> blocks, List<String> ids);
+
+
+    /**
+     * 批量更新
+     * @param models
+     * @return
+     */
+    boolean batchUpdateForNoJsonbData(List<GridRecordDataModel> models);
+
+    /**
+     * 清除指定层级下某条数据
+     * @param query   键值对
+     * @param keyName
+     * @return
+     */
+    boolean rmCellDataValue(JSONObject query, String keyName);
+
+    /**
+     * 更新jsonb中某条文本数据
+     * @param query    键值对
+     * @param keyName
+     * @param position
+     * @param v
+     * @return
+     */
+    boolean updateCellDataListTxtValue(JSONObject query, String keyName, Integer position, Object v);
+
+    /**
+     * 更新jsonb中某条文本数据
+     * @param query    键值对
+     * @param keyName
+     * @param position
+     * @param v
+     * @return
+     */
+    boolean updateCellDataListValue(JSONObject query, String keyName, String position, Object v);
+
+    /**
+     * jsonb数据中元素添加元素
+     * @param query
+     * @param word
+     * @param db
+     * @param position
+     * @return
+     */
+    boolean updateJsonbForElementInsert(JSONObject query, String word, JSONObject db, Integer position);
+
+    /**
+     * 更新
+     * @param query
+     * @param word
+     * @return
+     */
+    boolean rmJsonbDataForEmpty(JSONObject query, String word);
+
+    /**
+     * 更新
+     * @param query
+     * @param word
+     * @return
+     */
+    boolean updateJsonbDataForKeys(JSONObject query, JSONObject word);
+
+    /**
+     * 更新status状态
+     * @param model
+     * @return
+     */
+    boolean updateDataStatus(GridRecordDataModel model);
+
+    /**
+     * 更新sheet隐藏状态
+     * @param model
+     * @param hide
+     * @param index1
+     * @param index2
+     * @return
+     */
+    boolean updateDataMsgHide(GridRecordDataModel model, Integer hide, String index1, String index2);
+
+    /**
+     * 更新sheet隐藏状态
+     * @param model
+     * @param hide
+     * @param index
+     * @return
+     */
+    boolean updateDataMsgNoHide(GridRecordDataModel model, Integer hide, String index);
+
+    /**
+     * 更新jsonb中某条文本数据
+     * @param block_ids
+     * @param models
+     * @return
+     */
+    boolean batchUpdateCellDataValue(List<String> block_ids, List<GridRecordDataModel> models);
+
+    /**
+     * jsonb数据中元素添加元素(集合插入)
+     * @param query
+     * @param word
+     * @param db
+     * @param position
+     * @param words
+     * @return
+     */
+    boolean updateJsonbForInsertNull(JSONObject query, String word, JSONObject db, Integer position, String words);
+
+    /**
+     * jsonb数据中元素添加元素
+     * @param query
+     * @param word
+     * @param db
+     * @param position
+     * @return
+     */
+    boolean updateJsonbForSetNull(JSONObject query, String word, JSONObject db, Integer position);
+
+
+    /**
+     * jsonb数据中元素添加元素(根节点)
+     * @param query
+     * @param word
+     * @param db
+     * @param position
+     * @param words
+     * @return
+     */
+    boolean updateJsonbForSetRootNull(JSONObject query, String word, JSONObject db, Integer position, String words);
+
+
+}

+ 37 - 0
luckysheet-db/src/main/java/com/xc/luckysheet/db/IRecordDelHandle.java

@@ -0,0 +1,37 @@
+package com.xc.luckysheet.db;
+
+import com.xc.luckysheet.entity.GridRecordDataModel;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * 删除
+ * @author Administrator
+ */
+public interface IRecordDelHandle {
+    /**
+     * 删除sheet(非物理删除)
+     * @param model
+     * @return
+     */
+    boolean updateDataForReDel(GridRecordDataModel model);
+
+    /**
+     * 按ID 删除多个文档 (物理删除)
+     * @param ids
+     * @return
+     */
+    String delDocuments(List<String> ids);
+
+    /**
+     * 按list_id 删除记录 (物理删除)
+     * @param listIds
+     * @return
+     */
+    int[] delete(List<String> listIds);
+
+
+
+
+}

+ 115 - 0
luckysheet-db/src/main/java/com/xc/luckysheet/db/IRecordSelectHandle.java

@@ -0,0 +1,115 @@
+package com.xc.luckysheet.db;
+
+import com.alibaba.fastjson.JSONObject;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * 记录处理
+ * @author Administrator
+ */
+public interface IRecordSelectHandle {
+
+    /**
+     * 查看指定sheet页 查看第一块是否存在(控制块)
+     * @param listId
+     * @param index
+     * @return
+     */
+     Integer getFirstBlockByGridKey(String listId, String index);
+
+    /**
+     * 获取指定的xls激活的sheet页的 返回index(控制块)
+     * @param listId
+     * @return
+     */
+     String getFirstBlockIndexByGridKey(String listId);
+
+    /**
+     * 获取指定的xls,sheet 第一块的行列信息(控制块)
+     * @param listId
+     * @param index
+     * @return
+     */
+     String getFirstBlockRowColByGridKey(String listId,String index);
+
+    /**
+     * 按指定xls,sheet顺序返回整个xls结构
+     * 不返回celldata ,只获取信息块
+     * @param listId
+     * @return
+     */
+     List<JSONObject> getByGridKey_NOCelldata(String listId);
+
+    /**
+     * 按指定xls,sheet获取,返回指定的sheet集合
+     * @param listId
+     * @param index
+     * @return
+     */
+     List<JSONObject> getBlockAllByGridKey(String listId, String index);
+
+    /**
+     * 获取指定xls,sheet,block的数据
+     * @param listId
+     * @param index
+     * @param blockId
+     * @return
+     */
+     JSONObject getCelldataByGridKey(String listId, String index, String blockId);
+
+    /**
+     * 获取指定xls、sheet中的config中数据 (存放在第一块中)
+     * @param listId
+     * @param index
+     * @return
+     */
+     JSONObject getConfigByGridKey(String listId, String index);
+
+    /**
+     * 按list_id获取,返回指定sheet 当前sheet的全部分块数据(并合并)getMergeByGridKey
+     * 返回是DBObject,而下面这个方法返回仅仅只有celldata
+     * @param listId
+     * @param index
+     * @param ids 返回记录存在数据库的ID
+     * @return
+     */
+     JSONObject getBlockMergeByGridKey(String listId, String index, List<String> ids);
+
+    /**
+     * 按list_id获取(id,index),返回sheet集合
+     *
+     * @param listId
+     * @param flag 是否仅仅获取主要模块
+     * @return
+     */
+     List<JSONObject> getBlocksByGridKey(String listId, boolean flag);
+
+    /**
+     *  获取指定xls,多个sheet的全部分块
+     * @param listId
+     * @param indexs
+     * @return
+     */
+     List<JSONObject> getAllIndexsByGridKey(String listId, List<String> indexs);
+
+    /**
+     * 获取指定xls,sheet全部内容
+     * @param listId
+     * @param index
+     * @return
+     */
+     List<JSONObject> getIndexsByGridKey(String listId, String index);
+
+    /**
+     * 获取图表数据(第一块)
+     * @param listId
+     * @param index
+     * @return
+     */
+     JSONObject getChartByGridKey(String listId, String index);
+
+
+
+}

+ 57 - 0
luckysheet-db/src/main/java/com/xc/luckysheet/entity/GridRecordDataModel.java

@@ -0,0 +1,57 @@
+package com.xc.luckysheet.entity;
+
+
+import com.alibaba.fastjson.JSONObject;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 存储对象类
+ * @author Administrator
+ */
+@Data
+public class GridRecordDataModel {
+    /**
+     * 记录序列
+     */
+    Long id;
+    /**
+     * 文档ID
+     */
+    String list_id;
+    /**
+     * 本记录的行_列
+     */
+    String row_col;
+    /**
+     * sheet序号
+     */
+    String index;
+    /**
+     * 状态是否当前sheet页
+     */
+    Integer status;
+    /**
+     * 块编号 第一块 fblock
+     */
+    String block_id;
+    /**
+     * json串
+     */
+    JSONObject json_data;
+    /**
+     * 排序位置
+     */
+    Integer order;
+    /**
+     * 是否删除
+     */
+    Integer is_delete;
+
+    /**
+     * sheet页数据 未编号分组
+     */
+    List<JSONObject> dataList;
+
+}

+ 370 - 0
luckysheet-db/src/main/java/com/xc/luckysheet/util/JfGridFileUtil.java

@@ -0,0 +1,370 @@
+package com.xc.luckysheet.util;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *
+ * @author Administrator
+ */
+@Slf4j
+public class JfGridFileUtil {
+
+    /**
+     * 按工作簿index获取对应集合
+     * @param dbObject
+     * @param index
+     * @return
+     */
+    public static JSONArray getSheetByIndex(JSONObject dbObject, Integer index){
+        JSONArray _resultModel=null;
+        if(dbObject!=null && dbObject instanceof List){
+            List<JSONObject> _list=(List<JSONObject>)dbObject;
+            for(JSONObject _o:_list){
+                if(_o.containsKey("index")){
+                    try{
+                        if(index.equals(_o.get("index").toString())){
+                            if(_o.containsKey("celldata")){
+                                _resultModel=_o.getJSONArray("celldata");
+                            }
+                        }
+                    }catch (Exception ex){
+                        log.error(ex.toString());
+                    }
+                }
+            }
+        }
+        return _resultModel;
+    }
+
+    /**
+     * 从对象中获取数据calldata信息
+     * @param dbObject
+     * @return
+     */
+    public static JSONArray getSheetByIndex(JSONObject dbObject){
+        JSONArray _resultModel=null;
+        if(dbObject!=null){
+            if(dbObject.containsKey("celldata")){
+                _resultModel=dbObject.getJSONArray("celldata");
+            }
+        }
+        return _resultModel;
+    }
+
+    /**
+     * 按工作簿数量
+     * @param dbObject
+     * @return
+     */
+    public static Integer getSheetCount(JSONObject dbObject){
+        Integer _resultModel=0;
+        if(dbObject!=null){
+            if(dbObject.containsKey("jfgridfile")){
+                JSONObject _bs=dbObject.getJSONObject("jfgridfile");
+                return getSheetCount(_bs);
+            }else if(dbObject instanceof List){
+                List<JSONObject> _list=(List<JSONObject>)dbObject;
+                if(_list!=null){
+                    _resultModel=_list.size();
+                }
+            }
+        }
+        return _resultModel;
+    }
+
+    /**
+     * 按工作簿index获取对应集合的序号
+     * @param dbObject
+     * @param index
+     * @return
+     */
+    public static Integer getSheetPositionByIndex(JSONObject dbObject,Integer index){
+        Integer _resultModel=null;
+        if(dbObject!=null && dbObject instanceof List){
+            List<JSONObject> _list=(List<JSONObject>)dbObject;
+            //for(DBObject _o:_list){
+            for(int x=0;x<_list.size();x++){
+                JSONObject _o=_list.get(x);
+                if(_o.containsKey("index")){
+                    try{
+                        if(index.equals(_o.get("index").toString())){
+                            _resultModel=x;
+                            break;
+                        }
+                    }catch (Exception ex){
+                        log.error(ex.toString());
+                    }
+                }
+            }
+        }
+        return _resultModel;
+    }
+    public static Integer getSheetPositionByIndex(List<JSONObject> _list,String index){
+        Integer _resultModel=null;
+        if(_list!=null ){
+            for(int x=0;x<_list.size();x++){
+                JSONObject _o=_list.get(x);
+                if(_o.containsKey("index")){
+                    try{
+                        if(index.equals(_o.get("index").toString())){
+                            _resultModel=x;
+                            break;
+                        }
+                    }catch (Exception ex){
+                        log.error(ex.toString());
+                    }
+                }
+            }
+        }
+        return _resultModel;
+    }
+
+    /**
+     * 按index值获取mongodb的key
+     * @param _list
+     * @param index
+     * @return
+     */
+    public static List<String> getSheetKeyByIndex(List<JSONObject> _list,Integer index){
+        List<String> _resultModel=new ArrayList<String>();
+        if(_list!=null ){
+            for(int x=0;x<_list.size();x++){
+                JSONObject _o=_list.get(x);
+                if(_o.containsKey("index")){
+                    try{
+                        if(index.equals(_o.get("index").toString())){
+                            if(_o.containsKey("_id")){
+                                //_resultModel=_o.get("_id").toString();
+                                _resultModel.add(_o.get("_id").toString());
+                            }
+                            //break;
+                        }
+                    }catch (Exception ex){
+                        log.error(ex.toString());
+                    }
+                }
+            }
+        }
+        return _resultModel;
+    }
+
+    /**
+     * 按工作簿index 获取对象每一个工作簿的第一层对象
+     * @param dbObject
+     * @param index
+     * @param k
+     * @return
+     */
+    public static JSONObject getObjectByIndex(JSONObject dbObject,Integer index,String k){
+        JSONObject _resultModel=null;
+        if(dbObject!=null && dbObject instanceof List){
+            List<JSONObject> _list=(List<JSONObject>)dbObject;
+            for(JSONObject _o:_list){
+                if(_o.containsKey("index")){
+                    try{
+                        if(index.equals(_o.get("index").toString())){
+                            if(_o.containsKey(k)){
+                                _resultModel=_o.getJSONObject(k);
+                            }
+                            break;
+                        }
+                    }catch (Exception ex){
+                        log.error(ex.toString());
+                    }
+                }
+            }
+        }
+        return _resultModel;
+    }
+
+    /**
+     * 按工作簿index 获取对象每一个工作簿的第一层对象(传入为单sheet)
+     * @param dbObject
+     * @param k
+     * @return
+     */
+    public static Object getObjectByIndex(JSONObject dbObject,String k){
+        Object _resultModel=null;
+        if(dbObject!=null){
+            if(dbObject.containsKey(k)){
+                _resultModel=dbObject.get(k);
+            }
+        }
+        return _resultModel;
+    }
+    public static JSONObject getJSONObjectByIndex(JSONObject dbObject,String k){
+        JSONObject _resultModel=null;
+        if(dbObject!=null){
+            if(dbObject.containsKey(k)&& dbObject.get(k) instanceof JSONObject){
+                _resultModel=dbObject.getJSONObject(k);
+            }
+        }
+        return _resultModel;
+    }
+    public static JSONArray getJSONArrayByIndex(JSONObject dbObject,String k){
+        JSONArray _resultModel=null;
+        if(dbObject!=null){
+            if(dbObject.containsKey(k)&& dbObject.get(k) instanceof JSONArray){
+                _resultModel=dbObject.getJSONArray(k);
+            }
+        }
+        return _resultModel;
+    }
+
+
+    /**
+     * 按工作簿index 获取对象每一个工作簿的第一层对象
+     * @param dbObject
+     * @param index
+     * @param k
+     * @return
+     */
+    public static Integer getIntegerByIndex(JSONObject dbObject,Integer index,String k){
+        Integer _resultModel=null;
+        if(dbObject!=null && dbObject instanceof List){
+            List<JSONObject> _list=(List<JSONObject>)dbObject;
+            for(JSONObject _o:_list){
+                if(_o.containsKey("index")){
+                    try{
+                        if(index.equals(_o.get("index").toString())){
+                            if(_o.containsKey(k)){
+                                _resultModel=(Integer)_o.get(k);
+                            }
+                            break;
+                        }
+                    }catch (Exception ex){
+                        log.error(ex.toString());
+                    }
+                }
+            }
+        }
+        return _resultModel;
+    }
+
+    /**
+     * 按工作簿index 获取对象每一个工作簿的第一层对象(单个工作簿)
+     * @param dbObject
+     * @param k
+     * @return
+     */
+    public static Integer getIntegerByIndex(JSONObject dbObject,String k){
+        Integer _resultModel=null;
+        if(dbObject!=null){
+            if(dbObject.containsKey(k)){
+                _resultModel=(Integer)dbObject.get(k);
+            }
+        }
+        return _resultModel;
+    }
+
+    /**
+     * 从对象中获取一个指定的对象
+     * @param dbObject
+     * @param k
+     * @return
+     */
+    public static JSONObject getObjectByObject(JSONObject dbObject,String k){
+        if(dbObject!=null){
+            if(dbObject.containsKey(k)){
+                return dbObject.getJSONObject(k);
+            }
+        }
+        return null;
+    }
+
+
+
+    /**
+     * /获取测试用二维数组
+     * @param rc
+     * @param len
+     * @return
+     */
+    public static JSONArray getTestData(String rc,int len){
+        int row=0;
+        int column=0;
+        if(rc.equals("r")){
+            //增加行
+            row=len;
+            column=5;
+        }else{
+            //增加列
+            row=5;
+            column=len;
+        }
+        Object[][] strs=new String[row][column];
+        for(int x=0;x<row;x++){
+            for(int x1=0;x1<column;x1++){
+                if(x1==x){
+                    //continue;
+                }
+                strs[x][x1]=x+""+x1;
+            }
+        }
+        System.out.println(JSONArray.toJSONString(strs));
+        List<Object> strs1=JSONObject.parseObject(JSONArray.toJSONString(strs),ArrayList.class);
+
+        JSONArray _db=new JSONArray();
+        _db.addAll(strs1);
+        return _db;
+    }
+
+    /**
+     * 给出查询条件
+     * @param query
+     * @return
+     */
+    public static String getCondition(JSONObject query){
+        String condition="";
+        if(query!=null) {
+            Map<String, Object> queryDB = query.getInnerMap();
+            for (String key : queryDB.keySet()) {
+                condition = condition + " and t." + key + "='" + queryDB.get(key) + "'";
+            }
+        }
+        return condition;
+    }
+    /**
+     * 给出查询条件
+     * @param query
+     * @return
+     */
+    public static String getCondition(JSONObject query,List arr){
+        String condition="";
+        if(query!=null&&arr!=null) {
+            Map<String,Object> queryDB=query.getInnerMap();
+            for (String key : queryDB.keySet()) {
+                arr.add(queryDB.get(key));
+                condition=condition+" and t."+key+"=? ";
+            }
+        }
+        return condition;
+    }
+
+    /**
+     * 从jsonObject中找到第一个key的名字
+     * @param jsonObject
+     * @return
+     */
+    public static String getKeyName(JSONObject jsonObject){
+        try{
+            if(jsonObject!=null&&jsonObject.size()>0) {
+                Map<String, Object> map = jsonObject.getInnerMap();
+                return map.keySet().stream().findFirst().get();
+//                for(String key:map.keySet()){
+//                    return key;
+//                }
+            }
+        }catch (Exception ex){
+            log.error("jsonObject:{};{}",jsonObject.toString(SerializerFeature.WriteMapNullValue),ex.toString());
+        }
+        return "";
+    }
+}

+ 87 - 0
luckysheet-db/src/main/java/com/xc/luckysheet/util/SnowFlake.java

@@ -0,0 +1,87 @@
+package com.xc.luckysheet.util;
+
+/**
+ * 雪花算法
+ * @author Administrator
+ */
+public class SnowFlake {
+    // 起始的时间戳
+    private final static long START_STMP = 1577808000000L; //2020-01-01
+    // 每一部分占用的位数,就三个
+    private final static long SEQUENCE_BIT = 12; //序列号占用的位数
+    private final static long MACHINE_BIT = 5; //机器标识占用的位数
+    private final static long DATACENTER_BIT = 5; //数据中心占用的位数
+    // 每一部分最大值
+    private final static long MAX_DATACENTER_NUM = -1L ^ (-1L << DATACENTER_BIT);
+    private final static long MAX_MACHINE_NUM = -1L ^ (-1L << MACHINE_BIT);
+    private final static long MAX_SEQUENCE = -1L ^ (-1L << SEQUENCE_BIT);
+    // 每一部分向左的位移
+    private final static long MACHINE_LEFT = SEQUENCE_BIT;
+    private final static long DATACENTER_LEFT = SEQUENCE_BIT + MACHINE_BIT;
+    private final static long TIMESTMP_LEFT = DATACENTER_LEFT + DATACENTER_BIT;
+    private long datacenterId; //数据中心
+    private long machineId; //机器标识
+    private long sequence = 0L; //序列号
+    private long lastStmp = -1L; //上一次时间戳
+    //1323969484872069121
+    //1323969557093789698
+    public SnowFlake(long datacenterId, long machineId) {
+        if (datacenterId > MAX_DATACENTER_NUM || datacenterId < 0) {
+            throw new IllegalArgumentException("datacenterId can't be greater than MAX_DATACENTER_NUM or less than 0");
+        }
+        if (machineId > MAX_MACHINE_NUM || machineId < 0) {
+            throw new IllegalArgumentException("machineId can't be greater than MAX_MACHINE_NUM or less than 0");
+        }
+        this.datacenterId = datacenterId;
+        this.machineId = machineId;
+    }
+
+    //产生下一个ID
+    public synchronized Number nextId() {
+        long currStmp = timeGen();
+        if (currStmp < lastStmp) {
+            throw new RuntimeException("Clock moved backwards.  Refusing to generate id");
+        }
+
+        if (currStmp == lastStmp) {
+            //if条件里表示当前调用和上一次调用落在了相同毫秒内,只能通过第三部分,序列号自增来判断为唯一,所以+1.
+            sequence = (sequence + 1) & MAX_SEQUENCE;
+            //同一毫秒的序列数已经达到最大,只能等待下一个毫秒
+            if (sequence == 0L) {
+                currStmp = getNextMill();
+            }
+        } else {
+            //不同毫秒内,序列号置为0
+            //执行到这个分支的前提是currTimestamp > lastTimestamp,说明本次调用跟上次调用对比,已经不再同一个毫秒内了,这个时候序号可以重新回置0了。
+            sequence = 0L;
+        }
+
+        lastStmp = currStmp;
+        //就是用相对毫秒数、机器ID和自增序号拼接
+        return (currStmp - START_STMP) << TIMESTMP_LEFT //时间戳部分
+                | datacenterId << DATACENTER_LEFT       //数据中心部分
+                | machineId << MACHINE_LEFT             //机器标识部分
+                | sequence;                             //序列号部分
+    }
+
+    private long getNextMill() {
+        long mill = timeGen();
+        while (mill <= lastStmp) {
+            mill = timeGen();
+        }
+        return mill;
+    }
+
+    private long timeGen() {
+        return System.currentTimeMillis();
+    }
+
+    public static void main(String[] args){
+        SnowFlake n1=new SnowFlake(0,Math.abs("127.0.0.1".hashCode())%32);
+        SnowFlake n2=new SnowFlake(0,Math.abs("127.0.0.1".hashCode())%32);
+
+        System.out.println(n2.nextId());
+        System.out.println(n1.nextId());
+        System.out.println(n1.nextId()+"===="+n2.nextId());
+    }
+}

+ 86 - 0
luckysheet-mongo/README-zh.md

@@ -0,0 +1,86 @@
+mongodb版本 >= 3.6.1
+
+## 数据库初始化
+## 创建数据库
+### 方法一导入cursor.json文件
+### 方法二配置完成后执行初始化
+```
+地址:
+http://localhost:9004/luckysheet/test/dbInit
+类:
+src/com/xc/luckysheet/controller/TestController
+```
+
+
+## 项目中使用
+1、luckysheet中的pom.xml 注释postgre,引入mongo
+```aidl
+       <!-- 数据库接口以及实现 -->
+       <dependency>
+           <groupId>com.xc</groupId>
+           <artifactId>luckysheet-db</artifactId>
+           <version>${project.version}</version>
+       </dependency>
+       <dependency>
+           <groupId>com.xc</groupId>
+           <artifactId>luckysheet-mongo</artifactId>
+           <version>${project.version}</version>
+       </dependency>
+       <!--<dependency>-->
+           <!--<groupId>com.xc</groupId>-->
+           <!--<artifactId>luckysheet-mysql</artifactId>-->
+           <!--<version>${project.version}</version>-->
+       <!--</dependency>-->
+       <!--<dependency>-->
+           <!--<groupId>com.xc</groupId>-->
+           <!--<artifactId>luckysheet-postgre</artifactId>-->
+           <!--<version>${project.version}</version>-->
+       <!--</dependency>-->
+```
+
+2、com.xc.luckysheet.db.server 文件夹中
+JfGridFileGetService类
+JfGridUpdateService类
+
+mysql实现
+```$xslt
+@Resource(name = "mysqlRecordDataInsertHandle")
+private IRecordDataInsertHandle recordDataInsertHandle;
+
+@Resource(name = "mysqlRecordDataUpdataHandle")
+private IRecordDataUpdataHandle recordDataUpdataHandle;
+
+@Resource(name = "mysqlRecordDelHandle")
+private IRecordDelHandle recordDelHandle;
+
+@Resource(name = "mysqlRecordSelectHandle")
+private IRecordSelectHandle recordSelectHandle;
+```
+postgres实现
+```
+@Resource(name = "postgresRecordDataInsertHandle")
+private IRecordDataInsertHandle recordDataInsertHandle;
+
+@Resource(name = "postgresRecordDataUpdataHandle")
+private IRecordDataUpdataHandle recordDataUpdataHandle;
+
+@Resource(name = "postgresRecordDelHandle")
+private IRecordDelHandle recordDelHandle;
+
+@Resource(name = "postgresRecordSelectHandle")
+private IRecordSelectHandle recordSelectHandle;
+```
+mongo实现
+```aidl
+@Resource(name = "mongoRecordDataInsertHandle")
+private IRecordDataInsertHandle recordDataInsertHandle;
+
+@Resource(name = "mongoRecordDataUpdataHandle")
+private IRecordDataUpdataHandle recordDataUpdataHandle;
+
+@Resource(name = "mongoRecordDelHandle")
+private IRecordDelHandle recordDelHandle;
+
+@Resource(name = "mongoRecordSelectHandle")
+private IRecordSelectHandle recordSelectHandle;
+```

+ 69 - 0
luckysheet-mongo/pom.xml

@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>luckySheetServer</artifactId>
+        <groupId>com.xc</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.xc</groupId>
+    <artifactId>luckysheet-mongo</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <packaging>jar</packaging>
+    <name>luckysheet-mongo</name>
+    <description>mongo实现</description>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-webmvc</artifactId>
+            <version>5.1.6.RELEASE</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.annotation</groupId>
+            <artifactId>javax.annotation-api</artifactId>
+            <version>1.3.2</version>
+        </dependency>
+
+        <!--自动生成set get方法-->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.12</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <scope>compile</scope>
+            <optional>true</optional>
+        </dependency>
+
+
+
+
+
+        <!---数据库接口-->
+        <dependency>
+            <groupId>com.xc</groupId>
+            <artifactId>luckysheet-db</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <!-- mongo驱动 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-mongodb</artifactId>
+        </dependency>
+
+    </dependencies>
+</project>

+ 245 - 0
luckysheet-mongo/src/main/java/com/xc/luckysheet/mongo/impl/BaseHandle.java

@@ -0,0 +1,245 @@
+package com.xc.luckysheet.mongo.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.mongodb.WriteResult;
+import com.mongodb.client.result.UpdateResult;
+import com.xc.luckysheet.entity.GridRecordDataModel;
+import lombok.extern.slf4j.Slf4j;
+import org.bson.Document;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.mongodb.core.BulkOperations;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.data.mongodb.core.query.Update;
+import org.springframework.data.util.Pair;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 数据库连接
+ *
+ * @author cr
+ * @Date: 2021-02-27 14:06
+ */
+@Slf4j
+public class BaseHandle {
+
+    /**
+     * 注入MongoTemplate
+     */
+    @Autowired
+    protected MongoTemplate mongoTemplate;
+
+    /**
+     * 表名
+     */
+    protected static String COLLECTION_NAME = "luckysheet";
+
+    /**
+     * 数据中插入数据
+     * @param query
+     * @param update
+     * @return
+     */
+    public boolean updateOne(Query query,Update update){
+        try{
+            log.info("select:"+query.getQueryObject().toString()+" \r\n update:"+update.getUpdateObject().toString());
+        }catch (Exception ex){
+            log.error(ex.getMessage());
+        }
+        try{
+            UpdateResult writeResult=mongoTemplate.updateFirst(query,update,COLLECTION_NAME);
+            return true;
+        }catch (Exception ex){
+            log.error(ex.getMessage());
+            return false;
+        }
+    }
+    /**
+     * 批量更新
+     * @param query
+     * @param update
+     * @return
+     */
+    protected boolean updateMulti(Query query, Update update){
+        try{
+            log.info("select:"+query.getQueryObject().toString()+" \r\n update:"+update.getUpdateObject().toString());
+        }catch (Exception ex){
+            log.error(ex.getMessage());
+        }
+        try{
+            UpdateResult writeResult=mongoTemplate.updateMulti(query,update,COLLECTION_NAME);
+            return true;
+        }catch (Exception ex){
+            log.error(ex.getMessage());
+            return false;
+        }
+    }
+
+    /**
+     * 执行多个文档
+     * @param _updates
+     * @return
+     */
+    public Boolean updateMulti(List<Pair<Query,Update>> _updates){
+        try{
+            BulkOperations ops=mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, COLLECTION_NAME);
+            ops.updateMulti(_updates);
+            ops.execute();
+            return true;
+        }catch (Exception e){
+            log.error(e.getMessage());
+        }
+        return false;
+    }
+
+    /**
+     * 组装文档查询条件
+     * @param listId 文档ID
+     * @param index  文档序号
+     * @param block  块编号
+     * @return
+     */
+    protected Document getQueryCondition(String listId, String index,String block){
+        Document dbObject = new Document();
+        dbObject.put("list_id", listId);
+        dbObject.put("index", index);
+        dbObject.put("block_id", block);
+        dbObject.put("is_delete",0);
+        return dbObject;
+    }
+
+
+    /**
+     * 获取指定key的值
+     * @param jsonObject
+     * @param key
+     * @return
+     */
+    protected String getStringByKey(JSONObject jsonObject,String key){
+        Object obj=getByKey(jsonObject, key);
+        if(obj==null){
+            return null;
+        }
+        return obj.toString();
+    }
+    protected Object getByKey(JSONObject jsonObject,String key){
+        if(jsonObject!=null&&jsonObject.containsKey(key)){
+            return jsonObject.get(key);
+        }
+        return null;
+    }
+
+    /**
+     * 将对象转换成JSONObject
+     * @param m
+     * @return
+     */
+    protected JSONObject tranToJSONObject(GridRecordDataModel m){
+        //TODO: mongo的主键是字符串 _id 是否有使用
+        JSONObject jsonObject=new JSONObject();
+        jsonObject.put("list_id",m.getList_id());
+        jsonObject.put("row_col",m.getRow_col());
+        jsonObject.put("index",m.getIndex());
+        jsonObject.put("status",m.getStatus());
+        jsonObject.put("block_id",m.getBlock_id());
+        jsonObject.put("order",m.getOrder());
+        jsonObject.put("is_delete",m.getIs_delete()==null?0:m.getIs_delete());
+
+        jsonObject.put("json_data",m.getJson_data());
+        return jsonObject;
+    }
+
+    /**
+     * 查询条件转换
+     * query.addCriteria(Criteria.where("list_id").is(gridKey).and("index").is(i).and("block_id").is(JfGridConfigModel.FirstBlockID));
+     *
+     * @param query
+     * @return
+     */
+    protected Criteria tranToCriteria(JSONObject query){
+        Criteria criteria=null;
+        if(query.containsKey("list_id")) {
+            criteria=Criteria.where("list_id").is(query.get("list_id"));
+            for (String k : query.keySet()) {
+                if(!k.equals("list_id")){
+                    criteria.and(k).is(query.get(k));
+                }
+            }
+        }
+        return criteria;
+    }
+
+
+    /**
+     * 字符串位置处理
+     * x,y,z  -> x.y.z
+     * x,1,2  -> x.1.z
+     * @param str
+     * @return
+     */
+    protected String positionHandle(String str){
+        if(str==null||str.indexOf(",")==-1){
+            return str;
+        }
+
+        String[] strs=str.split(",");
+        String result="";
+        for(String s:strs){
+            if(result.length()==0){
+                result=s;
+            }else{
+                result+="."+s;
+//                if(isNumeric(s)){
+//                    result+="["+s+"]";
+//                }else{
+//                    result+="."+s;
+//                }
+            }
+        }
+        return "json_data."+result;
+    }
+    private Pattern patternIsNumeric = Pattern.compile("[0-9]*");
+    /**
+     * 利用正则表达式判断字符串是否是数字
+     * @param str
+     * @return
+     */
+    protected  boolean isNumeric(String str){
+        Matcher isNum = patternIsNumeric.matcher(str);
+        if( !isNum.matches() ){
+            return false;
+        }
+        return true;
+    }
+
+
+    /**
+     * 处理celldata中的数据(移动到顶级)
+     * @param jsonObject
+     */
+    protected void cellDataHandle(JSONObject jsonObject){
+        String cellDataKey="json_data";
+        if(jsonObject.containsKey(cellDataKey)){
+            boolean isDelCelldata=true;
+            JSONObject data=new JSONObject();
+            JSONObject jsonObject1=jsonObject.getJSONObject(cellDataKey);
+            for(String key:jsonObject1.keySet()){
+                if(cellDataKey.equals(key)){
+                    isDelCelldata=false;
+                }
+                data.put(key,jsonObject1.get(key));
+            }
+            jsonObject.putAll(data);
+            if(isDelCelldata){
+                jsonObject.remove(cellDataKey);
+            }
+        }
+    }
+
+
+}

+ 72 - 0
luckysheet-mongo/src/main/java/com/xc/luckysheet/mongo/impl/RecordDataInsertHandle.java

@@ -0,0 +1,72 @@
+package com.xc.luckysheet.mongo.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.xc.luckysheet.db.IRecordDataInsertHandle;
+import com.xc.luckysheet.entity.GridRecordDataModel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Repository;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 添加
+ * @author cr
+ * @Date: 2021-02-27 14:08
+ */
+@Slf4j
+@Repository(value = "mongoRecordDataInsertHandle")
+public class RecordDataInsertHandle extends BaseHandle implements IRecordDataInsertHandle {
+
+    /**
+     * 新增Sheet页,并返回刚刚插入的_id
+     *
+     * @param pgModel
+     * @return
+     */
+    @Override
+    public String insert(GridRecordDataModel pgModel) {
+        try{
+            JSONObject jsonObject=tranToJSONObject(pgModel);
+            mongoTemplate.insert(jsonObject,COLLECTION_NAME);
+            if(jsonObject.containsKey("_id")){
+                return jsonObject.get("_id").toString();
+            }
+        }catch (Exception e){
+            log.error(e.getMessage());
+        }
+        return null;
+    }
+
+    /**
+     * 批量添加 添加jsonb
+     *
+     * @param models
+     * @return
+     */
+    @Override
+    public String InsertIntoBatch(List<GridRecordDataModel> models) {
+        List<JSONObject> jsonObjects=new ArrayList<>(5);
+        for(GridRecordDataModel m:models){
+            jsonObjects.add(tranToJSONObject(m));
+        }
+        return InsertBatchDb(jsonObjects);
+    }
+
+    /**
+     * 批量添加 添加jsonb
+     *
+     * @param models
+     * @return
+     */
+    @Override
+    public String InsertBatchDb(List<JSONObject> models) {
+        try{
+            mongoTemplate.insert(models,COLLECTION_NAME);
+            return "";
+        }catch (Exception e){
+            log.error(e.getMessage());
+        }
+        return null;
+    }
+}

+ 439 - 0
luckysheet-mongo/src/main/java/com/xc/luckysheet/mongo/impl/RecordDataUpdataHandle.java

@@ -0,0 +1,439 @@
+package com.xc.luckysheet.mongo.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.mongodb.BasicDBList;
+import com.mongodb.BasicDBObject;
+import com.mongodb.DBObject;
+import com.mongodb.client.result.UpdateResult;
+import com.xc.luckysheet.JfGridConfigModel;
+import com.xc.luckysheet.db.IRecordDataUpdataHandle;
+import com.xc.luckysheet.entity.GridRecordDataModel;
+import lombok.extern.slf4j.Slf4j;
+import org.bson.types.ObjectId;
+import org.springframework.data.mongodb.core.BulkOperations;
+import org.springframework.data.util.Pair;
+import org.springframework.stereotype.Repository;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.data.mongodb.core.query.Update;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 更新
+ * @author cr
+ * @Date: 2021-02-27 14:09
+ */
+@Slf4j
+@Repository(value ="mongoRecordDataUpdataHandle" )
+public class RecordDataUpdataHandle extends BaseHandle implements IRecordDataUpdataHandle {
+
+    /**
+     * sheet多块更新(先删除后添加)
+     * 按IDS删除一组,然后新加处理后的
+     * @param blocks
+     * @param ids
+     * @return
+     */
+    @Override
+    public Boolean updateMulti2(List<JSONObject> blocks, List<String> ids) {
+        try{
+            List<ObjectId> objectIdList=new ArrayList<ObjectId>();
+            if(ids!=null && ids.size()>0){
+                for(String s:ids){
+                    objectIdList.add(new ObjectId(s));
+                }
+            }
+
+            Query del=new Query();
+            del.addCriteria(Criteria.where("_id").in(objectIdList.toArray()));
+
+            BulkOperations ops=mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED,COLLECTION_NAME);
+            ops.remove(del);
+            ops.insert(blocks);
+            ops.execute();
+            return true;
+        }catch (Exception e){
+            log.error(e.getMessage());
+        }
+        return false;
+    }
+
+    /**
+     * 批量更新order 按listId,index,首块
+     *
+     * @param models
+     * @return
+     */
+    @Override
+    public boolean batchUpdateForNoJsonbData(List<GridRecordDataModel> models) {
+        List<Pair<Query,Update>> _updates=new ArrayList<Pair<Query,Update>>(10);
+        for(GridRecordDataModel dataModel:models){
+            Query query=new Query();
+            // 只修改信息块
+            query.addCriteria(Criteria
+                    .where("list_id").is(dataModel.getList_id())
+                    .and("index").is(Integer.parseInt(dataModel.getIndex()))
+                    .and("block_id").is(JfGridConfigModel.FirstBlockID));
+            Update update=new Update();
+            update.set("order",dataModel.getOrder());
+            Pair<Query,Update> pair=Pair.of(query, update);
+            _updates.add(pair);
+        }
+
+        if(_updates.size()>0){
+            return updateMulti(_updates);
+        }
+        return false;
+    }
+
+    /**
+     * 清除指定层级下某条数据
+     *
+     * @param query   键值对
+     * @param keyName
+     * @return
+     */
+    @Override
+    public boolean rmCellDataValue(JSONObject query, String keyName) {
+        try{
+            Query q = new Query();
+            q.addCriteria(tranToCriteria(query));
+            //query.addCriteria(Criteria.where("list_id").is(gridKey).and("index").is(i).and("block_id").is(JfGridConfigModel.FirstBlockID));
+
+            Update u=new Update();
+            u.unset("json_data."+positionHandle(keyName));
+            return updateOne(q, u);
+        }catch (Exception e){
+            log.error(e.getMessage());
+        }
+        return false;
+    }
+
+    /**
+     * 更新jsonb中某条文本数据
+     *
+     * @param query    键值对
+     * @param keyName
+     * @param position 目前传入都是null
+     * @param v
+     * @return
+     */
+    @Override
+    public boolean updateCellDataListTxtValue(JSONObject query, String keyName, Integer position, Object v) {
+        try{
+            Query q = new Query();
+            q.addCriteria(tranToCriteria(query));
+            //query.addCriteria(Criteria.where("list_id").is(gridKey).and("index").is(i).and("block_id").is(JfGridConfigModel.FirstBlockID));
+            keyName=positionHandle(keyName);
+            Update u=new Update();
+            if(position==null){
+                u.set("json_data."+keyName,v);
+            }else{
+                u.set("json_data."+keyName+"."+position,v);
+            }
+            return updateOne(q, u);
+        }catch (Exception e){
+            log.error(e.getMessage());
+        }
+        return false;
+    }
+
+    /**
+     * 更新jsonb中某条文本数据
+     *
+     * @param query    键值对
+     * @param keyName
+     * @param position
+     * @param v
+     * @return
+     */
+    @Override
+    public boolean updateCellDataListValue(JSONObject query, String keyName, String position, Object v) {
+        //ToDo 与上一个方法一样
+        try{
+            Query q = new Query();
+            q.addCriteria(tranToCriteria(query));
+            //query.addCriteria(Criteria.where("list_id").is(gridKey).and("index").is(i).and("block_id").is(JfGridConfigModel.FirstBlockID));
+            keyName=positionHandle(keyName);
+            Update u=new Update();
+            if(position==null){
+                u.set("json_data."+keyName,v);
+            }else{
+                u.set("json_data."+keyName+"."+position,v);
+            }
+
+            return updateOne(q, u);
+        }catch (Exception e){
+            log.error(e.getMessage());
+        }
+        return false;
+    }
+
+    /**
+     * jsonb数据中元素添加元素
+     *
+     * @param query
+     * @param word
+     * @param db
+     * @param position
+     * @return
+     */
+    @Override
+    public boolean updateJsonbForElementInsert(JSONObject query, String word, JSONObject db, Integer position) {
+        try{
+            Query q = new Query();
+            q.addCriteria(tranToCriteria(query));
+            word=positionHandle(word);
+            Update u=new Update();
+            if(position==0){
+                u.push("json_data."+word, db);
+            }else {
+                u.push("json_data."+word + "." + position, db);
+            }
+            return updateOne(q, u);
+        }catch (Exception e){
+            log.error(e.getMessage());
+        }
+        return false;
+    }
+
+    /**
+     * 更新 ,将key设置NULL
+     * @param query
+     * @param word json字符串
+     * @return
+     */
+    @Override
+    public boolean rmJsonbDataForEmpty(JSONObject query, String word) {
+        DBObject v=new BasicDBObject();
+        try{
+            Query q = new Query();
+            q.addCriteria(tranToCriteria(query));
+            Update u=new Update();
+            JSONObject wordJson=JSONObject.parseObject("{"+word+"}");
+            for(String k:wordJson.keySet()){
+                u.set("json_data."+k,v);
+            }
+            return updateOne(q, u);
+        }catch (Exception e){
+            log.error(e.getMessage());
+        }
+        return false;
+    }
+
+    /**
+     * 更新 ,按key设置值
+     * @param query
+     * @param word json字符串
+     * @return
+     */
+    @Override
+    public boolean updateJsonbDataForKeys(JSONObject query, JSONObject word) {
+        try{
+            Query q = new Query();
+            q.addCriteria(tranToCriteria(query));
+            Update u=new Update();
+            for(String k:word.keySet()){
+                u.set("json_data."+k,word.get(k));
+            }
+            return updateOne(q, u);
+        }catch (Exception e){
+            log.error(e.getMessage());
+        }
+        return false;
+    }
+
+    /**
+     * 更新status状态
+     *
+     * @param model
+     * @return
+     */
+    @Override
+    public boolean updateDataStatus(GridRecordDataModel model) {
+        List<Pair<Query,Update>> _updates=new ArrayList<Pair<Query,Update>>();
+        //设置全部status=0
+        Query query=new Query();
+        query.addCriteria(Criteria.where("list_id").is(model.getList_id()).and("status").is(1).and("block_id").is(JfGridConfigModel.FirstBlockID));
+        Update update=new Update();
+        update.set("status",0);
+        Pair<Query,Update> pair=Pair.of(query, update);
+        _updates.add(pair);
+        //设置激活的文档
+        Query query2=new Query();
+        query2.addCriteria(Criteria.where("list_id").is(model.getList_id()).and("index").is(model.getIndex()).and("block_id").is(JfGridConfigModel.FirstBlockID));
+        Update update2=new Update();
+        update2.set("status",1);
+        Pair<Query,Update> pair2=Pair.of(query2, update2);
+        _updates.add(pair2);
+
+        return updateMulti(_updates);
+
+    }
+
+    /**
+     * 更新sheet隐藏状态
+     *
+     * @param model
+     * @param hide
+     * @param index1
+     * @param index2
+     * @return
+     */
+    @Override
+    public boolean updateDataMsgHide(GridRecordDataModel model, Integer hide, String index1, String index2) {
+        List<Pair<Query,Update>> _updates=new ArrayList<Pair<Query,Update>>();
+        //设置隐藏
+        //设置i对应文档隐藏,并且status=0
+        Query query=new Query();
+        query.addCriteria(Criteria.where("list_id").is(model.getList_id()).and("index").is(index1).and("block_id").is(JfGridConfigModel.FirstBlockID));
+        Update update=new Update();
+        update.set("hide",hide);
+        update.set("status",0);
+        Pair<Query,Update> pair=Pair.of(query, update);
+        _updates.add(pair);
+
+        if(index2!=null) {
+            //设置cur对应文档status=1
+            Query query2 = new Query();
+            query2.addCriteria(Criteria.where("list_id").is(model.getList_id()).and("index").is(index2).and("block_id").is(JfGridConfigModel.FirstBlockID));
+            Update update2 = new Update();
+            update2.set("status", 1);
+            Pair<Query, Update> pair2 = Pair.of(query2, update2);
+            _updates.add(pair2);
+        }
+
+        return updateMulti(_updates);
+
+    }
+
+    /**
+     * 更新sheet隐藏状态
+     *
+     * @param model
+     * @param hide
+     * @param index
+     * @return
+     */
+    @Override
+    public boolean updateDataMsgNoHide(GridRecordDataModel model, Integer hide, String index) {
+        List<Pair<Query,Update>> _updates=new ArrayList<Pair<Query,Update>>();
+        //设置全部status=0
+        Query query=new Query();
+        query.addCriteria(Criteria.where("list_id").is(model.getList_id()).and("block_id").is(JfGridConfigModel.FirstBlockID));
+        Update update=new Update();
+        update.set("status",0);
+        Pair<Query,Update> pair=Pair.of(query, update);
+        _updates.add(pair);
+
+        //设置取消隐藏的文档
+        Query query2=new Query();
+        query2.addCriteria(Criteria.where("list_id").is(model.getList_id()).and("index").is(index).and("block_id").is(JfGridConfigModel.FirstBlockID));
+        Update update2=new Update();
+        update2.set("hide",hide);
+        update2.set("status",1);
+        Pair<Query,Update> pair2=Pair.of(query2, update2);
+        _updates.add(pair2);
+        return updateMulti(_updates);
+
+    }
+
+    /**
+     * 更新jsonb中某条文本数据
+     *
+     * @param block_ids 要删除的
+     * @param models    新增加的
+     * @return
+     */
+    @Override
+    public boolean batchUpdateCellDataValue(List<String> block_ids, List<GridRecordDataModel> models) {
+        try{
+            Query del=new Query();
+            del.addCriteria(Criteria.where("list_id").is(models.get(0).getList_id())
+                    .and("index").is(models.get(0).getIndex())
+                    .and("block_id").in(block_ids.toArray()));
+
+            List<JSONObject> jsonObjects=new ArrayList<>(5);
+            for(GridRecordDataModel m:models){
+                jsonObjects.add(tranToJSONObject(m));
+            }
+
+            BulkOperations ops=mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, COLLECTION_NAME);
+            ops.remove(del);
+            ops.insert(jsonObjects);
+            ops.execute();
+            return true;
+        }catch (Exception ex){
+            log.error(ex.toString());
+            return false;
+        }
+    }
+
+    /**
+     * jsonb数据中元素添加元素(集合插入)
+     * @param query 查询条件
+     * @param word  路径
+     * @param db    内容
+     * @param position  位置   (无效)
+     * @param words  初始化的内容 (无效)
+     * @return
+     */
+    @Override
+    public boolean updateJsonbForInsertNull(JSONObject query, String word, JSONObject db, Integer position, String words) {
+        Query q=new Query();
+        q.addCriteria(tranToCriteria(query));
+
+        Update update=new Update();
+        BasicDBList _dlist=new BasicDBList();
+        _dlist.add(db);
+        update.set("json_data."+word, _dlist);
+
+        return updateOne(q,update);
+
+    }
+
+    /**
+     * jsonb数据中元素添加元素(集合插入),不存在创建一个空集合  (同上一个方法)
+     * @param query 查询条件
+     * @param word  路径
+     * @param db    内容
+     * @param position  位置  (无效)
+     * @return
+     */
+    @Override
+    public boolean updateJsonbForSetNull(JSONObject query, String word, JSONObject db, Integer position) {
+//        Query q=new Query();
+//        q.addCriteria(tranToCriteria(query));
+//
+//        Update update=new Update();
+//        BasicDBList _dlist=new BasicDBList();
+//        _dlist.add(db);
+//        update.set(word, _dlist);
+//
+//        return updateOne(q,update);
+        return updateJsonbForInsertNull(query,word,db,null,null);
+    }
+
+    /**
+     * jsonb数据中元素添加元素(根节点)
+     *
+     * @param query
+     * @param word
+     * @param db
+     * @param position (无效)
+     * @param words (无效)
+     * @return
+     */
+    @Override
+    public boolean updateJsonbForSetRootNull(JSONObject query, String word, JSONObject db, Integer position, String words) {
+        Query q=new Query();
+        q.addCriteria(tranToCriteria(query));
+
+        Update update=new Update();
+        update.set("json_data."+positionHandle(word), db);
+
+        return updateOne(q,update);
+    }
+}

+ 85 - 0
luckysheet-mongo/src/main/java/com/xc/luckysheet/mongo/impl/RecordDelHandle.java

@@ -0,0 +1,85 @@
+package com.xc.luckysheet.mongo.impl;
+
+import com.mongodb.client.result.DeleteResult;
+import com.xc.luckysheet.db.IRecordDelHandle;
+import com.xc.luckysheet.entity.GridRecordDataModel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.data.mongodb.core.query.Update;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * 删除
+ * @author cr
+ * @Date: 2021-02-27 14:10
+ */
+@Slf4j
+@Repository(value = "mongoRecordDelHandle")
+public class RecordDelHandle extends BaseHandle implements IRecordDelHandle {
+
+    /**
+     * 删除sheet(非物理删除)
+     *
+     * @param model
+     * @return
+     */
+    @Override
+    public boolean updateDataForReDel(GridRecordDataModel model) {
+        Query query=new Query();
+        query.addCriteria(Criteria.where("list_id").is(model.getList_id())
+        .and("index").is(model.getIndex()));
+
+        Update update=new Update();
+        update.set("is_delete",model.getIs_delete());
+        return updateMulti(query,update);
+    }
+
+    /**
+     * 按ID 删除多个文档 (物理删除)
+     *
+     * @param ids
+     * @return
+     */
+    @Override
+    public String delDocuments(List<String> ids) {
+        if(ids==null || ids.size()==0){
+            return "";
+        }
+        Query query=new Query();
+        query.addCriteria(Criteria.where("_id").in(ids.toArray()));
+        try{
+            mongoTemplate.remove(query,COLLECTION_NAME);
+            return "";
+        }catch (Exception ex){
+            log.error(ex.toString());
+            return ex.toString();
+        }
+    }
+
+    /**
+     * 按list_id 删除记录 (物理删除)
+     *
+     * @param listIds
+     * @return
+     */
+    @Override
+    public int[] delete(List<String> listIds) {
+        if(listIds==null || listIds.size()==0){
+            return null;
+        }
+        Query query=new Query();
+        query.addCriteria(Criteria.where("list_id").in(listIds.toArray()));
+        try{
+            DeleteResult result=mongoTemplate.remove(query,COLLECTION_NAME);
+            int[] i=new int[0];
+            i[0]=(int)result.getDeletedCount();
+            return i;
+        }catch (Exception ex){
+            log.error(ex.toString());
+            return null;
+        }
+    }
+}

+ 376 - 0
luckysheet-mongo/src/main/java/com/xc/luckysheet/mongo/impl/RecordSelectHandle.java

@@ -0,0 +1,376 @@
+package com.xc.luckysheet.mongo.impl;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.mongodb.DBObject;
+import com.xc.luckysheet.JfGridConfigModel;
+import com.xc.luckysheet.db.IRecordSelectHandle;
+import com.xc.luckysheet.util.JfGridFileUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.bson.Document;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.mongodb.core.query.BasicQuery;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * 查询
+ * @author cr
+ * @Date: 2021-02-27 14:11
+ */
+@Slf4j
+@Repository(value = "mongoRecordSelectHandle")
+public class RecordSelectHandle extends BaseHandle implements IRecordSelectHandle {
+
+    /**
+     * 查看指定sheet页 查看第一块是否存在(控制块)
+     *
+     * @param listId
+     * @param index
+     * @return
+     */
+    @Override
+    public Integer getFirstBlockByGridKey(String listId, String index) {
+        //默认获取第一块
+        Document dbObject = getQueryCondition(listId,index,JfGridConfigModel.FirstBlockID);
+
+        Document fieldsObject=new Document();
+        fieldsObject.put("_id",false);
+        fieldsObject.put("list_id",true);
+        fieldsObject.put("index",true);
+
+        try{
+            Query query = new BasicQuery(dbObject, fieldsObject);
+            JSONObject jsonObject=(JSONObject)mongoTemplate.findOne(query, JSONObject.class, COLLECTION_NAME);
+            if(jsonObject==null){
+                return null;
+            }
+            return 1;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 获取指定的xls激活的sheet页的 返回index(控制块)
+     *
+     * @param listId
+     * @return
+     */
+    @Override
+    public String getFirstBlockIndexByGridKey(String listId) {
+        Document dbObject = new Document();
+        dbObject.put("list_id", listId);
+        dbObject.put("block_id", JfGridConfigModel.FirstBlockID);
+        dbObject.put("status",1);
+        dbObject.put("is_delete",0);
+
+        Document fieldsObject=new Document();
+        fieldsObject.put("_id",false);
+        fieldsObject.put("list_id",true);
+        fieldsObject.put("index",true);
+
+        try{
+            Query query = new BasicQuery(dbObject, fieldsObject);
+            JSONObject jsonObject=(JSONObject)mongoTemplate.findOne(query, JSONObject.class, COLLECTION_NAME);
+            return getStringByKey(jsonObject,"index");
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+
+    }
+
+    /**
+     * 获取指定的xls,sheet 第一块的行列信息(控制块)
+     *
+     * @param listId
+     * @param index
+     * @return
+     */
+    @Override
+    public String getFirstBlockRowColByGridKey(String listId, String index) {
+        Document dbObject = getQueryCondition(listId,index,JfGridConfigModel.FirstBlockID);
+
+        Document fieldsObject=new Document();
+        fieldsObject.put("_id",false);
+        fieldsObject.put("list_id",true);
+        fieldsObject.put("index",true);
+        fieldsObject.put("row_col",true);
+
+        try{
+            Query query = new BasicQuery(dbObject, fieldsObject);
+            JSONObject jsonObject=(JSONObject)mongoTemplate.findOne(query, JSONObject.class, COLLECTION_NAME);
+            return getStringByKey(jsonObject,"row_col");
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 按指定xls,sheet顺序返回整个xls结构
+     * 不返回celldata ,只获取信息块
+     *
+     * @param listId
+     * @return
+     */
+    @Override
+    public List<JSONObject> getByGridKey_NOCelldata(String listId) {
+        try{
+            Document fieldsObject=new Document();
+            fieldsObject.put("json_data",false);
+            Document searchObject1=new Document();
+            Query query=new BasicQuery(searchObject1,fieldsObject);
+            //Query query=new Query();
+            query.addCriteria(
+                    Criteria.where("list_id").is(listId)
+                            .and("block_id").is(JfGridConfigModel.FirstBlockID)
+                            .and("is_delete").is(0))
+                    .with(new Sort(Sort.Direction.ASC, "order"));
+            log.info("query "+query+" COLLECTION_NAME:"+COLLECTION_NAME);
+            return mongoTemplate.find(query, JSONObject.class, COLLECTION_NAME);
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 按指定xls,sheet获取,返回指定的sheet集合
+     *
+     * @param listId
+     * @param index
+     * @return
+     */
+    @Override
+    public List<JSONObject> getBlockAllByGridKey(String listId, String index) {
+        try{
+            Query query=new Query();
+            query.addCriteria(Criteria.where("list_id").is(listId)
+                    .and("index").in(index)
+                    .and("is_delete").is(0));
+            List<JSONObject> jsonObjects= mongoTemplate.find(query, JSONObject.class, COLLECTION_NAME);
+            return jsonObjects;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 获取指定xls,sheet,block的数据
+     *
+     * @param listId
+     * @param index
+     * @param blockId
+     * @return
+     */
+    @Override
+    public JSONObject getCelldataByGridKey(String listId, String index, String blockId) {
+        try{
+            Document dbObject = getQueryCondition(listId,index,blockId);
+
+            Document fieldsObject=new Document();
+            fieldsObject.put("_id",true);
+            fieldsObject.put("list_id",true);
+            fieldsObject.put("index",true);
+            fieldsObject.put("json_data.celldata",true);
+            fieldsObject.put("json_data.column",true);
+            fieldsObject.put("json_data.row",true);
+
+            Query query = new BasicQuery(dbObject, fieldsObject);
+            JSONObject jsonObject=  mongoTemplate.findOne(query, JSONObject.class, COLLECTION_NAME);
+            cellDataHandle(jsonObject);
+            return jsonObject;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 获取指定xls、sheet中的config中数据 (存放在第一块中)
+     *
+     * @param listId
+     * @param index
+     * @return
+     */
+    @Override
+    public JSONObject getConfigByGridKey(String listId, String index) {
+        //默认获取第一块
+        try{
+            Document dbObject =getQueryCondition(listId,index,JfGridConfigModel.FirstBlockID);
+
+            Document fieldsObject=new Document();
+            fieldsObject.put("_id",false);
+            fieldsObject.put("list_id",true);
+            fieldsObject.put("index",true);
+            fieldsObject.put("json_data.config",true);
+            fieldsObject.put("json_data.calcChain",true);
+            fieldsObject.put("json_data.filter",true);
+            fieldsObject.put("block_id",true);
+
+            Query query = new BasicQuery(dbObject, fieldsObject);
+            JSONObject jsonObject=mongoTemplate.findOne(query, JSONObject.class, COLLECTION_NAME);
+            cellDataHandle(jsonObject);
+            return jsonObject;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 按list_id获取,返回指定sheet 当前sheet的全部分块数据(并合并)getMergeByGridKey
+     * 返回是DBObject,而下面这个方法返回仅仅只有celldata
+     *
+     * @param listId
+     * @param index
+     * @param ids    返回记录存在数据库的ID
+     * @return
+     */
+    @Override
+    public JSONObject getBlockMergeByGridKey(String listId, String index, List<String> ids) {
+        JSONObject _fblock=new JSONObject();
+        JSONArray _celldata=new JSONArray();
+        //获取全部块
+        List<JSONObject> blocks=getBlockAllByGridKey(listId, index);
+        if(blocks!=null && blocks.size()>0){
+            for(JSONObject _b:blocks){
+                if(ids!=null){
+                    if(_b.containsKey("_id")){
+                        ids.add(_b.get("_id").toString());
+                    }
+                }
+                if(_b.containsKey("block_id")){
+                    if(JfGridConfigModel.FirstBlockID.equals(_b.get("block_id"))){
+                        //信息块
+                        _fblock=_b;
+                    }else{
+                        //数据块
+                        //注意:此处与MySql不同
+                        JSONArray _blockCellData=JfGridFileUtil.getSheetByIndex(_b);
+                        if(_blockCellData!=null){
+                            _celldata.addAll(_blockCellData);
+                        }
+                    }
+                }
+            }
+        }
+        _fblock.put("celldata",_celldata);
+        return _fblock;
+    }
+
+    /**
+     * 按list_id获取(id,index),返回sheet集合
+     *
+     * @param listId
+     * @param flag   是否仅仅获取主要模块
+     * @return
+     */
+    @Override
+    public List<JSONObject> getBlocksByGridKey(String listId, boolean flag) {
+        try{
+//            Query query=new Query();
+//            query.addCriteria(Criteria.where("list_id").is(list_id).and("index").is(index));
+//            return mongoTemplate.find(query, DBObject.class, NEW_COLLECTION_NAME);
+
+            Document dbObject = new Document();
+            dbObject.put("list_id", listId);
+            if(flag){
+                dbObject.put("block_id", JfGridConfigModel.FirstBlockID);
+            }
+            dbObject.put("is_delete",0);
+
+            Document fieldsObject=new Document();
+            fieldsObject.put("_id",true);
+            fieldsObject.put("list_id",true);
+            fieldsObject.put("index",true);
+
+            Query query = new BasicQuery(dbObject, fieldsObject);
+            return  mongoTemplate.find(query, JSONObject.class, COLLECTION_NAME);
+        }catch (Exception e){
+            log.warn(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 获取指定xls,多个sheet的全部分块
+     *
+     * @param listId
+     * @param indexs
+     * @return
+     */
+    @Override
+    public List<JSONObject> getAllIndexsByGridKey(String listId, List<String> indexs) {
+        try{
+            Query query=new Query();
+            query.addCriteria(Criteria.where("list_id").is(listId)
+                    .and("index").in(indexs)
+                    .and("is_delete").is(0))
+                    .with(new Sort(Sort.Direction.ASC, "order"));
+            log.info("getByGridKey--"+query);
+            return mongoTemplate.find(query, JSONObject.class, COLLECTION_NAME);
+        }catch (Exception e){
+            log.warn(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 获取指定xls,sheet全部内容
+     *
+     * @param listId
+     * @param index
+     * @return
+     */
+    @Override
+    public List<JSONObject> getIndexsByGridKey(String listId, String index) {
+        try{
+            Query query=new Query();
+            query.addCriteria(Criteria.where("list_id").is(listId)
+                    .and("index").in(index)
+                    .and("is_delete").is(0))
+                    .with(new Sort(Sort.Direction.ASC, "order"));
+            return mongoTemplate.find(query, JSONObject.class, COLLECTION_NAME);
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 获取图表数据(第一块)
+     *
+     * @param listId
+     * @param index
+     * @return
+     */
+    @Override
+    public JSONObject getChartByGridKey(String listId, String index) {
+        try{
+            Document dbObject = getQueryCondition(listId,index,JfGridConfigModel.FirstBlockID);
+
+            Document fieldsObject=new Document();
+            fieldsObject.put("_id",false);
+            fieldsObject.put("list_id",true);
+            fieldsObject.put("index",true);
+            fieldsObject.put("json_data.chart",true);
+            fieldsObject.put("block_id",true);
+
+            Query query = new BasicQuery(dbObject, fieldsObject);
+            JSONObject jsonObject= mongoTemplate.findOne(query, JSONObject.class, COLLECTION_NAME);
+            cellDataHandle(jsonObject);
+            return jsonObject;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+}

+ 93 - 0
luckysheet-mysql/README-zh.md

@@ -0,0 +1,93 @@
+mysql版本 >= 8 
+
+## 数据库初始化
+
+创建数据库
+```
+CREATE DATABASE luckysheetdb
+```
+
+创建表 id采用雪花算法
+```
+CREATE TABLE `luckysheet` (
+  `id` bigint(30) NOT NULL,
+  `block_id` varchar(200) NOT NULL,
+  `row_col` varchar(50) DEFAULT NULL,
+  `index` varchar(200) NOT NULL,
+  `list_id` varchar(200) NOT NULL,
+  `status` int(1) DEFAULT NULL,
+  `json_data` json DEFAULT NULL,
+  `order` int(3) DEFAULT NULL,
+  `is_delete` int(1) DEFAULT NULL,
+  PRIMARY KEY (`id`),
+  KEY `lib` (`list_id`,`index`,`block_id`),
+  KEY ```order``` (`order`),
+  KEY ```status``` (`status`),
+  KEY ```is_delete``` (`is_delete`)
+) ENGINE=InnoDB DEFAULT CHARSET=armscii8
+```
+
+插入初始化语句
+```
+INSERT INTO luckysheet VALUES (139400313311449087, 'fblock', '', '1', '1079500#-8803#7c45f52b7d01486d88bc53cb17dcd2c3', 1, '{"row":84,"name":"Sheet1","chart":[],"color":"","index":"1","order":0,"column":60,"config":{},"status":0,"celldata":[],"ch_width":4748,"rowsplit":[],"rh_height":1790,"scrollTop":0,"scrollLeft":0,"visibledatarow":[],"visibledatacolumn":[],"jfgird_select_save":[],"jfgrid_selection_range":{}}', 0, 0);
+INSERT INTO luckysheet VALUES (139400313311449088, 'fblock', '', '2', '1079500#-8803#7c45f52b7d01486d88bc53cb17dcd2c3', 0, '{"row":84,"name":"Sheet2","chart":[],"color":"","index":"2","order":1,"column":60,"config":{},"status":0,"celldata":[],"ch_width":4748,"rowsplit":[],"rh_height":1790,"scrollTop":0,"scrollLeft":0,"visibledatarow":[],"visibledatacolumn":[],"jfgird_select_save":[],"jfgrid_selection_range":{}}', 1, 0);
+INSERT INTO luckysheet VALUES (139400313311449089, 'fblock', '', '3', '1079500#-8803#7c45f52b7d01486d88bc53cb17dcd2c3', 0, '{"row":84,"name":"Sheet3","chart":[],"color":"","index":"3","order":2,"column":60,"config":{},"status":0,"celldata":[],"ch_width":4748,"rowsplit":[],"rh_height":1790,"scrollTop":0,"scrollLeft":0,"visibledatarow":[],"visibledatacolumn":[],"jfgird_select_save":[],"jfgrid_selection_range":{}}', 2, 0);
+```
+
+注意:
+表中 index、order 是关键字
+
+
+## 项目中使用
+1、luckysheet中的pom.xml 注释postgre,引入mysql
+```aidl
+        <!-- 数据库接口以及实现 -->
+        <dependency>
+            <groupId>com.xc</groupId>
+            <artifactId>luckysheet-db</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.xc</groupId>
+            <artifactId>luckysheet-mysql</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <!--<dependency>-->
+            <!--<groupId>com.xc</groupId>-->
+            <!--<artifactId>luckysheet-postgre</artifactId>-->
+            <!--<version>${project.version}</version>-->
+        <!--</dependency>-->
+```
+
+2、com.xc.luckysheet.db.server 文件夹中
+JfGridFileGetService类
+JfGridUpdateService类
+
+mysql实现
+```$xslt
+@Resource(name = "mysqlRecordDataInsertHandle")
+private IRecordDataInsertHandle recordDataInsertHandle;
+
+@Resource(name = "mysqlRecordDataUpdataHandle")
+private IRecordDataUpdataHandle recordDataUpdataHandle;
+
+@Resource(name = "mysqlRecordDelHandle")
+private IRecordDelHandle recordDelHandle;
+
+@Resource(name = "mysqlRecordSelectHandle")
+private IRecordSelectHandle recordSelectHandle;
+```
+postgres实现
+```
+@Resource(name = "postgresRecordDataInsertHandle")
+private IRecordDataInsertHandle recordDataInsertHandle;
+
+@Resource(name = "postgresRecordDataUpdataHandle")
+private IRecordDataUpdataHandle recordDataUpdataHandle;
+
+@Resource(name = "postgresRecordDelHandle")
+private IRecordDelHandle recordDelHandle;
+
+@Resource(name = "postgresRecordSelectHandle")
+private IRecordSelectHandle recordSelectHandle;
+```

+ 81 - 0
luckysheet-mysql/pom.xml

@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>luckySheetServer</artifactId>
+        <groupId>com.xc</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.xc</groupId>
+    <artifactId>luckysheet-mysql</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <packaging>jar</packaging>
+    <name>luckysheet-mysql</name>
+    <description>mysql8实现</description>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-webmvc</artifactId>
+            <version>5.1.6.RELEASE</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.annotation</groupId>
+            <artifactId>javax.annotation-api</artifactId>
+            <version>1.3.2</version>
+        </dependency>
+
+        <!--自动生成set get方法-->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.12</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <scope>compile</scope>
+            <optional>true</optional>
+        </dependency>
+
+        <!-- spring-jdbc -->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-jdbc</artifactId>
+            <version>5.1.10.RELEASE</version>
+        </dependency>
+
+        <!--阿里的druid数据源-->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid</artifactId>
+            <version>1.1.20</version>
+        </dependency>
+
+        <!-- mysql  -->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <version>8.0.11</version>
+        </dependency>
+
+        <!---数据库接口-->
+        <dependency>
+            <groupId>com.xc</groupId>
+            <artifactId>luckysheet-db</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+    </dependencies>
+
+</project>

BIN
luckysheet-mysql/src/.DS_Store


BIN
luckysheet-mysql/src/main/.DS_Store


BIN
luckysheet-mysql/src/main/java/.DS_Store


BIN
luckysheet-mysql/src/main/java/com/.DS_Store


BIN
luckysheet-mysql/src/main/java/com/xc/.DS_Store


BIN
luckysheet-mysql/src/main/java/com/xc/luckysheet/.DS_Store


BIN
luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/.DS_Store


+ 35 - 0
luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/datasource/DataSourceConfig.java

@@ -0,0 +1,35 @@
+package com.xc.luckysheet.mysql.datasource;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import com.xc.luckysheet.util.SnowFlake;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.sql.DataSource;
+
+
+/**
+ * 数据源配置
+ * @author Administrator
+ */
+@Configuration
+@Slf4j
+public class DataSourceConfig {
+
+    @Bean(name = "mysqlDataSource")
+    @ConfigurationProperties(prefix = "db.mysql.druid")
+    public DataSource postgreDataSource(){
+        DataSource dataSource = DataSourceBuilder.create().type(DruidDataSource.class).build();
+        log.debug("数据源 mysql",dataSource);
+        return dataSource;
+    }
+
+    @Bean(name="snowFlake")
+    public SnowFlake getSnowFlake(){
+        return new SnowFlake(1l,1l);
+    }
+
+}

+ 30 - 0
luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/datasource/JdbcTempleConfig.java

@@ -0,0 +1,30 @@
+package com.xc.luckysheet.mysql.datasource;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import javax.annotation.Resource;
+import javax.sql.DataSource;
+
+
+/**
+ * @author Administrator
+ */
+@Configuration
+@Slf4j
+public class JdbcTempleConfig {
+
+    /**
+     * postgre数据源
+     */
+    @Resource(name = "mysqlDataSource")
+    private DataSource dataSource;
+
+    @Bean(name="mysqlJdbcTemplate")
+    public JdbcTemplate createJdbcTemplate(){
+        return new JdbcTemplate(dataSource);
+    }
+
+}

+ 49 - 0
luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/datasource/ProfiledemoApplication.java

@@ -0,0 +1,49 @@
+package com.xc.luckysheet.mysql.datasource;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+import org.springframework.transaction.annotation.TransactionManagementConfigurer;
+
+import javax.annotation.Resource;
+import javax.sql.DataSource;
+
+/**
+ * @author Administrator
+ */
+
+/**
+ * 开启注解事务管理,等同于xml配置文件中的 <tx:annotation-driven />
+ * @author Administrator
+ */
+@EnableTransactionManagement
+@Configuration
+public class ProfiledemoApplication implements TransactionManagementConfigurer {
+
+    /**
+     * postgre数据源
+     */
+    @Resource(name = "mysqlDataSource")
+    private DataSource dataSource;
+
+
+    @Bean(name = "mysqlTxManager")
+    public PlatformTransactionManager mysqlTxManager() {
+        return new DataSourceTransactionManager(dataSource);
+    }
+
+
+    @Resource(name="mysqlTxManager")
+    private PlatformTransactionManager txManager;
+
+    /**
+     * 实现接口 TransactionManagementConfigurer 方法,其返回值代表在拥有多个事务管理器的情况下默认使用的事务管理器
+     * @return
+     */
+    @Override
+    public PlatformTransactionManager annotationDrivenTransactionManager() {
+        return txManager;
+    }
+}

+ 72 - 0
luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/impl/BaseHandle.java

@@ -0,0 +1,72 @@
+package com.xc.luckysheet.mysql.impl;
+
+import com.xc.luckysheet.util.SnowFlake;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 数据库连接
+ * @author Administrator
+ */
+@Slf4j
+@Component
+public class BaseHandle {
+
+    @Resource(name = "mysqlJdbcTemplate")
+    protected JdbcTemplate luckySheetJdbcTemplate;
+
+
+    @Resource(name = "snowFlake")
+    protected SnowFlake snowFlake;
+
+    /**
+     * 字符串位置处理
+     * x,y,z  -> x.y.z
+     * x,1,2  -> x[1].z
+     * @param str
+     * @return
+     */
+    protected String positionHandle(String str){
+        if(str==null||str.indexOf(",")==-1){
+            return str;
+        }
+
+        String[] strs=str.split(",");
+        String result="";
+        for(String s:strs){
+            if(result.length()==0){
+                result=s;
+            }else{
+                if(isNumeric(s)){
+                    result+="["+s+"]";
+                }else{
+                    result+="."+s;
+                }
+            }
+        }
+        return result;
+    }
+
+
+    private Pattern patternIsNumeric = Pattern.compile("[0-9]*");
+    /**
+     * 利用正则表达式判断字符串是否是数字
+     * @param str
+     * @return
+     */
+    protected  boolean isNumeric(String str){
+        Matcher isNum = patternIsNumeric.matcher(str);
+        if( !isNum.matches() ){
+            return false;
+        }
+        return true;
+    }
+
+}

+ 134 - 0
luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/impl/RecordDataInsertHandle.java

@@ -0,0 +1,134 @@
+package com.xc.luckysheet.mysql.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.xc.luckysheet.JfGridConfigModel;
+import com.xc.luckysheet.db.IRecordDataInsertHandle;
+import com.xc.luckysheet.entity.GridRecordDataModel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Repository;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 添加
+ * @author Administrator
+ */
+@Slf4j
+@Repository(value = "mysqlRecordDataInsertHandle")
+public class RecordDataInsertHandle extends BaseHandle implements IRecordDataInsertHandle {
+    /**
+     * 新增Sheet页,并返回刚刚插入的_id
+     *
+     * @param pgModel
+     * @return
+     */
+    @Override
+    public String insert(GridRecordDataModel pgModel) {
+        String sql = "insert into "+JfGridConfigModel.TABLENAME +" (id,row_col,block_id,`index`,list_id,status,json_data,`order`,is_delete) values " +
+                " (?,?,?,?,?,?,?,?,0)";
+        try{
+            pgModel.setId(snowFlake.nextId().longValue());
+            luckySheetJdbcTemplate.update(sql,pgModel.getId(),pgModel.getRow_col(),pgModel.getBlock_id().trim(),pgModel.getIndex(),pgModel.getList_id(),pgModel.getStatus(),pgModel.getJson_data().toJSONString(),pgModel.getOrder());
+            return pgModel.getId().toString();
+        }catch (Exception e){
+            log.error(e.getMessage());
+        }
+        return null;
+    }
+
+    /**
+     * 批量添加 添加jsonb
+     *
+     * @param models
+     * @return
+     */
+    @Override
+    public String InsertIntoBatch(List<GridRecordDataModel> models) {
+        String sql = "insert into "+JfGridConfigModel.TABLENAME +" (id,block_id,row_col,`index`,list_id,status,`order`,json_data,is_delete) values " +
+                " (?,?,?,?,?,?,?,?,0)";
+        List<Object[]>batch=new ArrayList<Object[]>();
+        for(GridRecordDataModel b : models){
+            List<Object> objectList=new ArrayList<Object>();
+            objectList.add(snowFlake.nextId().longValue());
+            objectList.add(b.getBlock_id().trim());
+            objectList.add(b.getRow_col());
+            objectList.add(b.getIndex());
+            objectList.add(b.getList_id());
+            objectList.add(b.getStatus());
+            objectList.add(b.getOrder());
+            objectList.add(b.getJson_data().toJSONString());
+
+            Object[] params=(Object[])objectList.toArray(new Object[objectList.size()]);
+            batch.add(params);
+        }
+        try{
+            log.info("InsertIntoBatch sql{}",sql);
+            int[] i= luckySheetJdbcTemplate.batchUpdate(sql,batch);
+            log.info("InsertIntoBatch count {}",i);
+            return "";
+        }catch (Exception ex){
+            log.error(ex.toString());
+            return null;
+        }
+    }
+
+    /**
+     * 批量添加 添加jsonb
+     *
+     * @param models
+     * @return
+     */
+    @Override
+    public String InsertBatchDb(List<JSONObject> models) {
+        String sql = "insert into "+JfGridConfigModel.TABLENAME+" (id,block_id,row_col,`index`,list_id,status,`order`,json_data,is_delete) values " +
+                " (?,?,?,?,?,?,?,?,0)";
+        List<Object[]>batch=new ArrayList<Object[]>();
+        int order=0;
+        for(JSONObject b : models){
+            List<Object> objectList=new ArrayList<Object>();
+            objectList.add(snowFlake.nextId().longValue());
+            objectList.add(b.get("block_id").toString().trim());
+            if(b.containsKey("row_col") && b.get("row_col")!=null){
+                objectList.add(b.get("row_col"));
+            }else{
+                objectList.add(null);
+            }
+            objectList.add(b.get("index"));
+            objectList.add(b.get("list_id"));
+            if(b.containsKey("status") && b.get("status")!=null){
+                objectList.add(b.get("status"));
+            }else{
+                objectList.add(0);
+            }
+
+            if(b.containsKey("order") && b.get("order")!=null){
+                objectList.add(b.get("order"));
+                order=Integer.valueOf(b.get("order").toString());
+            }else{
+                objectList.add(order);
+            }
+
+            JSONObject db=new JSONObject();
+            if(b.containsKey("json_data")){
+                db=(JSONObject) b.get("json_data");
+            }else{
+                db.put("celldata", b.get("celldata"));
+            }
+            objectList.add(db.toJSONString());
+
+            Object[] params=(Object[])objectList.toArray(new Object[objectList.size()]);
+            batch.add(params);
+        }
+
+        try{
+            log.info("InsertBatchDb sql{}",sql);
+            int[] i= luckySheetJdbcTemplate.batchUpdate(sql,batch);
+            log.info("InsertBatchDb count {}",i);
+            return "";
+        }catch (Exception ex){
+            log.error(ex.getMessage());
+            return null;
+        }
+    }
+}

+ 561 - 0
luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/impl/RecordDataUpdataHandle.java

@@ -0,0 +1,561 @@
+package com.xc.luckysheet.mysql.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.xc.luckysheet.JfGridConfigModel;
+import com.xc.luckysheet.db.IRecordDataInsertHandle;
+import com.xc.luckysheet.db.IRecordDataUpdataHandle;
+import com.xc.luckysheet.db.IRecordDelHandle;
+import com.xc.luckysheet.entity.GridRecordDataModel;
+import com.xc.luckysheet.util.JfGridFileUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.jdbc.core.BatchPreparedStatementSetter;
+import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 更新
+ * @author Administrator
+ */
+@Slf4j
+@Repository(value ="mysqlRecordDataUpdataHandle" )
+public class RecordDataUpdataHandle extends BaseHandle implements IRecordDataUpdataHandle {
+
+    @Resource
+    @Qualifier("mysqlRecordDataInsertHandle")
+    private IRecordDataInsertHandle RecordDataInsertHandle;
+
+    @Resource
+    @Qualifier("mysqlRecordDelHandle")
+    private IRecordDelHandle recordDelHandle;
+
+    /**
+     * sheet多块更新(先删除后添加)
+     * 按IDS删除一组,然后新加处理后的
+     * @param blocks
+     * @param ids
+     * @return
+     */
+    @Transactional(value = "mysqlTxManager",rollbackFor = Exception.class)
+    @Override
+    public Boolean updateMulti2(List<JSONObject> blocks, List<String> ids) {
+        try{
+            if(ids!=null && ids.size()>0){
+                recordDelHandle.delDocuments(ids);
+            }
+            String _mongodbKey = RecordDataInsertHandle.InsertBatchDb(blocks);
+            if (_mongodbKey == null) {
+                throw new RuntimeException("插入报错");
+            }
+            return true;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+    /**
+     * 批量更新order 按listId,index,首块
+     *
+     * @param models
+     * @return
+     */
+    @Override
+    public boolean batchUpdateForNoJsonbData(List<GridRecordDataModel> models) {
+        try{
+            String sql="update "+JfGridConfigModel.TABLENAME+" set `order`=?  where  list_id=? and `index`=? and block_id=?";
+            log.info("batchUpdateForNoJsonbData:"+sql);
+            luckySheetJdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
+                public int getBatchSize() {
+                    return models.size();
+                    //这个方法设定更新记录数,通常List里面存放的都是我们要更新的,所以返回list.size();
+                }
+                public void setValues(PreparedStatement ps, int i)throws SQLException {
+                    GridRecordDataModel linkset =  models.get(i);
+                    ps.setInt(1, linkset.getOrder());
+                    ps.setString(2, linkset.getList_id());
+                    ps.setString(3, linkset.getIndex());
+                    ps.setString(4, JfGridConfigModel.FirstBlockID);
+                }
+            });
+            return true;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return false;
+        }
+    }
+
+    /**
+     * 清除指定层级下某条数据
+     *
+     * @param query   键值对
+     * @param keyName
+     * @return
+     */
+    @Override
+    public boolean rmCellDataValue(JSONObject query, String keyName) {
+        try{
+            log.info("select:"+query.toString(SerializerFeature.WriteMapNullValue));
+            String condition= JfGridFileUtil.getCondition(query);
+            String updateSql="update "+JfGridConfigModel.TABLENAME+" t set t.json_data=json_remove(t.json_data,\"$."+keyName+"\")  where 1=1 " +condition;
+            log.info("rmCellDataValue--"+updateSql);
+            luckySheetJdbcTemplate.update(updateSql);
+            return true;
+        }catch (Exception ex){
+            log.error(ex.getMessage());
+            return false;
+        }
+    }
+
+    /**
+     * 更新jsonb中某条文本数据
+     *
+     * @param query    键值对
+     * @param keyName
+     * @param position
+     * @param v
+     * @return
+     */
+    @Override
+    public boolean updateCellDataListTxtValue(JSONObject query, String keyName, Integer position, Object v) {
+        try{
+            log.info("select:"+query.toString(SerializerFeature.WriteMapNullValue));
+            String condition= JfGridFileUtil.getCondition(query);
+            if(position!=null){
+                keyName=keyName+"["+position+"]";
+            }
+            StringBuffer updateSql=new StringBuffer();
+            //updateSql.append("update "+JfGridConfigModel.TABLENAME+" t set t.json_data=jsonb_set(t.json_data,'{"+keyName);
+            //updateSql.append("}'::text[],'"+v+"',true) where 1=1 "+condition);
+            updateSql.append("update "+JfGridConfigModel.TABLENAME+" t set t.json_data=json_set(t.json_data,\"$."+keyName+"\",");
+            if(v instanceof JSON){
+                updateSql.append("CAST('"+((JSON) v).toJSONString()+"' as JSON)");
+            }else{
+                updateSql.append("\""+v+"\"");
+            }
+            updateSql.append(") where 1=1 "+condition);
+
+            luckySheetJdbcTemplate.update(updateSql.toString());
+            return true;
+        }catch (Exception ex){
+            log.error(ex.getMessage());
+            return false;
+        }
+    }
+
+    /**
+     * 更新jsonb中某条文本数据
+     *
+     * @param query    键值对
+     * @param keyName
+     * @param position
+     * @param v
+     * @return
+     */
+    @Override
+    public boolean updateCellDataListValue(JSONObject query, String keyName, String position, Object v) {
+        try{
+            keyName=positionHandle(keyName);
+            log.info("select:"+query.toString(SerializerFeature.WriteMapNullValue));
+            String condition= JfGridFileUtil.getCondition(query);
+            if(position!=null){
+                keyName=keyName+"["+position+"]";
+            }
+            StringBuffer updateSql=new StringBuffer();
+            //updateSql.append("update "+JfGridConfigModel.TABLENAME+" t set t.json_data=jsonb_set(t.json_data,'{"+keyName);
+            //updateSql.append("}','"+v+"',true) where 1=1 "+condition);
+            updateSql.append("update "+JfGridConfigModel.TABLENAME+" t set t.json_data=json_set(t.json_data,\"$."+keyName+"\",");
+            if(v instanceof JSON){
+                updateSql.append("CAST('"+((JSON) v).toJSONString()+"' as JSON)");
+            }else{
+                updateSql.append("\""+v+"\"");
+            }
+            updateSql.append(") where 1=1 "+condition);
+
+            log.info("updateSql:"+updateSql.toString());
+            luckySheetJdbcTemplate.update(updateSql.toString());
+            return true;
+        }catch (Exception ex){
+            log.error(ex.getMessage());
+            return false;
+        }
+    }
+
+    /**
+     * jsonb数据中元素添加元素
+     *
+     * @param query
+     * @param word
+     * @param db
+     * @param position
+     * @return
+     */
+    @Override
+    public boolean updateJsonbForElementInsert(JSONObject query, String word, JSONObject db, Integer position) {
+        try{
+            log.info("select:"+query.toString(SerializerFeature.WriteMapNullValue));
+            List arr=new ArrayList<>();
+            String condition= JfGridFileUtil.getCondition(query,arr);
+            if(position!=null){
+                word=word+"["+position+"]";
+            }
+            //(jsonb_v,'{myinfo,celldata,0}','{"c":1,"r":1,"v":{"con":"str"}}',false)
+            //String updateSql="update "+JfGridConfigModel.TABLENAME+" set json_data=jsonb_insert(json_data,'{"+word+"}','"+db.toString()+"',false) where 1=1 " +condition;
+
+            StringBuffer updateSql=new StringBuffer();
+            updateSql.append("update "+JfGridConfigModel.TABLENAME+" t set t.json_data=json_set(t.json_data,\"$."+word+"\",");
+            updateSql.append("CAST('"+db.toString(SerializerFeature.WriteMapNullValue)+"' as JSON)");
+            updateSql.append(") where 1=1 "+condition);
+
+            log.info("updateSql:"+updateSql.toString());
+            luckySheetJdbcTemplate.update(updateSql.toString(),arr.toArray());
+            return true;
+        }catch (Exception ex){
+            log.error(ex.getMessage());
+            return false;
+        }
+    }
+
+    /**
+     * 更新 ,将key设置NULL
+     * @param query
+     * @param word json字符串
+     * @return
+     */
+    @Override
+    public boolean rmJsonbDataForEmpty(JSONObject query, String word) {
+        try{
+            log.info("select:"+query.toString(SerializerFeature.WriteMapNullValue));
+            List arr=new ArrayList<>();
+            String condition= JfGridFileUtil.getCondition(query,arr);
+
+            //String sql="update "+JfGridConfigModel.TABLENAME+" set json_data=json_data||'{"+word+"}'::jsonb where 1=1 "+condition;
+            StringBuilder sb=new StringBuilder(20);
+            JSONObject wordJson=JSONObject.parseObject("{"+word+"}");
+            Map<String, Object> queryDB = wordJson.getInnerMap();
+            for (String key : queryDB.keySet()) {
+                if(sb.toString().length()>0){
+                    sb.append(",");
+                }
+                sb.append("t.jsontest=json_set(t.jsontest,\"$."+key+"\",null)");
+            }
+
+            StringBuffer updateSql=new StringBuffer();
+            updateSql.append("update "+JfGridConfigModel.TABLENAME+" t set "+sb.toString());
+            updateSql.append(" where 1=1 "+condition);
+            log.info("updateSql:"+ updateSql.toString());
+            luckySheetJdbcTemplate.update(updateSql.toString(),arr.toArray());
+            return true;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return false;
+        }
+    }
+
+    /**
+     * 更新 ,按key设置值
+     * @param query
+     * @param word json字符串
+     * @return
+     */
+    @Override
+    public boolean updateJsonbDataForKeys(JSONObject query, JSONObject word) {
+        try{
+            log.info("select:"+query.toString(SerializerFeature.WriteMapNullValue));
+            List arr=new ArrayList<>();
+            String condition= JfGridFileUtil.getCondition(query,arr);
+            //String sql="update "+JfGridConfigModel.TABLENAME+" set json_data=json_data||'"+word.toString()+"'::jsonb where 1=1 "+condition;
+            StringBuilder sb=new StringBuilder(20);
+            JSONObject wordJson=word;
+            Map<String, Object> queryDB = wordJson.getInnerMap();
+            for (String key : queryDB.keySet()) {
+                if(sb.toString().length()>0){
+                    sb.append(",");
+                }
+                sb.append("t.jsontest=json_set(t.jsontest,\"$."+key+"\",\""+queryDB.get(key)+"\")");
+            }
+
+            StringBuffer updateSql=new StringBuffer();
+            updateSql.append("update "+JfGridConfigModel.TABLENAME+" t set "+sb.toString());
+            updateSql.append(" where 1=1 "+condition);
+            log.info("updateSql:"+ updateSql.toString());
+            luckySheetJdbcTemplate.update(updateSql.toString(),arr.toArray());
+            return true;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return false;
+        }
+
+    }
+
+    /**
+     * 更新status状态
+     *
+     * @param model
+     * @return
+     */
+    @Transactional(value = "mysqlTxManager",rollbackFor = Exception.class)
+    @Override
+    public boolean updateDataStatus(GridRecordDataModel model) {
+        try{
+            String sql1="update "+JfGridConfigModel.TABLENAME+" set status=0  where  list_id=? and status=1 and block_id=?";
+            log.info("updateSql1:"+sql1);
+            luckySheetJdbcTemplate.update(sql1,new Object[]{model.getList_id(),model.getBlock_id()});
+
+            String sql2="update "+JfGridConfigModel.TABLENAME+" set status=1  where  list_id=? and index=? and block_id=?";
+            log.info("updateSql2:"+sql2);
+            luckySheetJdbcTemplate.update(sql2,new Object[]{model.getList_id(),model.getIndex(),model.getBlock_id()});
+            return true;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+    /**
+     * 更新sheet隐藏状态
+     *
+     * @param model
+     * @param hide
+     * @param index1
+     * @param index2
+     * @return
+     */
+    @Transactional(value = "mysqlTxManager",rollbackFor = Exception.class)
+    @Override
+    public boolean updateDataMsgHide(GridRecordDataModel model, Integer hide, String index1, String index2) {
+        try{
+            //String sql1="update "+JfGridConfigModel.TABLENAME+" set status=0 ,json_data=jsonb_set(json_data,'{hide}'::text[],'"+hide+"',true) where  list_id=? and `index`=? and block_id=?";
+            String sql1="update "+JfGridConfigModel.TABLENAME+" set status=0 ,json_data=json_set(json_data,\"$.hide\","+hide+") where  list_id=? and `index`=? and block_id=?";
+            log.info("updateSql1:"+sql1);
+            luckySheetJdbcTemplate.update(sql1,new Object[]{model.getList_id(),index1,JfGridConfigModel.FirstBlockID});
+            String sql2="update "+JfGridConfigModel.TABLENAME+" set status=1  where  list_id=? and `index`=? and block_id=?";
+            log.info("updateSql2:"+sql2);
+            luckySheetJdbcTemplate.update(sql2,new Object[]{model.getList_id(),index2,model.getBlock_id()});
+            return true;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+    /**
+     * 更新sheet隐藏状态
+     *
+     * @param model
+     * @param hide
+     * @param index
+     * @return
+     */
+    @Transactional(value = "mysqlTxManager",rollbackFor = Exception.class)
+    @Override
+    public boolean updateDataMsgNoHide(GridRecordDataModel model, Integer hide, String index) {
+        try{
+            String sql1="update "+JfGridConfigModel.TABLENAME+" set status=0  where  list_id=?  and block_id=?";
+            log.info("updateSql1:"+sql1);
+            luckySheetJdbcTemplate.update(sql1,new Object[]{model.getList_id(),model.getBlock_id()});
+
+            //String sql2="update "+JfGridConfigModel.TABLENAME+" set status=1 ,json_data=jsonb_set(json_data,'{hide}'::text[],'"+hide+"',true) where  list_id=? and index=? and block_id=?";
+            String sql2="update "+JfGridConfigModel.TABLENAME+" set status=1 ,json_data=json_set(json_data,\"$.hide\","+hide+") where  list_id=? and `index`=? and block_id=?";
+            log.info("updateSql2:"+sql2);
+            luckySheetJdbcTemplate.update(sql2,new Object[]{model.getList_id(),index,model.getBlock_id()} );
+            return true;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+    /**
+     * 更新jsonb中某条文本数据
+     *
+     * @param block_ids
+     * @param models
+     * @return
+     */
+    @Override
+    public boolean batchUpdateCellDataValue(List<String> block_ids, List<GridRecordDataModel> models) {
+        try{
+            String id="";
+            for (String str : block_ids) {
+                id=id+"'"+str+"',";
+            }
+            id=id.substring(0, id.length()-1);
+            log.info("id:"+id);
+            String delsql="DELETE from "+JfGridConfigModel.TABLENAME+" t where t.list_id=? and t.index=? and t.block_id in ("+id+")  ";
+            luckySheetJdbcTemplate.update(delsql,new Object[]{models.get(0).getList_id(),models.get(0).getIndex()});
+
+            String sql = "insert into "+JfGridConfigModel.TABLENAME+" (id,block_id,`index`,list_id,status,`order`,json_data,is_delete) values " +
+                    "( ?,?,?,?,?,?,?,0)";
+            List<Object[]>batch=new ArrayList<Object[]>();
+            for(GridRecordDataModel b : models){
+                List<Object> objectList=new ArrayList<Object>();
+                objectList.add(snowFlake.nextId());
+                objectList.add(b.getBlock_id().trim());
+                objectList.add(b.getIndex());
+                objectList.add(b.getList_id());
+                objectList.add(b.getStatus());
+                objectList.add(b.getOrder());
+                objectList.add(b.getJson_data().toString(SerializerFeature.WriteMapNullValue));
+
+                Object[] params=(Object[])objectList.toArray(new Object[objectList.size()]);
+                batch.add(params);
+            }
+            log.info("sqls:{}",sql);
+            luckySheetJdbcTemplate.batchUpdate(sql,batch);
+            log.info("batchUpdateCellDataValue--end");
+            return true;
+        }catch (Exception ex){
+            log.error(ex.getMessage());
+            return false;
+        }
+    }
+
+    /**
+     * jsonb数据中元素添加元素(集合插入)
+     * @param query 查询条件
+     * @param word  路径
+     * @param db    内容
+     * @param position  位置
+     * @param words  初始化的内容
+     * @return
+     */
+    @Transactional(value = "mysqlTxManager",rollbackFor = Exception.class)
+    @Override
+    public boolean updateJsonbForInsertNull(JSONObject query, String word, JSONObject db, Integer position, String words) {
+        try{
+            if(word!=null){
+                word=word.replace(",",".");
+            }
+            log.info("select:"+query.toString(SerializerFeature.WriteMapNullValue));
+            List arr=new ArrayList<>();
+            String condition= JfGridFileUtil.getCondition(query,arr);
+
+            JSONObject newObj=JSONObject.parseObject("{"+words+"}");
+            String key=JfGridFileUtil.getKeyName(newObj);
+
+            //不存在创建节点
+            //String createSql="update "+JfGridConfigModel.TABLENAME+" set json_data=json_data||'{"+words+"}'::jsonb where 1=1 " +condition;
+            String createSql="update "+JfGridConfigModel.TABLENAME+" set json_data=json_set(json_data,\"$."+key+"\",CAST('"+newObj.getString(key)+"' AS JSON)) where 1=1 " +condition+
+                    " and JSON_CONTAINS_PATH(jsontest,'one',\"$."+key+"\")=0";
+            log.info("createSql:{}",createSql);
+            luckySheetJdbcTemplate.update(createSql,arr.toArray());
+
+            if(position!=null){
+                word=word+"."+position;
+            }
+            //(jsonb_v,'{myinfo,celldata,0}','{"c":1,"r":1,"v":{"con":"str"}}',false)
+            //String updateSql="update "+JfGridConfigModel.TABLENAME+" set json_data=jsonb_insert(json_data,'{"+word+"}','"+db.toString()+"',false) where 1=1 " +condition;
+            StringBuffer updateSql=new StringBuffer();
+            updateSql.append("update "+JfGridConfigModel.TABLENAME+" t set t.json_data=json_set(t.json_data,\"$."+word+"\",");
+            updateSql.append("CAST('"+db.toString(SerializerFeature.WriteMapNullValue)+"' as JSON)");
+            updateSql.append(") where 1=1 "+condition);
+
+            log.info("updateSql:{}",updateSql.toString());
+            luckySheetJdbcTemplate.update(updateSql.toString(),arr.toArray());
+            return true;
+        }catch (Exception ex){
+            log.error(ex.getMessage());
+            throw new RuntimeException(ex.getMessage());
+        }
+    }
+
+    /**
+     * jsonb数据中元素添加元素(集合插入),不存在创建一个空集合
+     * @param query 查询条件
+     * @param word  路径
+     * @param db    内容
+     * @param position  位置
+     * @return
+     */
+    @Transactional(value = "mysqlTxManager",rollbackFor = Exception.class)
+    @Override
+    public boolean updateJsonbForSetNull(JSONObject query, String word, JSONObject db, Integer position) {
+        try{
+            log.info("select:"+query.toString(SerializerFeature.WriteMapNullValue));
+            List arr=new ArrayList<>();
+            String condition= JfGridFileUtil.getCondition(query,arr);
+
+            //不存在创建节点
+            //String createSql="update "+JfGridConfigModel.TABLENAME+" set json_data=jsonb_set(json_data,'{"+word+"}'::text[],'[]',true)  where 1=1 " +condition;
+            String createSql="update "+JfGridConfigModel.TABLENAME+" set json_data=json_set(json_data,\"$."+word+"\",CAST('[]' AS JSON)) where 1=1 " +condition+
+                    " and JSON_CONTAINS_PATH(jsontest,'one',\"$."+word+"\")=0";
+            log.info("createSql:{}",createSql);
+            luckySheetJdbcTemplate.update(createSql,arr.toArray());
+
+            if(position!=null){
+                word=word+","+position;
+            }
+            //(jsonb_v,'{myinfo,celldata,0}','{"c":1,"r":1,"v":{"con":"str"}}',false)
+            //String updateSql="update "+JfGridConfigModel.TABLENAME+" set json_data=jsonb_set(json_data,'{"+word+"}'::text[],'"+db.toString()+"',true) where 1=1 " +condition;
+            StringBuffer updateSql=new StringBuffer();
+            updateSql.append("update "+JfGridConfigModel.TABLENAME+" t set t.json_data=json_set(t.json_data,\"$."+word+"\",");
+            updateSql.append("CAST('"+db.toString(SerializerFeature.WriteMapNullValue)+"' as JSON)");
+            updateSql.append(") where 1=1 "+condition);
+
+            log.info("updateSql:{}",updateSql.toString());
+            luckySheetJdbcTemplate.update(updateSql.toString(),arr.toArray());
+            return true;
+        }catch (Exception ex){
+            log.error(ex.getMessage());
+            throw new RuntimeException(ex.getMessage());
+        }
+    }
+
+    /**
+     * jsonb数据中元素添加元素(根节点)
+     *
+     * @param query
+     * @param word
+     * @param db
+     * @param position
+     * @param words
+     * @return
+     */
+    @Transactional(value = "mysqlTxManager",rollbackFor = Exception.class)
+    @Override
+    public boolean updateJsonbForSetRootNull(JSONObject query, String word, JSONObject db, Integer position, String words) {
+        return updateJsonbForInsertNull(query, word, db, position, words);
+//        try{
+//            log.info("select:"+query.toString(SerializerFeature.WriteMapNullValue));
+//            List arr=new ArrayList<>();
+//            String condition= JfGridFileUtil.getCondition(query,arr);
+//
+//            JSONObject newObj=JSONObject.parseObject("{"+words+"}");
+//            String key=JfGridFileUtil.getKeyName(newObj);
+//
+//            //不存在创建节点
+//            //String createSql="update "+JfGridConfigModel.TABLENAME+" set json_data=json_data||'{"+words+"}'::jsonb where 1=1 " +condition;
+//            String createSql="update "+JfGridConfigModel.TABLENAME+" set json_data=json_set(json_data,\"$."+key+"\",CAST('"+newObj.getString(key)+"' AS JSON)) where 1=1 " +condition+
+//                    " and JSON_CONTAINS_PATH(jsontest,'one',\"$."+key+"\")=0";
+//            log.info("createSql:{}",createSql);
+//            luckySheetJdbcTemplate.update(createSql,arr.toArray());
+//
+//            if(position!=null){
+//                word=word+","+position;
+//            }
+//            //(jsonb_v,'{myinfo,celldata,0}','{"c":1,"r":1,"v":{"con":"str"}}',false)
+//            //String updateSql="update "+JfGridConfigModel.TABLENAME+" set json_data=jsonb_set(json_data,'{"+word+"}','"+db.toString()+"',false) where 1=1 " +condition;
+//            StringBuffer updateSql=new StringBuffer();
+//            updateSql.append("update "+JfGridConfigModel.TABLENAME+" t set t.json_data=jsonb_set(t.json_data,\"$."+word+",");
+//            updateSql.append("CAST('"+db.toString(SerializerFeature.WriteMapNullValue)+"' as JSON)");
+//            updateSql.append(") where 1=1 "+condition);
+//
+//            log.info("updateSql:{}",updateSql.toString());
+//            luckySheetJdbcTemplate.update(updateSql.toString(),arr.toArray());
+//            return true;
+//        }catch (Exception ex){
+//            log.error(ex.getMessage());
+//            throw new RuntimeException(ex.getMessage());
+//        }
+    }
+}

+ 83 - 0
luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/impl/RecordDelHandle.java

@@ -0,0 +1,83 @@
+package com.xc.luckysheet.mysql.impl;
+
+import com.xc.luckysheet.JfGridConfigModel;
+import com.xc.luckysheet.db.IRecordDelHandle;
+import com.xc.luckysheet.entity.GridRecordDataModel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.jdbc.object.BatchSqlUpdate;
+import org.springframework.stereotype.Repository;
+
+import javax.sql.DataSource;
+import java.sql.Types;
+import java.util.List;
+
+/**
+ * 删除
+ * @author Administrator
+ */
+@Slf4j
+@Repository(value = "mysqlRecordDelHandle")
+public class RecordDelHandle extends BaseHandle implements IRecordDelHandle {
+    /**
+     * 删除sheet(非物理删除)
+     *
+     * @param model
+     * @return
+     */
+    @Override
+    public boolean updateDataForReDel(GridRecordDataModel model) {
+        try{
+            String sql1="update "+ JfGridConfigModel.TABLENAME+"  set is_delete=?  where  list_id=? and index=? ";
+            log.info("updateSql1:"+sql1);
+            luckySheetJdbcTemplate.update(sql1,new Object[]{model.getIs_delete(),model.getList_id(),model.getIndex()});
+            return true;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return false;
+        }
+    }
+
+    /**
+     * 按ID 删除多个文档 (物理删除)
+     *
+     * @param ids
+     * @return
+     */
+    @Override
+    public String delDocuments(List<String> ids) {
+        try{
+            String id="";
+            for (String str : ids) {
+                id=id+str+",";
+            }
+            id=id.substring(0, id.length()-1);
+            String delsql="DELETE from "+JfGridConfigModel.TABLENAME+" where id in ("+id+")";
+            luckySheetJdbcTemplate.update(delsql);
+            return "";
+        }catch (Exception ex){
+            log.error(ex.toString());
+            return ex.toString();
+        }
+    }
+
+    /**
+     * 按list_id 删除记录 (物理删除)
+     *
+     * @param listIds
+     * @return
+     */
+    @Override
+    public int[] delete(List<String> listIds) {
+        if(listIds==null && listIds.size()==0){
+            return new int[]{};
+        }
+        DataSource ds = luckySheetJdbcTemplate.getDataSource();
+        BatchSqlUpdate bsu = new BatchSqlUpdate(ds, " delete  from "+JfGridConfigModel.TABLENAME +" where list_id = ? ");
+        bsu.setBatchSize(4);
+        bsu.setTypes(new int[]{Types.VARCHAR});
+        for(int i = 0; i < listIds.size(); i++){
+            log.info(bsu.update(new Object[]{listIds.get(i)})+"");
+        }
+        return bsu.flush();
+    }
+}

+ 397 - 0
luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/impl/RecordSelectHandle.java

@@ -0,0 +1,397 @@
+package com.xc.luckysheet.mysql.impl;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.xc.luckysheet.JfGridConfigModel;
+import com.xc.luckysheet.db.IRecordSelectHandle;
+import com.xc.luckysheet.util.JfGridFileUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Repository;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 查询
+ * @author Administrator
+ */
+@Slf4j
+@Repository(value = "mysqlRecordSelectHandle")
+public class RecordSelectHandle extends BaseHandle implements IRecordSelectHandle {
+    /**
+     * 查看指定sheet页 查看第一块是否存在(控制块)
+     *
+     * @param listId
+     * @param index
+     * @return
+     */
+    @Override
+    public Integer getFirstBlockByGridKey(String listId, String index) {
+        //默认获取第一块
+        String sql="select count(1) from "+JfGridConfigModel.TABLENAME +" p where p.list_id=? and p.index=? and p.block_id=? and p.is_delete=0";
+        try{
+            return  luckySheetJdbcTemplate.queryForObject(sql, new Object[]{listId,index,JfGridConfigModel.FirstBlockID},Integer.class);
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 获取指定的xls激活的sheet页的 返回index(控制块)
+     *
+     * @param listId
+     * @return
+     */
+    @Override
+    public String getFirstBlockIndexByGridKey(String listId) {
+        //默认获取第一块
+        String sql="select p.index from "+JfGridConfigModel.TABLENAME+" p where p.list_id=? and p.block_id=? and p.status=1 and p.is_delete=0 ";
+        try{
+            return  luckySheetJdbcTemplate.queryForObject(sql, new Object[]{listId,JfGridConfigModel.FirstBlockID},String.class);
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 获取指定的xls,sheet 第一块的行列信息(控制块)
+     *
+     * @param listId
+     * @param index
+     * @return
+     */
+    @Override
+    public String getFirstBlockRowColByGridKey(String listId, String index) {
+        //默认获取第一块
+        String sql="select p.row_col from "+JfGridConfigModel.TABLENAME+" p where p.list_id=? and p.index=? and p.block_id=? and p.is_delete=0";
+        try{
+            return  luckySheetJdbcTemplate.queryForObject(sql, new Object[]{listId,index,JfGridConfigModel.FirstBlockID},String.class);
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 按指定xls,sheet顺序返回整个xls结构
+     * 不返回celldata ,只获取信息块
+     *
+     * @param listId
+     * @return
+     */
+    @Override
+    public List<JSONObject> getByGridKey_NOCelldata(String listId) {
+        try{
+            String sql="select id,block_id,`index`,list_id,status, json_remove(json_data,'$.celldata') AS json_data,`order` from "+JfGridConfigModel.TABLENAME+" p where p.list_id=? and p.block_id=? and p.is_delete=0  order by p.order";
+            List<Map<String, Object>> list= luckySheetJdbcTemplate.queryForList(sql, new Object[]{listId,JfGridConfigModel.FirstBlockID});
+            List<JSONObject> result=new ArrayList<JSONObject>();
+
+            for (Map<String, Object> map : list) {
+                JSONObject pgd=JSONObject.parseObject(map.get("json_data").toString(),JSONObject.class);
+                for (String key : map.keySet()) {
+                    if("json_data".equals(key)){
+                    }else{
+                        pgd.put(key.toLowerCase(), map.get(key));
+                    }
+                }
+                result.add(pgd);
+            }
+            return result;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 按指定xls,sheet获取,返回指定的sheet集合
+     *
+     * @param listId
+     * @param index
+     * @return
+     */
+    @Override
+    public List<JSONObject> getBlockAllByGridKey(String listId, String index) {
+        try{
+            String sql="select * from "+JfGridConfigModel.TABLENAME+" p where  p.list_id=? and p.index =? and p.is_delete=0 order by p.order asc";
+            List<Map<String, Object>> list= luckySheetJdbcTemplate.queryForList(sql, new Object[]{listId,index});
+            List<JSONObject> result=new ArrayList<JSONObject>(4);
+            for (Map<String, Object> map : list) {
+                result.add(getDBObjectFromMap(map));
+            }
+            return result;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 获取指定xls,sheet,block的数据
+     *
+     * @param listId
+     * @param index
+     * @param blockId
+     * @return
+     */
+    @Override
+    public JSONObject getCelldataByGridKey(String listId, String index, String blockId) {
+        try{
+            String sql="select `index`,json_data->>'$.celldata' AS celldata,json_data->>'$.column' AS `column`,json_data->>'$.row' AS `row` from "+JfGridConfigModel.TABLENAME+" p where  p.list_id=? and p.index=? and p.block_id=? and p.is_delete=0 ORDER BY p.id DESC LIMIT 1 ";
+            Map<String, Object> map= luckySheetJdbcTemplate.queryForMap(sql, new Object[]{listId,index,blockId});
+            JSONObject db=new JSONObject();
+
+            for (String key : map.keySet()) {
+                if("celldata".equals(key)){
+                    //JSONObject pgd=JSONObject.parseObject(map.get(key).toString(),JSONObject.class);
+                    JSONArray pgd=JSONArray.parseArray(map.get(key).toString());
+                    db.put(key.toLowerCase(), pgd);
+                }else{
+                    db.put(key.toLowerCase(), map.get(key));
+                }
+            }
+            return db;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 获取指定xls、sheet中的config中数据 (存放在第一块中)
+     *
+     * @param listId
+     * @param index
+     * @return
+     */
+    @Override
+    public JSONObject getConfigByGridKey(String listId, String index) {
+        try{
+            String sql="select `index`,list_id,json_data->>'$.config' AS config,json_data->>'$.calcChain' AS calcChain,json_data->>'$.filter' AS filter from "+JfGridConfigModel.TABLENAME+" p where p.list_id=? and p.index=? and p.block_id=? and p.is_delete=0 ";
+            Map<String, Object> map= luckySheetJdbcTemplate.queryForMap(sql, new Object[]{listId,index,JfGridConfigModel.FirstBlockID});
+            JSONObject db=new JSONObject();
+
+            for (String key : map.keySet()) {
+                if("config".equals(key)|| "calcChain".equals(key)|| "filter".equals(key)){
+                    JSONObject pgd=null;
+                    try{
+                        if(map.get(key)!=null){
+                            pgd=JSONObject.parseObject(map.get(key).toString(),JSONObject.class);
+                        }else{
+                            pgd=JSONObject.parseObject("");
+                        }
+                    }catch (Exception e) {
+                        pgd=new JSONObject();
+                    }
+                    db.put(key.toLowerCase(), pgd);
+                }else{
+                    db.put(key.toLowerCase(), map.get(key));
+                }
+            }
+            return db;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 按list_id获取,返回指定sheet 当前sheet的全部分块数据(并合并)getMergeByGridKey
+     * 返回是DBObject,而下面这个方法返回仅仅只有celldata
+     *
+     * @param listId
+     * @param index
+     * @param ids    返回记录存在数据库的ID
+     * @return
+     */
+    @Override
+    public JSONObject getBlockMergeByGridKey(String listId, String index, List<String> ids) {
+        JSONObject _fblock=new JSONObject();
+        JSONArray _celldata=new JSONArray();
+        //获取全部块
+        List<JSONObject> blocks=getBlockAllByGridKey(listId, index);
+        if(blocks!=null && blocks.size()>0){
+            for(JSONObject _b:blocks){
+                if(ids!=null){
+                    if(_b.containsKey("id")){
+                        ids.add(_b.get("id").toString());
+                    }
+                }
+                if(_b.containsKey("block_id")){
+                    if(JfGridConfigModel.FirstBlockID.equals(_b.get("block_id").toString().trim())){
+                        //信息块
+                        _fblock=_b;
+                    }else{
+                        //数据块
+                        JSONObject db=JfGridFileUtil.getJSONObjectByIndex(_b, "json_data");
+                        JSONArray _blockCellData=JfGridFileUtil.getSheetByIndex(db);
+                        if(_blockCellData!=null){
+                            _celldata.addAll(_blockCellData);
+                        }
+                    }
+                }
+            }
+        }
+        _fblock.put("celldata",_celldata);
+        return _fblock;
+    }
+
+    /**
+     * 按list_id获取(id,index),返回sheet集合
+     *
+     * @param listId
+     * @param flag   是否仅仅获取主要模块
+     * @return
+     */
+    @Override
+    public List<JSONObject> getBlocksByGridKey(String listId, boolean flag) {
+        try{
+            List<Object> _param=new ArrayList<>(2);
+            String sql="select id,`index` from "+JfGridConfigModel.TABLENAME+" p where  p.list_id=? ";
+            _param.add(listId);
+            if(flag){
+                sql=sql+" and block_id=? ";
+                _param.add(JfGridConfigModel.FirstBlockID);
+            }
+            sql=sql+" and p.is_delete=0 ";
+
+            List<Map<String, Object>> list= luckySheetJdbcTemplate.queryForList(sql, _param.toArray());
+            List<JSONObject> result=new ArrayList<JSONObject>();
+            for (Map<String, Object> map : list) {
+                result.add(getDBObjectFromMap(map));
+            }
+            return result;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 获取指定xls,多个sheet的全部分块
+     *
+     * @param listId
+     * @param indexs
+     * @return
+     */
+    @Override
+    public List<JSONObject> getAllIndexsByGridKey(String listId, List<String> indexs) {
+        try{
+            StringBuffer sql=new StringBuffer();
+            sql.append("select * from "+JfGridConfigModel.TABLENAME+" p where  p.list_id=? and p.index in (");
+            String mockInStatement="";
+            int i=0;
+            for (String type: indexs){
+                if (i < indexs.size()-1){
+                    mockInStatement = mockInStatement + "'"+type + "',";
+                }
+                else {
+                    mockInStatement = mockInStatement + "'"+type+"'";
+                }
+                i++;
+            }
+            sql.append(mockInStatement);
+            sql.append(") and p.is_delete=0 order by p.order asc");
+            List<Map<String, Object>> list= luckySheetJdbcTemplate.queryForList(sql.toString(), new Object[]{listId});
+            List<JSONObject> result=new ArrayList<JSONObject>();
+            for (Map<String, Object> map : list) {
+                result.add(getDBObjectFromMap(map));
+            }
+            return result;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 获取指定xls,sheet全部内容
+     *
+     * @param listId
+     * @param index
+     * @return
+     */
+    @Override
+    public List<JSONObject> getIndexsByGridKey(String listId, String index) {
+        try{
+            StringBuffer sql=new StringBuffer();
+            sql.append("select * from "+JfGridConfigModel.TABLENAME+" p where  p.list_id=? and p.index =? and p.is_delete=0 order by p.id asc ");
+            List<Map<String, Object>> list= luckySheetJdbcTemplate.queryForList(sql.toString(), new Object[]{listId,index});
+            List<JSONObject> result=new ArrayList<JSONObject>();
+            for (Map<String, Object> map : list) {
+                result.add(getDBObjectFromMap(map));
+            }
+            return result;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 获取图表数据(第一块)
+     *
+     * @param listId
+     * @param index
+     * @return
+     */
+    @Override
+    public JSONObject getChartByGridKey(String listId, String index) {
+        //默认获取第一块
+        try{
+            String sql="select `index`,list_id,json_data->>'$.chart' AS chart,block_id from "+JfGridConfigModel.TABLENAME+" p where p.list_id=? and p.index=? and p.block_id=? and p.is_delete=0 ";
+            Map<String, Object> map= luckySheetJdbcTemplate.queryForMap(sql, new Object[]{listId,index,JfGridConfigModel.FirstBlockID});
+            JSONObject db=new JSONObject();
+
+            for (String key : map.keySet()) {
+                if("chart".equals(key)){
+                    if(map.get(key)!=null){
+                        try{
+                            JSONArray pgd=JSONArray.parseArray(map.get(key).toString());
+                            db.put(key.toLowerCase(), pgd);
+                        }catch (Exception e) {
+                            db.put(key.toLowerCase(), new JSONArray());
+                        }
+                    }else{
+                        db.put(key.toLowerCase(), null);
+                    }
+
+                }else{
+                    db.put(key.toLowerCase(), map.get(key));
+                }
+            }
+            return db;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+
+    private JSONObject getDBObjectFromMap(Map<String, Object> map){
+        JSONObject db=new JSONObject();
+
+        for (String key : map.keySet()) {
+            try{
+                if("json_data".equals(key)){
+                    JSONObject pgd=null;
+                    try{
+                        pgd=JSONObject.parseObject(map.get(key).toString(),JSONObject.class);
+                    }catch (Exception e) {
+                        pgd=JSONObject.parseObject(map.get(key).toString(),JSONObject.class);
+                    }
+                    db.put(key.toLowerCase(), pgd);
+                }else{
+                    db.put(key.toLowerCase(), map.get(key));
+                }
+            }catch (Exception e) {
+                log.error(e.toString());
+                continue;
+            }
+        }
+        return db;
+    }
+}

+ 138 - 0
luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/test/TestTransaction1.java

@@ -0,0 +1,138 @@
+package com.xc.luckysheet.mysql.test;
+
+
+import com.xc.luckysheet.mysql.impl.BaseHandle;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Date;
+
+/**
+ * Spring使用声明式事务处理,默认情况下,
+ * 如果被注解的数据库操作方法中发生了unchecked异常,所有的数据库操作将rollback;
+ * 如果发生的异常是checked异常,默认情况下数据库操作还是会提交的。
+ *
+ * 默认配置下,spring只有在抛出的异常为运行时unchecked异常时才回滚该事务,
+ * 也就是抛出的异常为RuntimeException的子类(Errors也会导致事务回滚),而抛出checked异常则不会导致事务回滚。
+ *
+ * Spring的AOP即声明式事务管理默认是针对unchecked exception回滚。Spring的事务边界是在调用业务方法之前开始的,业务方法执行完毕之后来执行commit or rollback(Spring默认取决于是否抛出runtimeException)。
+ *
+ * 如果你在方法中有try{}catch(Exception e){}处理,那么try里面的代码块就脱离了事务的管理,
+ * 若要事务生效需要在catch中throw new RuntimeException ("xxxxxx");
+ *
+ *
+ CREATE TABLE `test` (
+ `id` bigint(120) unsigned NOT NULL,
+ `jsontest` json DEFAULT NULL,
+ `updatetime` datetime DEFAULT NULL,
+ PRIMARY KEY (`id`)
+ ) ENGINE=InnoDB DEFAULT CHARSET=armscii8
+ */
+@Slf4j
+@Service
+public class TestTransaction1 extends BaseHandle {
+
+    public Integer clear(){
+        String sql="delete from test";
+        try{
+            return luckySheetJdbcTemplate.update(sql);
+        }catch (Exception e){
+            log.error(e.getMessage());
+        }
+        return null;
+    }
+
+    public Integer add1(){
+        String sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+        try{
+            return luckySheetJdbcTemplate.update(sql,snowFlake.nextId().longValue(),"{}",new Date());
+        }catch (Exception e){
+            log.error(e.getMessage());
+        }
+        return null;
+    }
+
+    public String add2(){
+        try{
+            String sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+            luckySheetJdbcTemplate.update(sql,snowFlake.nextId().longValue(),"{}",new Date());
+
+            //类型错误
+            sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+            luckySheetJdbcTemplate.update(sql,"qewqeqw","{}",new Date());
+
+            sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+            luckySheetJdbcTemplate.update(sql,snowFlake.nextId().longValue(),"{}",new Date());
+
+            return "success";
+        }catch (Exception e){
+            log.error(e.getMessage());
+        }
+        return null;
+    }
+
+
+    //回滚
+    @Transactional(value = "mysqlTxManager",rollbackFor = Exception.class)
+    public String add3(){
+        try{
+            String sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+            luckySheetJdbcTemplate.update(sql,snowFlake.nextId().longValue(),"{}",new Date());
+
+            //类型错误
+            sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+            luckySheetJdbcTemplate.update(sql,"qewqeqw","{}",new Date());
+
+            sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+            luckySheetJdbcTemplate.update(sql,snowFlake.nextId().longValue(),"{}",new Date());
+
+            return "success";
+        }catch (Exception e){
+            log.error(e.getMessage());
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+    @Transactional(value = "mysqlTxManager")
+    public String add4() throws Exception {
+        try{
+            String sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+            luckySheetJdbcTemplate.update(sql,snowFlake.nextId().longValue(),"{}",new Date());
+
+            //类型错误
+            sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+            luckySheetJdbcTemplate.update(sql,"qewqeqw","{}",new Date());
+
+            sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+            luckySheetJdbcTemplate.update(sql,snowFlake.nextId().longValue(),"{}",new Date());
+
+            return "success";
+        }catch (Exception e){
+            log.error(e.getMessage());
+            throw new Exception(e.getMessage());
+        }
+    }
+
+    //回滚
+    //rollbackFor这属性指定了,既使你出现了checked这种例外,那么它也会对事务进行回滚
+    @Transactional(value = "mysqlTxManager",rollbackFor = Exception.class)
+    public String add5() throws Exception {
+        try{
+            String sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+            luckySheetJdbcTemplate.update(sql,snowFlake.nextId().longValue(),"{}",new Date());
+
+            //类型错误
+            sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+            luckySheetJdbcTemplate.update(sql,"qewqeqw","{}",new Date());
+
+            sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+            luckySheetJdbcTemplate.update(sql,snowFlake.nextId().longValue(),"{}",new Date());
+
+            return "success";
+        }catch (Exception e){
+            log.error(e.getMessage());
+            throw new Exception(e.getMessage());
+        }
+    }
+}

+ 58 - 0
luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/test/TestTransaction2.java

@@ -0,0 +1,58 @@
+package com.xc.luckysheet.mysql.test;
+
+
+import com.xc.luckysheet.mysql.impl.BaseHandle;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Date;
+
+/**
+ * 注解在类上,如果方法上有注解,覆盖
+ */
+@Slf4j
+@Service
+@Transactional(value = "mysqlTxManager",rollbackFor = Exception.class)
+public class TestTransaction2 extends BaseHandle {
+
+
+    public String add3(){
+        try{
+            String sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+            luckySheetJdbcTemplate.update(sql,snowFlake.nextId().longValue(),"{}",new Date());
+
+            //类型错误
+            sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+            luckySheetJdbcTemplate.update(sql,"qewqeqw","{}",new Date());
+
+            sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+            luckySheetJdbcTemplate.update(sql,snowFlake.nextId().longValue(),"{}",new Date());
+
+            return "success";
+        }catch (Exception e){
+            log.error(e.getMessage());
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+
+    public String add5() throws Exception {
+        try{
+            String sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+            luckySheetJdbcTemplate.update(sql,snowFlake.nextId().longValue(),"{}",new Date());
+
+            //类型错误
+            sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+            luckySheetJdbcTemplate.update(sql,"qewqeqw","{}",new Date());
+
+            sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+            luckySheetJdbcTemplate.update(sql,snowFlake.nextId().longValue(),"{}",new Date());
+
+            return "success";
+        }catch (Exception e){
+            log.error(e.getMessage());
+            throw new Exception(e.getMessage());
+        }
+    }
+}

+ 53 - 0
luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/test/TestTransaction3.java

@@ -0,0 +1,53 @@
+package com.xc.luckysheet.mysql.test;
+
+
+import com.xc.luckysheet.mysql.impl.BaseHandle;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Date;
+
+/**
+ * 测试方法调用方法
+ */
+@Slf4j
+@Service
+public class TestTransaction3 extends BaseHandle {
+
+    @Transactional(value = "mysqlTxManager",rollbackFor = Exception.class)
+    public String test(){
+        addsuccess();
+        adderror();
+        addsuccess();
+        return "success";
+    }
+
+    @Transactional(value = "mysqlTxManager",rollbackFor = Exception.class)
+    public String addsuccess(){
+        try{
+            String sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+            luckySheetJdbcTemplate.update(sql,snowFlake.nextId().longValue(),"{}",new Date());
+
+            return "success";
+        }catch (Exception e){
+            log.error(e.getMessage());
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+    @Transactional(value = "mysqlTxManager",rollbackFor = Exception.class)
+    public String adderror(){
+        try{
+            //类型错误
+            String sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+            luckySheetJdbcTemplate.update(sql,"qewqeqw","{}",new Date());
+            return "success";
+        }catch (Exception e){
+            log.error(e.getMessage());
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+
+}

+ 54 - 0
luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/test/TestTransaction4.java

@@ -0,0 +1,54 @@
+package com.xc.luckysheet.mysql.test;
+
+
+import com.xc.luckysheet.mysql.impl.BaseHandle;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Date;
+
+/**
+ * 测试方法调用方法
+ */
+@Slf4j
+@Service
+@Transactional(value = "mysqlTxManager",rollbackFor = Exception.class)
+public class TestTransaction4 extends BaseHandle {
+
+
+    public String test(){
+        addsuccess();
+        adderror();
+        addsuccess();
+        return "success";
+    }
+
+
+    public String addsuccess(){
+        try{
+            String sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+            luckySheetJdbcTemplate.update(sql,snowFlake.nextId().longValue(),"{}",new Date());
+
+            return "success";
+        }catch (Exception e){
+            log.error(e.getMessage());
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+
+    public String adderror(){
+        try{
+            //类型错误
+            String sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+            luckySheetJdbcTemplate.update(sql,"qewqeqw","{}",new Date());
+            return "success";
+        }catch (Exception e){
+            log.error(e.getMessage());
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+
+}

+ 42 - 0
luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/test/TestTransaction51.java

@@ -0,0 +1,42 @@
+package com.xc.luckysheet.mysql.test;
+
+
+import com.xc.luckysheet.mysql.impl.BaseHandle;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Date;
+
+/**
+ * 测试方法调用方法
+ */
+@Slf4j
+@Service
+@Transactional(value = "mysqlTxManager",rollbackFor = Exception.class)
+public class TestTransaction51 extends BaseHandle {
+
+    @Autowired
+    private TestTransaction52 testTransaction52;
+
+    public String test(){
+        addsuccess();
+        testTransaction52.adderror();
+        addsuccess();
+        return "success";
+    }
+
+    public String addsuccess(){
+        try{
+            String sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+            luckySheetJdbcTemplate.update(sql,snowFlake.nextId().longValue(),"{}",new Date());
+
+            return "success";
+        }catch (Exception e){
+            log.error(e.getMessage());
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+}

+ 30 - 0
luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/test/TestTransaction52.java

@@ -0,0 +1,30 @@
+package com.xc.luckysheet.mysql.test;
+
+
+import com.xc.luckysheet.mysql.impl.BaseHandle;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Date;
+
+/**
+ * 测试方法调用方法
+ */
+@Slf4j
+@Service
+@Transactional(value = "mysqlTxManager",rollbackFor = Exception.class)
+public class TestTransaction52 extends BaseHandle {
+
+    public String adderror(){
+        try{
+            //类型错误
+            String sql="insert into test(id,jsontest,updatetime) values(?,?,?)";
+            luckySheetJdbcTemplate.update(sql,"qewqeqw","{}",new Date());
+            return "success";
+        }catch (Exception e){
+            log.error(e.getMessage());
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+}

+ 6 - 0
luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/testinvocationhandler/test1/People.java

@@ -0,0 +1,6 @@
+package com.xc.luckysheet.mysql.testinvocationhandler.test1;
+
+public interface People {
+    public People work(String workName);
+    public String time();
+}

+ 14 - 0
luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/testinvocationhandler/test1/Student.java

@@ -0,0 +1,14 @@
+package com.xc.luckysheet.mysql.testinvocationhandler.test1;
+
+public class Student implements People{
+
+    @Override
+    public People work(String workName) {
+        System.out.println("工作内容是"+workName);
+        return this;
+    }
+    @Override
+    public String time() {
+        return "2018-06-12";
+    }
+}

+ 41 - 0
luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/testinvocationhandler/test1/Test.java

@@ -0,0 +1,41 @@
+package com.xc.luckysheet.mysql.testinvocationhandler.test1;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Proxy;
+
+public class Test {
+
+    public static void main(String[] args) {
+        test1();
+        System.out.println("========================");
+        test2();
+    }
+    private static void test1(){
+        People people = new Student();
+        InvocationHandler handler = new WorkHandler(people);
+
+        People proxy = (People) Proxy.newProxyInstance(people.getClass().getClassLoader(), people.getClass().getInterfaces(), handler);
+        People p = proxy.work("写代码").work("开会").work("上课");
+
+        System.out.println("打印返回的对象");
+        System.out.println(p.getClass());
+
+        String time = proxy.time();
+        System.out.println(time);
+    }
+
+    private static void test2(){
+        People people = new Student();
+        WorkHandler2 handler = new WorkHandler2();
+
+        People proxy = (People) handler.bind(people);
+        People p = proxy.work("写代码").work("开会").work("上课");
+
+        System.out.println("打印返回的对象");
+        System.out.println(p.getClass());
+
+        String time = proxy.time();
+        System.out.println(time);
+
+    }
+}

+ 37 - 0
luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/testinvocationhandler/test1/WorkHandler.java

@@ -0,0 +1,37 @@
+package com.xc.luckysheet.mysql.testinvocationhandler.test1;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+
+/**
+ * JDK自带的动态代理主要是指,实现了InvocationHandler接口的代理类,实现了InvocationHandler接口的类,会继承一个invoke方法,
+ * 通过在这个方法中添加某些代码,从而完成在方法前后添加一些动态的东西。JDK自带的动态代理依赖于接口,如果有些类没有接口,则不能实现动态代理。
+ *
+ * proxy是真实对象的真实代理对象,invoke方法可以返回调用代理对象方法的返回结果,也可以返回对象的真实代理对象
+ * proxy参数是invoke方法的第一个参数,通常情况下我们都是返回真实对象方法的返回结果,但是我们也可以将proxy返回,
+ * proxy是真实对象的真实代理对象,我们可以通过这个返回对象对真实的对象做各种各样的操作。
+ */
+public class WorkHandler implements InvocationHandler {
+
+    private Object obj;
+
+    public WorkHandler(Object obj) {
+        this.obj = obj;
+    }
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        System.out.println("before 动态代理...");
+        System.out.println(proxy.getClass().getName());
+        System.out.println(this.obj.getClass().getName());
+        if(method.getName().equals("work")) {
+            method.invoke(this.obj, args);
+            System.out.println("after 动态代理(work)...");
+            return proxy;
+        } else {
+            System.out.println("after 动态代理...");
+            return method.invoke(this.obj, args);
+        }
+    }
+
+}
+

+ 40 - 0
luckysheet-mysql/src/main/java/com/xc/luckysheet/mysql/testinvocationhandler/test1/WorkHandler2.java

@@ -0,0 +1,40 @@
+package com.xc.luckysheet.mysql.testinvocationhandler.test1;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+/**
+ * JDK自带的动态代理主要是指,实现了InvocationHandler接口的代理类,实现了InvocationHandler接口的类,会继承一个invoke方法,
+ * 通过在这个方法中添加某些代码,从而完成在方法前后添加一些动态的东西。JDK自带的动态代理依赖于接口,如果有些类没有接口,则不能实现动态代理。
+ * 
+ * proxy是真实对象的真实代理对象,invoke方法可以返回调用代理对象方法的返回结果,也可以返回对象的真实代理对象
+ * proxy参数是invoke方法的第一个参数,通常情况下我们都是返回真实对象方法的返回结果,但是我们也可以将proxy返回,
+ * proxy是真实对象的真实代理对象,我们可以通过这个返回对象对真实的对象做各种各样的操作。
+ */
+public class WorkHandler2 implements InvocationHandler {
+
+    private Object obj;
+
+    public Object bind(Object obj) {
+        this.obj = obj;
+        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
+    }
+
+    @Override
+    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        System.out.println("before 动态代理...");
+        System.out.println(proxy.getClass().getName());
+        System.out.println(this.obj.getClass().getName());
+        if(method.getName().equals("work")) {
+            method.invoke(this.obj, args);
+            System.out.println("after 动态代理(work)...");
+            return proxy;
+        } else {
+            System.out.println("after 动态代理...");
+            return method.invoke(this.obj, args);
+        }
+    }
+
+}
+

BIN
luckysheet-mysql/src/test/.DS_Store


+ 82 - 0
luckysheet-postgre/pom.xml

@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>luckySheetServer</artifactId>
+        <groupId>com.xc</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.xc</groupId>
+    <artifactId>luckysheet-postgre</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <packaging>jar</packaging>
+    <name>luckysheet-postgre</name>
+    <description>postgres实现</description>
+
+    <dependencies>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-webmvc</artifactId>
+            <version>5.1.6.RELEASE</version>
+        </dependency>
+        <dependency>
+            <groupId>javax.annotation</groupId>
+            <artifactId>javax.annotation-api</artifactId>
+            <version>1.3.2</version>
+        </dependency>
+
+        <!--自动生成set get方法-->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.12</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+            <scope>compile</scope>
+            <optional>true</optional>
+        </dependency>
+
+        <!-- spring-jdbc -->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-jdbc</artifactId>
+            <version>5.1.10.RELEASE</version>
+        </dependency>
+
+        <!--阿里的druid数据源-->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid</artifactId>
+            <version>1.1.20</version>
+        </dependency>
+
+        <!-- postgresql  -->
+        <dependency>
+            <groupId>org.postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+            <version>42.1.1</version><!--$NO-MVN-MAN-VER$-->
+        </dependency>
+
+        <!---数据库接口-->
+        <dependency>
+            <groupId>com.xc</groupId>
+            <artifactId>luckysheet-db</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+    </dependencies>
+
+
+</project>

+ 35 - 0
luckysheet-postgre/src/main/java/com/xc/luckysheet/postgres/datasource/DataSourceConfig.java

@@ -0,0 +1,35 @@
+package com.xc.luckysheet.postgres.datasource;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import com.xc.luckysheet.util.SnowFlake;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.sql.DataSource;
+
+
+/**
+ * 数据源配置
+ * @author Administrator
+ */
+@Configuration
+@Slf4j
+public class DataSourceConfig {
+
+    @Bean(name = "postgresDataSource")
+    @ConfigurationProperties(prefix = "db.postgre.druid")
+    public DataSource postgreDataSource(){
+        DataSource postgre = DataSourceBuilder.create().type(DruidDataSource.class).build();
+        log.debug("数据源postgre",postgre);
+        return postgre;
+    }
+
+    @Bean(name="snowFlake")
+    public SnowFlake getSnowFlake(){
+        return new SnowFlake(1l,1l);
+    }
+
+}

+ 30 - 0
luckysheet-postgre/src/main/java/com/xc/luckysheet/postgres/datasource/JdbcTempleConfig.java

@@ -0,0 +1,30 @@
+package com.xc.luckysheet.postgres.datasource;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import javax.annotation.Resource;
+import javax.sql.DataSource;
+
+
+/**
+ * @author Administrator
+ */
+@Configuration
+@Slf4j
+public class JdbcTempleConfig {
+
+    /**
+     * postgre数据源
+     */
+    @Resource(name = "postgresDataSource")
+    private DataSource postgresDataSource;
+
+    @Bean(name="postgreJdbcTemplate")
+    public JdbcTemplate createPostgreJdbcTemplate(){
+        return new JdbcTemplate(postgresDataSource);
+    }
+
+}

+ 49 - 0
luckysheet-postgre/src/main/java/com/xc/luckysheet/postgres/datasource/ProfiledemoApplication.java

@@ -0,0 +1,49 @@
+package com.xc.luckysheet.postgres.datasource;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
+import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+import org.springframework.transaction.annotation.TransactionManagementConfigurer;
+
+import javax.annotation.Resource;
+import javax.sql.DataSource;
+
+/**
+ * @author Administrator
+ */
+
+/**
+ * 开启注解事务管理,等同于xml配置文件中的 <tx:annotation-driven />
+ * @author Administrator
+ */
+@EnableTransactionManagement
+@Configuration
+public class ProfiledemoApplication implements TransactionManagementConfigurer {
+
+    /**
+     * postgre数据源
+     */
+    @Resource(name = "postgresDataSource")
+    private DataSource postgresDataSource;
+
+
+    @Bean(name = "postgresTxManager")
+    public PlatformTransactionManager postgreTxManager() {
+        return new DataSourceTransactionManager(postgresDataSource);
+    }
+
+
+    @Resource(name="postgresTxManager")
+    private PlatformTransactionManager txManager;
+
+    /**
+     * 实现接口 TransactionManagementConfigurer 方法,其返回值代表在拥有多个事务管理器的情况下默认使用的事务管理器
+     * @return
+     */
+    @Override
+    public PlatformTransactionManager annotationDrivenTransactionManager() {
+        return txManager;
+    }
+}

+ 16 - 0
luckysheet-postgre/src/main/java/com/xc/luckysheet/postgres/impl/BaseHandle.java

@@ -0,0 +1,16 @@
+package com.xc.luckysheet.postgres.impl;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Repository;
+
+import javax.annotation.Resource;
+
+@Slf4j
+@Component
+public class BaseHandle {
+
+    @Resource(name = "postgreJdbcTemplate")
+    protected JdbcTemplate jdbcTemplate_postgresql;
+}

+ 161 - 0
luckysheet-postgre/src/main/java/com/xc/luckysheet/postgres/impl/RecordDataInsertHandle.java

@@ -0,0 +1,161 @@
+package com.xc.luckysheet.postgres.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.xc.luckysheet.JfGridConfigModel;
+import com.xc.luckysheet.db.IRecordDataInsertHandle;
+import com.xc.luckysheet.entity.GridRecordDataModel;
+import lombok.extern.slf4j.Slf4j;
+import org.postgresql.util.PGobject;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.stereotype.Repository;
+
+import javax.annotation.Resource;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 添加
+ * @author Administrator
+ */
+@Slf4j
+@Repository(value = "postgresRecordDataInsertHandle")
+public class RecordDataInsertHandle extends BaseHandle implements IRecordDataInsertHandle{
+
+    /**
+     * 新增Sheet页,并返回刚刚插入的_id
+     *
+     * @param pgModel
+     * @return
+     */
+    @Override
+    public String insert(GridRecordDataModel pgModel) {
+        JSONObject bson=pgModel.getJson_data();
+        PGobject pg=new PGobject();
+        pg.setType("json");
+        try {
+            pg.setValue(bson.toString());
+        } catch (SQLException e) {
+            log.error(e.getMessage());
+        }
+
+        String sql = "insert into "+JfGridConfigModel.TABLENAME +" (id,block_id,index,list_id,status,json_data,\"order\",is_delete) values " +
+                " (nextval('luckysheet_id_seq'),?,?,?,?,?,?,0)";
+        try{
+            jdbcTemplate_postgresql.update(sql,pgModel.getBlock_id().trim(),pgModel.getIndex(),pgModel.getList_id(),pgModel.getStatus(),pg,pgModel.getOrder());
+            return "";
+        }catch (Exception e){
+            log.warn(e.getMessage());
+        }
+        return null;
+    }
+
+    /**
+     * 批量添加 添加jsonb
+     *
+     * @param models
+     * @return
+     */
+    @Override
+    public String InsertIntoBatch(List<GridRecordDataModel> models) {
+        String sql = "insert into "+JfGridConfigModel.TABLENAME +" (id,block_id,row_col,index,list_id,status,\"order\",json_data,is_delete) values " +
+                " (nextval('luckysheet_id_seq'),?,?,?,?,?,?,?,0)";
+        List<Object[]>batch=new ArrayList<Object[]>();
+        for(GridRecordDataModel b : models){
+            List<Object> objectList=new ArrayList<Object>();
+            objectList.add(b.getBlock_id().trim());
+            objectList.add(b.getRow_col());
+            objectList.add(b.getIndex());
+            objectList.add(b.getList_id());
+            objectList.add(b.getStatus());
+            objectList.add(b.getOrder());
+            PGobject pg=new PGobject();
+            pg.setType("json");
+            try {
+                pg.setValue(b.getJson_data().toString());
+            } catch (SQLException e) {
+                log.error(e.getMessage());
+            }
+            objectList.add(pg);
+
+            Object[] params=(Object[])objectList.toArray(new Object[objectList.size()]);
+            batch.add(params);
+        }
+        try{
+            log.info("InsertIntoBatch sql{}",sql);
+            int[] i=jdbcTemplate_postgresql.batchUpdate(sql,batch);
+            log.info("InsertIntoBatch count {}",i);
+            return "";
+        }catch (Exception ex){
+            log.error(ex.toString());
+            return null;
+        }
+    }
+
+    /**
+     * 批量添加 添加jsonb
+     *
+     * @param models
+     * @return
+     */
+    @Override
+    public String InsertBatchDb(List<JSONObject> models) {
+        String sql = "insert into "+JfGridConfigModel.TABLENAME+" (id,block_id,row_col,index,list_id,status,\"order\",json_data,is_delete) values " +
+                " (nextval('luckysheet_id_seq'),?,?,?,?,?,?,?,0)";
+        List<Object[]>batch=new ArrayList<Object[]>();
+        int order=0;
+        for(JSONObject b : models){
+            List<Object> objectList=new ArrayList<Object>();
+            objectList.add(b.get("block_id").toString().trim());
+            if(b.containsKey("row_col") && b.get("row_col")!=null){
+                objectList.add(b.get("row_col"));
+            }else{
+                objectList.add(null);
+            }
+            objectList.add(b.get("index"));
+            objectList.add(b.get("list_id"));
+            if(b.containsKey("status") && b.get("status")!=null){
+                objectList.add(b.get("status"));
+            }else{
+                objectList.add(0);
+            }
+
+            if(b.containsKey("order") && b.get("order")!=null){
+                objectList.add(b.get("order"));
+                order=Integer.valueOf(b.get("order").toString());
+            }else{
+                objectList.add(order);
+            }
+
+            PGobject pg=new PGobject();
+            pg.setType("json");
+            try {
+                JSONObject db=new JSONObject();
+                if(b.containsKey("json_data")){
+                    db=(JSONObject) b.get("json_data");
+                }else{
+                    db.put("celldata", b.get("celldata"));
+                }
+
+                pg.setValue(db.toString());
+            } catch (SQLException e) {
+                log.error(e.getMessage());
+            }
+            objectList.add(pg);
+
+            Object[] params=(Object[])objectList.toArray(new Object[objectList.size()]);
+            batch.add(params);
+        }
+
+        try{
+            log.info("InsertBatchDb sql{}",sql);
+            int[] i=jdbcTemplate_postgresql.batchUpdate(sql,batch);
+            log.info("InsertBatchDb count {}",i);
+            return "";
+        }catch (Exception ex){
+            log.error(ex.getMessage());
+            return null;
+        }
+    }
+}
+

+ 523 - 0
luckysheet-postgre/src/main/java/com/xc/luckysheet/postgres/impl/RecordDataUpdataHandle.java

@@ -0,0 +1,523 @@
+package com.xc.luckysheet.postgres.impl;
+
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.xc.luckysheet.JfGridConfigModel;
+import com.xc.luckysheet.db.IRecordDataInsertHandle;
+import com.xc.luckysheet.db.IRecordDataUpdataHandle;
+import com.xc.luckysheet.db.IRecordDelHandle;
+import com.xc.luckysheet.entity.GridRecordDataModel;
+import lombok.extern.slf4j.Slf4j;
+import org.postgresql.util.PGobject;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.jdbc.core.BatchPreparedStatementSetter;
+import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 更新
+ * @author Administrator
+ */
+@Slf4j
+@Repository(value ="postgresRecordDataUpdataHandle" )
+public class RecordDataUpdataHandle extends BaseHandle implements IRecordDataUpdataHandle {
+
+    @Resource
+    @Qualifier("postgresRecordDataInsertHandle")
+    private IRecordDataInsertHandle RecordDataInsertHandle;
+
+    @Resource
+    @Qualifier("postgresRecordDelHandle")
+    private IRecordDelHandle recordDelHandle;
+
+    /**
+     * sheet多块更新(先删除后添加)
+     * 按IDS删除一组,然后新加处理后的
+     * @param blocks
+     * @param ids
+     * @return
+     */
+    @Transactional(value = "postgresTxManager",rollbackFor = Exception.class)
+    @Override
+    public Boolean updateMulti2(List<JSONObject> blocks, List<String> ids) {
+        try{
+            if(ids!=null && ids.size()>0){
+                recordDelHandle.delDocuments(ids);
+            }
+            String _mongodbKey = RecordDataInsertHandle.InsertBatchDb(blocks);
+            if (_mongodbKey == null) {
+                throw new RuntimeException("插入报错");
+            }
+            return true;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+    /**
+     * 批量更新order 按listId,index,首块
+     *
+     * @param models
+     * @return
+     */
+    @Override
+    public boolean batchUpdateForNoJsonbData(List<GridRecordDataModel> models) {
+        try{
+            String sql="update "+JfGridConfigModel.TABLENAME+" set \"order\"=?  where  list_id=? and index=? and block_id=?";
+            log.info("batchUpdateForNoJsonbData:"+sql);
+            jdbcTemplate_postgresql.batchUpdate(sql, new BatchPreparedStatementSetter() {
+                public int getBatchSize() {
+                    return models.size();
+                    //这个方法设定更新记录数,通常List里面存放的都是我们要更新的,所以返回list.size();
+                }
+                public void setValues(PreparedStatement ps, int i)throws SQLException {
+                    GridRecordDataModel linkset =  models.get(i);
+                    ps.setInt(1, linkset.getOrder());
+                    ps.setString(2, linkset.getList_id());
+                    ps.setString(3, linkset.getIndex());
+                    ps.setString(4, JfGridConfigModel.FirstBlockID);
+                }
+            });
+            return true;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return false;
+        }
+    }
+
+    /**
+     * 清除指定层级下某条数据
+     *
+     * @param query   键值对
+     * @param keyName
+     * @return
+     */
+    @Override
+    public boolean rmCellDataValue(JSONObject query, String keyName) {
+        String condition="";
+        try{
+            log.info("select:"+query.toString(SerializerFeature.WriteMapNullValue));
+            Map<String,Object> queryDB=query.getInnerMap();
+            for (String key : queryDB.keySet()) {
+                condition=condition+"and "+key+"='"+queryDB.get(key)+"'";
+            }
+            String updateSql="update "+JfGridConfigModel.TABLENAME+" set json_data=json_data #- '{"+keyName+"}'  where 1=1 " +condition;
+            log.info("rmCellDataValue--"+updateSql);
+            jdbcTemplate_postgresql.update(updateSql);
+            return true;
+        }catch (Exception ex){
+            log.error(ex.getMessage());
+            return false;
+        }
+    }
+
+    /**
+     * 更新jsonb中某条文本数据
+     *
+     * @param query    键值对
+     * @param keyName
+     * @param position
+     * @param v
+     * @return
+     */
+    @Override
+    public boolean updateCellDataListTxtValue(JSONObject query, String keyName, Integer position, Object v) {
+        String condition="";
+        try{
+            log.info("select:"+query.toString(SerializerFeature.WriteMapNullValue));
+            Map<String,Object> queryDB=query.getInnerMap();
+            for (String key : queryDB.keySet()) {
+                condition=condition+"and "+key+"='"+queryDB.get(key)+"'";
+            }
+            if(position!=null){
+                keyName=keyName+","+position;
+            }
+            StringBuffer updateSql=new StringBuffer();
+            updateSql.append("update "+JfGridConfigModel.TABLENAME+" set json_data=jsonb_set(json_data,'{"+keyName);
+            updateSql.append("}'::text[],'"+v+"',true) where 1=1 "+condition);
+
+            jdbcTemplate_postgresql.update(updateSql.toString());
+            return true;
+        }catch (Exception ex){
+            log.error(ex.getMessage());
+            return false;
+        }
+    }
+
+    /**
+     * 更新jsonb中某条文本数据
+     *
+     * @param query    键值对
+     * @param keyName
+     * @param position
+     * @param v
+     * @return
+     */
+    @Override
+    public boolean updateCellDataListValue(JSONObject query, String keyName, String position, Object v) {
+        String condition="";
+        try{
+            log.info("select:"+query.toString(SerializerFeature.WriteMapNullValue));
+            Map<String,Object> queryDB=query.getInnerMap();
+            for (String key : queryDB.keySet()) {
+                condition=condition+"and "+key+"='"+queryDB.get(key)+"'";
+            }
+            if(position!=null){
+                keyName=keyName+","+position;
+            }
+            StringBuffer updateSql=new StringBuffer();
+            updateSql.append("update "+JfGridConfigModel.TABLENAME+" set json_data=jsonb_set(json_data,'{"+keyName);
+            updateSql.append("}','"+v+"',true) where 1=1 "+condition);
+            log.info("updateSql:"+updateSql);
+            jdbcTemplate_postgresql.update(updateSql.toString());
+            return true;
+        }catch (Exception ex){
+            log.error(ex.getMessage());
+            return false;
+        }
+    }
+
+    /**
+     * jsonb数据中元素添加元素
+     *
+     * @param query
+     * @param word
+     * @param db
+     * @param position
+     * @return
+     */
+    @Override
+    public boolean updateJsonbForElementInsert(JSONObject query, String word, JSONObject db, Integer position) {
+        String condition="";
+        try{
+            log.info("select:"+query.toString(SerializerFeature.WriteMapNullValue));
+            Map<String,Object> queryDB=query.getInnerMap();
+            if(position!=null){
+                word=word+","+position;
+            }
+            List arr=new ArrayList<>();
+            for (String key : queryDB.keySet()) {
+                arr.add(queryDB.get(key));
+                condition=condition+"and "+key+"=? ";
+            }
+            //(jsonb_v,'{myinfo,celldata,0}','{"c":1,"r":1,"v":{"con":"str"}}',false)
+            String updateSql="update "+JfGridConfigModel.TABLENAME+" set json_data=jsonb_insert(json_data,'{"+word+"}','"+db.toString()+"',false) where 1=1 " +condition;
+            log.info("updateSql:"+updateSql);
+            jdbcTemplate_postgresql.update(updateSql,arr.toArray());
+            return true;
+        }catch (Exception ex){
+            log.error(ex.getMessage());
+            return false;
+        }
+    }
+
+    /**
+     * 更新
+     *
+     * @param query
+     * @param word
+     * @return
+     */
+    @Override
+    public boolean rmJsonbDataForEmpty(JSONObject query, String word) {
+        String condition="";
+        try{
+            log.info("select:"+query.toString(SerializerFeature.WriteMapNullValue));
+            Map<String,Object> queryDB=query.getInnerMap();
+            List arr=new ArrayList<>();
+            for (String key : queryDB.keySet()) {
+                arr.add(queryDB.get(key));
+                condition=condition+"and "+key+"=? ";
+            }
+            String sql="update "+JfGridConfigModel.TABLENAME+" set json_data=json_data||'{"+word+"}'::jsonb where 1=1 "+condition;
+            log.info("updateSql:"+sql);
+            jdbcTemplate_postgresql.update(sql,arr.toArray());
+            return true;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return false;
+        }
+    }
+
+    /**
+     * 更新
+     *
+     * @param query
+     * @param word
+     * @return
+     */
+    @Override
+    public boolean updateJsonbDataForKeys(JSONObject query, JSONObject word) {
+        String condition="";
+        try{
+            log.info("select:"+query.toString(SerializerFeature.WriteMapNullValue));
+            Map<String,Object> queryDB=query.getInnerMap();
+
+            List arr=new ArrayList<>();
+            for (String key : queryDB.keySet()) {
+                arr.add(queryDB.get(key));
+                condition=condition+"and "+key+"=? ";
+            }
+            String sql="update "+JfGridConfigModel.TABLENAME+" set json_data=json_data||'"+word.toString()+"'::jsonb where 1=1 "+condition;
+            log.info("updateSql:"+sql);
+            jdbcTemplate_postgresql.update(sql,arr.toArray());
+            return true;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return false;
+        }
+    }
+
+    /**
+     * 更新status状态
+     *
+     * @param model
+     * @return
+     */
+    @Transactional(value = "postgresTxManager",rollbackFor = Exception.class)
+    @Override
+    public boolean updateDataStatus(GridRecordDataModel model) {
+        try{
+            String sql1="update "+JfGridConfigModel.TABLENAME+" set status=0  where  list_id=? and status=1 and block_id=?";
+            log.info("updateSql1:"+sql1);
+            jdbcTemplate_postgresql.update(sql1,new Object[]{model.getList_id(),model.getBlock_id()});
+
+            String sql2="update "+JfGridConfigModel.TABLENAME+" set status=1  where  list_id=? and index=? and block_id=?";
+            log.info("updateSql2:"+sql2);
+            jdbcTemplate_postgresql.update(sql2,new Object[]{model.getList_id(),model.getIndex(),model.getBlock_id()});
+            return true;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+    /**
+     * 更新sheet隐藏状态
+     *
+     * @param model
+     * @param hide
+     * @param index1
+     * @param index2
+     * @return
+     */
+    @Transactional(value = "postgresTxManager",rollbackFor = Exception.class)
+    @Override
+    public boolean updateDataMsgHide(GridRecordDataModel model, Integer hide, String index1, String index2) {
+        try{
+            String sql1="update "+JfGridConfigModel.TABLENAME+" set status=0 ,json_data=jsonb_set(json_data,'{hide}'::text[],'"+hide+"',true) where  list_id='"+model.getList_id()+"' and index='"+index1+"' and block_id='fblock'";
+            log.info("updateSql1:"+sql1);
+            jdbcTemplate_postgresql.update(sql1);
+            String sql2="update "+JfGridConfigModel.TABLENAME+" set status=1  where  list_id=? and index=? and block_id=?";
+            log.info("updateSql2:"+sql2);
+            jdbcTemplate_postgresql.update(sql2,new Object[]{model.getList_id(),index2,model.getBlock_id()});
+            return true;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+    /**
+     * 更新sheet隐藏状态
+     *
+     * @param model
+     * @param hide
+     * @param index
+     * @return
+     */
+    @Transactional(value = "postgresTxManager",rollbackFor = Exception.class)
+    @Override
+    public boolean updateDataMsgNoHide(GridRecordDataModel model, Integer hide, String index) {
+        try{
+            String sql1="update "+JfGridConfigModel.TABLENAME+" set status=0  where  list_id=?  and block_id=?";
+            log.info("updateSql1:"+sql1);
+            jdbcTemplate_postgresql.update(sql1,new Object[]{model.getList_id(),model.getBlock_id()});
+
+            String sql2="update "+JfGridConfigModel.TABLENAME+" set status=1 ,json_data=jsonb_set(json_data,'{hide}'::text[],'"+hide+"',true) where  list_id='"+model.getList_id()+"' and index='"+index+"' and block_id='"+model.getBlock_id()+"'";
+            log.info("updateSql2:"+sql2);
+            jdbcTemplate_postgresql.update(sql2);
+            return true;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+    /**
+     * 更新jsonb中某条文本数据
+     *
+     * @param block_ids
+     * @param models
+     * @return
+     */
+    @Override
+    public boolean batchUpdateCellDataValue(List<String> block_ids, List<GridRecordDataModel> models) {
+        try{
+            String id="";
+            for (String str : block_ids) {
+                id=id+"'"+str+"',";
+            }
+            id=id.substring(0, id.length()-1);
+            log.info("id:"+id);
+            String delsql="DELETE from "+JfGridConfigModel.TABLENAME+" where list_id=? and block_id in ("+id+") and index=? ";
+            jdbcTemplate_postgresql.update(delsql,new Object[]{models.get(0).getList_id(),models.get(0).getIndex()});
+            String sql = "insert into "+JfGridConfigModel.TABLENAME+" (id,block_id,index,list_id,status,\"order\",json_data,is_delete) values " +
+                    " (nextval('luckysheet_id_seq'),?,?,?,?,?,?,0)";
+            List<Object[]>batch=new ArrayList<Object[]>();
+            for(GridRecordDataModel b : models){
+                List<Object> objectList=new ArrayList<Object>();
+                objectList.add(b.getBlock_id().trim());
+                objectList.add(b.getIndex());
+                objectList.add(b.getList_id());
+                objectList.add(b.getStatus());
+                objectList.add(b.getOrder());
+                PGobject pg=new PGobject();
+                pg.setType("json");
+                try {
+                    pg.setValue(b.getJson_data().toString(SerializerFeature.WriteMapNullValue));
+                } catch (SQLException e) {
+                    log.error(e.getMessage());
+                }
+                objectList.add(pg);
+
+                Object[] params=(Object[])objectList.toArray(new Object[objectList.size()]);
+                batch.add(params);
+            }
+            log.info("sqls:{}",sql);
+            jdbcTemplate_postgresql.batchUpdate(sql,batch);
+            log.info("batchUpdateCellDataValue--end");
+            return true;
+
+
+        }catch (Exception ex){
+            log.error(ex.getMessage());
+            return false;
+        }
+    }
+
+    /**
+     * jsonb数据中元素添加元素(集合插入)
+     *
+     * @param query
+     * @param word
+     * @param db
+     * @param position
+     * @param words
+     * @return
+     */
+    @Transactional(value = "postgresTxManager",rollbackFor = Exception.class)
+    @Override
+    public boolean updateJsonbForInsertNull(JSONObject query, String word, JSONObject db, Integer position, String words) {
+        String condition="";
+        try{
+            log.info("select:"+query.toString(SerializerFeature.WriteMapNullValue));
+            Map<String,Object> queryDB=query.getInnerMap();
+            List arr=new ArrayList<>();
+            for (String key : queryDB.keySet()) {
+                arr.add(queryDB.get(key));
+                condition=condition+"and "+key+"=? ";
+            }
+            String createSql="update "+JfGridConfigModel.TABLENAME+" set json_data=json_data||'{"+words+"}'::jsonb where 1=1 " +condition;
+            log.info("createSql:{}",createSql);
+            jdbcTemplate_postgresql.update(createSql,arr.toArray());
+            if(position!=null){
+                word=word+","+position;
+            }
+            //(jsonb_v,'{myinfo,celldata,0}','{"c":1,"r":1,"v":{"con":"str"}}',false)
+            String updateSql="update "+JfGridConfigModel.TABLENAME+" set json_data=jsonb_insert(json_data,'{"+word+"}','"+db.toString()+"',false) where 1=1 " +condition;
+            log.info("updateSql:{}",updateSql);
+            jdbcTemplate_postgresql.update(updateSql,arr.toArray());
+            return true;
+        }catch (Exception ex){
+            log.error(ex.getMessage());
+            throw new RuntimeException(ex.getMessage());
+        }
+    }
+
+    /**
+     * jsonb数据中元素添加元素
+     *
+     * @param query
+     * @param word
+     * @param db
+     * @param position
+     * @return
+     */
+    @Transactional(value = "postgresTxManager",rollbackFor = Exception.class)
+    @Override
+    public boolean updateJsonbForSetNull(JSONObject query, String word, JSONObject db, Integer position) {
+        String condition="";
+        try{
+            log.info("select:"+query.toString(SerializerFeature.WriteMapNullValue));
+            Map<String,Object> queryDB=query.getInnerMap();
+            List arr=new ArrayList<>();
+            for (String key : queryDB.keySet()) {
+                arr.add(queryDB.get(key));
+                condition=condition+"and "+key+"=? ";
+            }
+            log.info("arr:"+arr);
+            String createSql="update "+JfGridConfigModel.TABLENAME+" set json_data=jsonb_set(json_data,'{"+word+"}'::text[],'[]',true)  where 1=1 " +condition;
+            log.info("createSql:"+createSql);
+            jdbcTemplate_postgresql.update(createSql,arr.toArray());
+            if(position!=null){
+                word=word+","+position;
+            }
+            //(jsonb_v,'{myinfo,celldata,0}','{"c":1,"r":1,"v":{"con":"str"}}',false)
+            String updateSql="update "+JfGridConfigModel.TABLENAME+" set json_data=jsonb_set(json_data,'{"+word+"}'::text[],'"+db.toString()+"',true) where 1=1 " +condition;
+            log.info("updateSql:"+updateSql);
+            jdbcTemplate_postgresql.update(updateSql,arr.toArray());
+            return true;
+        }catch (Exception ex){
+            log.error(ex.getMessage());
+            throw new RuntimeException(ex.getMessage());
+        }
+    }
+
+    /**
+     * jsonb数据中元素添加元素(根节点)
+     *
+     * @param query
+     * @param word
+     * @param db
+     * @param position
+     * @param words
+     * @return
+     */
+    @Transactional(value = "postgresTxManager",rollbackFor = Exception.class)
+    @Override
+    public boolean updateJsonbForSetRootNull(JSONObject query, String word, JSONObject db, Integer position, String words) {
+        String condition="";
+        try{
+            log.info("select:{}",query.toString(SerializerFeature.WriteMapNullValue));
+            Map<String,Object> queryDB=query.getInnerMap();
+            List arr=new ArrayList<>();
+            for (String key : queryDB.keySet()) {
+                arr.add(queryDB.get(key));
+                condition=condition+"and "+key+"=? ";
+            }
+            String createSql="update "+JfGridConfigModel.TABLENAME+" set json_data=json_data||'{"+words+"}'::jsonb where 1=1 " +condition;
+            log.info("createSql:"+createSql);
+            jdbcTemplate_postgresql.update(createSql,arr.toArray());
+            if(position!=null){
+                word=word+","+position;
+            }
+            //(jsonb_v,'{myinfo,celldata,0}','{"c":1,"r":1,"v":{"con":"str"}}',false)
+            String updateSql="update "+JfGridConfigModel.TABLENAME+" set json_data=jsonb_set(json_data,'{"+word+"}','"+db.toString()+"',false) where 1=1 " +condition;
+            log.info("updateSql:"+updateSql);
+            jdbcTemplate_postgresql.update(updateSql,arr.toArray());
+            return true;
+        }catch (Exception ex){
+            log.error(ex.getMessage());
+            throw new RuntimeException(ex.getMessage());
+        }
+    }
+}

+ 84 - 0
luckysheet-postgre/src/main/java/com/xc/luckysheet/postgres/impl/RecordDelHandle.java

@@ -0,0 +1,84 @@
+package com.xc.luckysheet.postgres.impl;
+
+import com.xc.luckysheet.JfGridConfigModel;
+import com.xc.luckysheet.db.IRecordDelHandle;
+import com.xc.luckysheet.entity.GridRecordDataModel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.jdbc.object.BatchSqlUpdate;
+import org.springframework.stereotype.Repository;
+
+import javax.sql.DataSource;
+import java.sql.Types;
+import java.util.List;
+
+/**
+ * 删除
+ * @author Administrator
+ */
+@Slf4j
+@Repository(value = "postgresRecordDelHandle")
+public class RecordDelHandle extends BaseHandle implements IRecordDelHandle {
+
+    /**
+     * 删除sheet(非物理删除)
+     *
+     * @param model
+     * @return
+     */
+    @Override
+    public boolean updateDataForReDel(GridRecordDataModel model) {
+        try{
+            String sql1="update "+ JfGridConfigModel.TABLENAME+"  set is_delete=?  where  list_id=? and index=? ";
+            log.info("updateSql1:"+sql1);
+            jdbcTemplate_postgresql.update(sql1,new Object[]{model.getIs_delete(),model.getList_id(),model.getIndex()});
+            return true;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return false;
+        }
+    }
+
+    /**
+     * 按ID 删除多个文档 (物理删除)
+     *
+     * @param ids
+     * @return
+     */
+    @Override
+    public String delDocuments(List<String> ids) {
+        try{
+            String id="";
+            for (String str : ids) {
+                id=id+str+",";
+            }
+            id=id.substring(0, id.length()-1);
+            String delsql="DELETE from "+JfGridConfigModel.TABLENAME+" where id in ("+id+")";
+            jdbcTemplate_postgresql.update(delsql);
+            return "";
+        }catch (Exception ex){
+            log.error(ex.toString());
+            return ex.toString();
+        }
+    }
+
+    /**
+     * 按list_id 删除记录 (物理删除)
+     *
+     * @param listIds
+     * @return
+     */
+    @Override
+    public int[] delete(List<String> listIds) {
+        if(listIds==null && listIds.size()==0){
+            return new int[]{};
+        }
+        DataSource ds = jdbcTemplate_postgresql.getDataSource();
+        BatchSqlUpdate bsu = new BatchSqlUpdate(ds, " delete  from "+JfGridConfigModel.TABLENAME +" where list_id = ? ");
+        bsu.setBatchSize(4);
+        bsu.setTypes(new int[]{Types.VARCHAR});
+        for(int i = 0; i < listIds.size(); i++){
+            log.info(bsu.update(new Object[]{listIds.get(i)})+"");
+        }
+        return bsu.flush();
+    }
+}

+ 416 - 0
luckysheet-postgre/src/main/java/com/xc/luckysheet/postgres/impl/RecordSelectHandle.java

@@ -0,0 +1,416 @@
+package com.xc.luckysheet.postgres.impl;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.xc.luckysheet.JfGridConfigModel;
+import com.xc.luckysheet.db.IRecordSelectHandle;
+import com.xc.luckysheet.util.JfGridFileUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.postgresql.util.PGobject;
+import org.springframework.stereotype.Repository;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 查询
+ * @author Administrator
+ */
+@Slf4j
+@Repository(value = "postgresRecordSelectHandle")
+public class RecordSelectHandle extends BaseHandle implements IRecordSelectHandle {
+    /**
+     * 查看指定sheet页 第一块是否存在(控制块)
+     *
+     * @param listId
+     * @param index
+     * @return
+     */
+    @Override
+    public Integer getFirstBlockByGridKey(String listId, String index) {
+        //默认获取第一块
+        String sql="select count(1) from "+JfGridConfigModel.TABLENAME +" p where p.list_id=? and p.index=? and p.block_id=? and p.is_delete=0";
+        try{
+            return  jdbcTemplate_postgresql.queryForObject(sql, new Object[]{listId,index,JfGridConfigModel.FirstBlockID},Integer.class);
+        }catch (Exception e){
+            log.warn(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 获取指定的xls激活的sheet页的 返回index(控制块)
+     *
+     * @param listId
+     * @return
+     */
+    @Override
+    public String getFirstBlockIndexByGridKey(String listId) {
+        //默认获取第一块
+        String sql="select p.index from "+JfGridConfigModel.TABLENAME+" p where p.list_id=? and p.block_id=? and p.status=1 and p.is_delete=0 ";
+        try{
+            return  jdbcTemplate_postgresql.queryForObject(sql, new Object[]{listId,JfGridConfigModel.FirstBlockID},String.class);
+        }catch (Exception e){
+            log.warn(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 获取指定的xls,sheet 第一块的行列信息(控制块)
+     *
+     * @param listId
+     * @param index
+     * @return
+     */
+    @Override
+    public String getFirstBlockRowColByGridKey(String listId,String index) {
+        //默认获取第一块
+        String sql="select p.row_col from "+JfGridConfigModel.TABLENAME+" p where p.list_id=? and p.index=? and p.block_id=? and p.is_delete=0";
+        try{
+            return  jdbcTemplate_postgresql.queryForObject(sql, new Object[]{listId,index,JfGridConfigModel.FirstBlockID},String.class);
+        }catch (Exception e){
+            log.warn(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 按指定xls,sheet顺序返回整个xls结构
+     * 不返回celldata ,只获取信息块
+     *
+     * @param listId
+     * @return
+     */
+    @Override
+    public List<JSONObject> getByGridKey_NOCelldata(String listId) {
+        try{
+            String sql="select id,block_id,index,list_id,status,json_data-'celldata' AS json_data,\"order\" from "+JfGridConfigModel.TABLENAME+" p where p.list_id=? and p.block_id=? and p.is_delete=0  order by p.order";
+            List<Map<String, Object>> list=jdbcTemplate_postgresql.queryForList(sql, new Object[]{listId,JfGridConfigModel.FirstBlockID});
+            List<JSONObject> result=new ArrayList<JSONObject>();
+
+            for (Map<String, Object> map : list) {
+                JSONObject pgd=null;
+                try{
+                    PGobject pg=(PGobject) map.get("json_data");
+                    pgd=JSONObject.parseObject(pg.getValue(),JSONObject.class);
+                }catch (Exception e) {
+                    pgd=JSONObject.parseObject(map.get("json_data").toString(),JSONObject.class);
+                }
+                for (String key : map.keySet()) {
+                    if("json_data".equals(key)){
+                    }else{
+                        pgd.put(key.toLowerCase(), map.get(key));
+                    }
+                }
+                result.add(pgd);
+            }
+            return result;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 按指定xls,sheet获取,返回指定的sheet集合
+     *
+     * @param listId
+     * @param index
+     * @return
+     */
+    @Override
+    public List<JSONObject> getBlockAllByGridKey(String listId, String index) {
+        try{
+            String sql="select * from "+JfGridConfigModel.TABLENAME+" p where  p.list_id=? and p.index =? and p.is_delete=0 order by p.order asc";
+            List<Map<String, Object>> list=jdbcTemplate_postgresql.queryForList(sql, new Object[]{listId,index});
+            List<JSONObject> result=new ArrayList<JSONObject>(4);
+            for (Map<String, Object> map : list) {
+                result.add(getDBObjectFromMap(map));
+            }
+            return result;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 获取指定xls,sheet,block 的数据
+     *
+     * @param listId
+     * @param index
+     * @param blockId
+     * @return
+     */
+    @Override
+    public JSONObject getCelldataByGridKey(String listId, String index, String blockId) {
+        try{
+            String sql="select index,json_data->>'celldata' AS celldata,json_data->>'column' AS column,json_data->>'row' AS row from "+JfGridConfigModel.TABLENAME+" p where  p.list_id=? and p.index=? and p.block_id=? and p.is_delete=0 ORDER BY p.id DESC LIMIT 1 ";
+            Map<String, Object> map=jdbcTemplate_postgresql.queryForMap(sql, new Object[]{listId,index,blockId});
+            JSONObject db=new JSONObject();
+
+            for (String key : map.keySet()) {
+                if("celldata".equals(key)){
+                    JSONArray pgd=null;
+                    try{
+                        PGobject pg=(PGobject) map.get(key);
+                        pgd=JSONObject.parseObject(pg.getValue(),JSONArray.class);
+                    }catch (Exception e) {
+                        pgd=JSONObject.parseObject(map.get(key).toString(),JSONArray.class);
+                    }
+                    db.put(key.toLowerCase(), pgd);
+                }else{
+                    db.put(key.toLowerCase(), map.get(key));
+                }
+            }
+            return db;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 获取指定xls、sheet中的config中数据 (存放在第一块中)
+     *
+     * @param listId
+     * @param index
+     * @return
+     */
+    @Override
+    public JSONObject getConfigByGridKey(String listId, String index) {
+        try{
+            String sql="select index,list_id,json_data->>'config' AS config,json_data->>'calcChain' AS calcChain,json_data->>'filter' AS filter from "+JfGridConfigModel.TABLENAME+" p where p.list_id=? and p.index=? and p.block_id=? and p.is_delete=0 ";
+            Map<String, Object> map=jdbcTemplate_postgresql.queryForMap(sql, new Object[]{listId,index,JfGridConfigModel.FirstBlockID});
+            JSONObject db=new JSONObject();
+
+            for (String key : map.keySet()) {
+                if("config".equals(key)|| "calcChain".equals(key)|| "filter".equals(key)){
+                    JSONObject pgd=null;
+                    try{
+                        if(map.get(key)!=null){
+                            PGobject pg=(PGobject) map.get(key);
+                            pgd=JSONObject.parseObject(pg.getValue(),JSONObject.class);
+                        }else{
+                            pgd=JSONObject.parseObject("");
+                        }
+                    }catch (Exception e) {
+                        pgd=JSONObject.parseObject(map.get(key).toString(),JSONObject.class);
+                    }
+                    db.put(key.toLowerCase(), pgd);
+                }else{
+                    db.put(key.toLowerCase(), map.get(key));
+                }
+            }
+            return db;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 按list_id,index获取,返回指定sheet 当前sheet的全部分块数据(并合并)getMergeByGridKey
+     * 返回是DBObject,而下面这个方法返回仅仅只有celldata
+     *
+     * @param listId
+     * @param index
+     * @param ids
+     * @return
+     */
+    @Override
+    public JSONObject getBlockMergeByGridKey(String listId, String index, List<String> ids) {
+        JSONObject _fblock=new JSONObject();
+        JSONArray _celldata=new JSONArray();
+        //获取全部块
+        List<JSONObject> blocks=getBlockAllByGridKey(listId, index);
+        if(blocks!=null && blocks.size()>0){
+            for(JSONObject _b:blocks){
+                if(ids!=null){
+                    if(_b.containsKey("id")){
+                        ids.add(_b.get("id").toString());
+                    }
+                }
+                if(_b.containsKey("block_id")){
+                    if(JfGridConfigModel.FirstBlockID.equals(_b.get("block_id").toString().trim())){
+                        //信息块
+                        _fblock=_b;
+                    }else{
+                        //数据块
+                        JSONObject db=JfGridFileUtil.getJSONObjectByIndex(_b, "json_data");
+                        JSONArray _blockCellData=JfGridFileUtil.getSheetByIndex(db);
+                        if(_blockCellData!=null){
+                            _celldata.addAll(_blockCellData);
+                        }
+                    }
+                }
+            }
+        }
+        _fblock.put("celldata",_celldata);
+        return _fblock;
+    }
+
+    /**
+     * 按list_id获取(id,index),返回sheet集合
+     *
+     * @param listId
+     * @param flag 是否仅仅获取主要模块
+     * @return
+     */
+    @Override
+    public List<JSONObject> getBlocksByGridKey(String listId, boolean flag) {
+        try{
+            List<Object> _param=new ArrayList<>(2);
+            String sql="select id,index from "+JfGridConfigModel.TABLENAME+" p where  p.list_id=? ";
+            _param.add(listId);
+            if(flag){
+                sql=sql+" and block_id=? ";
+                _param.add(JfGridConfigModel.FirstBlockID);
+            }
+            sql=sql+" and p.is_delete=0 ";
+
+            List<Map<String, Object>> list=jdbcTemplate_postgresql.queryForList(sql, Arrays.asList(_param));
+            List<JSONObject> result=new ArrayList<JSONObject>();
+            for (Map<String, Object> map : list) {
+                result.add(getDBObjectFromMap(map));
+            }
+            return result;
+        }catch (Exception e){
+            log.warn(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 获取指定xls,多个sheet的全部分块
+     *
+     * @param listId
+     * @param indexs
+     * @return
+     */
+    @Override
+    public List<JSONObject> getAllIndexsByGridKey(String listId, List<String> indexs) {
+        try{
+            StringBuffer sql=new StringBuffer();
+            sql.append("select * from "+JfGridConfigModel.TABLENAME+" p where  p.list_id=? and p.index in (");
+            String mockInStatement="";
+            int i=0;
+            for (String type: indexs){
+                if (i < indexs.size()-1){
+                    mockInStatement = mockInStatement + "'"+type + "',";
+                }
+                else {
+                    mockInStatement = mockInStatement + "'"+type+"'";
+                }
+                i++;
+            }
+            sql.append(mockInStatement);
+            sql.append(") and p.is_delete=0 order by p.order asc");
+            List<Map<String, Object>> list=jdbcTemplate_postgresql.queryForList(sql.toString(), new Object[]{listId});
+            List<JSONObject> result=new ArrayList<JSONObject>();
+            for (Map<String, Object> map : list) {
+                result.add(getDBObjectFromMap(map));
+            }
+            return result;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 获取指定xls,sheet全部内容
+     *
+     * @param listId
+     * @param index
+     * @return
+     */
+    @Override
+    public List<JSONObject> getIndexsByGridKey(String listId, String index) {
+        try{
+            StringBuffer sql=new StringBuffer();
+            sql.append("select * from "+JfGridConfigModel.TABLENAME+" p where  p.list_id=? and p.index =? and p.is_delete=0 order by p.id asc ");
+            List<Map<String, Object>> list=jdbcTemplate_postgresql.queryForList(sql.toString(), new Object[]{listId,index});
+            List<JSONObject> result=new ArrayList<JSONObject>();
+            for (Map<String, Object> map : list) {
+                result.add(getDBObjectFromMap(map));
+            }
+            return result;
+        }catch (Exception e){
+            log.warn(e.getMessage());
+            return null;
+        }
+    }
+
+    /**
+     * 获取图表数据(第一块)
+     *
+     * @param listId
+     * @param index
+     * @return
+     */
+    @Override
+    public JSONObject getChartByGridKey(String listId, String index) {
+        //默认获取第一块
+        try{
+            String sql="select index,list_id,json_data->>'chart' AS chart,block_id from "+JfGridConfigModel.TABLENAME+" p where p.list_id=? and p.index=? and p.block_id=? and p.is_delete=0 ";
+            Map<String, Object> map=jdbcTemplate_postgresql.queryForMap(sql, new Object[]{listId,index,JfGridConfigModel.FirstBlockID});
+            JSONObject db=new JSONObject();
+
+            for (String key : map.keySet()) {
+                if("chart".equals(key)){
+                    JSONObject pgd=null;
+                    if(map.get(key)!=null){
+                        try{
+                            PGobject pg=(PGobject) map.get(key);
+                            pgd=JSONObject.parseObject(pg.getValue(),JSONObject.class);
+                        }catch (Exception e) {
+                            pgd=JSONObject.parseObject(map.get(key).toString(),JSONObject.class);
+                        }
+                        db.put(key.toLowerCase(), pgd);
+                    }else{
+                        db.put(key.toLowerCase(), null);
+                    }
+
+                }else{
+                    db.put(key.toLowerCase(), map.get(key));
+                }
+            }
+            return db;
+        }catch (Exception e){
+            log.error(e.getMessage());
+            return null;
+        }
+    }
+
+
+
+    private JSONObject getDBObjectFromMap(Map<String, Object> map){
+        JSONObject db=new JSONObject();
+
+        for (String key : map.keySet()) {
+            try{
+                if("json_data".equals(key)){
+                    JSONObject pgd=null;
+                    try{
+                        PGobject pg=(PGobject) map.get(key);
+                        pgd=JSONObject.parseObject(pg.getValue(),JSONObject.class);
+                    }catch (Exception e) {
+                        pgd=JSONObject.parseObject(map.get(key).toString(),JSONObject.class);
+                    }
+                    db.put(key.toLowerCase(), pgd);
+                }else{
+                    db.put(key.toLowerCase(), map.get(key));
+                }
+            }catch (Exception e) {
+                log.error(e.toString());
+                continue;
+            }
+        }
+        return db;
+    }
+}

+ 199 - 0
luckysheet/pom.xml

@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>luckySheetServer</artifactId>
+        <groupId>com.xc</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>luckysheet</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <packaging>jar</packaging>
+    <name>luckysheet</name>
+    <description>luckysheet</description>
+
+    <dependencies>
+        <!-- spring web -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <!-- 剔除hibernate-validator包,做入参数据校验的 -->
+            <exclusions>
+                <exclusion>
+                    <groupId>org.hibernate.validator</groupId>
+                    <artifactId>hibernate-validator</artifactId>
+                </exclusion>
+                <!--和内置tomcat有关-->
+                <!--  <exclusion>
+                      <groupId>javax.annotation</groupId>
+                      <artifactId>javax.annotation-api</artifactId>
+                  </exclusion>-->
+                <!--剔除spring boot的jackson,用fastjson替代-->
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-json</artifactId>
+                </exclusion>
+                <!-- 剔除slf4j日志jar -->
+                <exclusion>
+                    <groupId>org.apache.logging.log4j</groupId>
+                    <artifactId>log4j-to-slf4j</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+
+        <!--引入AOP依赖-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+
+        <!---核心包-->
+        <dependency>
+            <groupId>com.xc</groupId>
+            <artifactId>common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <!-- 数据库接口以及实现 -->
+        <dependency>
+            <groupId>com.xc</groupId>
+            <artifactId>luckysheet-db</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+<!--        <dependency>-->
+<!--            <groupId>com.xc</groupId>-->
+<!--            <artifactId>luckysheet-mysql</artifactId>-->
+<!--            <version>${project.version}</version>-->
+<!--        </dependency>-->
+        <dependency>
+            <groupId>com.xc</groupId>
+            <artifactId>luckysheet-postgre</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <!-- websocket start -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-websocket</artifactId>
+            <version>1.3.5.RELEASE</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-websocket</artifactId>
+            <version>4.3.6.RELEASE</version>
+        </dependency>
+        <!-- websocket end -->
+
+        <!-- jackson相关依赖 -->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.68</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>2.10.3</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-core</artifactId>
+            <version>2.10.3</version>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+            <version>2.10.3</version>
+        </dependency>
+
+        <!--&lt;!&ndash; mongodb driver start &ndash;&gt;-->
+        <!--<dependency>-->
+            <!--<groupId>org.springframework.data</groupId>-->
+            <!--<artifactId>spring-data-mongodb</artifactId>-->
+            <!--<version>1.9.0.RELEASE</version>&lt;!&ndash;$NO-MVN-MAN-VER$&ndash;&gt;-->
+        <!--</dependency>-->
+        <!--<dependency>-->
+            <!--<groupId>org.mongodb</groupId>-->
+            <!--<artifactId>mongo-java-driver</artifactId>-->
+            <!--<version>3.6.0</version>-->
+        <!--</dependency>-->
+        <!--&lt;!&ndash; mongodb driver start &ndash;&gt;-->
+
+        <!-- poi -->
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi</artifactId>
+            <version>4.1.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+            <version>4.1.2</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml-schemas</artifactId>
+            <version>4.1.2</version>
+        </dependency>
+        <!-- poi -->
+
+        <!-- zip -->
+        <dependency>
+            <groupId>org.apache.ant</groupId>
+            <artifactId>ant</artifactId>
+            <version>1.9.7</version>
+        </dependency>
+
+        <!-- 数据库加密 -->
+        <dependency>
+            <groupId>com.github.ulisesbocchio</groupId>
+            <artifactId>jasypt-spring-boot-starter</artifactId>
+            <version>2.1.1</version>
+        </dependency>
+
+
+    </dependencies>
+
+    <profiles>
+        <profile>
+            <id>postgres</id>
+            <properties>
+                <profiles.active>postgres</profiles.active>
+            </properties>
+        </profile>
+        <profile>
+            <id>mysql</id>
+            <properties>
+                <profiles.active>mysql</profiles.active>
+            </properties>
+        </profile>
+    </profiles>
+
+
+    <build>
+        <finalName>web-lockysheet-${profiles.active}</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+        <resources>
+            <resource>
+                <filtering>true</filtering>
+                <directory>src/main/resources</directory>
+                <includes>
+                    <include>application.yml</include>
+                    <include>application-${profiles.active}.yml</include>
+                    <include>*.xml</include>
+                </includes>
+            </resource>
+        </resources>
+    </build>
+
+</project>

+ 63 - 0
luckysheet/read.txt

@@ -0,0 +1,63 @@
+本地测试地址
+http://127.0.0.1:8080/luckysheet/demo/
+
+```
+```
+
+创建数据库
+CREATE DATABASE luckysheetdb
+
+创建序列
+DROP SEQUENCE IF EXISTS "public"."luckysheet_id_seq";
+CREATE SEQUENCE "public"."luckysheet_id_seq"
+INCREMENT 1
+MINVALUE  1
+MAXVALUE 9999999999999
+START 1
+CACHE 10;
+
+创建表
+DROP TABLE IF EXISTS "public"."luckysheet";
+CREATE TABLE "luckysheet" (
+  "id" int8 NOT NULL,
+  "block_id" varchar(200) COLLATE "pg_catalog"."default" NOT NULL,
+  "row_col" varchar(50) ,
+  "index" varchar(200) COLLATE "pg_catalog"."default" NOT NULL,
+  "list_id" varchar(200) COLLATE "pg_catalog"."default" NOT NULL,
+  "status" int2 NOT NULL,
+  "json_data" jsonb,
+  "order" int2,
+  "is_delete" int2
+);
+CREATE INDEX "block_id" ON "public"."luckysheet" USING btree (
+  "block_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
+  "list_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
+);
+CREATE INDEX "index" ON "public"."luckysheet" USING btree (
+  "index" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
+  "list_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
+);
+CREATE INDEX "is_delete" ON "public"."luckysheet" USING btree (
+  "is_delete" "pg_catalog"."int2_ops" ASC NULLS LAST
+);
+CREATE INDEX "list_id" ON "public"."luckysheet" USING btree (
+  "list_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST
+);
+CREATE INDEX "order" ON "public"."luckysheet" USING btree (
+  "list_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
+  "order" "pg_catalog"."int2_ops" ASC NULLS LAST
+);
+CREATE INDEX "status" ON "public"."luckysheet" USING btree (
+  "list_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
+  "status" "pg_catalog"."int2_ops" ASC NULLS LAST
+);
+ALTER TABLE "public"."luckysheet" ADD CONSTRAINT "luckysheet_pkey" PRIMARY KEY ("id");
+
+插入初始化语句
+INSERT INTO "public"."luckysheet" VALUES (nextval('luckysheet_id_seq'), 'fblock', '1', '1079500#-8803#7c45f52b7d01486d88bc53cb17dcd2xc', 1, '{"row":84,"name":"Sheet1","chart":[],"color":"","index":"1","order":0,"column":60,"config":{},"status":0,"celldata":[],"ch_width":4748,"rowsplit":[],"rh_height":1790,"scrollTop":0,"scrollLeft":0,"visibledatarow":[],"visibledatacolumn":[],"jfgird_select_save":[],"jfgrid_selection_range":{}}', 0, 0);
+INSERT INTO "public"."luckysheet" VALUES (nextval('luckysheet_id_seq'), 'fblock', '2', '1079500#-8803#7c45f52b7d01486d88bc53cb17dcd2xc', 0, '{"row":84,"name":"Sheet2","chart":[],"color":"","index":"2","order":1,"column":60,"config":{},"status":0,"celldata":[],"ch_width":4748,"rowsplit":[],"rh_height":1790,"scrollTop":0,"scrollLeft":0,"visibledatarow":[],"visibledatacolumn":[],"jfgird_select_save":[],"jfgrid_selection_range":{}}', 1, 0);
+INSERT INTO "public"."luckysheet" VALUES (nextval('luckysheet_id_seq'), 'fblock', '3', '1079500#-8803#7c45f52b7d01486d88bc53cb17dcd2xc', 0, '{"row":84,"name":"Sheet3","chart":[],"color":"","index":"3","order":2,"column":60,"config":{},"status":0,"celldata":[],"ch_width":4748,"rowsplit":[],"rh_height":1790,"scrollTop":0,"scrollLeft":0,"visibledatarow":[],"visibledatacolumn":[],"jfgird_select_save":[],"jfgrid_selection_range":{}}', 2, 0);
+
+INSERT INTO "public"."luckysheet" VALUES (nextval('luckysheet_id_seq'), 'fblock', '1', '1079500#-8803#7c45f52b7d01486d88bc53cb17dcd2c3', 1, '{"row":84,"name":"Sheet1","chart":[],"color":"","index":"1","order":0,"column":60,"config":{},"status":0,"celldata":[],"ch_width":4748,"rowsplit":[],"rh_height":1790,"scrollTop":0,"scrollLeft":0,"visibledatarow":[],"visibledatacolumn":[],"jfgird_select_save":[],"jfgrid_selection_range":{}}', 0, 0);
+INSERT INTO "public"."luckysheet" VALUES (nextval('luckysheet_id_seq'), 'fblock', '2', '1079500#-8803#7c45f52b7d01486d88bc53cb17dcd2c3', 0, '{"row":84,"name":"Sheet2","chart":[],"color":"","index":"2","order":1,"column":60,"config":{},"status":0,"celldata":[],"ch_width":4748,"rowsplit":[],"rh_height":1790,"scrollTop":0,"scrollLeft":0,"visibledatarow":[],"visibledatacolumn":[],"jfgird_select_save":[],"jfgrid_selection_range":{}}', 1, 0);
+INSERT INTO "public"."luckysheet" VALUES (nextval('luckysheet_id_seq'), 'fblock', '3', '1079500#-8803#7c45f52b7d01486d88bc53cb17dcd2c3', 0, '{"row":84,"name":"Sheet3","chart":[],"color":"","index":"3","order":2,"column":60,"config":{},"status":0,"celldata":[],"ch_width":4748,"rowsplit":[],"rh_height":1790,"scrollTop":0,"scrollLeft":0,"visibledatarow":[],"visibledatacolumn":[],"jfgird_select_save":[],"jfgrid_selection_range":{}}', 2, 0);

+ 50 - 0
luckysheet/src/main/java/com/xc/luckysheet/WebApplication.java

@@ -0,0 +1,50 @@
+package com.xc.luckysheet;
+
+import lombok.extern.slf4j.Slf4j;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+//import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.transaction.PlatformTransactionManager;
+
+/**
+ * @author cr
+ */
+@Slf4j
+@EnableScheduling
+@Configuration
+//@SpringBootApplication(scanBasePackages = "com.xc",exclude={MongoAutoConfiguration.class})
+@SpringBootApplication
+@ComponentScan(basePackages ={"com.xc"} )
+public class WebApplication extends SpringBootServletInitializer {
+
+    public static void main(String[] args) {
+        SpringApplication.run(WebApplication.class, args);
+        log.info("luckysheet server is started");
+    }
+
+    @Override
+    protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
+        return builder.sources(WebApplication.class);
+    }
+
+    /**
+     * mysqlTxManager postgresTxManager
+     * @param platformTransactionManager
+     * @return
+     */
+//    @Bean
+//    public Object testBean(@Qualifier("mysqlTxManager") PlatformTransactionManager platformTransactionManager){
+//        //启动类中添加如下方法,Debug测试,能知道自动注入的是 PlatformTransactionManager 接口的哪个实现类
+//        System.out.println(">>>>>>>>>>" + platformTransactionManager.getClass().getName());
+//        return new Object();
+//    }
+
+}

+ 202 - 0
luckysheet/src/main/java/com/xc/luckysheet/controller/JfGridFileController.java

@@ -0,0 +1,202 @@
+package com.xc.luckysheet.controller;
+
+import com.alibaba.fastjson.JSONObject;
+import com.xc.common.api.ResponseVO;
+import com.xc.common.utils.JsonUtil;
+import com.xc.luckysheet.db.server.JfGridFileGetService;
+import com.xc.luckysheet.db.server.JfGridUpdateService;
+import com.xc.luckysheet.entity.LuckySheetGridModel;
+import com.xc.luckysheet.entity.enummodel.OperationTypeEnum;
+import com.xc.luckysheet.entity.project.ProjectSummaryParamExcelDto;
+import com.xc.luckysheet.utils.Pako_GzipUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ *  图表格页面调用
+ * @author Administrator
+ */
+@Slf4j
+@RestController
+@Api(description = "luckysheet测试接口")
+@RequestMapping(value = {"/api"})
+public class JfGridFileController {
+    /*
+        /load       加载默认表格   ()
+        /loadsheet  加载指定表格   ()
+
+        打开表格
+        /tu/api?id=listid
+    */
+
+
+    @Autowired
+    private JfGridFileGetService jfGridFileGetService;
+
+    @Autowired
+    private JfGridUpdateService jfGridUpdateService;
+
+    /**
+     * 默认加载表格 分块
+     * @param request
+     * @param response
+     * @param gridKey
+     * @return
+     */
+    @ApiOperation(value = "默认加载表格",notes = "默认加载表格")
+    @PostMapping("/load")
+    public String load(HttpServletRequest request, HttpServletResponse response, @RequestParam(defaultValue = "") String gridKey) {
+        //告诉浏览器,当前发送的是gzip格式的内容
+        response.setHeader("Content-Encoding", "gzip");
+        response.setContentType("text/html");
+        String resultStr="";
+        if(gridKey.trim().length()!=0){
+            try {
+                gridKey = gridKey.split("_:_")[0];
+                String _checkStr=check(request,gridKey.toString(),null,OperationTypeEnum.Read);
+                if(_checkStr.length()>0){
+                    return null;
+                }
+                List<JSONObject> dbObject=null;
+                dbObject=jfGridFileGetService.getDefaultByGridKey(gridKey);
+                if(dbObject!=null){
+                    delErrorKey(dbObject);
+                    resultStr=JsonUtil.toJson(dbObject);
+                }
+            } catch (Exception e) {
+                log.error(gridKey+e.getMessage());
+            }
+
+
+        }
+        log.info("load");
+        try {
+            byte dest[]= Pako_GzipUtils.compress2(resultStr);
+            OutputStream out=response.getOutputStream();
+            out.write(dest);
+            out.close();
+            out.flush();
+        } catch (Exception e) {
+            log.error("load---ioerror:"+e);
+        }
+        return null;
+    }
+
+    /**
+     * 加载指定表格
+     * @param map
+     * @param request
+     * @param response
+     * @param gridKey
+     * @param index
+     * @return
+     */
+    @ApiOperation(value = "加载指定表格",notes = "加载指定表格")
+    @PostMapping("/loadsheet")
+    public byte[] loadsheet(Map map, HttpServletRequest request, HttpServletResponse response,
+                            @RequestParam(defaultValue = "") String gridKey,
+                            @RequestParam(defaultValue = "") String[] index) {
+        log.info("loadsheet--gridKey:"+gridKey+" index:"+ Arrays.toString(index));
+        ////告诉浏览器,当前发送的是gzip格式的内容
+        response.setHeader("Content-Encoding", "gzip");
+        response.setContentType("text/html");
+        String resultStr="";
+        if(gridKey.trim().length()!=0){
+            try {
+                gridKey = gridKey.split("_:_")[0];
+                String _id=gridKey;
+                String _checkStr=check(request,_id,null,OperationTypeEnum.Read);
+                log.info(_checkStr);
+                if(_checkStr.length()>0){
+                    return null;
+                }
+                LinkedHashMap dbObject=null;
+                dbObject=jfGridFileGetService.getByGridKeys(_id, Arrays.asList(index));
+                log.info("loadsheet--dbObject--");
+                if(dbObject!=null){
+                    resultStr=JsonUtil.toJson(dbObject);
+                }
+            } catch (Exception e) {
+                log.info(gridKey+e.getMessage());
+            }
+        }
+
+        byte dest[]= Pako_GzipUtils.compress2(resultStr);
+        log.info("loadsheet");
+        OutputStream out=null;
+        try {
+            out = response.getOutputStream();
+            out.write(dest);
+            out.close();
+            out.flush();
+        } catch (IOException e) {
+            // TODO Auto-generated catch block
+            log.error("loadsheet---ioerror:"+e);
+        }catch (Exception ex){
+            log.error("loadsheet---error:"+ex);
+        }
+
+        return null;
+    }
+
+    /**
+     * 默认加载表格 分块
+     * @param dto
+     * @return
+     */
+    @ApiOperation(value = "自动生成excel",notes = "自动生成excel")
+    @PostMapping("/genLuckysheetExcel")
+    public ResponseVO genLuckysheetExcel(@RequestBody ProjectSummaryParamExcelDto dto) {
+        String listId = jfGridUpdateService.genLuckysheetExcel(dto);
+
+        ResponseVO responseVO = ResponseVO.successInstance(listId);
+        responseVO.setCode("200");
+        return responseVO;
+    }
+
+    /**
+     * 文档权限的检查
+     * @param request
+     * @param _id
+     * @param curmodel
+     * @param operationTypeEnum
+     * @return
+     */
+    private String check(HttpServletRequest request, String _id, LuckySheetGridModel curmodel, OperationTypeEnum operationTypeEnum){
+        //校验代码
+        return "";
+    }
+
+
+
+    /**
+     * 数据返回时,去掉数组变字符串,引发错误的key
+     * 删除会发生错误的对象
+     */
+    private void delErrorKey(List<JSONObject> dbObject){
+        if(dbObject!=null){
+            for(JSONObject obj :dbObject){
+                delErrorKeyByCheck(obj,"calcChain");
+                delErrorKeyByCheck(obj,"luckysheet_alternateformat_save");
+                delErrorKeyByCheck(obj,"luckysheet_conditionformat_save");
+            }
+        }
+    }
+    private void delErrorKeyByCheck(JSONObject obj,String key){
+        if(obj.containsKey(key) && obj.get(key) instanceof String){
+            obj.remove(key);
+        }
+    }
+}

+ 207 - 0
luckysheet/src/main/java/com/xc/luckysheet/controller/TestController.java

@@ -0,0 +1,207 @@
+package com.xc.luckysheet.controller;
+
+import com.alibaba.fastjson.JSONObject;
+import com.xc.common.api.ResponseVO;
+import com.xc.common.config.redis.RedisCacheService;
+import com.xc.common.utils.JsonUtil;
+import com.xc.luckysheet.db.server.JfGridFileGetService;
+import com.xc.luckysheet.db.server.JfGridUpdateService;
+import com.xc.luckysheet.entity.GridRecordDataModel;
+import com.xc.luckysheet.utils.TimeUtil;
+import com.xc.luckysheet.xlsutils.poiutil.XlsUtil;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.apache.tools.zip.ZipEntry;
+import org.apache.tools.zip.ZipOutputStream;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.*;
+import java.util.*;
+
+/**
+ * jar启动
+ * java -jar luckysheet.jar
+ * 测试类
+ * http://localhost:9004/luckysheet/doc.html#/home
+ * http://luckysheet.lashuju.com/demo/qkIndex.html
+ * http://127.0.0.1:85/luckysheet/demo/
+ * http://localhost:9004/luckysheet/test/constant?param=123
+ * http://localhost:9004/luckysheet/test/down?listId=xc79500%23-8803%237c45f52b7d01486d88bc53cb17dcd2c3&fileName=list.xls
+ * http://localhost:9004/luckysheet/test/down?listId=1079500%23-8803%237c45f52b7d01486d88bc53cb17dcd2xc&fileName=list.xls
+ * @author Administrator
+ */
+@Slf4j
+@RestController
+@Api(description = "测试接口")
+@RequestMapping("test")
+public class TestController {
+
+    @Autowired
+    private RedisCacheService redisCacheService;
+
+    @Autowired
+    private JfGridUpdateService jfGridUpdateService;
+
+    @Autowired
+    private JfGridFileGetService jfGridFileGetService;
+
+    @Autowired
+    JfGridUpdateService postgresJfGridUpdateService;
+
+    @GetMapping("constant")
+    public String getConstant(String param){
+        Map<String,String> map=new HashMap<>();
+        map.put("threadName",Thread.currentThread().getName());
+        map.put("SUCCESS","true");
+        map.put("param",param);
+
+        log.info(JsonUtil.toJson(map));
+        return JsonUtil.toJson(map);
+    }
+
+    @ApiOperation(value = "redis添加",notes = "保存到redis")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "key", value = "键", paramType = "query", required = true, dataType = "String"),
+            @ApiImplicitParam(name = "value", value = "值", paramType = "query", required = true, dataType = "String")
+    })
+    @GetMapping("redis/addCache")
+    public ResponseVO addCache(String key, String value){
+        redisCacheService.addCache(key,value);
+        return ResponseVO.successInstance("ok");
+    }
+    @ApiOperation(value = "redis查询",notes = "从redis获取")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "key", value = "键", paramType = "query", required = true, dataType = "String")
+    })
+    @GetMapping("redis/getCache")
+    public ResponseVO getCache(String key){
+        return ResponseVO.successInstance(redisCacheService.getCache(key));
+    }
+
+    @ApiOperation(value = "初始化db",notes = "初始化db")
+    @GetMapping("dbInit")
+    public ResponseVO dbInit(){
+        jfGridUpdateService.initTestData();
+        return ResponseVO.successInstance("success");
+    }
+
+    @ApiOperation(value = "初始化db单个",notes = "初始化db单个")
+    @GetMapping("dbInit/one")
+    public ResponseVO dbInit(String listId){
+        List<String> listName=new ArrayList<String>();
+        listName.add(listId);
+        jfGridUpdateService.initTestData(listName);
+        return ResponseVO.successInstance("success");
+    }
+
+    @ApiOperation(value = "获取整个xls结构",notes = "初始化db单个")
+    @GetMapping("get/LuckySheetJson")
+    public ResponseVO getLuckySheetJson(String listId){
+        List<JSONObject> list=jfGridFileGetService.getAllSheetByGridKey(listId);
+        return ResponseVO.successInstance(list);
+    }
+
+    @ApiOperation(value = "下载xls",notes = "下载xls")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "fileName", value = "文档名称", paramType = "query", required = true, dataType = "String"),
+            @ApiImplicitParam(name = "listId", value = "文档id", paramType = "query", required = true, dataType = "String")
+    })
+    @GetMapping("down")
+    public ResponseVO down(HttpServletResponse response,String fileName,String listId){
+        if(fileName==null||listId==null){
+            return ResponseVO.errorInstance("参数错误");
+        }
+        if(!fileName.endsWith(".xls")&&!fileName.endsWith(".xlsx")){
+            return ResponseVO.errorInstance("文件扩展名错误");
+        }
+        boolean isXlsx=false;
+        String zipFileName="";
+        if(fileName.endsWith(".xlsx")){
+            isXlsx=true;
+            zipFileName=fileName.substring(0,fileName.length()-5);
+        }else{
+            zipFileName=fileName.substring(0,fileName.length()-4);
+        }
+        List<JSONObject> lists=jfGridFileGetService.getAllSheetByGridKey(listId);
+        //输出的文件名
+        String _fileName= null;
+        try {
+            _fileName = new String(zipFileName.getBytes("gb2312"), "ISO8859-1");
+        } catch (UnsupportedEncodingException e) {
+            return ResponseVO.errorInstance(e.getMessage());
+        }
+        response.setContentType("application/zip");
+        response.setHeader("Content-Disposition", "attachment;fileName=" +_fileName+".zip" );
+
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        try {
+            XlsUtil.exportXlsFile(baos,isXlsx,lists);
+        } catch (FileNotFoundException e) {
+            return ResponseVO.errorInstance(e.getMessage());
+        } catch (IOException e) {
+            return ResponseVO.errorInstance(e.getMessage());
+        }
+        byte [] data = baos.toByteArray();
+        try{
+            ZipOutputStream out=new ZipOutputStream(response.getOutputStream());
+            ZipEntry zipEntry=new ZipEntry(fileName);
+            zipEntry.setSize(data.length);
+            zipEntry.setTime(System.currentTimeMillis());
+            out.putNextEntry(zipEntry);
+            out.setEncoding("GBK");
+            out.write(data);
+            out.closeEntry();
+            out.finish();
+            log.info("down ok");
+            return null;
+        }catch (Exception ex){
+            return ResponseVO.errorInstance(ex.getMessage());
+        }
+
+
+    }
+
+    /**
+     * @param file EXCEL文件
+     * @description 导入EXCEL
+     * @author zhouhang
+     * @date 2021/4/25
+     */
+    @PostMapping("/import_excel")
+    public ResponseVO importExcel(@RequestParam("file") MultipartFile file, HttpServletResponse response) {
+        try {
+            InputStream inputStream = file.getInputStream();
+            if (Objects.requireNonNull(file.getOriginalFilename()).endsWith(".xls") || file.getOriginalFilename().endsWith(".xlsx")) {
+                Workbook workbook = WorkbookFactory.create(inputStream);
+                //读取EXCEL
+                List<GridRecordDataModel> modelList = XlsUtil.readExcel(workbook);
+                String fileName = file.getOriginalFilename().substring(0, file.getOriginalFilename().lastIndexOf("."));
+                String docCode = TimeUtil.getTodayBeginTime() + "#-" + (int) (Math.random() * 100) + "#-" + UUID.randomUUID().toString().replace("-", "");
+                //插入文档数据
+                postgresJfGridUpdateService.initImportExcel(modelList, docCode);
+                Map<String, String> map = new HashMap<>(2);
+                map.put("docName", fileName);
+                map.put("docCode", docCode);
+                return ResponseVO.successInstance(map);
+            } else {
+                return ResponseVO.errorInstance("无效文件");
+            }
+        } catch (Exception e) {
+            log.error("", e);
+            return ResponseVO.errorInstance(e.getMessage());
+        }
+    }
+
+
+
+
+}

+ 223 - 0
luckysheet/src/main/java/com/xc/luckysheet/db/server/JfGridFileGetService.java

@@ -0,0 +1,223 @@
+package com.xc.luckysheet.db.server;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.xc.luckysheet.JfGridConfigModel;
+import com.xc.luckysheet.db.IRecordDataInsertHandle;
+import com.xc.luckysheet.db.IRecordDataUpdataHandle;
+import com.xc.luckysheet.db.IRecordDelHandle;
+import com.xc.luckysheet.db.IRecordSelectHandle;
+import com.xc.luckysheet.redisserver.GridFileRedisCacheService;
+import com.xc.luckysheet.util.JfGridFileUtil;
+import com.xc.luckysheet.utils.GzipHandle;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author Administrator
+ */
+@Slf4j
+@Service
+public class JfGridFileGetService {
+
+    @Resource(name = "postgresRecordDataInsertHandle")
+    private IRecordDataInsertHandle recordDataInsertHandle;
+
+    @Resource(name = "postgresRecordDataUpdataHandle")
+    private IRecordDataUpdataHandle recordDataUpdataHandle;
+
+    @Resource(name = "postgresRecordDelHandle")
+    private IRecordDelHandle recordDelHandle;
+
+    @Resource(name = "postgresRecordSelectHandle")
+    private IRecordSelectHandle recordSelectHandle;
+
+//    @Resource(name = "mysqlRecordDataInsertHandle")
+//    private IRecordDataInsertHandle recordDataInsertHandle;
+//
+//    @Resource(name = "mysqlRecordDataUpdataHandle")
+//    private IRecordDataUpdataHandle recordDataUpdataHandle;
+//
+//    @Resource(name = "mysqlRecordDelHandle")
+//    private IRecordDelHandle recordDelHandle;
+//
+//    @Resource(name = "mysqlRecordSelectHandle")
+//    private IRecordSelectHandle recordSelectHandle;
+
+    @Autowired
+    private GridFileRedisCacheService redisService;
+
+
+    /**
+     * 1.3.3	获取表格数据 按gridKey获取,默认载入status为1
+     * @param listId
+     * @return
+     */
+    public List<JSONObject> getDefaultByGridKey(String listId){
+        String i=recordSelectHandle.getFirstBlockIndexByGridKey(listId);
+        redisService.raddFlagContent(listId+i, true);
+        List<JSONObject>  dbObject=recordSelectHandle.getByGridKey_NOCelldata(listId);
+        log.info("getDefaultByGridKey--dbObjectList:start");
+        if(dbObject!=null && dbObject.size()>0){
+            log.info("getDefaultByGridKey--start---dbObject");
+            for(int x=0;x<dbObject.size();x++){
+                JSONObject _o =dbObject.get(x);
+                if(_o.containsKey("status") && _o.get("status").toString().equals("1")){
+                    //获取当前显示的数据
+                    //DBObject n=jfGridFileDao.getByGridKey(gridKey,Integer.parseInt(_o.get("index").toString()));
+                    //dbObject.set(x,n);
+                    String index=_o.get("index").toString();
+                    //覆盖当前对象的数据信息
+                    JSONArray _celldata=getCelldataBlockMergeByGridKey(listId,index);
+                    _o.put("celldata",_celldata);
+                }
+
+                if(_o.containsKey("calcChain")){
+                    Object calcChain=JfGridFileUtil.getObjectByIndex(_o, "calcChain");
+
+                    log.info("calcChain--"+calcChain);
+                    _o.put("calcChain", calcChain);
+                }
+
+            }
+        }
+        log.info("dbObject:true");
+        return dbObject;
+    }
+
+    /**
+     * 按list_id获取,返回指定sheet 当前sheet的全部分块数据(并合并)
+     * @param listId
+     * @param index
+     * @return
+     */
+    public JSONArray getCelldataBlockMergeByGridKey(String listId,String index){
+        //每一个分块数据合并后的对象
+        JSONArray _celldata=new JSONArray();
+        //获取全部块
+        List<JSONObject> blocks=getBlocksByGridKey(listId, index);
+        if(blocks!=null && blocks.size()>0){
+            for(JSONObject _b:blocks){
+                if(_b.containsKey("block_id")){
+                    if(JfGridConfigModel.FirstBlockID.equals(_b.get("block_id"))){
+                        //信息块
+                    }else{
+                        //数据块
+                        JSONObject db=JfGridFileUtil.getJSONObjectByIndex(_b, "json_data");
+                        JSONArray _blockCellData=JfGridFileUtil.getSheetByIndex(db);
+                        if(_blockCellData!=null){
+                            _celldata.addAll(_blockCellData);
+                        }
+                    }
+                }
+            }
+        }
+        return _celldata;
+    }
+
+    /**
+     * 按list_id获取,返回指定sheet分块组
+     * @param listId
+     * @param index
+     * @return
+     */
+    public List<JSONObject> getBlocksByGridKey(String listId,String index){
+        return recordSelectHandle.getBlockAllByGridKey(listId, index);
+    }
+
+    /**
+     * 1.3.4	获取sheet数据  参数为gridKey(表格主键) 和 index(sheet主键合集
+     * @param listId
+     * @param indexs
+     * @return
+     */
+    public LinkedHashMap getByGridKeys(String listId, List<String> indexs){
+        LinkedHashMap _resultModel=null;
+        if(indexs==null || indexs.size()==0){
+            return _resultModel;
+        }
+        //获取全部多个sheet的分块
+        List<JSONObject> dbObject=null;
+        if(indexs.size()==1){
+            dbObject=recordSelectHandle.getIndexsByGridKey(listId, indexs.get(0));
+        }else{
+            dbObject= recordSelectHandle.getAllIndexsByGridKey(listId.toString(),indexs);
+        }
+
+        if(dbObject!=null && dbObject.size()>0){
+            if(_resultModel==null){
+                _resultModel=new LinkedHashMap<Integer,Object>();
+            }
+            log.info("getByGridKeys--dbObject-start");
+            for(JSONObject _o:dbObject){
+                if(!_o.containsKey("block_id")){
+                    continue;
+                }
+                if(JfGridConfigModel.FirstBlockID.equals(_o.get("block_id"))){
+                    continue;
+                }
+                //数据块处理
+                if(_o.containsKey("index")){
+                    try{
+                        GzipHandle.toUncompressBySheet(_o);
+                        String _index=_o.get("index").toString();
+                        if(indexs.contains(_index)){
+                            //数据块
+                            JSONObject data=JfGridFileUtil.getJSONObjectByIndex(_o,"json_data");
+                            JSONArray _cellData=JfGridFileUtil.getSheetByIndex(data);
+                            if(_cellData!=null){
+                                if(_resultModel.containsKey(_index)){
+                                     JSONArray _blockCellData=(JSONArray)_resultModel.get(_index);
+                                    _blockCellData.addAll(_cellData);
+                                }else {
+                                    _resultModel.put(_index, _cellData);
+                                }
+                            }
+                        }
+                    }catch (Exception ex){
+                        log.error(ex.toString());
+                    }
+                }
+            }
+        }
+        return _resultModel;
+    }
+
+    /**
+     * 获取全部结构以及数据
+     * @param gridKey
+     * @return
+     */
+    public List<JSONObject> getAllSheetByGridKey(String gridKey) {
+        //返回全部结构
+        List<JSONObject>  dbObject=recordSelectHandle.getByGridKey_NOCelldata(gridKey);
+        if(dbObject!=null&&dbObject.size()>0){
+            //获取全部的index
+            List<String> indexs=dbObject.stream().map(k->k.get("index").toString()).collect(Collectors.toList());
+            //获取数据
+            LinkedHashMap celldatas=getByGridKeys(gridKey,indexs);
+            if(celldatas!=null&&celldatas.size()>0) {
+                for (JSONObject _o : dbObject) {
+                    _o.put("celldata", celldatas.get(_o.get("index")));
+                }
+            }
+            return dbObject;
+        }
+        return null;
+    }
+
+    /**
+     * 获取指定的xls激活的sheet页的 返回index(控制块)
+     * @param gridKey
+     * @return
+     */
+    public String getFirstBlockIndexByGridKey(String gridKey){
+        return recordSelectHandle.getFirstBlockIndexByGridKey(gridKey);
+    }
+}

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 2316 - 0
luckysheet/src/main/java/com/xc/luckysheet/db/server/JfGridUpdateService.java


+ 19 - 0
luckysheet/src/main/java/com/xc/luckysheet/entity/BaseModel.java

@@ -0,0 +1,19 @@
+package com.xc.luckysheet.entity;
+
+
+/**
+ * @author Administrator
+ */
+public interface BaseModel {
+    //错误提示
+    String errorNotBlank="不能为空";
+    String errorNotSet="未设置";
+    String errorNotChose="未选择";
+
+//    public void del(){
+//        errorNotBlank=null;
+//        errorNotSet=null;
+//        errorNotChose=null;
+//    }
+
+}

+ 41 - 0
luckysheet/src/main/java/com/xc/luckysheet/entity/BaseOperationModel.java

@@ -0,0 +1,41 @@
+package com.xc.luckysheet.entity;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: 1
+ * Date: 17-12-12
+ * Time: 下午3:43
+ * To change this template use File | Settings | File Templates.
+ * @author Administrator
+ */
+@Data
+public class BaseOperationModel implements BaseModel,Serializable {
+    /**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+
+    /**
+     * 创建时间
+     */
+	private Date create_time;
+    /**
+     * 修改时间
+     */
+    private Date update_time;
+    /**
+     * 创建人id
+     */
+    private Long create_user_id;
+    /**
+     * 修改人id
+     */
+    private Long update_user_id;
+
+
+}

+ 102 - 0
luckysheet/src/main/java/com/xc/luckysheet/entity/ConfigMergeModel.java

@@ -0,0 +1,102 @@
+package com.xc.luckysheet.entity;
+
+import com.alibaba.fastjson.JSONObject;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * config 中 merge 对象
+ * @author Administrator
+ */
+@Slf4j
+@Data
+public class ConfigMergeModel {
+    /**
+     * 行
+     */
+    private int r;
+    /**
+     * 列
+     */
+    private int c;
+    /**
+     * 行数
+     */
+    private int rs;
+    /**
+     * 列数
+     */
+    private int cs;
+
+    /**
+     * 最大行
+     */
+    private int maxr;
+    /**
+     * 最大列
+     */
+    private int maxc;
+
+    /**
+     * 将config的merge对象转换为对象
+     * @param mc
+     * @return
+     */
+    public static List<ConfigMergeModel>getListByDBObject(JSONObject mc){
+        List<ConfigMergeModel> _list=new ArrayList<ConfigMergeModel>();
+        if(mc!=null){
+            for(String k:mc.keySet()){
+                try{
+                    ConfigMergeModel c=getByDBObject(mc.getJSONObject(k));
+                    if(c!=null){
+                        _list.add(c);
+                    }
+                }catch (Exception ex){
+
+                }
+            }
+        }
+        return _list;
+    }
+    private static ConfigMergeModel getByDBObject(JSONObject mc){
+        if(mc!=null){
+            if(mc.containsKey("r") && mc.containsKey("c") && mc.containsKey("rs") && mc.containsKey("cs")){
+               try{
+                   ConfigMergeModel c=new ConfigMergeModel();
+                   c.r=Integer.parseInt(mc.get("r").toString());
+                   c.c=Integer.parseInt(mc.get("c").toString());
+                   c.rs=Integer.parseInt(mc.get("rs").toString());
+                   c.cs=Integer.parseInt(mc.get("cs").toString());
+
+                   //   { "2_1" : { "rs" : 5 , "cs" : 2 , "r" : 2 , "c" : 1}}
+                   //   1~2   c=1  cs=2
+                   //   2~6   r=2  rs=5
+                   c.maxc=c.c+c.cs-1;
+                   c.maxr=c.r+c.rs-1;
+
+                   return c;
+               }catch (Exception ex){
+                   return null;
+               }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 是否在范围内
+     * @param r
+     * @param c
+     * @return
+     */
+    public boolean isRange(int r,int c){
+        if(r>=this.r && r<=this.maxr && c>=this.c && c<=this.maxc){
+            return true;
+        }
+        return false;
+    }
+
+}

+ 28 - 0
luckysheet/src/main/java/com/xc/luckysheet/entity/LuckySheetGridModel.java

@@ -0,0 +1,28 @@
+package com.xc.luckysheet.entity;
+
+
+import lombok.Data;
+
+
+/**
+ * Created with IntelliJ IDEA.
+ * User: 1
+ * Date: 17-12-15
+ * Time: 上午11:34
+ * To change this template use File | Settings | File Templates.
+ * @author cr
+ */
+@Data
+public class LuckySheetGridModel implements BaseModel{
+    private String list_id;
+
+    /**
+     * 表格名称
+     */
+    private String grid_name;
+    /**
+     *  '缩略图'
+     */
+    private byte[] grid_thumb;
+
+}

+ 9 - 0
luckysheet/src/main/java/com/xc/luckysheet/entity/Test.java

@@ -0,0 +1,9 @@
+package com.xc.luckysheet.entity;
+
+import lombok.Data;
+
+@Data
+public class Test {
+    private Integer id;
+    private String name;
+}

+ 42 - 0
luckysheet/src/main/java/com/xc/luckysheet/entity/enummodel/DisabledTypeEnum.java

@@ -0,0 +1,42 @@
+package com.xc.luckysheet.entity.enummodel;
+
+/**
+ * @author zhouhang
+ * @description 禁用状态
+ * @date 2021/2/1
+ */
+public enum DisabledTypeEnum {
+
+    /**
+     * 启用
+     */
+    ENABLE(0, "启用"),
+    /**
+     * 禁用
+     */
+    DISABLE(1, "禁用"),
+    ;
+
+    DisabledTypeEnum(Integer index, String name) {
+        this.index = index;
+        this.name = name;
+    }
+
+    /**
+     * index
+     */
+    private final Integer index;
+
+    /**
+     * 名称
+     */
+    private final String name;
+
+    public Integer getIndex() {
+        return index;
+    }
+
+    public String getName() {
+        return name;
+    }
+}

+ 73 - 0
luckysheet/src/main/java/com/xc/luckysheet/entity/enummodel/ExcelCenterStyleEnum.java

@@ -0,0 +1,73 @@
+package com.xc.luckysheet.entity.enummodel;
+
+/**
+ * @author zhouhang
+ * @description EXCEL居中方式
+ * @date 2021/4/26
+ */
+public enum ExcelCenterStyleEnum {
+    /**
+     * 左对齐
+     */
+    LEFT((short) 1, 1, "左对齐"),
+    /**
+     * 右对齐
+     */
+    RIGHT((short) 3, 2, "右对齐"),
+    /**
+     * 居中
+     */
+    CENTER((short) 2, 0, "居中"),
+    ;
+
+    /**
+     * excel居中code
+     */
+    private final short excelCode;
+
+    /**
+     * 在线文档居中code
+     */
+    private final Integer onlineExcelCode;
+
+    /**
+     * 名称
+     */
+    private final String name;
+
+
+    public Integer getOnlineExcelCode() {
+        return onlineExcelCode;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public short getExcelCode() {
+        return excelCode;
+    }
+
+    ExcelCenterStyleEnum(short excelCode, Integer onlineExcelCode, String name) {
+        this.excelCode = excelCode;
+        this.onlineExcelCode = onlineExcelCode;
+        this.name = name;
+    }
+
+    /**
+     * @param code excel居中样式code
+     * @return Enum_ExcelCenterStyle
+     * @description 根据excel居中样式获取在线文档居中样式
+     * @author zhouhang
+     * @date 2021/4/26
+     */
+    public static ExcelCenterStyleEnum getExcelCenterStyleByExcelCenterCode(short code) {
+        for (ExcelCenterStyleEnum value : ExcelCenterStyleEnum.values()) {
+            if (code == value.getExcelCode()) {
+                return value;
+            }
+        }
+        return CENTER;
+    }
+
+}

+ 17 - 0
luckysheet/src/main/java/com/xc/luckysheet/entity/enummodel/OperationTypeEnum.java

@@ -0,0 +1,17 @@
+package com.xc.luckysheet.entity.enummodel;
+
+
+/**
+ * @author Administrator
+ */
+
+public enum OperationTypeEnum {
+    /**
+     * 读取
+     */
+    Read,
+    /**
+     * 修改
+     */
+    Update;
+}

+ 44 - 0
luckysheet/src/main/java/com/xc/luckysheet/entity/enummodel/SheetOperationEnum.java

@@ -0,0 +1,44 @@
+package com.xc.luckysheet.entity.enummodel;
+
+/**
+ * 各类操作
+ */
+public enum SheetOperationEnum {
+    fc, //3.4.1 函数链接
+    f,//3.6.1 选择筛选条件
+    fsc,//3.6.2	清除筛
+    fsr,//3.6.3	恢复筛选
+
+    thumb, //3.10.2	缩略图    修改数据库
+    na,   //3.10.1	表格名称 修改数据库
+
+    c,     //3.9	图表操作 全部转向rails
+
+    sh,    //3.8.1	隐藏    3.8	sheet属性sh
+    shs,   //3.7.5	激活shs
+    shr,   //3.7.4	位置shr
+    shd,   //3.7.3	删除shd
+    shc,   //3.7.2	复制shc
+    sha,   //3.7.1	新建sha  3.7 sheet操作
+
+    arc,   //3.5.2	增加行或列
+    drc,   //3.5.1 删除行或列
+    all, //3.3 通用保存
+    cg, //3.2   config操作cg
+    v,  //3.1	单元格操作v
+    rv,//批量单元格操作
+    shre,//撤销删除
+	mv;//记录光标位置不保存
+
+
+    public static boolean contains(String _name){
+        SheetOperationEnum[] season = values();
+        for(SheetOperationEnum s:season){
+            if(s.name().equals(_name)){
+                return true;
+            }
+        }
+        return false;
+
+    }
+}

+ 46 - 0
luckysheet/src/main/java/com/xc/luckysheet/entity/project/AssembleCellParam.java

@@ -0,0 +1,46 @@
+package com.xc.luckysheet.entity.project;
+
+import lombok.*;
+
+@Setter
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class AssembleCellParam {
+
+    /**
+     * 起始单元格列
+     */
+    private Integer startColPos;
+
+    /**
+     * 起始单元格行
+     */
+    private Integer startRowPos;
+
+    /**
+     * 列数
+     */
+    private Integer colSize;
+
+    /**
+     * 行数
+     */
+    private Integer rowSize;
+
+    /**
+     * 单元格值
+     */
+    private String value;
+
+    /**
+     * 字体大小
+     */
+    private Integer fontsize;
+
+    /**
+     * 垂直对齐:0 中间、1 上、2下
+     */
+    private Integer verticaltype;
+}

+ 41 - 0
luckysheet/src/main/java/com/xc/luckysheet/entity/project/ProjectSummaryParamExcelDto.java

@@ -0,0 +1,41 @@
+package com.xc.luckysheet.entity.project;
+
+import com.alibaba.fastjson.JSONObject;
+import lombok.*;
+
+import java.util.List;
+
+@Setter
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class ProjectSummaryParamExcelDto {
+
+    private String projectId;
+
+    /**
+     * 文件名,不带后缀名
+     */
+    private String fileName;
+
+    /**
+     * 完整文件路径
+     */
+    private String fullPathFile;
+
+    /**
+     * 机号列表
+     */
+    private List<String> deviceNumberList;
+
+    /**
+     * 构件名称
+     */
+    private List<String> structureList;
+
+    /**
+     * 车间列表
+     */
+    private List<JSONObject> workshopList;
+}

+ 38 - 0
luckysheet/src/main/java/com/xc/luckysheet/entity/project/SheetConfigResultDto.java

@@ -0,0 +1,38 @@
+package com.xc.luckysheet.entity.project;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import lombok.*;
+
+@Setter
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class SheetConfigResultDto {
+
+    /**
+     * 合并配置
+     */
+    private JSONObject mergeConfig;
+
+    /**
+     * 边框配置
+     */
+    private JSONArray borderInfoConfig;
+
+    /**
+     * 行高配置
+     */
+    private JSONObject rowlenConfig;
+
+    /**
+     * 下拉框
+     */
+    private JSONObject dataVerification;
+
+    /**
+     * 单元格数据
+     */
+    private JSONArray celldata;
+}

+ 23 - 0
luckysheet/src/main/java/com/xc/luckysheet/entity/project/SheetInfoParam.java

@@ -0,0 +1,23 @@
+package com.xc.luckysheet.entity.project;
+
+import lombok.*;
+
+@Setter
+@Getter
+@NoArgsConstructor
+@AllArgsConstructor
+@Builder
+public class SheetInfoParam {
+
+    /**
+     * sheet页名称
+     */
+    private String sheetName;
+
+    private String index;
+
+    /**
+     * 下标
+     */
+    private Integer order;
+}

+ 33 - 0
luckysheet/src/main/java/com/xc/luckysheet/mapper/TestDao.java

@@ -0,0 +1,33 @@
+package com.xc.luckysheet.mapper;
+
+import com.xc.luckysheet.entity.Test;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Administrator
+ */
+public interface TestDao {
+
+    @Select({
+            "<script>",
+            "SELECT ",
+            "id,name  ",
+            "FROM ",
+            "test ",
+            "WHERE ",
+            "1=1 ",
+
+            "<if test='param.id!=null'>",
+            "AND  id=#{param.id} ",
+            "</if>",
+
+            "ORDER BY ",
+            "id",
+            "</script>"
+    })
+    List<Test> select(@Param("param") Map<String, Object> param);
+}

+ 119 - 0
luckysheet/src/main/java/com/xc/luckysheet/redisserver/GridFileRedisCacheService.java

@@ -0,0 +1,119 @@
+package com.xc.luckysheet.redisserver;
+
+import com.alibaba.fastjson.JSONObject;
+import com.xc.common.config.redis.RedisCacheService;
+import com.xc.common.config.redis.RedisQueueService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+
+/**
+ * @author Administrator
+ */
+@Slf4j
+@Service
+public class GridFileRedisCacheService {
+    @Autowired
+    private RedisCacheService redisCache;
+    @Autowired
+    private RedisQueueService redisQueueService;
+
+
+    /**
+     * 批量更新数据
+     */
+    private String dbdata_content="lk:dbdata:";
+
+    /**
+     * 收集指令信息
+     */
+    private String hand_flag_content="lk:upflag:";
+
+    /**
+     * 收集指令信息内容
+     */
+    private String qk_handle_content="lk:handler:";
+
+
+    public List<JSONObject> rgetDbDataContent(String key){
+        try{
+            String redisKey=dbdata_content+key;
+            List<JSONObject> lists=redisCache.getListBySize(redisKey, -1);
+            if(lists!=null && lists.size()>0){
+                //从redis中删除
+                redisCache.delList(redisKey, lists.size());
+                return lists;
+            }
+        }catch(Exception ex){
+            return null;
+        }
+        return null;
+    }
+
+
+    /**
+     *
+     * @param key
+     * @param db
+     */
+    public void raddDbContent(String key,JSONObject db){
+        String redisKey=dbdata_content+key;
+        redisCache.addList(redisKey, db);
+    }
+
+
+    /**
+     * 存入启用存储指令信息
+     * @param key
+     * @param val
+     */
+    public void raddFlagContent(String key, Object val) {
+        String redisKey = hand_flag_content + key;
+        log.info("raddFlagContent---redisKey="+redisKey+"val="+val);
+        redisCache.addCache(redisKey, val, 240);
+    }
+
+    /**
+     * 根据key 获得email验证码信息
+     * @param key
+     */
+    public Boolean rgetFlagContent(String key) {
+        Boolean flag=false;
+        try{
+            String redisKey = hand_flag_content + key;
+            log.info("rgetFlagContent---redisKey="+redisKey);
+            flag=(Boolean) redisCache.getCache(redisKey);
+        }catch (Exception e) {
+            // TODO: handle exception
+        }
+        return flag;
+    }
+
+
+    /**
+     * 获取数据
+     * @param key
+     * @return
+     */
+    public List<String> rgetHandlerContent(String key){
+        try{
+            String redisKey=qk_handle_content+key;
+            //多节点使用
+            List<String> lists=redisQueueService.popList(redisKey,String.class,500);
+            return lists;
+            //单节点使用
+//            List<String> lists=redisCache.getListBySize(redisKey, -1);
+//            if(lists!=null && lists.size()>0){
+//                //从redis中删除
+//                redisCache.delList(redisKey, lists.size());
+//                return lists;
+//            }
+        }catch(Exception ex){
+            return null;
+        }
+    }
+
+}

+ 179 - 0
luckysheet/src/main/java/com/xc/luckysheet/redisserver/RedisLock.java

@@ -0,0 +1,179 @@
+package com.xc.luckysheet.redisserver;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+
+
+/**
+ * @author Administrator
+ */
+public class RedisLock {
+
+	@Autowired
+    private RedisTemplate redisTemplate;
+    /**
+     * 重试时间
+     */
+    private static final int DEFAULT_ACQUIRY_RETRY_MILLIS = 100;
+    /**
+     * 锁的前缀
+     */
+    private static final String LOCK_SUFFIX = "redis_lock:";
+    /**
+     * 锁的key
+     */
+    private String lockKey;
+    /**
+     * 锁超时时间,防止线程在入锁以后,防止阻塞后面的线程无法获取锁
+     */
+    private int expireMsecs = 60 * 1000;
+    /**
+     * 线程获取锁的等待时间
+     */
+    private int timeoutMsecs = 10 * 1000;
+    /**
+     * 是否锁定标志
+     */
+    private volatile boolean locked = false;
+
+    /**
+     * 当前线程
+     */
+    private String uid="";
+
+    /**
+     * 构造器
+     * @param redisTemplate
+     * @param lockKey 锁的key
+     */
+    public RedisLock(RedisTemplate redisTemplate, String lockKey) {
+        this.redisTemplate = redisTemplate;
+        this.lockKey = LOCK_SUFFIX+lockKey;
+    }
+
+    /**
+     * 构造器
+     * @param redisTemplate
+     * @param lockKey 锁的key
+     * @param timeoutMsecs 获取锁的超时时间
+     */
+    public RedisLock(RedisTemplate redisTemplate, String lockKey, int timeoutMsecs) {
+        this(redisTemplate, lockKey);
+        this.timeoutMsecs = timeoutMsecs;
+    }
+    public RedisLock(RedisTemplate redisTemplate, String lockKey, int timeoutMsecs, String uid) {
+        this(redisTemplate, lockKey);
+        this.timeoutMsecs = timeoutMsecs;
+        this.uid=uid;
+    }
+
+    /**
+     * 构造器
+     * @param redisTemplate
+     * @param lockKey 锁的key
+     * @param timeoutMsecs 获取锁的超时时间
+     * @param expireMsecs 锁的有效期
+     */
+    public RedisLock(RedisTemplate redisTemplate, String lockKey, int timeoutMsecs, int expireMsecs) {
+        this(redisTemplate, lockKey, timeoutMsecs);
+        this.expireMsecs = expireMsecs;
+    }
+
+    public String getLockKey() {
+        return lockKey;
+    }
+
+    /**
+     * 封装和jedis方法
+     * @param key
+     * @return
+     */
+    private String get(final String key) {
+        Object obj = redisTemplate.opsForValue().get(key);
+        return obj != null ? obj.toString() : null;
+    }
+
+    /**
+     * 封装和jedis方法
+     * @param key
+     * @param value
+     * @return
+     */
+    private boolean setNX(final String key, final String value) {
+        return redisTemplate.opsForValue().setIfAbsent(key,value);
+    }
+
+    /**
+     * 封装和jedis方法
+     * @param key
+     * @param value
+     * @return
+     */
+    private String getSet(final String key, final String value) {
+        Object obj = redisTemplate.opsForValue().getAndSet(key,value);
+        return obj != null ? (String) obj : null;
+    }
+
+    /**
+     * 获取锁
+     * @return 获取锁成功返回ture,超时返回false
+     * @throws InterruptedException
+     */
+    public synchronized boolean lock() throws InterruptedException {
+        //线程获取锁的等待时间
+        int timeout = timeoutMsecs;
+        while (timeout >= 0) {
+            //超时时间
+            long expires = System.currentTimeMillis() + expireMsecs + 1;
+            //锁到期时间
+            String expiresStr = String.valueOf(expires);
+            if (this.setNX(lockKey, expiresStr)) {
+                locked = true;
+                return true;
+            }
+            //redis里key的时间
+            String currentValue = this.get(lockKey);
+            //判断锁是否已经过期,过期则重新设置并获取
+            if (currentValue != null && Long.parseLong(currentValue) < System.currentTimeMillis()) {
+                //设置锁并返回旧值
+                String oldValue = this.getSet(lockKey, expiresStr);
+                //比较锁的时间,如果不一致则可能是其他锁已经修改了值并获取
+                if (oldValue != null && oldValue.equals(currentValue)) {
+                    locked = true;
+                    return true;
+                }
+            }
+            timeout -= DEFAULT_ACQUIRY_RETRY_MILLIS;
+            //延时
+            Thread.sleep(DEFAULT_ACQUIRY_RETRY_MILLIS);
+        }
+        return false;
+    }
+    /**
+     * 释放获取到的锁
+     */
+    public  synchronized void unlock() {
+        if (locked) {
+            redisTemplate.delete(lockKey);
+            locked = false;
+        }
+    }
+
+}
+
+/*
+
+
+    //使用方法,创建RedisLock对象
+    RedisLock lock = new RedisLock(redisTemplate, "lock_" + product.getId());
+    try {
+        if (lock.lock()) {}
+    } finally {
+        lock.unlock();
+    }
+
+
+
+*/
+
+

+ 47 - 0
luckysheet/src/main/java/com/xc/luckysheet/redisserver/RedisMessageListener.java

@@ -0,0 +1,47 @@
+package com.xc.luckysheet.redisserver;
+
+import com.google.gson.Gson;
+import com.xc.luckysheet.utils.MyStringUtil;
+import com.xc.luckysheet.websocket.MyWebSocketHandler;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.connection.Message;
+import org.springframework.data.redis.connection.MessageListener;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.RedisSerializer;
+
+/**
+ * 监听
+ * @author Administrator
+ */
+public class RedisMessageListener implements MessageListener {
+
+    @Autowired
+    private RedisTemplate<String, String> redisTemplate;
+
+    /**
+     * 订阅者收到消息
+     * @param message
+     * @param pattern
+     */
+    @Override
+    public void onMessage(Message message, byte[] pattern) {
+        //JSON.parse(serializerValue.deserialize(message.getBody()).toString())
+        RedisSerializer<?> serializerKey = redisTemplate.getKeySerializer();
+        RedisSerializer<?> serializerValue = redisTemplate.getValueSerializer();
+        Object channel = serializerKey.deserialize(message.getChannel());
+        Object body = serializerValue.deserialize(message.getBody());
+        //System.out.println("主题: " + channel);
+        //System.out.println("消息内容: " + String.valueOf(body));
+        RedisMessageModel bson1=new Gson().fromJson(body.toString(),RedisMessageModel.class);
+        System.out.println("得到Redis推送消息:"+MyStringUtil.getStringShow(bson1.toString()));
+        MyWebSocketHandler.sendMessageToUserByRedis(bson1);
+    }
+
+    public RedisTemplate<String, String> getRedisTemplate() {
+        return redisTemplate;
+    }
+
+    public void setRedisTemplate(RedisTemplate<String, String> redisTemplate) {
+        this.redisTemplate = redisTemplate;
+    }
+}

+ 61 - 0
luckysheet/src/main/java/com/xc/luckysheet/redisserver/RedisMessageModel.java

@@ -0,0 +1,61 @@
+package com.xc.luckysheet.redisserver;
+
+import com.alibaba.fastjson.JSONObject;
+import lombok.Data;
+
+/**
+ * redis消息
+ * @author Administrator
+ */
+@Data
+public class RedisMessageModel {
+
+    /**
+     * 节点端口与ip (或者其他唯一标示)
+     */
+    private String ipandport;
+    /**
+     * 文档id
+     */
+    private String gridkey;
+    /**
+     * 内容
+     */
+    private String content;
+
+    public RedisMessageModel(String _ipandport,String _gridkey,String _content){
+        this.ipandport=_ipandport;
+        this.gridkey=_gridkey;
+        this.content=_content;
+    }
+    public RedisMessageModel(JSONObject jsonObject){
+        if(jsonObject!=null) {
+            if (jsonObject.containsKey("ipandport")) {
+                this.ipandport = jsonObject.getString("ipandport");
+            }
+            if (jsonObject.containsKey("gridkey")) {
+                this.gridkey = jsonObject.getString("gridkey");
+            }
+            if (jsonObject.containsKey("content")) {
+                this.content = jsonObject.getString("content");
+            }
+        }
+    }
+
+    public JSONObject toDBObject(){
+        JSONObject jsonObject=new JSONObject();
+        jsonObject.put("ipandport",ipandport);
+        jsonObject.put("gridkey",gridkey);
+        jsonObject.put("content",content);
+        return jsonObject;
+    }
+
+    @Override
+    public String toString() {
+        return "RedisMessageModel{" +
+                "ipandport='" + ipandport + '\'' +
+                ", gridkey='" + gridkey + '\'' +
+                ", content='" + content + '\'' +
+                '}';
+    }
+}

+ 42 - 0
luckysheet/src/main/java/com/xc/luckysheet/redisserver/RedisMessagePublish.java

@@ -0,0 +1,42 @@
+package com.xc.luckysheet.redisserver;
+
+import com.google.gson.Gson;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+
+/**
+ * 发布
+ * @author Administrator
+ */
+@Slf4j
+@Data
+@Service
+public class RedisMessagePublish {
+    /**
+     * 管道
+     */
+    public static String channel;
+
+    @Autowired
+    private RedisTemplate redisTemplate;
+
+    /**
+     * 发布者
+     * @param redisMessageModel  消息内容
+     * @return
+     */
+    public boolean publishMessage(RedisMessageModel redisMessageModel){
+        try{
+            redisTemplate.convertAndSend(channel,new Gson().toJson(redisMessageModel));
+            return true;
+        }catch (Exception ex){
+            log.error("publishMessage Error:{}",ex);
+            return false;
+        }
+    }
+
+}

+ 38 - 0
luckysheet/src/main/java/com/xc/luckysheet/service/ConfigerService.java

@@ -0,0 +1,38 @@
+package com.xc.luckysheet.service;
+
+
+import com.xc.luckysheet.JfGridConfigModel;
+import com.xc.luckysheet.redisserver.RedisMessagePublish;
+import com.xc.luckysheet.websocket.WebSocketConfig;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.stereotype.Service;
+import org.springframework.beans.factory.annotation.Value;
+
+
+/**
+ * @author Administrator
+ */
+@Slf4j
+@Configuration
+@Service
+public class ConfigerService {
+
+    @Value("${redis.channel}")
+    public void setRedisChannel(String path){
+        RedisMessagePublish.channel=path;
+    }
+    @Value("${row_size}")
+    public void setRowSize(Integer rowSize){
+        JfGridConfigModel.row_size=rowSize;
+    }
+    @Value("${col_size}")
+    public void setColSize(Integer colSize){
+        JfGridConfigModel.col_size=colSize;
+    }
+    @Value("${servertype}")
+    public void setServerType(String servertype){
+        WebSocketConfig.servertype=servertype;
+    }
+
+}

+ 38 - 0
luckysheet/src/main/java/com/xc/luckysheet/service/ScheduleService.java

@@ -0,0 +1,38 @@
+package com.xc.luckysheet.service;
+
+import com.xc.luckysheet.db.server.JfGridUpdateService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * 定时任务
+ * @author cr
+ */
+@Slf4j
+@Service
+public class ScheduleService {
+
+    @Autowired
+    private JfGridUpdateService jfGridUpdateService;
+
+    private static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+    @Scheduled(cron = "0 */5 * * * *")
+    public void test(){
+        System.out.println(format.format(new Date()));
+    }
+
+
+
+    @Scheduled(cron = "0 0 1 * * *")
+    public void pgInit(){
+//        jfGridUpdateService.initTestData();
+        System.out.println(format.format(new Date())+" luckysheet table init!!!");
+    }
+
+}

+ 87 - 0
luckysheet/src/main/java/com/xc/luckysheet/utils/GzipHandle.java

@@ -0,0 +1,87 @@
+package com.xc.luckysheet.utils;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.List;
+
+/**
+ * 压缩处理类
+ * @author Administrator
+ */
+@Slf4j
+public class GzipHandle {
+    /**
+     * 是否对celldata的数据压缩(分块存储,不再使用压缩)
+     */
+    public static boolean runGzip=false;
+
+    /**
+     * 加密 单个sheet,celldata处理
+     * @param sheet
+     */
+    public static void toCompressBySheet(JSONObject sheet){
+        if(runGzip){
+            if(sheet!=null && sheet.containsKey("celldata")){
+                List<JSONObject> _celldata=(List<JSONObject>)sheet.get("celldata");
+                //String _gzipStr= Pako_GzipUtils.compress(_celldata.toString());
+                sheet.put("celldata",toCompressByCelldata(_celldata));
+            }
+        }
+    }
+
+    /**
+     * 压缩  celldata
+     * @param _celldata
+     * @return
+     */
+    public static String toCompressByCelldata(List<JSONObject> _celldata){
+        if(_celldata!=null){
+            String _gzipStr= Pako_GzipUtils.compress(_celldata.toString());
+            return _gzipStr;
+        }else{
+            return "";
+        }
+    }
+
+    /**
+     * 压缩  celldata
+     * @param _celldata
+     * @return
+     */
+    public static String toCompressByCelldata(JSONArray _celldata){
+        if(_celldata!=null){
+            String _gzipStr= Pako_GzipUtils.compress(_celldata.toString());
+            return _gzipStr;
+        }else{
+            return "";
+        }
+    }
+
+    /**
+     * 将celldata中数据解压
+     * @param sheet
+     */
+    public static void toUncompressBySheet(JSONObject sheet){
+        if(sheet!=null && sheet.containsKey("celldata")){
+            if(sheet.get("celldata") instanceof String){
+                String celldataStr=sheet.get("celldata").toString();
+                sheet.put("celldata",toUncompressBySheet(celldataStr));
+            }
+        }
+    }
+    public static JSONArray toUncompressBySheet(String celldataStr){
+        JSONArray list=new JSONArray();
+        if(celldataStr!=null){
+            String _gzipStr= Pako_GzipUtils.uncompress(celldataStr);
+            try{
+                list=JSONArray.parseArray(_gzipStr);
+            }catch (Exception ex){
+                log.error(ex.getMessage());
+            }
+        }
+        return list;
+    }
+
+}

+ 674 - 0
luckysheet/src/main/java/com/xc/luckysheet/utils/LuckySheet4SummaryHelp.java

@@ -0,0 +1,674 @@
+package com.xc.luckysheet.utils;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.xc.luckysheet.entity.project.AssembleCellParam;
+import com.xc.luckysheet.entity.project.ProjectSummaryParamExcelDto;
+import com.xc.luckysheet.entity.project.SheetInfoParam;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class LuckySheet4SummaryHelp {
+
+    /**
+     * 机号下班组
+     */
+    public static final String[] MACHINE_TITLE_COLS = {"状态", "施工部门", "施工分包商/班组", "责任部门", "责任分包商/班组", "完成日期"};
+
+    public static final String[] MAIN_TITLE_FIRST = { "总序号","监理编号","部位","内容" };
+
+    /**
+     * 主标题下第二部门
+     */
+    public static final String[] MAIN_TITLE_SECOND = {"总状态","提出日期","整改期限","提出者","备注1","备注2"};
+
+    /**
+     * {
+     * 		"c": 0,
+     * 		"r": 0,
+     * 		"v": {
+     * 			"m": "1002000938马士基埃及桥吊项目整改文字版",
+     * 			"v": "1002000938马士基埃及桥吊项目整改文字版",
+     * 			"bg": "rgb(51, 102, 255)",
+     * 			"bl": 1,
+     * 			"ct": {
+     * 				"t": "g",
+     * 				"fa": "General"
+     *                        },
+     * 			"fc": "rgb(0, 0, 0)",
+     * 			"ff": 5,
+     * 			"fs": 16,
+     * 			"ht": 0,
+     * 			"it": 0,
+     * 			"mc": {
+     * 				"c": 0,
+     * 				"r": 0,
+     * 				"cs": 58,
+     * 				"rs": 1
+     *            },
+     * 			"vt": 0* 		}
+     *    }
+     *
+     * @param fileName
+     * @param colSize
+     * @return
+     */
+    public static JSONArray assembleFirstTitle(String fileName, int colSize) {
+
+        AssembleCellParam cellParam = AssembleCellParam.builder()
+                .fontsize(16)
+                .startRowPos(0)
+                .startColPos(0)
+                .rowSize(1)
+                .colSize(colSize)
+                .value(fileName)
+                .build();
+        return assembleMergeTitle(cellParam);
+    }
+
+    /**
+     * {
+     * 		"c": 0,
+     * 		"r": 1,
+     * 		"v": {
+     * 			"m": "总序号",
+     * 			"v": "总序号",
+     * 			"bg": "rgb(204, 255, 204)",
+     * 			"bl": 0,
+     * 			"ct": {
+     * 				"t": "g",
+     * 				"fa": "General"
+     *           },
+     * 			"fc": "rgb(0, 0, 0)",
+     * 			"ff": 5,
+     * 			"fs": 11,
+     * 			"ht": 0,
+     * 			"it": 0,
+     * 			"mc": {
+     * 				"c": 0,
+     * 				"r": 1,
+     * 				"cs": 1,
+     * 				"rs": 2
+     *           },
+     * 			"vt": 0
+     * 		}
+     * }
+     *
+     * @return
+     */
+    public static JSONArray assembleCommonCol1() {
+
+        JSONArray result = new JSONArray();
+
+        for(int m = 0, n = MAIN_TITLE_FIRST.length; m < n; m++) {
+            //一级标题
+            JSONObject remark2 = new JSONObject();
+            remark2.put("c", m);
+            remark2.put("r", 1);
+            JSONObject remark2v = new JSONObject();
+            remark2v.put("m", MAIN_TITLE_FIRST[m]);
+            remark2v.put("v", MAIN_TITLE_FIRST[m]);
+            remark2v.put("bg", "rgb(204, 255, 204)");
+            remark2v.put("bl", 1);
+            remark2v.put("fc", "rgb(0, 0, 0)");
+            remark2v.put("ff", 5);
+            remark2v.put("fs", 11);
+            remark2v.put("ht", 0);
+            remark2v.put("it", 0);
+            remark2v.put("vt", 1);
+
+            JSONObject ct = new JSONObject();
+            ct.put("t", "g");
+            ct.put("fa", "General");
+            remark2v.put("ct", ct);
+
+            JSONObject mc = new JSONObject();
+            mc.put("c", m);
+            mc.put("r", 1);
+            mc.put("cs", 1);
+            mc.put("rs", 2);
+            remark2v.put("mc", mc);
+
+            remark2.put("v", remark2v);
+            result.add(remark2);
+        }
+
+        return result;
+    }
+
+    /**
+     * 第三行开头
+     *
+     * @return
+     */
+    public static JSONArray assembleCommonRow2Col1() {
+
+        JSONArray result = new JSONArray();
+
+        for(int m = 0; m < MAIN_TITLE_FIRST.length; m++) {
+            JSONObject temp = new JSONObject();
+
+            JSONObject mc2 = new JSONObject();
+            mc2.put("c", m);
+            mc2.put("r", 1);
+
+            JSONObject v = new JSONObject();
+            v.put("mc",  mc2);
+
+            temp.put("c", m);
+            temp.put("r", 2);
+            temp.put("v", v);
+            result.add(temp);
+        }
+
+        return result;
+    }
+
+    /**
+     * 状态	提出日期	整改期限	提出者	备注1	备注2
+     * {
+     * 		"c": 57,
+     * 		"r": 2,
+     * 		"v": {
+     * 			"m": "备注2",
+     * 			"v": "备注2",
+     * 			"bl": 1,
+     * 			"ct": {
+     * 				"t": "g",
+     * 				"fa": "General"
+     *                        },
+     * 			"fc": "rgb(0, 0, 0)",
+     * 			"ff": 5,
+     * 			"fs": 11,
+     * 			"ht": 0,
+     * 			"it": 0,
+     * 			"vt": 1
+     * 	    }
+     * }
+     *
+     * @param startColPosition 起始位置
+     * @return
+     */
+    public static JSONArray assembleCommonCol2(int startColPosition) {
+        return assembleSingleTitle(startColPosition, 2, MAIN_TITLE_SECOND);
+    }
+
+    /**
+     * 第二行最后六个
+     * {
+     * 		"c": 56,
+     * 		"r": 1,
+     * 		"v": {
+     * 			"m": "",
+     * 			"bg": "rgb(204, 255, 204)",
+     * 			"bl": 1,
+     * 			"fc": "rgb(0, 0, 0)",
+     * 			"ff": 5,
+     * 			"fs": 11,
+     * 			"ht": 0,
+     * 			"it": 0,
+     * 			"vt": 0
+     *       }
+     * }
+     *
+     * @param startColPosition
+     * @return
+     */
+    public static JSONArray assembleCommonRow1Col2(int startColPosition) {
+
+        JSONArray result = new JSONArray();
+
+        for(int m = 0, n = 6; m < n; m++) {
+            //备注2
+            JSONObject remark2 = new JSONObject();
+            remark2.put("c", startColPosition + m);
+            remark2.put("r", 1);
+
+            JSONObject remark2v = new JSONObject();
+            remark2v.put("m", "");
+            remark2v.put("bl", 1);
+            remark2v.put("fc", "rgb(0, 0, 0)");
+            remark2v.put("ff", 5);
+            remark2v.put("fs", 11);
+            remark2v.put("ht", 0);
+            remark2v.put("it", 0);
+            remark2v.put("vt", 0);
+
+            remark2.put("v", remark2v);
+            result.add(remark2);
+        }
+        return result;
+    }
+
+    /**
+     * 机号一级标题
+     *
+     * @param startColPosition
+     * @return
+     */
+    public static JSONArray genDeviceNumberFirstTitle(String cellName, int startColPosition) {
+        AssembleCellParam cellParam = AssembleCellParam.builder()
+                .fontsize(11)
+                .startRowPos(1)
+                .startColPos(startColPosition)
+                .rowSize(1)
+                .colSize(MACHINE_TITLE_COLS.length)
+                .value(cellName)
+                .build();
+        return assembleMergeTitle(cellParam);
+    }
+
+    /**
+     * 生成机号标题
+     *
+     * @param startColPosition
+     * @return
+     */
+    public static JSONArray assembleDeviceNumberSecondTitle(int startColPosition) {
+        return assembleSingleTitle(startColPosition, 2, MACHINE_TITLE_COLS);
+    }
+
+    /**
+     * 生成单个单元格
+     *
+     * @param startColPosition
+     * @param cols
+     * @return
+     */
+    public static JSONArray assembleSingleTitle(int startColPosition, int startRowPosition, String[] cols) {
+
+        JSONArray result = new JSONArray();
+
+        for(int m = 0, n = cols.length; m < n; m++) {
+            //备注2
+            JSONObject remark2 = new JSONObject();
+            remark2.put("c", startColPosition + m);
+            remark2.put("r", startRowPosition);
+            JSONObject remark2v = new JSONObject();
+            remark2v.put("m", cols[m]);
+            remark2v.put("v", cols[m]);
+            remark2v.put("bl", 1);
+            remark2v.put("fc", "rgb(0, 0, 0)");
+            remark2v.put("ff", 5);
+            remark2v.put("fs", 11);
+            remark2v.put("ht", 0);
+            remark2v.put("it", 0);
+            remark2v.put("vt", 1);
+            JSONObject ct = new JSONObject();
+            ct.put("t", "g");
+            ct.put("fa", "General");
+            remark2v.put("ct", ct);
+            remark2.put("v", remark2v);
+            result.add(remark2);
+        }
+        return result;
+    }
+
+    /**
+     * 组装合并单元格
+     *
+     * @param param
+     * @return
+     */
+    public static JSONArray assembleMergeTitle(AssembleCellParam param) {
+        JSONArray result = new JSONArray();
+        //一级标题
+        JSONObject remark2 = new JSONObject();
+        remark2.put("c", param.getStartColPos());
+        remark2.put("r", param.getStartRowPos());
+        JSONObject remark2v = new JSONObject();
+        remark2v.put("m", param.getValue());
+        remark2v.put("v", param.getValue());
+        remark2v.put("bl", 1);
+        remark2v.put("fc", "rgb(0, 0, 0)");
+        remark2v.put("ff", 5);
+        remark2v.put("fs", param.getFontsize());
+        remark2v.put("ht", 0);
+        remark2v.put("it", 0);
+        remark2v.put("vt", 1);
+        JSONObject ct = new JSONObject();
+        ct.put("t", "g");
+        ct.put("fa", "General");
+        remark2v.put("ct", ct);
+
+        JSONObject mc = new JSONObject();
+        mc.put("c", param.getStartColPos());
+        mc.put("r", param.getStartRowPos());
+        mc.put("cs", param.getColSize());
+        mc.put("rs", param.getRowSize());
+        remark2v.put("mc", mc);
+
+        remark2.put("v", remark2v);
+        result.add(remark2);
+
+        /**
+         * {
+         * 		"c": 1,
+         * 		"r": 0,
+         * 		"v": {
+         * 			"mc": {
+         * 				"c": 0,
+         * 				"r": 0
+         *          }
+         *       }
+         * 	}
+         */
+        for(int m = 1; m < param.getColSize(); m++) {
+            JSONObject temp = new JSONObject();
+
+            JSONObject mc2 = new JSONObject();
+            mc2.put("c", param.getStartColPos());
+            mc2.put("r", param.getStartRowPos());
+
+            JSONObject v = new JSONObject();
+            v.put("mc",  mc2);
+
+            temp.put("c", m + param.getStartColPos());
+            temp.put("r", param.getStartRowPos());
+            temp.put("v", v);
+            result.add(temp);
+        }
+
+        return result;
+    }
+
+    /**
+     * 获取空的sheet对象
+     *
+     * {
+     * 	"row": 84,
+     * 	"name": "Sheet2",
+     * 	"chart": [],
+     * 	"color": "",
+     * 	"index": "2",
+     * 	"order": 1,
+     * 	"column": 60,
+     * 	"config": {},
+     * 	"status": 0,
+     * 	"celldata": [],
+     * 	"ch_width": 4748,
+     * 	"rowsplit": [],
+     * 	"rh_height": 1790,
+     * 	"scrollTop": 0,
+     * 	"scrollLeft": 0,
+     * 	"visibledatarow": [],
+     * 	"visibledatacolumn": [],
+     * 	"jfgird_select_save": [{
+     * 		"row": [4, 4],
+     * 		"top": 85,
+     * 		"left": 0,
+     * 		"width": 73,
+     * 		"column": [0, 0],
+     * 		"height": 19,
+     * 		"top_move": 85,
+     * 		"left_move": 0,
+     * 		"row_focus": 4,
+     * 		"width_move": 73,
+     * 		"height_move": 19,
+     * 		"column_focus": 0
+     *        }],
+     * 	"jfgrid_selection_range": {}
+     * }
+     *
+     * @param param
+     * @return
+     */
+    public static JSONObject getEmptySheet(SheetInfoParam param) {
+        JSONObject obj = new JSONObject();
+        obj.put("row", 84);
+        obj.put("name", param.getSheetName());
+        obj.put("chart", new JSONArray());
+        obj.put("color", "");
+        obj.put("index", param.getIndex());
+        obj.put("order", param.getOrder());
+        obj.put("column", 60);
+        obj.put("config", new JSONObject());
+        obj.put("status", 0);
+        obj.put("celldata", new JSONArray());
+        obj.put("ch_width", 4748);
+        obj.put("rowsplit", new JSONArray());
+        obj.put("rh_height", 1790);
+        obj.put("scrollTop", 0);
+        obj.put("scrollLeft", 0);
+        obj.put("dataVerification", new JSONObject());
+        obj.put("visibledatarow", new JSONArray());
+        obj.put("visibledatacolumn", new JSONArray());
+
+        /**
+         * {
+     * 		"row": [4, 4],
+     * 		"top": 85,
+     * 		"left": 0,
+     * 		"width": 73,
+     * 		"column": [0, 0],
+     * 		"height": 19,
+     * 		"top_move": 85,
+     * 		"left_move": 0,
+     * 		"row_focus": 4,
+     * 		"width_move": 73,
+     * 		"height_move": 19,
+     * 		"column_focus": 0
+     *        }
+         */
+        JSONObject selectSave = new JSONObject();
+        selectSave.put("row", new String[]{"4", "4"});
+        selectSave.put("top", 85);
+        selectSave.put("left", 0);
+        selectSave.put("width", 73);
+        selectSave.put("column", new String[]{"0", "0"});
+        selectSave.put("height", 19);
+        selectSave.put("top_move", 85);
+        selectSave.put("left_move", 0);
+        selectSave.put("row_focus", 4);
+        selectSave.put("width_move", 73);
+        selectSave.put("height_move", 19);
+        selectSave.put("column_focus", 0);
+
+        JSONArray selectSaves = new JSONArray();
+        selectSaves.add(selectSave);
+
+        obj.put("jfgird_select_save", selectSaves);
+        obj.put("jfgrid_selection_range", new JSONObject());
+
+        return obj;
+    }
+
+    /**
+     * 获取合并配置
+     *           "0_0": {
+     * 				"c": 0,
+     * 				"r": 0,
+     * 				"cs": 58,
+     * 				"rs": 1
+     *           },
+     *
+     * @param deviceNumberList
+     * @return
+     */
+    public static JSONObject getMergeConfig(List<String> deviceNumberList) {
+        JSONObject result = new JSONObject();
+
+        int colSize = deviceNumberList.size() * MACHINE_TITLE_COLS.length
+                + MAIN_TITLE_FIRST.length
+                + MAIN_TITLE_SECOND.length;
+
+        //第一行 标题
+        JSONObject row0Title = new JSONObject();
+        row0Title.put("c", 0);
+        row0Title.put("r", 0);
+        row0Title.put("cs", colSize);
+        row0Title.put("rs", 1);
+        result.put("0_0", row0Title);
+
+        //第二行 前4列
+        for(int m = 0, n = MAIN_TITLE_FIRST.length; m < n; m++) {
+            JSONObject row1Col0Title = new JSONObject();
+            row1Col0Title.put("c", m);
+            row1Col0Title.put("r", 1);
+            row1Col0Title.put("cs", 1);
+            row1Col0Title.put("rs", 2);
+            result.put("1_".concat(String.valueOf(m)), row1Col0Title);
+        }
+
+        //第二行机号
+        for(int m = 0,  n = deviceNumberList.size(); m < n; m++) {
+            JSONObject deviceNumObj = new JSONObject();
+            int colPos = MAIN_TITLE_FIRST.length + m * MACHINE_TITLE_COLS.length;
+            deviceNumObj.put("c", colPos);
+            deviceNumObj.put("r", 1);
+            deviceNumObj.put("cs", MACHINE_TITLE_COLS.length);
+            deviceNumObj.put("rs", 1);
+            result.put("1_".concat(String.valueOf(colPos)), deviceNumObj);
+        }
+
+        return result;
+    }
+
+    /**
+     * {
+     * 			"value": {
+     * 				"b": {
+     * 					"color": "rgb(0, 0, 0)",
+     * 					"style": 1
+     *              },
+     * 				"l": {
+     * 					"color": "rgb(0, 0, 0)",
+     * 					"style": 1
+     *              },
+     * 				"t": {
+     * 					"color": "rgb(0, 0, 0)",
+     * 					"style": 1
+     *                },
+     * 				"col_index": 0,
+     * 				"row_index": 0
+     * 			},
+     * 			"rangeType": "cell"
+     * }
+     *
+     * @param deviceNumberList
+     * @return
+     */
+    public static JSONArray getBorderInfo(List<String> deviceNumberList) {
+        JSONArray result = new JSONArray();
+
+        //计算列行
+        int rowsSize = 3, colsSize = deviceNumberList.size() * MACHINE_TITLE_COLS.length
+                + MAIN_TITLE_FIRST.length
+                + MAIN_TITLE_SECOND.length;;
+
+        //行
+        for(int m = 0; m < rowsSize; m++) {
+            for(int n = 0; n < colsSize; n++) {
+                JSONObject value = new JSONObject();
+                JSONObject b = new JSONObject();
+                b.put("color", "rgb(0, 0, 0)");
+                b.put("style", 1);
+                value.put("b", b);
+
+                JSONObject l = new JSONObject();
+                l.put("color", "rgb(0, 0, 0)");
+                l.put("style", 1);
+                value.put("l", l);
+
+                JSONObject t = new JSONObject();
+                t.put("color", "rgb(0, 0, 0)");
+                t.put("style", 1);
+                value.put("t", t);
+
+                value.put("col_index", n);
+                value.put("row_index", m);
+
+                JSONObject obj = new JSONObject();
+                obj.put("rangeType", "cell");
+                obj.put("value", value);
+                result.add(obj);
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * 数据校验
+     *
+     * @param paramExcelDto
+     * @return
+     */
+    public static JSONObject getDataVerification(ProjectSummaryParamExcelDto paramExcelDto) {
+        JSONObject result = new JSONObject();
+
+        //部门
+        List<String> departList = paramExcelDto.getWorkshopList().stream()
+                .map(item -> item.getString("SHORTNAME"))
+                .collect(Collectors.toList());
+        String departChose = StringUtils.join(departList, ",");
+
+        for(int m = 0,  n = paramExcelDto.getDeviceNumberList().size() - 1; m <= n; m++) {
+            int colPos = MAIN_TITLE_FIRST.length + m * MACHINE_TITLE_COLS.length;
+//            int departColPos = 4 + 4 * m;
+            for(int startRows = 3, endRows = 200; startRows < endRows; startRows++) {
+
+                //状态
+                /**
+                 * "3_4": {
+                 * 			"type": "dropdown",
+                 * 			"remote": false,
+                 * 			"value1": "OK,X,√",
+                 * 			"value2": "",
+                 * 			"checked": false,
+                 * 			"hintShow": false,
+                 * 			"hintText": "",
+                 * 			"prohibitInput": false
+                 * }
+                 */
+                JSONObject statusObj = getNewDataVerification("OK,X,√");
+                result.put(String.valueOf(startRows).concat("_").concat(String.valueOf(colPos)), statusObj);
+
+                //部门
+                /**
+                 * "3_4": {
+                 * 			"type": "dropdown",
+                 * 			"remote": false,
+                 * 			"value1": "OK,X,√",
+                 * 			"value2": "",
+                 * 			"checked": false,
+                 * 			"hintShow": false,
+                 * 			"hintText": "",
+                 * 			"prohibitInput": false
+                 * }
+                 */
+                //施工部门
+                JSONObject departObj = getNewDataVerification(departChose);
+                result.put(String.valueOf(startRows).concat("_").concat(String.valueOf(colPos + 1)), departObj);
+
+                //责任部门
+                JSONObject depart2Obj = getNewDataVerification(departChose);
+                result.put(String.valueOf(startRows).concat("_").concat(String.valueOf(colPos + 3)), depart2Obj);
+            }
+        }
+
+        //总状态
+        int statusColIndex = MAIN_TITLE_FIRST.length + paramExcelDto.getDeviceNumberList().size() * MACHINE_TITLE_COLS.length;
+        for(int startRows = 3, endRows = 200; startRows < endRows; startRows++) {
+            JSONObject statusObj = getNewDataVerification("OK,X,√");
+            result.put(String.valueOf(startRows).concat("_").concat(String.valueOf(statusColIndex)), statusObj);
+        }
+
+        return result;
+    }
+
+    public static JSONObject getNewDataVerification(String options) {
+        JSONObject departObj = new JSONObject();
+        departObj.put("type", "dropdown");
+        departObj.put("remote", false);
+        departObj.put("value1", options);
+        departObj.put("value2", "");
+        departObj.put("checked", false);
+        departObj.put("hintShow", false);
+        departObj.put("hintText", "");
+        departObj.put("prohibitInput", false);
+        return departObj;
+    }
+}

+ 0 - 0
luckysheet/src/main/java/com/xc/luckysheet/utils/MyStringUtil.java


برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است