pangqijun 1 год назад
Сommit
758a68a012
100 измененных файлов с 8350 добавлено и 0 удалено
  1. 27 0
      .gitignore
  2. 15 0
      Dockerfile
  3. 191 0
      LICENSE
  4. 187 0
      README.md
  5. 1 0
      doc/script/service.cmd
  6. 76 0
      doc/script/service.sh
  7. 153 0
      doc/sql/blade-saber-mysql.sql
  8. 153 0
      doc/sql/blade-sword-mysql.sql
  9. 213 0
      pom.xml
  10. 37 0
      src/main/java/org/springblade/Application.java
  11. 32 0
      src/main/java/org/springblade/common/cache/CacheNames.java
  12. 52 0
      src/main/java/org/springblade/common/config/BladeConfiguration.java
  13. 42 0
      src/main/java/org/springblade/common/config/BladeReportConfiguration.java
  14. 119 0
      src/main/java/org/springblade/common/config/SwaggerConfiguration.java
  15. 50 0
      src/main/java/org/springblade/common/constant/CommonConstant.java
  16. 63 0
      src/main/java/org/springblade/common/constant/LauncherConstant.java
  17. 37 0
      src/main/java/org/springblade/common/launch/LauncherServiceImpl.java
  18. 25 0
      src/main/java/org/springblade/common/tool/CommonUtil.java
  19. 71 0
      src/main/java/org/springblade/core/log/config/BladeLogToolAutoConfiguration.java
  20. 58 0
      src/main/java/org/springblade/core/log/event/ApiLogListener.java
  21. 55 0
      src/main/java/org/springblade/core/log/event/ErrorLogListener.java
  22. 56 0
      src/main/java/org/springblade/core/log/event/UsualLogListener.java
  23. 57 0
      src/main/java/org/springblade/core/secure/AuthInfo.java
  24. 524 0
      src/main/java/org/springblade/core/secure/utils/SecureUtil.java
  25. 100 0
      src/main/java/org/springblade/modules/auth/controller/AuthController.java
  26. 94 0
      src/main/java/org/springblade/modules/auth/controller/SocialController.java
  27. 44 0
      src/main/java/org/springblade/modules/auth/enums/BladeUserEnum.java
  28. 76 0
      src/main/java/org/springblade/modules/auth/granter/CaptchaTokenGranter.java
  29. 36 0
      src/main/java/org/springblade/modules/auth/granter/ITokenGranter.java
  30. 60 0
      src/main/java/org/springblade/modules/auth/granter/PasswordTokenGranter.java
  31. 56 0
      src/main/java/org/springblade/modules/auth/granter/RefreshTokenGranter.java
  32. 89 0
      src/main/java/org/springblade/modules/auth/granter/SocialTokenGranter.java
  33. 61 0
      src/main/java/org/springblade/modules/auth/granter/TokenGranterBuilder.java
  34. 31 0
      src/main/java/org/springblade/modules/auth/granter/TokenParameter.java
  35. 100 0
      src/main/java/org/springblade/modules/auth/utils/TokenUtil.java
  36. 180 0
      src/main/java/org/springblade/modules/desk/controller/DashBoardController.java
  37. 122 0
      src/main/java/org/springblade/modules/desk/controller/NoticeController.java
  38. 75 0
      src/main/java/org/springblade/modules/desk/entity/Notice.java
  39. 46 0
      src/main/java/org/springblade/modules/desk/mapper/NoticeMapper.java
  40. 39 0
      src/main/java/org/springblade/modules/desk/mapper/NoticeMapper.xml
  41. 37 0
      src/main/java/org/springblade/modules/desk/service/INoticeService.java
  42. 38 0
      src/main/java/org/springblade/modules/desk/service/impl/NoticeServiceImpl.java
  43. 20 0
      src/main/java/org/springblade/modules/desk/vo/NoticeVO.java
  44. 50 0
      src/main/java/org/springblade/modules/desk/wrapper/NoticeWrapper.java
  45. 154 0
      src/main/java/org/springblade/modules/develop/controller/CodeController.java
  46. 126 0
      src/main/java/org/springblade/modules/develop/controller/DatasourceController.java
  47. 125 0
      src/main/java/org/springblade/modules/develop/entity/Code.java
  48. 82 0
      src/main/java/org/springblade/modules/develop/entity/Datasource.java
  49. 28 0
      src/main/java/org/springblade/modules/develop/mapper/CodeMapper.java
  50. 22 0
      src/main/java/org/springblade/modules/develop/mapper/CodeMapper.xml
  51. 28 0
      src/main/java/org/springblade/modules/develop/mapper/DatasourceMapper.java
  52. 22 0
      src/main/java/org/springblade/modules/develop/mapper/DatasourceMapper.xml
  53. 37 0
      src/main/java/org/springblade/modules/develop/service/ICodeService.java
  54. 28 0
      src/main/java/org/springblade/modules/develop/service/IDatasourceService.java
  55. 39 0
      src/main/java/org/springblade/modules/develop/service/impl/CodeServiceImpl.java
  56. 32 0
      src/main/java/org/springblade/modules/develop/service/impl/DatasourceServiceImpl.java
  57. 173 0
      src/main/java/org/springblade/modules/resource/OssEndpoint.java
  58. 118 0
      src/main/java/org/springblade/modules/system/controller/AuthClientController.java
  59. 121 0
      src/main/java/org/springblade/modules/system/controller/DataScopeController.java
  60. 114 0
      src/main/java/org/springblade/modules/system/controller/DeptController.java
  61. 129 0
      src/main/java/org/springblade/modules/system/controller/DictController.java
  62. 80 0
      src/main/java/org/springblade/modules/system/controller/LogApiController.java
  63. 80 0
      src/main/java/org/springblade/modules/system/controller/LogErrorController.java
  64. 80 0
      src/main/java/org/springblade/modules/system/controller/LogUsualController.java
  65. 211 0
      src/main/java/org/springblade/modules/system/controller/MenuController.java
  66. 93 0
      src/main/java/org/springblade/modules/system/controller/ParamController.java
  67. 142 0
      src/main/java/org/springblade/modules/system/controller/PostController.java
  68. 159 0
      src/main/java/org/springblade/modules/system/controller/RegionController.java
  69. 144 0
      src/main/java/org/springblade/modules/system/controller/RoleController.java
  70. 137 0
      src/main/java/org/springblade/modules/system/controller/TenantController.java
  71. 271 0
      src/main/java/org/springblade/modules/system/controller/UserController.java
  72. 32 0
      src/main/java/org/springblade/modules/system/dto/DeptDTO.java
  73. 32 0
      src/main/java/org/springblade/modules/system/dto/DictDTO.java
  74. 32 0
      src/main/java/org/springblade/modules/system/dto/MenuDTO.java
  75. 32 0
      src/main/java/org/springblade/modules/system/dto/ParamDTO.java
  76. 32 0
      src/main/java/org/springblade/modules/system/dto/RoleDTO.java
  77. 32 0
      src/main/java/org/springblade/modules/system/dto/RoleMenuDTO.java
  78. 108 0
      src/main/java/org/springblade/modules/system/entity/AuthClient.java
  79. 97 0
      src/main/java/org/springblade/modules/system/entity/DataScope.java
  80. 101 0
      src/main/java/org/springblade/modules/system/entity/Dept.java
  81. 95 0
      src/main/java/org/springblade/modules/system/entity/Dict.java
  82. 141 0
      src/main/java/org/springblade/modules/system/entity/Menu.java
  83. 75 0
      src/main/java/org/springblade/modules/system/entity/Param.java
  84. 77 0
      src/main/java/org/springblade/modules/system/entity/Post.java
  85. 127 0
      src/main/java/org/springblade/modules/system/entity/Region.java
  86. 89 0
      src/main/java/org/springblade/modules/system/entity/Role.java
  87. 64 0
      src/main/java/org/springblade/modules/system/entity/RoleMenu.java
  88. 64 0
      src/main/java/org/springblade/modules/system/entity/RoleScope.java
  89. 82 0
      src/main/java/org/springblade/modules/system/entity/Tenant.java
  90. 104 0
      src/main/java/org/springblade/modules/system/entity/User.java
  91. 60 0
      src/main/java/org/springblade/modules/system/entity/UserInfo.java
  92. 107 0
      src/main/java/org/springblade/modules/system/entity/UserOauth.java
  93. 88 0
      src/main/java/org/springblade/modules/system/excel/UserExcel.java
  94. 56 0
      src/main/java/org/springblade/modules/system/excel/UserImportListener.java
  95. 28 0
      src/main/java/org/springblade/modules/system/mapper/AuthClientMapper.java
  96. 27 0
      src/main/java/org/springblade/modules/system/mapper/AuthClientMapper.xml
  97. 28 0
      src/main/java/org/springblade/modules/system/mapper/DataScopeMapper.java
  98. 5 0
      src/main/java/org/springblade/modules/system/mapper/DataScopeMapper.xml
  99. 57 0
      src/main/java/org/springblade/modules/system/mapper/DeptMapper.java
  100. 55 0
      src/main/java/org/springblade/modules/system/mapper/DeptMapper.xml

+ 27 - 0
.gitignore

@@ -0,0 +1,27 @@
+# maven #
+target
+
+logs
+
+# windows #
+Thumbs.db
+
+# Mac #
+.DS_Store
+
+# eclipse #
+.settings
+.project
+.classpath
+.log
+*.class
+
+# idea #
+.idea
+*.iml
+
+# Package Files #
+*.jar
+*.war
+*.ear
+/target

+ 15 - 0
Dockerfile

@@ -0,0 +1,15 @@
+FROM anapsix/alpine-java:8_server-jre_unlimited
+
+MAINTAINER smallchill@163.com
+
+RUN mkdir -p /blade
+
+WORKDIR /blade
+
+EXPOSE 8800
+
+ADD ./target/SpringBlade.jar ./app.jar
+
+ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
+
+CMD ["--spring.profiles.active=test"]

+ 191 - 0
LICENSE

@@ -0,0 +1,191 @@
+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:
+
+You must give any other recipients of the Work or Derivative Works a copy of
+this License; and
+You must cause any modified files to carry prominent notices stating that You
+changed the files; and
+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
+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 2023 BladeX (https://bladex.cn)
+
+   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.

+ 187 - 0
README.md

@@ -0,0 +1,187 @@
+ <p align="center">
+      <img src="https://img.shields.io/badge/Release-V3.7.0-green.svg" alt="Downloads">
+      <img src="https://img.shields.io/badge/JDK-1.8+-green.svg" alt="Build Status">
+  <img src="https://img.shields.io/badge/license-Apache%202-blue.svg" alt="Build Status">
+   <img src="https://img.shields.io/badge/Spring%20Cloud-2021-blue.svg" alt="Coverage Status">
+   <img src="https://img.shields.io/badge/Spring%20Boot-2.7.10-blue.svg" alt="Downloads">
+   <a target="_blank" href="https://bladex.cn">
+   <img src="https://img.shields.io/badge/Author-Small%20Chill-ff69b4.svg" alt="Downloads">
+ </a>
+ <a target="_blank" href="https://bladex.cn">
+   <img src="https://img.shields.io/badge/Copyright%20-@BladeX-%23ff3f59.svg" alt="Downloads">
+ </a>
+ </p>  
+
+## SpringBlade微服务开发平台
+* 采用前后端分离的模式,前端开源两个框架:[Sword](https://gitee.com/smallc/Sword) (基于 React、Ant Design)、[Saber](https://gitee.com/smallc/Saber) (基于 Vue、Element-UI)
+* 后端采用SpringCloud全家桶,并同时对其基础组件做了高度的封装,单独开源出一个框架:[BladeTool](https://gitee.com/smallc/blade-tool)
+* [BladeTool](https://github.com/chillzhuang/blade-tool)已推送至Maven中央库,直接引入即可,减少了工程的臃肿,也可更注重于业务开发
+* 集成Sentinel从流量控制、熔断降级、系统负载等多个维度保护服务的稳定性。
+* 注册中心、配置中心选型Nacos,为工程瘦身的同时加强各模块之间的联动。
+* 使用Traefik进行反向代理,监听后台变化自动化应用新的配置文件。
+* 极简封装了多租户底层,用更少的代码换来拓展性更强的SaaS多租户系统。
+* 借鉴OAuth2,实现了多终端认证系统,可控制子系统的token权限互相隔离。
+* 借鉴Security,封装了Secure模块,采用JWT做Token认证,可拓展集成Redis等细颗粒度控制方案。
+* 稳定生产了三年,经历了从 Camden -> Hoxton -> 2021 的技术架构,也经历了从fat jar -> docker -> k8s + jenkins的部署架构。
+* 项目分包明确,规范微服务的开发模式,使包与包之间的分工清晰。
+
+## 架构图
+<img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-framework.png"/>
+
+## 工程结构
+``` 
+SpringBlade
+├── blade-auth -- 授权服务提供
+├── blade-common -- 常用工具封装包
+├── blade-gateway -- Spring Cloud 网关
+├── blade-ops -- 运维中心
+├    ├── blade-admin -- spring-cloud后台管理
+├    ├── blade-develop -- 代码生成
+├    ├── blade-resource -- 资源管理
+├    ├── blade-seata-order -- seata分布式事务demo
+├    ├── blade-seata-storage -- seata分布式事务demo
+├── blade-service -- 业务模块
+├    ├── blade-desk -- 工作台模块 
+├    ├── blade-log -- 日志模块 
+├    ├── blade-system -- 系统模块 
+├    └── blade-user -- 用户模块 
+├── blade-service-api -- 业务模块api封装
+├    ├── blade-desk-api -- 工作台api 
+├    ├── blade-dict-api -- 字典api 
+├    ├── blade-system-api -- 系统api 
+└──  └── blade-user-api -- 用户api 
+```
+
+## 官方信息
+* 官网地址:[https://bladex.cn](https://bladex.cn)
+* 问答社区:[https://sns.bladex.cn](https://sns.bladex.cn)
+* 会员计划:[SpringBlade会员计划](https://gitee.com/smallc/SpringBlade/wikis/SpringBlade会员计划)
+* 交流一群:`477853168`(满)
+* 交流二群:`751253339`(满)
+* 交流三群:`784729540`(满)
+* 交流四群:`1034621754`(满)
+* 交流五群:`946350912`(满)
+* 交流六群:`511624269`(满)
+* 交流七群:`298061704`
+
+## 在线演示
+* Saber-基于Vue:[https://saber.bladex.cn](https://saber.bladex.cn)
+* Sword-基于React:[https://sword.bladex.cn](https://sword.bladex.cn)
+
+## 数据大屏
+* 数据大屏展示系统:[https://data.bladex.cn](https://data.bladex.cn)
+
+## 技术文档
+* [SpringBlade开发手册一览](https://gitee.com/smallc/SpringBlade/wikis/SpringBlade开发手册)
+* [SpringBlade常见问题集锦](https://sns.bladex.cn/article-14966.html)
+* [SpringBlade基于Kuboard部署K8S](https://kuboard.cn/learning/k8s-practice/spring-blade/)
+
+## 项目地址
+* 核心框架项目地址:[https://gitee.com/smallc/blade-tool](https://gitee.com/smallc/blade-tool)
+* 后端Gitee地址:[https://gitee.com/smallc/SpringBlade](https://gitee.com/smallc/SpringBlade)
+* 后端Github地址:[https://github.com/chillzhuang/SpringBlade](https://github.com/chillzhuang/SpringBlade)
+* 后端SpringBoot版:[https://gitee.com/smallc/SpringBlade/tree/boot/](https://gitee.com/smallc/SpringBlade/tree/boot/)
+* 前端框架Sword(基于React):[https://gitee.com/smallc/Sword](https://gitee.com/smallc/Sword)
+* 前端框架Saber(基于Vue2):[https://gitee.com/smallc/Saber](https://gitee.com/smallc/Saber)
+* 前端框架Saber3(基于Vue3):[https://gitee.com/smallc/Saber3](https://gitee.com/smallc/Saber/tree/3.x/)
+
+# 开源协议
+Apache Licence 2.0 ([英文原文](http://www.apache.org/licenses/LICENSE-2.0.html))
+Apache Licence是著名的非盈利开源组织Apache采用的协议。该协议和BSD类似,同样鼓励代码共享和尊重原作者的著作权,同样允许代码修改,再发布(作为开源或商业软件)。
+需要满足的条件如下:
+* 需要给代码的用户一份Apache Licence
+* 如果你修改了代码,需要在被修改的文件中说明。
+* 在延伸的代码中(修改和有源代码衍生的代码中)需要带有原来代码中的协议,商标,专利声明和其他原来作者规定需要包含的说明。
+* 如果再发布的产品中包含一个Notice文件,则在Notice文件中需要带有Apache Licence。你可以在Notice中增加自己的许可,但不可以表现为对Apache Licence构成更改。
+  Apache Licence也是对商业应用友好的许可。使用者也可以在需要的时候修改代码来满足需要并作为开源或商业产品发布/销售。
+
+## 用户权益
+* 允许免费用于学习、毕设、公司项目、私活等,但请保留源码作者信息。
+* 对未经过授权和不遵循 Apache 2.0 协议二次开源或者商业化我们将追究到底。
+* 参考请注明:参考自 SpringBlade:https://gitee.com/smallc/SpringBlade。
+
+# 界面
+
+## [BladeX](https://bladex.cn/#/vip) 工作流一览
+<table>
+    <tr>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/bladex-flow1.png"/></td>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/bladex-flow2.png"/></td>
+    </tr>
+    <tr>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/bladex-flow3.png"/></td>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/bladex-flow4.png"/></td>
+    </tr>
+    <tr>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/bladex-flow5.png"/></td>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/bladex-flow6.png"/></td>
+    </tr>
+</table>
+
+## [Sword](https://gitee.com/smallc/Sword) 界面一览
+<table>
+    <tr>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/sword-main.png"/></td>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/sword-menu.png"/></td>
+    </tr>
+    <tr>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/sword-menu-edit.png"/></td>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/sword-menu-icon.png"/></td>
+    </tr>
+    <tr>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/sword-role.png"/></td>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/sword-user.png"/></td>
+    </tr>
+    <tr>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/sword-dict.png "/></td>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/sword-log.png"/></td>
+    </tr>
+    <tr>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/sword-locale-cn.png"/></td>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/sword-locale-us.png"/></td>
+    </tr>
+</table>
+
+## [Saber](https://gitee.com/smallc/Saber) 界面一览
+<table>
+    <tr>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/saber-user.png"/></td>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/saber-role.png"/></td>
+    </tr>
+    <tr>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/saber-dict.png"/></td>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/saber-dict-select.png"/></td>
+    </tr>
+    <tr>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/saber-log.png"/></td>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/saber-code.png"/></td>
+    </tr>
+</table>
+
+## 监控界面一览
+<table>
+    <tr>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-k8s1.png"/></td>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-k8s2.png"/></td>
+    </tr>
+    <tr>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-grafana.png"/></td>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-harbor.png"/></td>
+    </tr>
+    <tr>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-traefik.png"/></td>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-traefik-health.png"/></td>
+    </tr>
+    <tr>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-nacos.png"/></td>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-sentinel.png"/></td>
+    </tr>
+    <tr>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-admin1.png"/></td>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-admin2.png"/></td>
+    </tr>
+    <tr>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-swagger1.png"/></td>
+        <td><img src="https://gitee.com/smallc/SpringBlade/raw/master/pic/springblade-swagger2.png"/></td>
+    </tr>
+</table>

+ 1 - 0
doc/script/service.cmd

@@ -0,0 +1 @@
+java -jar app.jar

+ 76 - 0
doc/script/service.sh

@@ -0,0 +1,76 @@
+#!/bin/bash
+
+#设置jar文件名
+APP_NAME=app.jar
+
+#使用说明,用来提示输入参数
+usage() {
+echo "Usage: sh 执行脚本.sh [start|stop|restart|status]"
+exit 1
+}
+
+#检查程序是否在运行
+is_exist(){
+pid=`ps -ef|grep $APP_NAME|grep -v grep|awk '{print $2}' `
+#如果不存在返回1,存在返回0
+if [ -z "${pid}" ]; then
+return 1
+else
+return 0
+fi
+}
+
+#启动方法
+start(){
+is_exist
+if [ $? -eq "0" ]; then
+echo "${APP_NAME} is already running. pid=${pid} ."
+else
+nohup java -jar $APP_NAME > /dev/null 2>&1 &
+fi
+}
+
+#停止方法
+stop(){
+is_exist
+if [ $? -eq "0" ]; then
+kill -9 $pid
+else
+echo "${APP_NAME} is not running"
+fi
+}
+
+#输出运行状态
+status(){
+is_exist
+if [ $? -eq "0" ]; then
+echo "${APP_NAME} is running. Pid is ${pid}"
+else
+echo "${APP_NAME} is NOT running."
+fi
+}
+
+#重启
+restart(){
+stop
+start
+}
+
+#根据输入参数,选择执行对应方法,不输入则执行使用说明
+case "$1" in
+"start")
+start
+;;
+"stop")
+stop
+;;
+"status")
+status
+;;
+"restart")
+restart
+;;
+*)
+usage
+;;
+esac

Разница между файлами не показана из-за своего большого размера
+ 153 - 0
doc/sql/blade-saber-mysql.sql


Разница между файлами не показана из-за своего большого размера
+ 153 - 0
doc/sql/blade-sword-mysql.sql


+ 213 - 0
pom.xml

@@ -0,0 +1,213 @@
+<?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">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.springblade</groupId>
+    <artifactId>SpringBlade</artifactId>
+    <packaging>jar</packaging>
+    <version>3.7.0</version>
+
+    <properties>
+        <blade.tool.version>3.7.0</blade.tool.version>
+
+        <java.version>1.8</java.version>
+
+        <knife4j.version>4.1.0</knife4j.version>
+        <protostuff.version>1.6.0</protostuff.version>
+        <captcha.version>1.6.2</captcha.version>
+        <easyexcel.version>2.2.11</easyexcel.version>
+
+        <spring.version>5.3.29</spring.version>
+        <spring.boot.version>2.7.15</spring.boot.version>
+
+        <!-- 推荐使用Harbor -->
+        <docker.registry.url>192.168.186.129</docker.registry.url>
+        <docker.registry.host>http://${docker.registry.url}:2375</docker.registry.host>
+        <docker.plugin.version>1.2.0</docker.plugin.version>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.springframework</groupId>
+                <artifactId>spring-framework-bom</artifactId>
+                <version>${spring.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>${spring.boot.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+            <dependency>
+                <groupId>com.github.xiaoymin</groupId>
+                <artifactId>knife4j-dependencies</artifactId>
+                <version>${knife4j.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-core-boot</artifactId>
+            <version>${blade.tool.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springblade</groupId>
+                    <artifactId>blade-core-cloud</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-core-develop</artifactId>
+            <version>${blade.tool.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-core-oss</artifactId>
+            <version>${blade.tool.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-core-report</artifactId>
+            <version>${blade.tool.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-core-social</artifactId>
+            <version>${blade.tool.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-core-datascope</artifactId>
+            <version>${blade.tool.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>knife4j-openapi2-ui</artifactId>
+            <version>${knife4j.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.whvcse</groupId>
+            <artifactId>easy-captcha</artifactId>
+            <version>${captcha.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>easyexcel</artifactId>
+            <version>${easyexcel.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springblade</groupId>
+            <artifactId>blade-core-test</artifactId>
+            <version>${blade.tool.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>SpringBlade</finalName>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+            </resource>
+            <resource>
+                <directory>src/main/java</directory>
+                <includes>
+                    <include>**/*.xml</include>
+                </includes>
+            </resource>
+        </resources>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-maven-plugin</artifactId>
+                    <version>${spring.boot.version}</version>
+                    <configuration>
+                        <finalName>${project.build.finalName}</finalName>
+                    </configuration>
+                    <executions>
+                        <execution>
+                            <goals>
+                                <goal>repackage</goal>
+                            </goals>
+                        </execution>
+                    </executions>
+                </plugin>
+                <plugin>
+                    <groupId>com.spotify</groupId>
+                    <artifactId>docker-maven-plugin</artifactId>
+                    <version>${docker.plugin.version}</version>
+                    <configuration>
+                        <imageName>${docker.registry.url}/blade/${project.artifactId}:${project.version}</imageName>
+                        <dockerDirectory>${project.basedir}</dockerDirectory>
+                        <dockerHost>${docker.registry.host}</dockerHost>
+                        <resources>
+                            <resource>
+                                <targetPath>/</targetPath>
+                                <directory>${project.build.directory}</directory>
+                                <include>${project.build.finalName}.jar</include>
+                            </resource>
+                        </resources>
+                        <registryUrl>${docker.registry.url}</registryUrl>
+                        <serverId>${docker.registry.url}</serverId>
+                        <pushImage>true</pushImage>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+            <plugin>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>${java.version}</source>
+                    <target>${java.version}</target>
+                    <encoding>UTF-8</encoding>
+                    <compilerArgs>
+                        <arg>-parameters</arg>
+                    </compilerArgs>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <repositories>
+        <repository>
+            <id>aliyun-repos</id>
+            <url>https://maven.aliyun.com/nexus/content/groups/public/</url>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </repository>
+    </repositories>
+
+    <pluginRepositories>
+        <pluginRepository>
+            <id>aliyun-plugin</id>
+            <url>https://maven.aliyun.com/nexus/content/groups/public/</url>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </pluginRepository>
+    </pluginRepositories>
+
+</project>

+ 37 - 0
src/main/java/org/springblade/Application.java

@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade;
+
+import org.springblade.common.constant.LauncherConstant;
+import org.springblade.core.launch.BladeApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+/**
+ * 启动器
+ *
+ * @author Chill
+ */
+@EnableScheduling
+@SpringBootApplication
+public class Application {
+
+	public static void main(String[] args) {
+		BladeApplication.run(LauncherConstant.APPLICATION_NAME, Application.class, args);
+	}
+
+}
+

+ 32 - 0
src/main/java/org/springblade/common/cache/CacheNames.java

@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.common.cache;
+
+/**
+ * 缓存名
+ *
+ * @author Chill
+ */
+public interface CacheNames {
+
+	String NOTICE_ONE = "notice:one";
+
+	String DICT_VALUE = "dict:value";
+	String DICT_LIST = "dict:list";
+
+	String CAPTCHA_KEY = "blade:auth::captcha:";
+
+}

+ 52 - 0
src/main/java/org/springblade/common/config/BladeConfiguration.java

@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.common.config;
+
+
+import org.springblade.core.secure.registry.SecureRegistry;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * Blade配置
+ *
+ * @author Chill
+ */
+@Configuration(proxyBeanMethods = false)
+public class BladeConfiguration implements WebMvcConfigurer {
+
+	@Bean
+	public SecureRegistry secureRegistry() {
+		SecureRegistry secureRegistry = new SecureRegistry();
+		secureRegistry.setEnabled(true);
+		secureRegistry.excludePathPatterns("/blade-auth/**");
+		secureRegistry.excludePathPatterns("/blade-system/menu/auth-routes");
+		secureRegistry.excludePathPatterns("/blade-system/tenant/info");
+		secureRegistry.excludePathPatterns("/doc.html");
+		secureRegistry.excludePathPatterns("/js/**");
+		secureRegistry.excludePathPatterns("/webjars/**");
+		secureRegistry.excludePathPatterns("/swagger-resources/**");
+		return secureRegistry;
+	}
+
+	@Override
+	public void addResourceHandlers(ResourceHandlerRegistry registry) {
+		registry.addResourceHandler("/js/**").addResourceLocations("classpath:/js/");
+	}
+
+}

+ 42 - 0
src/main/java/org/springblade/common/config/BladeReportConfiguration.java

@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.common.config;
+
+import org.springblade.core.report.datasource.ReportDataSource;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.sql.DataSource;
+
+/**
+ * 报表配置类
+ *
+ * @author Chill
+ */
+@Configuration(proxyBeanMethods = false)
+@ConditionalOnProperty(value = "report.enabled", havingValue = "true", matchIfMissing = true)
+public class BladeReportConfiguration {
+
+	/**
+	 * 自定义报表可选数据源
+	 */
+	@Bean
+	public ReportDataSource reportDataSource(DataSource dataSource) {
+		return new ReportDataSource(dataSource);
+	}
+
+}

+ 119 - 0
src/main/java/org/springblade/common/config/SwaggerConfiguration.java

@@ -0,0 +1,119 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.common.config;
+
+import com.github.xiaoymin.knife4j.spring.extension.OpenApiExtensionResolver;
+import com.google.common.collect.Lists;
+import lombok.AllArgsConstructor;
+import org.springblade.core.launch.constant.AppConstant;
+import org.springblade.core.secure.BladeUser;
+import org.springblade.core.swagger.EnableSwagger;
+import org.springblade.core.swagger.SwaggerProperties;
+import org.springblade.core.swagger.SwaggerUtil;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.service.*;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spi.service.contexts.SecurityContext;
+import springfox.documentation.spring.web.plugins.Docket;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Swagger配置类
+ *
+ * @author Chill
+ */
+@Configuration(proxyBeanMethods = false)
+@EnableSwagger
+@AllArgsConstructor
+public class SwaggerConfiguration {
+
+	/**
+	 * 引入swagger配置类
+	 */
+	private final SwaggerProperties swaggerProperties;
+
+	/**
+	 * 引入Knife4j扩展类
+	 */
+	private final OpenApiExtensionResolver openApiExtensionResolver;
+
+	@Bean
+	public Docket deskDocket() {
+		return docket("工作台模块", Collections.singletonList(AppConstant.BASE_PACKAGES + ".modules.desk"));
+	}
+
+	@Bean
+	public Docket authDocket() {
+		return docket("授权模块", Collections.singletonList(AppConstant.BASE_PACKAGES + ".modules.auth"));
+	}
+
+	@Bean
+	public Docket sysDocket() {
+		return docket("系统模块",
+			Arrays.asList(AppConstant.BASE_PACKAGES + ".modules.system", AppConstant.BASE_PACKAGES + ".modules.resource"));
+	}
+
+	private Docket docket(String groupName, List<String> basePackages) {
+		return new Docket(DocumentationType.SWAGGER_2)
+			.groupName(groupName)
+			.apiInfo(apiInfo())
+			.ignoredParameterTypes(BladeUser.class)
+			.select()
+			.apis(SwaggerUtil.basePackages(basePackages))
+			.paths(PathSelectors.any())
+			.build().securityContexts(securityContexts()).securitySchemes(securitySchemas())
+			.extensions(openApiExtensionResolver.buildExtensions(groupName));
+	}
+
+	private List<SecurityContext> securityContexts() {
+		return Collections.singletonList(SecurityContext.builder()
+			.securityReferences(defaultAuth())
+			.forPaths(PathSelectors.regex("^.*$"))
+			.build());
+	}
+
+	List<SecurityReference> defaultAuth() {
+		AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverywhere");
+		AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
+		authorizationScopes[0] = authorizationScope;
+		return Lists.newArrayList(new SecurityReference(SwaggerUtil.clientInfo().getName(), authorizationScopes),
+			new SecurityReference(SwaggerUtil.bladeAuth().getName(), authorizationScopes),
+			new SecurityReference(SwaggerUtil.bladeTenant().getName(), authorizationScopes));
+	}
+
+	private List<SecurityScheme> securitySchemas() {
+		return Lists.newArrayList(SwaggerUtil.clientInfo(), SwaggerUtil.bladeAuth(), SwaggerUtil.bladeTenant());
+	}
+
+	private ApiInfo apiInfo() {
+		return new ApiInfoBuilder()
+			.title(swaggerProperties.getTitle())
+			.description(swaggerProperties.getDescription())
+			.license(swaggerProperties.getLicense())
+			.licenseUrl(swaggerProperties.getLicenseUrl())
+			.termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl())
+			.contact(new Contact(swaggerProperties.getContact().getName(), swaggerProperties.getContact().getUrl(), swaggerProperties.getContact().getEmail()))
+			.version(swaggerProperties.getVersion())
+			.build();
+	}
+
+}

+ 50 - 0
src/main/java/org/springblade/common/constant/CommonConstant.java

@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.common.constant;
+
+/**
+ * 通用常量
+ *
+ * @author Chill
+ */
+public interface CommonConstant {
+
+	/**
+	 * sword 系统名
+	 */
+	String SWORD_NAME = "sword";
+
+	/**
+	 * saber 系统名
+	 */
+	String SABER_NAME = "saber";
+
+	/**
+	 * 顶级父节点id
+	 */
+	Long TOP_PARENT_ID = 0L;
+
+	/**
+	 * 顶级父节点名称
+	 */
+	String TOP_PARENT_NAME = "顶级";
+
+	/**
+	 * 默认密码
+	 */
+	String DEFAULT_PASSWORD = "123456";
+
+}

+ 63 - 0
src/main/java/org/springblade/common/constant/LauncherConstant.java

@@ -0,0 +1,63 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.common.constant;
+
+import org.springblade.core.launch.constant.AppConstant;
+
+/**
+ * 通用常量
+ *
+ * @author Chill
+ */
+public interface LauncherConstant {
+
+	/**
+	 * app name
+	 */
+	String APPLICATION_NAME = AppConstant.APPLICATION_NAME_PREFIX + "api";
+
+	/**
+	 * sentinel dev 地址
+	 */
+	String SENTINEL_DEV_ADDR = "127.0.0.1:8858";
+
+	/**
+	 * sentinel prod 地址
+	 */
+	String SENTINEL_PROD_ADDR = "192.168.186.129:8858";
+
+	/**
+	 * sentinel test 地址
+	 */
+	String SENTINEL_TEST_ADDR = "192.168.186.129:8858";
+
+	/**
+	 * 动态获取sentinel地址
+	 *
+	 * @param profile 环境变量
+	 * @return addr
+	 */
+	static String sentinelAddr(String profile) {
+		switch (profile) {
+			case (AppConstant.PROD_CODE):
+				return SENTINEL_PROD_ADDR;
+			case (AppConstant.TEST_CODE):
+				return SENTINEL_TEST_ADDR;
+			default:
+				return SENTINEL_DEV_ADDR;
+		}
+	}
+}

+ 37 - 0
src/main/java/org/springblade/common/launch/LauncherServiceImpl.java

@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.common.launch;
+
+import org.springblade.common.constant.LauncherConstant;
+import org.springblade.core.launch.service.LauncherService;
+import org.springframework.boot.builder.SpringApplicationBuilder;
+
+import java.util.Properties;
+
+/**
+ * 启动参数拓展
+ *
+ * @author smallchil
+ */
+public class LauncherServiceImpl implements LauncherService {
+
+	@Override
+	public void launcher(SpringApplicationBuilder builder, String appName, String profile) {
+		Properties props = System.getProperties();
+		props.setProperty("spring.cloud.sentinel.transport.dashboard", LauncherConstant.sentinelAddr(profile));
+	}
+
+}

+ 25 - 0
src/main/java/org/springblade/common/tool/CommonUtil.java

@@ -0,0 +1,25 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.common.tool;
+
+/**
+ * 通用工具类
+ *
+ * @author Chill
+ */
+public class CommonUtil {
+
+}

+ 71 - 0
src/main/java/org/springblade/core/log/config/BladeLogToolAutoConfiguration.java

@@ -0,0 +1,71 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springblade.core.log.config;
+
+import lombok.AllArgsConstructor;
+import org.springblade.core.launch.props.BladeProperties;
+import org.springblade.core.launch.server.ServerInfo;
+import org.springblade.core.log.aspect.ApiLogAspect;
+import org.springblade.core.log.event.ApiLogListener;
+import org.springblade.core.log.event.ErrorLogListener;
+import org.springblade.core.log.event.UsualLogListener;
+import org.springblade.core.log.logger.BladeLogger;
+import org.springblade.modules.system.service.ILogService;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 日志工具自动配置
+ *
+ * @author Chill
+ */
+@Configuration(proxyBeanMethods = false)
+@AllArgsConstructor
+@ConditionalOnWebApplication
+public class BladeLogToolAutoConfiguration {
+
+	private final ILogService logService;
+	private final ServerInfo serverInfo;
+	private final BladeProperties bladeProperties;
+
+	@Bean
+	public ApiLogAspect apiLogAspect() {
+		return new ApiLogAspect();
+	}
+
+	@Bean
+	public BladeLogger bladeLogger() {
+		return new BladeLogger();
+	}
+
+	@Bean
+	public ApiLogListener apiLogListener() {
+		return new ApiLogListener(logService, serverInfo, bladeProperties);
+	}
+
+	@Bean
+	public ErrorLogListener errorEventListener() {
+		return new ErrorLogListener(logService, serverInfo, bladeProperties);
+	}
+
+	@Bean
+	public UsualLogListener bladeEventListener() {
+		return new UsualLogListener(logService, serverInfo, bladeProperties);
+	}
+
+}

+ 58 - 0
src/main/java/org/springblade/core/log/event/ApiLogListener.java

@@ -0,0 +1,58 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springblade.core.log.event;
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.core.launch.props.BladeProperties;
+import org.springblade.core.launch.server.ServerInfo;
+import org.springblade.core.log.constant.EventConstant;
+import org.springblade.core.log.model.LogApi;
+import org.springblade.core.log.utils.LogAbstractUtil;
+import org.springblade.modules.system.service.ILogService;
+import org.springframework.context.event.EventListener;
+import org.springframework.core.annotation.Order;
+import org.springframework.scheduling.annotation.Async;
+
+import java.util.Map;
+
+
+/**
+ * 异步监听日志事件
+ *
+ * @author Chill
+ */
+@Slf4j
+@AllArgsConstructor
+public class ApiLogListener {
+
+	private final ILogService logService;
+	private final ServerInfo serverInfo;
+	private final BladeProperties bladeProperties;
+
+
+	@Async
+	@Order
+	@EventListener(ApiLogEvent.class)
+	public void saveApiLog(ApiLogEvent event) {
+		Map<String, Object> source = (Map<String, Object>) event.getSource();
+		LogApi logApi = (LogApi) source.get(EventConstant.EVENT_LOG);
+		LogAbstractUtil.addOtherInfoToLog(logApi, bladeProperties, serverInfo);
+		logService.saveApiLog(logApi);
+	}
+
+}

+ 55 - 0
src/main/java/org/springblade/core/log/event/ErrorLogListener.java

@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.log.event;
+
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.core.launch.props.BladeProperties;
+import org.springblade.core.launch.server.ServerInfo;
+import org.springblade.core.log.constant.EventConstant;
+import org.springblade.core.log.model.LogError;
+import org.springblade.core.log.utils.LogAbstractUtil;
+import org.springblade.modules.system.service.ILogService;
+import org.springframework.context.event.EventListener;
+import org.springframework.core.annotation.Order;
+import org.springframework.scheduling.annotation.Async;
+
+import java.util.Map;
+
+/**
+ * 异步监听错误日志事件
+ *
+ * @author Chill
+ */
+@Slf4j
+@AllArgsConstructor
+public class ErrorLogListener {
+
+	private final ILogService logService;
+	private final ServerInfo serverInfo;
+	private final BladeProperties bladeProperties;
+
+	@Async
+	@Order
+	@EventListener(ErrorLogEvent.class)
+	public void saveErrorLog(ErrorLogEvent event) {
+		Map<String, Object> source = (Map<String, Object>) event.getSource();
+		LogError logError = (LogError) source.get(EventConstant.EVENT_LOG);
+		LogAbstractUtil.addOtherInfoToLog(logError, bladeProperties, serverInfo);
+		logService.saveErrorLog(logError);
+	}
+}

+ 56 - 0
src/main/java/org/springblade/core/log/event/UsualLogListener.java

@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.log.event;
+
+
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springblade.core.launch.props.BladeProperties;
+import org.springblade.core.launch.server.ServerInfo;
+import org.springblade.core.log.constant.EventConstant;
+import org.springblade.core.log.model.LogUsual;
+import org.springblade.core.log.utils.LogAbstractUtil;
+import org.springblade.modules.system.service.ILogService;
+import org.springframework.context.event.EventListener;
+import org.springframework.core.annotation.Order;
+import org.springframework.scheduling.annotation.Async;
+
+import java.util.Map;
+
+/**
+ * 异步监听日志事件
+ *
+ * @author Chill
+ */
+@Slf4j
+@AllArgsConstructor
+public class UsualLogListener {
+
+	private final ILogService logService;
+	private final ServerInfo serverInfo;
+	private final BladeProperties bladeProperties;
+
+	@Async
+	@Order
+	@EventListener(UsualLogEvent.class)
+	public void saveUsualLog(UsualLogEvent event) {
+		Map<String, Object> source = (Map<String, Object>) event.getSource();
+		LogUsual logUsual = (LogUsual) source.get(EventConstant.EVENT_LOG);
+		LogAbstractUtil.addOtherInfoToLog(logUsual, bladeProperties, serverInfo);
+		logService.saveUsualLog(logUsual);
+	}
+
+}

+ 57 - 0
src/main/java/org/springblade/core/secure/AuthInfo.java

@@ -0,0 +1,57 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.gnu.org/licenses/lgpl.html
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.secure;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * AuthInfo
+ *
+ * @author Chill
+ */
+@Data
+@ApiModel(description = "认证信息")
+public class AuthInfo {
+	@ApiModelProperty(value = "令牌")
+	private String accessToken;
+	@ApiModelProperty(value = "令牌类型")
+	private String tokenType;
+	@ApiModelProperty(value = "刷新令牌")
+	private String refreshToken;
+	@ApiModelProperty(value = "用户ID")
+	@JsonSerialize(using = ToStringSerializer.class)
+	private Long userId;
+	@ApiModelProperty(value = "租户ID")
+	private String tenantId;
+	@ApiModelProperty(value = "第三方系统ID")
+	private String oauthId;
+	@ApiModelProperty(value = "头像")
+	private String avatar = "https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png";
+	@ApiModelProperty(value = "角色名")
+	private String authority;
+	@ApiModelProperty(value = "用户名")
+	private String userName;
+	@ApiModelProperty(value = "账号名")
+	private String account;
+	@ApiModelProperty(value = "过期时间")
+	private long expiresIn;
+	@ApiModelProperty(value = "许可证")
+	private String license = "powered by blade";
+}

+ 524 - 0
src/main/java/org/springblade/core/secure/utils/SecureUtil.java

@@ -0,0 +1,524 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.gnu.org/licenses/lgpl.html
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.secure.utils;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.JwtBuilder;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import lombok.SneakyThrows;
+import org.springblade.core.launch.constant.TokenConstant;
+import org.springblade.core.secure.BladeUser;
+import org.springblade.core.secure.TokenInfo;
+import org.springblade.core.secure.constant.SecureConstant;
+import org.springblade.core.secure.exception.SecureException;
+import org.springblade.core.secure.props.BladeTokenProperties;
+import org.springblade.core.secure.provider.IClientDetails;
+import org.springblade.core.secure.provider.IClientDetailsService;
+import org.springblade.core.tool.constant.RoleConstant;
+import org.springblade.core.tool.utils.*;
+
+import javax.crypto.spec.SecretKeySpec;
+import javax.servlet.http.HttpServletRequest;
+import java.security.Key;
+import java.util.*;
+
+/**
+ * Secure工具类
+ *
+ * @author Chill
+ */
+public class SecureUtil {
+	private static final String BLADE_USER_REQUEST_ATTR = "_BLADE_USER_REQUEST_ATTR_";
+
+	private final static String HEADER = TokenConstant.HEADER;
+	private final static String BEARER = TokenConstant.BEARER;
+	private final static String CRYPTO = TokenConstant.CRYPTO;
+	private final static String ACCOUNT = TokenConstant.ACCOUNT;
+	private final static String USER_ID = TokenConstant.USER_ID;
+	private final static String ROLE_ID = TokenConstant.ROLE_ID;
+	private final static String DEPT_ID = TokenConstant.DEPT_ID;
+	private final static String USER_NAME = TokenConstant.USER_NAME;
+	private final static String ROLE_NAME = TokenConstant.ROLE_NAME;
+	private final static String TENANT_ID = TokenConstant.TENANT_ID;
+	private final static String CLIENT_ID = TokenConstant.CLIENT_ID;
+	private final static Integer AUTH_LENGTH = TokenConstant.AUTH_LENGTH;
+	private static IClientDetailsService CLIENT_DETAILS_SERVICE;
+	private static BladeTokenProperties TOKEN_PROPERTIES;
+	private static String BASE64_SECURITY;
+
+
+	/**
+	 * 获取客户端服务类
+	 *
+	 * @return clientDetailsService
+	 */
+	private static IClientDetailsService getClientDetailsService() {
+		if (CLIENT_DETAILS_SERVICE == null) {
+			CLIENT_DETAILS_SERVICE = SpringUtil.getBean(IClientDetailsService.class);
+		}
+		return CLIENT_DETAILS_SERVICE;
+	}
+
+	/**
+	 * 获取配置类
+	 *
+	 * @return jwtProperties
+	 */
+	private static BladeTokenProperties getTokenProperties() {
+		if (TOKEN_PROPERTIES == null) {
+			TOKEN_PROPERTIES = SpringUtil.getBean(BladeTokenProperties.class);
+		}
+		return TOKEN_PROPERTIES;
+	}
+
+	/**
+	 * 获取Token签名
+	 *
+	 * @return String
+	 */
+	private static String getBase64Security() {
+		if (BASE64_SECURITY == null) {
+			BASE64_SECURITY = Base64.getEncoder().encodeToString(getTokenProperties().getSignKey().getBytes(Charsets.UTF_8));
+		}
+		return BASE64_SECURITY;
+	}
+
+	/**
+	 * 获取用户信息
+	 *
+	 * @return BladeUser
+	 */
+	public static BladeUser getUser() {
+		HttpServletRequest request = WebUtil.getRequest();
+		if (request == null) {
+			return null;
+		}
+		// 优先从 request 中获取
+		Object bladeUser = request.getAttribute(BLADE_USER_REQUEST_ATTR);
+		if (bladeUser == null) {
+			bladeUser = getUser(request);
+			if (bladeUser != null) {
+				// 设置到 request 中
+				request.setAttribute(BLADE_USER_REQUEST_ATTR, bladeUser);
+			}
+		}
+		return (BladeUser) bladeUser;
+	}
+
+	/**
+	 * 获取用户信息
+	 *
+	 * @param request request
+	 * @return BladeUser
+	 */
+	public static BladeUser getUser(HttpServletRequest request) {
+		Claims claims = getClaims(request);
+		if (claims == null) {
+			return null;
+		}
+		String clientId = Func.toStr(claims.get(SecureUtil.CLIENT_ID));
+		Long userId = Func.toLong(claims.get(SecureUtil.USER_ID));
+		String tenantId = Func.toStr(claims.get(SecureUtil.TENANT_ID));
+		String roleId = Func.toStr(claims.get(SecureUtil.ROLE_ID));
+		String deptId = Func.toStr(claims.get(SecureUtil.DEPT_ID));
+		String account = Func.toStr(claims.get(SecureUtil.ACCOUNT));
+		String roleName = Func.toStr(claims.get(SecureUtil.ROLE_NAME));
+		String userName = Func.toStr(claims.get(SecureUtil.USER_NAME));
+		BladeUser bladeUser = new BladeUser();
+		bladeUser.setClientId(clientId);
+		bladeUser.setUserId(userId);
+		bladeUser.setTenantId(tenantId);
+		bladeUser.setAccount(account);
+		bladeUser.setRoleId(roleId);
+		bladeUser.setDeptId(deptId);
+		bladeUser.setRoleName(roleName);
+		bladeUser.setUserName(userName);
+		return bladeUser;
+	}
+
+	/**
+	 * 是否为超管
+	 *
+	 * @return boolean
+	 */
+	public static boolean isAdministrator() {
+		return StringUtil.containsAny(getUserRole(), RoleConstant.ADMIN);
+	}
+
+	/**
+	 * 获取用户id
+	 *
+	 * @return userId
+	 */
+	public static Long getUserId() {
+		BladeUser user = getUser();
+		return (null == user) ? -1 : user.getUserId();
+	}
+
+	/**
+	 * 获取用户id
+	 *
+	 * @param request request
+	 * @return userId
+	 */
+	public static Long getUserId(HttpServletRequest request) {
+		BladeUser user = getUser(request);
+		return (null == user) ? -1 : user.getUserId();
+	}
+
+	/**
+	 * 获取用户账号
+	 *
+	 * @return userAccount
+	 */
+	public static String getUserAccount() {
+		BladeUser user = getUser();
+		return (null == user) ? StringPool.EMPTY : user.getAccount();
+	}
+
+	/**
+	 * 获取用户账号
+	 *
+	 * @param request request
+	 * @return userAccount
+	 */
+	public static String getUserAccount(HttpServletRequest request) {
+		BladeUser user = getUser(request);
+		return (null == user) ? StringPool.EMPTY : user.getAccount();
+	}
+
+	/**
+	 * 获取用户名
+	 *
+	 * @return userName
+	 */
+	public static String getUserName() {
+		BladeUser user = getUser();
+		return (null == user) ? StringPool.EMPTY : user.getUserName();
+	}
+
+	/**
+	 * 获取用户名
+	 *
+	 * @param request request
+	 * @return userName
+	 */
+	public static String getUserName(HttpServletRequest request) {
+		BladeUser user = getUser(request);
+		return (null == user) ? StringPool.EMPTY : user.getUserName();
+	}
+
+	/**
+	 * 获取用户角色
+	 *
+	 * @return userName
+	 */
+	public static String getUserRole() {
+		BladeUser user = getUser();
+		return (null == user) ? StringPool.EMPTY : user.getRoleName();
+	}
+
+	/**
+	 * 获取用角色
+	 *
+	 * @param request request
+	 * @return userName
+	 */
+	public static String getUserRole(HttpServletRequest request) {
+		BladeUser user = getUser(request);
+		return (null == user) ? StringPool.EMPTY : user.getRoleName();
+	}
+
+	/**
+	 * 获取租户ID
+	 *
+	 * @return tenantId
+	 */
+	public static String getTenantId() {
+		BladeUser user = getUser();
+		return (null == user) ? StringPool.EMPTY : user.getTenantId();
+	}
+
+	/**
+	 * 获取租户ID
+	 *
+	 * @param request request
+	 * @return tenantId
+	 */
+	public static String getTenantId(HttpServletRequest request) {
+		BladeUser user = getUser(request);
+		return (null == user) ? StringPool.EMPTY : user.getTenantId();
+	}
+
+	/**
+	 * 获取客户端id
+	 *
+	 * @return tenantId
+	 */
+	public static String getClientId() {
+		BladeUser user = getUser();
+		return (null == user) ? StringPool.EMPTY : user.getClientId();
+	}
+
+	/**
+	 * 获取客户端id
+	 *
+	 * @param request request
+	 * @return tenantId
+	 */
+	public static String getClientId(HttpServletRequest request) {
+		BladeUser user = getUser(request);
+		return (null == user) ? StringPool.EMPTY : user.getClientId();
+	}
+
+	/**
+	 * 获取Claims
+	 *
+	 * @param request request
+	 * @return Claims
+	 */
+	public static Claims getClaims(HttpServletRequest request) {
+		String auth = request.getHeader(SecureUtil.HEADER);
+		String token = getToken(
+			StringUtil.isNotBlank(auth) ? auth : request.getParameter(SecureUtil.HEADER)
+		);
+		return SecureUtil.parseJWT(token);
+	}
+
+	/**
+	 * 获取请求传递的token串
+	 *
+	 * @param auth token
+	 * @return String
+	 */
+	public static String getToken(String auth) {
+		if (isBearer(auth)) {
+			return auth.substring(AUTH_LENGTH);
+		}
+		if (isCrypto(auth)) {
+			return AesUtil.decryptFormBase64ToString(auth.substring(AUTH_LENGTH), getTokenProperties().getAesKey());
+		}
+		return null;
+	}
+
+	/**
+	 * 判断token类型为bearer
+	 *
+	 * @param auth token
+	 * @return String
+	 */
+	public static Boolean isBearer(String auth) {
+		if ((auth != null) && (auth.length() > AUTH_LENGTH)) {
+			String headStr = auth.substring(0, 6).toLowerCase();
+			return headStr.compareTo(BEARER) == 0;
+		}
+		return false;
+	}
+
+	/**
+	 * 判断token类型为crypto
+	 *
+	 * @param auth token
+	 * @return String
+	 */
+	public static Boolean isCrypto(String auth) {
+		if ((auth != null) && (auth.length() > AUTH_LENGTH)) {
+			String headStr = auth.substring(0, 6).toLowerCase();
+			return headStr.compareTo(CRYPTO) == 0;
+		}
+		return false;
+	}
+
+	/**
+	 * 获取请求头
+	 *
+	 * @return header
+	 */
+	public static String getHeader() {
+		return getHeader(Objects.requireNonNull(WebUtil.getRequest()));
+	}
+
+	/**
+	 * 获取请求头
+	 *
+	 * @param request request
+	 * @return header
+	 */
+	public static String getHeader(HttpServletRequest request) {
+		return request.getHeader(HEADER);
+	}
+
+	/**
+	 * 解析jsonWebToken
+	 *
+	 * @param jsonWebToken jsonWebToken
+	 * @return Claims
+	 */
+	public static Claims parseJWT(String jsonWebToken) {
+		try {
+			return Jwts.parserBuilder()
+				.setSigningKey(Base64.getDecoder().decode(getBase64Security())).build()
+				.parseClaimsJws(jsonWebToken).getBody();
+		} catch (Exception ex) {
+			return null;
+		}
+	}
+
+	/**
+	 * 创建令牌
+	 *
+	 * @param user      user
+	 * @param audience  audience
+	 * @param issuer    issuer
+	 * @param tokenType tokenType
+	 * @return jwt
+	 */
+	public static TokenInfo createJWT(Map<String, String> user, String audience, String issuer, String tokenType) {
+
+		String[] tokens = extractAndDecodeHeader();
+		assert tokens.length == 2;
+		String clientId = tokens[0];
+		String clientSecret = tokens[1];
+
+		// 获取客户端信息
+		IClientDetails clientDetails = clientDetails(clientId);
+
+		// 校验客户端信息
+		if (!validateClient(clientDetails, clientId, clientSecret)) {
+			throw new SecureException("客户端认证失败!");
+		}
+
+		SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
+
+		long nowMillis = System.currentTimeMillis();
+		Date now = new Date(nowMillis);
+
+		//生成签名密钥
+		byte[] apiKeySecretBytes = Base64.getDecoder().decode(getBase64Security());
+		Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
+
+		//添加构成JWT的类
+		JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT")
+			.setIssuer(issuer)
+			.setAudience(audience)
+			.signWith(signingKey);
+
+		//设置JWT参数
+		user.forEach(builder::claim);
+
+		//设置应用id
+		builder.claim(CLIENT_ID, clientId);
+
+		//添加Token过期时间
+		long expireMillis;
+		if (tokenType.equals(TokenConstant.ACCESS_TOKEN)) {
+			expireMillis = clientDetails.getAccessTokenValidity() * 1000;
+		} else if (tokenType.equals(TokenConstant.REFRESH_TOKEN)) {
+			expireMillis = clientDetails.getRefreshTokenValidity() * 1000;
+		} else {
+			expireMillis = getExpire();
+		}
+		long expMillis = nowMillis + expireMillis;
+		Date exp = new Date(expMillis);
+		builder.setExpiration(exp).setNotBefore(now);
+
+		// 组装Token信息
+		TokenInfo tokenInfo = new TokenInfo();
+		tokenInfo.setToken(builder.compact());
+		tokenInfo.setExpire((int) expireMillis / 1000);
+
+		return tokenInfo;
+	}
+
+	/**
+	 * 获取过期时间(次日凌晨3点)
+	 *
+	 * @return expire
+	 */
+	public static long getExpire() {
+		Calendar cal = Calendar.getInstance();
+		cal.add(Calendar.DAY_OF_YEAR, 1);
+		cal.set(Calendar.HOUR_OF_DAY, 3);
+		cal.set(Calendar.SECOND, 0);
+		cal.set(Calendar.MINUTE, 0);
+		cal.set(Calendar.MILLISECOND, 0);
+		return cal.getTimeInMillis() - System.currentTimeMillis();
+	}
+
+	/**
+	 * 客户端信息解码
+	 */
+	@SneakyThrows
+	public static String[] extractAndDecodeHeader() {
+		// 获取请求头客户端信息
+		String header = Objects.requireNonNull(WebUtil.getRequest()).getHeader(SecureConstant.BASIC_HEADER_KEY);
+		header = Func.toStr(header).replace(SecureConstant.BASIC_HEADER_PREFIX_EXT, SecureConstant.BASIC_HEADER_PREFIX);
+		if (!header.startsWith(SecureConstant.BASIC_HEADER_PREFIX)) {
+			throw new SecureException("No client information in request header");
+		}
+		byte[] base64Token = header.substring(6).getBytes(Charsets.UTF_8_NAME);
+
+		byte[] decoded;
+		try {
+			decoded = Base64.getDecoder().decode(base64Token);
+		} catch (IllegalArgumentException var7) {
+			throw new RuntimeException("Failed to decode basic authentication token");
+		}
+
+		String token = new String(decoded, Charsets.UTF_8_NAME);
+		int index = token.indexOf(StringPool.COLON);
+		if (index == -1) {
+			throw new RuntimeException("Invalid basic authentication token");
+		} else {
+			return new String[]{token.substring(0, index), token.substring(index + 1)};
+		}
+	}
+
+	/**
+	 * 获取请求头中的客户端id
+	 */
+	public static String getClientIdFromHeader() {
+		String[] tokens = extractAndDecodeHeader();
+		assert tokens.length == 2;
+		return tokens[0];
+	}
+
+	/**
+	 * 获取客户端信息
+	 *
+	 * @param clientId 客户端id
+	 * @return clientDetails
+	 */
+	private static IClientDetails clientDetails(String clientId) {
+		return getClientDetailsService().loadClientByClientId(clientId);
+	}
+
+	/**
+	 * 校验Client
+	 *
+	 * @param clientId     客户端id
+	 * @param clientSecret 客户端密钥
+	 * @return boolean
+	 */
+	private static boolean validateClient(IClientDetails clientDetails, String clientId, String clientSecret) {
+		if (clientDetails != null) {
+			return StringUtil.equals(clientId, clientDetails.getClientId()) && StringUtil.equals(clientSecret, clientDetails.getClientSecret());
+		}
+		return false;
+	}
+
+}

+ 100 - 0
src/main/java/org/springblade/modules/auth/controller/AuthController.java

@@ -0,0 +1,100 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.auth.controller;
+
+import com.wf.captcha.SpecCaptcha;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.AllArgsConstructor;
+import org.springblade.common.cache.CacheNames;
+import org.springblade.core.secure.AuthInfo;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.support.Kv;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.RedisUtil;
+import org.springblade.core.tool.utils.WebUtil;
+import org.springblade.modules.auth.granter.ITokenGranter;
+import org.springblade.modules.auth.granter.TokenGranterBuilder;
+import org.springblade.modules.auth.granter.TokenParameter;
+import org.springblade.modules.auth.utils.TokenUtil;
+import org.springblade.modules.system.entity.UserInfo;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.UUID;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 认证模块
+ *
+ * @author Chill
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("blade-auth")
+@Api(value = "用户授权认证", tags = "授权接口")
+public class AuthController {
+
+	private RedisUtil redisUtil;
+
+	@PostMapping("token")
+	@ApiOperation(value = "获取认证token", notes = "传入租户ID:tenantId,账号:account,密码:password")
+	public R<AuthInfo> token(@ApiParam(value = "授权类型", required = true) @RequestParam(defaultValue = "password", required = false) String grantType,
+							 @ApiParam(value = "刷新令牌") @RequestParam(required = false) String refreshToken,
+							 @ApiParam(value = "租户ID", required = true) @RequestParam(defaultValue = "000000", required = false) String tenantId,
+							 @ApiParam(value = "账号") @RequestParam(required = false) String account,
+							 @ApiParam(value = "密码") @RequestParam(required = false) String password) {
+
+		String userType = Func.toStr(WebUtil.getRequest().getHeader(TokenUtil.USER_TYPE_HEADER_KEY), TokenUtil.DEFAULT_USER_TYPE);
+
+		TokenParameter tokenParameter = new TokenParameter();
+		tokenParameter.getArgs().set("tenantId", tenantId)
+			.set("account", account)
+			.set("password", password)
+			.set("grantType", grantType)
+			.set("refreshToken", refreshToken)
+			.set("userType", userType);
+
+		ITokenGranter granter = TokenGranterBuilder.getGranter(grantType);
+		UserInfo userInfo = granter.grant(tokenParameter);
+
+		if (userInfo == null || userInfo.getUser() == null) {
+			return R.fail(TokenUtil.USER_NOT_FOUND);
+		}
+
+		return R.data(TokenUtil.createAuthInfo(userInfo));
+	}
+
+	@GetMapping("/captcha")
+	@ApiOperation(value = "获取验证码")
+	public R<Kv> captcha() {
+		SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
+		String verCode = specCaptcha.text().toLowerCase();
+		String key = UUID.randomUUID().toString();
+		// 存入redis并设置过期时间为30分钟
+		redisUtil.set(CacheNames.CAPTCHA_KEY + key, verCode, 30L, TimeUnit.MINUTES);
+		// 将key和base64返回给前端
+		return R.data(Kv.init().set("key", key).set("image", specCaptcha.toBase64()));
+	}
+
+	@PostMapping("/logout")
+	@ApiOperation(value = "登出")
+	public R<Kv> logout() {
+		// 登出预留逻辑
+		return R.data(Kv.init().set("code", "200").set("msg", "操作成功"));
+	}
+
+}

+ 94 - 0
src/main/java/org/springblade/modules/auth/controller/SocialController.java

@@ -0,0 +1,94 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.auth.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import me.zhyd.oauth.model.AuthCallback;
+import me.zhyd.oauth.model.AuthToken;
+import me.zhyd.oauth.request.AuthRequest;
+import me.zhyd.oauth.utils.AuthStateUtils;
+import org.springblade.core.launch.constant.AppConstant;
+import org.springblade.core.social.props.SocialProperties;
+import org.springblade.core.social.utils.SocialUtil;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * 第三方登陆端点
+ *
+ * @author Chill
+ */
+@Slf4j
+@RestController
+@AllArgsConstructor
+@RequestMapping(AppConstant.APPLICATION_AUTH_NAME)
+@ConditionalOnProperty(value = "social.enabled", havingValue = "true")
+@Api(value = "第三方登陆", tags = "第三方登陆端点")
+public class SocialController {
+
+	private final SocialProperties socialProperties;
+
+	/**
+	 * 授权完毕跳转
+	 */
+	@ApiOperation(value = "授权完毕跳转")
+	@RequestMapping("/oauth/render/{source}")
+	public void renderAuth(@PathVariable("source") String source, HttpServletResponse response) throws IOException {
+		AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties);
+		String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
+		response.sendRedirect(authorizeUrl);
+	}
+
+	/**
+	 * 获取认证信息
+	 */
+	@ApiOperation(value = "获取认证信息")
+	@RequestMapping("/oauth/callback/{source}")
+	public Object login(@PathVariable("source") String source, AuthCallback callback) {
+		AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties);
+		return authRequest.login(callback);
+	}
+
+	/**
+	 * 撤销授权
+	 */
+	@ApiOperation(value = "撤销授权")
+	@RequestMapping("/oauth/revoke/{source}/{token}")
+	public Object revokeAuth(@PathVariable("source") String source, @PathVariable("token") String token) {
+		AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties);
+		return authRequest.revoke(AuthToken.builder().accessToken(token).build());
+	}
+
+	/**
+	 * 续期accessToken
+	 */
+	@ApiOperation(value = "续期令牌")
+	@RequestMapping("/oauth/refresh/{source}")
+	public Object refreshAuth(@PathVariable("source") String source, String token) {
+		AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties);
+		return authRequest.refresh(AuthToken.builder().refreshToken(token).build());
+	}
+
+
+}

+ 44 - 0
src/main/java/org/springblade/modules/auth/enums/BladeUserEnum.java

@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.auth.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 用户类型枚举
+ *
+ * @author Chill
+ */
+@Getter
+@AllArgsConstructor
+public enum BladeUserEnum {
+
+	/**
+	 * web
+	 */
+	WEB("web", 1),
+
+	/**
+	 * app
+	 */
+	APP("app", 2),
+	;
+
+	final String name;
+	final int category;
+
+}

+ 76 - 0
src/main/java/org/springblade/modules/auth/granter/CaptchaTokenGranter.java

@@ -0,0 +1,76 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.auth.granter;
+
+import lombok.AllArgsConstructor;
+import org.springblade.common.cache.CacheNames;
+import org.springblade.core.log.exception.ServiceException;
+import org.springblade.core.tool.utils.*;
+import org.springblade.modules.auth.enums.BladeUserEnum;
+import org.springblade.modules.auth.utils.TokenUtil;
+import org.springblade.modules.system.entity.UserInfo;
+import org.springblade.modules.system.service.IUserService;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * 验证码TokenGranter
+ *
+ * @author Chill
+ */
+@Component
+@AllArgsConstructor
+public class CaptchaTokenGranter implements ITokenGranter {
+
+	public static final String GRANT_TYPE = "captcha";
+
+	private IUserService userService;
+	private RedisUtil redisUtil;
+
+	@Override
+	public UserInfo grant(TokenParameter tokenParameter) {
+		HttpServletRequest request = WebUtil.getRequest();
+
+		String key = request.getHeader(TokenUtil.CAPTCHA_HEADER_KEY);
+		String code = request.getHeader(TokenUtil.CAPTCHA_HEADER_CODE);
+		// 获取验证码
+		String redisCode = String.valueOf(redisUtil.get(CacheNames.CAPTCHA_KEY + key));
+		// 判断验证码
+		if (code == null || !StringUtil.equalsIgnoreCase(redisCode, code)) {
+			throw new ServiceException(TokenUtil.CAPTCHA_NOT_CORRECT);
+		}
+
+		String tenantId = tokenParameter.getArgs().getStr("tenantId");
+		String account = tokenParameter.getArgs().getStr("account");
+		String password = tokenParameter.getArgs().getStr("password");
+		UserInfo userInfo = null;
+		if (Func.isNoneBlank(account, password)) {
+			// 获取用户类型
+			String userType = tokenParameter.getArgs().getStr("userType");
+			// 根据不同用户类型调用对应的接口返回数据,用户可自行拓展
+			if (userType.equals(BladeUserEnum.WEB.getName())) {
+				userInfo = userService.userInfo(tenantId, account, DigestUtil.encrypt(password));
+			} else if (userType.equals(BladeUserEnum.APP.getName())) {
+				userInfo = userService.userInfo(tenantId, account, DigestUtil.encrypt(password));
+			} else {
+				userInfo = userService.userInfo(tenantId, account, DigestUtil.encrypt(password));
+			}
+		}
+		return userInfo;
+	}
+
+}

+ 36 - 0
src/main/java/org/springblade/modules/auth/granter/ITokenGranter.java

@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.auth.granter;
+
+
+import org.springblade.modules.system.entity.UserInfo;
+
+/**
+ * 授权认证统一接口.
+ *
+ * @author Chill
+ */
+public interface ITokenGranter {
+
+	/**
+	 * 获取用户信息
+	 *
+	 * @param tokenParameter 授权参数
+	 * @return UserInfo
+	 */
+	UserInfo grant(TokenParameter tokenParameter);
+
+}

+ 60 - 0
src/main/java/org/springblade/modules/auth/granter/PasswordTokenGranter.java

@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.auth.granter;
+
+import lombok.AllArgsConstructor;
+import org.springblade.core.tool.utils.DigestUtil;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.modules.auth.enums.BladeUserEnum;
+import org.springblade.modules.system.entity.UserInfo;
+import org.springblade.modules.system.service.IUserService;
+import org.springframework.stereotype.Component;
+
+/**
+ * PasswordTokenGranter
+ *
+ * @author Chill
+ */
+@Component
+@AllArgsConstructor
+public class PasswordTokenGranter implements ITokenGranter {
+
+	public static final String GRANT_TYPE = "password";
+
+	private IUserService userService;
+
+	@Override
+	public UserInfo grant(TokenParameter tokenParameter) {
+		String tenantId = tokenParameter.getArgs().getStr("tenantId");
+		String account = tokenParameter.getArgs().getStr("account");
+		String password = tokenParameter.getArgs().getStr("password");
+		UserInfo userInfo = null;
+		if (Func.isNoneBlank(account, password)) {
+			// 获取用户类型
+			String userType = tokenParameter.getArgs().getStr("userType");
+			// 根据不同用户类型调用对应的接口返回数据,用户可自行拓展
+			if (userType.equals(BladeUserEnum.WEB.getName())) {
+				userInfo = userService.userInfo(tenantId, account, DigestUtil.encrypt(password));
+			} else if (userType.equals(BladeUserEnum.APP.getName())) {
+				userInfo = userService.userInfo(tenantId, account, DigestUtil.encrypt(password));
+			} else {
+				userInfo = userService.userInfo(tenantId, account, DigestUtil.encrypt(password));
+			}
+		}
+		return userInfo;
+	}
+
+}

+ 56 - 0
src/main/java/org/springblade/modules/auth/granter/RefreshTokenGranter.java

@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.auth.granter;
+
+import io.jsonwebtoken.Claims;
+import lombok.AllArgsConstructor;
+import org.springblade.core.launch.constant.TokenConstant;
+import org.springblade.core.secure.utils.SecureUtil;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.modules.system.entity.UserInfo;
+import org.springblade.modules.system.service.IUserService;
+import org.springframework.stereotype.Component;
+
+import java.util.Objects;
+
+/**
+ * RefreshTokenGranter
+ *
+ * @author Chill
+ */
+@Component
+@AllArgsConstructor
+public class RefreshTokenGranter implements ITokenGranter {
+
+	public static final String GRANT_TYPE = "refresh_token";
+
+	private IUserService userService;
+
+	@Override
+	public UserInfo grant(TokenParameter tokenParameter) {
+		String grantType = tokenParameter.getArgs().getStr("grantType");
+		String refreshToken = tokenParameter.getArgs().getStr("refreshToken");
+		UserInfo userInfo = null;
+		if (Func.isNoneBlank(grantType, refreshToken) && grantType.equals(TokenConstant.REFRESH_TOKEN)) {
+			Claims claims = SecureUtil.parseJWT(refreshToken);
+			String tokenType = Func.toStr(Objects.requireNonNull(claims).get(TokenConstant.TOKEN_TYPE));
+			if (tokenType.equals(TokenConstant.REFRESH_TOKEN)) {
+				userInfo= userService.userInfo(Func.toLong(claims.get(TokenConstant.USER_ID)));
+			}
+		}
+		return userInfo;
+	}
+}

+ 89 - 0
src/main/java/org/springblade/modules/auth/granter/SocialTokenGranter.java

@@ -0,0 +1,89 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.auth.granter;
+
+import lombok.AllArgsConstructor;
+import me.zhyd.oauth.model.AuthCallback;
+import me.zhyd.oauth.model.AuthResponse;
+import me.zhyd.oauth.model.AuthUser;
+import me.zhyd.oauth.request.AuthRequest;
+import org.springblade.core.log.exception.ServiceException;
+import org.springblade.core.social.props.SocialProperties;
+import org.springblade.core.social.utils.SocialUtil;
+import org.springblade.core.tool.utils.BeanUtil;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.WebUtil;
+import org.springblade.modules.auth.utils.TokenUtil;
+import org.springblade.modules.system.entity.UserInfo;
+import org.springblade.modules.system.entity.UserOauth;
+import org.springblade.modules.system.service.IUserService;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Objects;
+
+/**
+ * SocialTokenGranter
+ *
+ * @author Chill
+ */
+@Component
+@AllArgsConstructor
+public class SocialTokenGranter implements ITokenGranter {
+
+	public static final String GRANT_TYPE = "social";
+
+	private static final Integer AUTH_SUCCESS_CODE = 2000;
+
+	private final IUserService userService;
+	private final SocialProperties socialProperties;
+
+	@Override
+	public UserInfo grant(TokenParameter tokenParameter) {
+		HttpServletRequest request = WebUtil.getRequest();
+		String tenantId = Func.toStr(request.getHeader(TokenUtil.TENANT_HEADER_KEY), TokenUtil.DEFAULT_TENANT_ID);
+		// 开放平台来源
+		String sourceParameter = request.getParameter("source");
+		// 匹配是否有别名定义
+		String source = socialProperties.getAlias().getOrDefault(sourceParameter, sourceParameter);
+		// 开放平台授权码
+		String code = request.getParameter("code");
+		// 开放平台状态吗
+		String state = request.getParameter("state");
+
+		// 获取开放平台授权数据
+		AuthRequest authRequest = SocialUtil.getAuthRequest(source, socialProperties);
+		AuthCallback authCallback = new AuthCallback();
+		authCallback.setCode(code);
+		authCallback.setState(state);
+		AuthResponse authResponse = authRequest.login(authCallback);
+		AuthUser authUser;
+		if (authResponse.getCode() == AUTH_SUCCESS_CODE) {
+			authUser = (AuthUser) authResponse.getData();
+		} else {
+			throw new ServiceException("social grant failure, auth response is not success");
+		}
+
+		// 组装数据
+		UserOauth userOauth = Objects.requireNonNull(BeanUtil.copy(authUser, UserOauth.class));
+		userOauth.setSource(authUser.getSource());
+		userOauth.setTenantId(tenantId);
+		userOauth.setUuid(authUser.getUuid());
+		// 返回UserInfo
+		return userService.userInfo(userOauth);
+	}
+
+}

+ 61 - 0
src/main/java/org/springblade/modules/auth/granter/TokenGranterBuilder.java

@@ -0,0 +1,61 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.auth.granter;
+
+import lombok.AllArgsConstructor;
+import org.springblade.core.secure.exception.SecureException;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.SpringUtil;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * TokenGranterBuilder
+ *
+ * @author Chill
+ */
+@AllArgsConstructor
+public class TokenGranterBuilder {
+
+	/**
+	 * TokenGranter缓存池
+	 */
+	private static final Map<String, ITokenGranter> GRANTER_POOL = new ConcurrentHashMap<>();
+
+	static {
+		GRANTER_POOL.put(PasswordTokenGranter.GRANT_TYPE, SpringUtil.getBean(PasswordTokenGranter.class));
+		GRANTER_POOL.put(CaptchaTokenGranter.GRANT_TYPE, SpringUtil.getBean(CaptchaTokenGranter.class));
+		GRANTER_POOL.put(RefreshTokenGranter.GRANT_TYPE, SpringUtil.getBean(RefreshTokenGranter.class));
+		GRANTER_POOL.put(SocialTokenGranter.GRANT_TYPE, SpringUtil.getBean(SocialTokenGranter.class));
+	}
+
+	/**
+	 * 获取TokenGranter
+	 *
+	 * @param grantType 授权类型
+	 * @return ITokenGranter
+	 */
+	public static ITokenGranter getGranter(String grantType) {
+		ITokenGranter tokenGranter = GRANTER_POOL.get(Func.toStr(grantType, PasswordTokenGranter.GRANT_TYPE));
+		if (tokenGranter == null) {
+			throw new SecureException("no grantType was found");
+		} else {
+			return tokenGranter;
+		}
+	}
+
+}

+ 31 - 0
src/main/java/org/springblade/modules/auth/granter/TokenParameter.java

@@ -0,0 +1,31 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.auth.granter;
+
+import lombok.Data;
+import org.springblade.core.tool.support.Kv;
+
+/**
+ * TokenParameter
+ *
+ * @author Chill
+ */
+@Data
+public class TokenParameter {
+
+	private Kv args = Kv.init();
+
+}

+ 100 - 0
src/main/java/org/springblade/modules/auth/utils/TokenUtil.java

@@ -0,0 +1,100 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.auth.utils;
+
+import org.springblade.core.launch.constant.TokenConstant;
+import org.springblade.core.secure.AuthInfo;
+import org.springblade.core.secure.TokenInfo;
+import org.springblade.core.secure.utils.SecureUtil;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.modules.system.entity.User;
+import org.springblade.modules.system.entity.UserInfo;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 认证工具类
+ *
+ * @author Chill
+ */
+public class TokenUtil {
+
+	public final static String CAPTCHA_HEADER_KEY = "Captcha-Key";
+	public final static String CAPTCHA_HEADER_CODE = "Captcha-Code";
+	public final static String CAPTCHA_NOT_CORRECT = "验证码不正确";
+	public final static String TENANT_HEADER_KEY = "Tenant-Id";
+	public final static String DEFAULT_TENANT_ID = "000000";
+	public final static String USER_TYPE_HEADER_KEY = "User-Type";
+	public final static String DEFAULT_USER_TYPE = "web";
+	public final static String USER_NOT_FOUND = "用户名或密码错误";
+	public final static String HEADER_KEY = "Authorization";
+	public final static String HEADER_PREFIX = "Basic ";
+	public final static String DEFAULT_AVATAR = "https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png";
+
+	/**
+	 * 创建认证token
+	 *
+	 * @param userInfo 用户信息
+	 * @return token
+	 */
+	public static AuthInfo createAuthInfo(UserInfo userInfo) {
+		User user = userInfo.getUser();
+
+		//设置jwt参数
+		Map<String, String> param = new HashMap<>(16);
+		param.put(TokenConstant.TOKEN_TYPE, TokenConstant.ACCESS_TOKEN);
+		param.put(TokenConstant.TENANT_ID, user.getTenantId());
+		param.put(TokenConstant.OAUTH_ID, userInfo.getOauthId());
+		param.put(TokenConstant.USER_ID, Func.toStr(user.getId()));
+		param.put(TokenConstant.ROLE_ID, user.getRoleId());
+		param.put(TokenConstant.DEPT_ID, user.getDeptId());
+		param.put(TokenConstant.ACCOUNT, user.getAccount());
+		param.put(TokenConstant.USER_NAME, user.getAccount());
+		param.put(TokenConstant.ROLE_NAME, Func.join(userInfo.getRoles()));
+
+		TokenInfo accessToken = SecureUtil.createJWT(param, "audience", "issuser", TokenConstant.ACCESS_TOKEN);
+		AuthInfo authInfo = new AuthInfo();
+		authInfo.setUserId(user.getId());
+		authInfo.setTenantId(user.getTenantId());
+		authInfo.setOauthId(userInfo.getOauthId());
+		authInfo.setAccount(user.getAccount());
+		authInfo.setUserName(user.getRealName());
+		authInfo.setAuthority(Func.join(userInfo.getRoles()));
+		authInfo.setAccessToken(accessToken.getToken());
+		authInfo.setExpiresIn(accessToken.getExpire());
+		authInfo.setRefreshToken(createRefreshToken(userInfo).getToken());
+		authInfo.setTokenType(TokenConstant.BEARER);
+		authInfo.setLicense(TokenConstant.LICENSE_NAME);
+
+		return authInfo;
+	}
+
+	/**
+	 * 创建refreshToken
+	 *
+	 * @param userInfo 用户信息
+	 * @return refreshToken
+	 */
+	private static TokenInfo createRefreshToken(UserInfo userInfo) {
+		User user = userInfo.getUser();
+		Map<String, String> param = new HashMap<>(16);
+		param.put(TokenConstant.TOKEN_TYPE, TokenConstant.REFRESH_TOKEN);
+		param.put(TokenConstant.USER_ID, Func.toStr(user.getId()));
+		return SecureUtil.createJWT(param, "audience", "issuser", TokenConstant.REFRESH_TOKEN);
+	}
+
+}

+ 180 - 0
src/main/java/org/springblade/modules/desk/controller/DashBoardController.java

@@ -0,0 +1,180 @@
+package org.springblade.modules.desk.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.AllArgsConstructor;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.support.Kv;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import springfox.documentation.annotations.ApiIgnore;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 首页
+ *
+ * @author zhuangqian
+ */
+@ApiIgnore
+@RestController
+@RequestMapping("/blade-desk/dashboard")
+@AllArgsConstructor
+@Api(value = "首页", tags = "首页")
+public class DashBoardController {
+
+	/**
+	 * 活跃用户
+	 *
+	 * @return
+	 */
+	@GetMapping("/activities")
+	@ApiOperation(value = "活跃用户", notes = "活跃用户")
+	public R activities() {
+
+		List<Map<String, Object>> list = new ArrayList<>();
+		Map<String, Object> map1 = new HashMap<>(16);
+		map1.put("id", "trend-1");
+		map1.put("updatedAt", "2019-01-01");
+		map1.put("user", Kv.init().set("name", "曲丽丽").set("avatar", "https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png"));
+		map1.put("group", Kv.init().set("name", "高逼格设计天团").set("link", "http://github.com/"));
+		map1.put("project", Kv.init().set("name", "六月迭代").set("link", "http://github.com/"));
+		map1.put("template", "在 @{group} 新建项目 @{project}");
+		list.add(map1);
+
+		Map<String, Object> map2 = new HashMap<>(16);
+		map2.put("id", "trend-2");
+		map2.put("updatedAt", "2019-01-01");
+		map2.put("user", Kv.init().set("name", "付小小").set("avatar", "https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png"));
+		map2.put("group", Kv.init().set("name", "高逼格设计天团").set("link", "http://github.com/"));
+		map2.put("project", Kv.init().set("name", "七月月迭代").set("link", "http://github.com/"));
+		map2.put("template", "在  @{group} 新建项目 @{project}");
+		list.add(map2);
+
+		return R.data(list);
+	}
+
+	/**
+	 * 获取消息
+	 *
+	 * @return
+	 */
+	@GetMapping("/notices")
+	@ApiOperation(value = "消息", notes = "消息")
+	public R notices() {
+		List<Map<String, String>> list = new ArrayList<>();
+		Map<String, String> map1 = new HashMap<>(16);
+		map1.put("logo", "https://spring.io/img/homepage/icon-spring-framework.svg");
+		map1.put("title", "SpringBoot");
+		map1.put("description", "现在的web项目几乎都会用到spring框架,而要使用spring难免需要配置大量的xml配置文件,而 springboot的出现解   决了这一问题,一个项目甚至不用部署到服务器上直接开跑,真像springboot所说:“just run”。");
+		map1.put("member", "Chill");
+		map1.put("href", "http://spring.io/projects/spring-boot");
+		list.add(map1);
+
+		Map<String, String> map2 = new HashMap<>(16);
+		map2.put("logo", "https://spring.io/img/homepage/icon-spring-cloud.svg");
+		map2.put("title", "SpringCloud");
+		map2.put("description", "SpringCloud是基于SpringBoot的一整套实现微服务的框架。他提供了微服务开发所需的配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等组件。");
+		map2.put("member", "Chill");
+		map2.put("href", "http://spring.io/projects/spring-cloud");
+		list.add(map2);
+
+		Map<String, String> map3 = new HashMap<>(16);
+		map3.put("logo", "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1546359961068&di=05ff9406e6675ca9a58a525a7e7950b9&imgtype=jpg&src=http%3A%2F%2Fimg0.imgtn.bdimg.com%2Fit%2Fu%3D575314515%2C4268715674%26fm%3D214%26gp%3D0.jpg");
+		map3.put("title", "Mybatis");
+		map3.put("description", "MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的记录。");
+		map3.put("member", "Chill");
+		map3.put("href", "http://www.mybatis.org/mybatis-3/getting-started.html");
+		list.add(map3);
+
+		Map<String, String> map4 = new HashMap<>(16);
+		map4.put("logo", "https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png");
+		map4.put("title", "React");
+		map4.put("description", "React 起源于 Facebook 的内部项目,因为该公司对市场上所有 JavaScript MVC 框架,都不满意,就决定自己写一套,用来架设Instagram 的网站。做出来以后,发现这套东西很好用,就在2013年5月开源了。");
+		map4.put("member", "Chill");
+		map4.put("href", "https://reactjs.org/");
+		list.add(map4);
+
+		Map<String, String> map5 = new HashMap<>(16);
+		map5.put("logo", "https://gw.alipayobjects.com/zos/rmsportal/dURIMkkrRFpPgTuzkwnB.png");
+		map5.put("title", "Ant Design");
+		map5.put("description", "蚂蚁金服体验技术部经过大量的项目实践和总结,沉淀出设计语言 Ant Design,这可不单纯只是设计原则、控件规范和视觉尺寸,还配套有前端代码实现方案。也就是说采用Ant Design后,UI设计和前端界面研发可同步完成,效率大大提升。");
+		map5.put("member", "Chill");
+		map5.put("href", "https://ant.design/docs/spec/introduce-cn");
+		list.add(map5);
+
+		Map<String, String> map6 = new HashMap<>(16);
+		map6.put("logo", "https://gw.alipayobjects.com/zos/rmsportal/sfjbOqnsXXJgNCjCzDBL.png");
+		map6.put("title", "Ant Design Pro");
+		map6.put("description", "Ant Design Pro 是一个企业级开箱即用的中后台前端/设计解决方案。符合阿里追求的'敏捷的前端+强大的中台'的思想。");
+		map6.put("member", "Chill");
+		map6.put("href", "https://pro.ant.design");
+		list.add(map6);
+
+		return R.data(list);
+	}
+
+	/**
+	 * 获取我的消息
+	 *
+	 * @return
+	 */
+	@GetMapping("/my-notices")
+	@ApiOperation(value = "消息", notes = "消息")
+	public R myNotices() {
+		List<Map<String, String>> list = new ArrayList<>();
+		Map<String, String> map1 = new HashMap<>(16);
+		map1.put("id", "000000001");
+		map1.put("avatar", "https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png");
+		map1.put("title", "你收到了 14 份新周报");
+		map1.put("datetime", "2018-08-09");
+		map1.put("type", "notification");
+		list.add(map1);
+
+		Map<String, String> map2 = new HashMap<>(16);
+		map2.put("id", "000000002");
+		map2.put("avatar", "https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png");
+		map2.put("title", "你推荐的 曲妮妮 已通过第三轮面试");
+		map2.put("datetime", "2018-08-08");
+		map2.put("type", "notification");
+		list.add(map2);
+
+
+		Map<String, String> map3 = new HashMap<>(16);
+		map3.put("id", "000000003");
+		map3.put("avatar", "https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg");
+		map3.put("title", "曲丽丽 评论了你");
+		map3.put("description", "描述信息描述信息描述信息");
+		map3.put("datetime", "2018-08-07");
+		map3.put("type", "message");
+		map3.put("clickClose", "true");
+		list.add(map3);
+
+
+		Map<String, String> map4 = new HashMap<>(16);
+		map4.put("id", "000000004");
+		map4.put("avatar", "https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg");
+		map4.put("title", "朱偏右 回复了你");
+		map4.put("description", "这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像");
+		map4.put("type", "message");
+		map4.put("datetime", "2018-08-07");
+		map4.put("clickClose", "true");
+		list.add(map4);
+
+
+		Map<String, String> map5 = new HashMap<>(16);
+		map5.put("id", "000000005");
+		map5.put("title", "任务名称");
+		map5.put("description", "任务需要在 2018-01-12 20:00 前启动");
+		map5.put("extra", "未开始");
+		map5.put("status", "todo");
+		map5.put("type", "event");
+		list.add(map5);
+
+		return R.data(list);
+	}
+}

+ 122 - 0
src/main/java/org/springblade/modules/desk/controller/NoticeController.java

@@ -0,0 +1,122 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.desk.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import com.github.xiaoymin.knife4j.annotations.ApiSort;
+import io.swagger.annotations.*;
+import lombok.AllArgsConstructor;
+import org.springblade.common.cache.CacheNames;
+import org.springblade.core.boot.ctrl.BladeController;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.secure.annotation.PreAuth;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.constant.RoleConstant;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.modules.desk.entity.Notice;
+import org.springblade.modules.desk.service.INoticeService;
+import org.springblade.modules.desk.vo.NoticeVO;
+import org.springblade.modules.desk.wrapper.NoticeWrapper;
+import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
+
+import java.util.Map;
+
+/**
+ * 控制器
+ *
+ * @author Chill
+ */
+@PreAuth(RoleConstant.HAS_CRYPTO)
+@RestController
+@RequestMapping("/blade-desk/notice")
+@AllArgsConstructor
+@ApiSort(2)
+@Api(value = "用户博客", tags = "博客接口")
+public class NoticeController extends BladeController implements CacheNames {
+
+	private INoticeService noticeService;
+
+	/**
+	 * 详情
+	 */
+	@GetMapping("/detail")
+	@ApiOperationSupport(order = 1)
+	@ApiOperation(value = "详情", notes = "传入notice")
+	public R<NoticeVO> detail(Notice notice) {
+		Notice detail = noticeService.getOne(Condition.getQueryWrapper(notice));
+		return R.data(NoticeWrapper.build().entityVO(detail));
+	}
+
+	/**
+	 * 分页
+	 */
+	@GetMapping("/list")
+	@ApiImplicitParams({
+		@ApiImplicitParam(name = "category", value = "公告类型", paramType = "query", dataType = "integer"),
+		@ApiImplicitParam(name = "title", value = "公告标题", paramType = "query", dataType = "string")
+	})
+	@ApiOperationSupport(order = 2)
+	@ApiOperation(value = "分页", notes = "传入notice")
+	public R<IPage<NoticeVO>> list(@ApiIgnore @RequestParam Map<String, Object> notice, Query query) {
+		IPage<Notice> pages = noticeService.page(Condition.getPage(query), Condition.getQueryWrapper(notice, Notice.class));
+		return R.data(NoticeWrapper.build().pageVO(pages));
+	}
+
+	/**
+	 * 新增
+	 */
+	@PostMapping("/save")
+	@ApiOperationSupport(order = 3)
+	@ApiOperation(value = "新增", notes = "传入notice")
+	public R save(@RequestBody Notice notice) {
+		return R.status(noticeService.save(notice));
+	}
+
+	/**
+	 * 修改
+	 */
+	@PostMapping("/update")
+	@ApiOperationSupport(order = 4)
+	@ApiOperation(value = "修改", notes = "传入notice")
+	public R update(@RequestBody Notice notice) {
+		return R.status(noticeService.updateById(notice));
+	}
+
+	/**
+	 * 新增或修改
+	 */
+	@PostMapping("/submit")
+	@ApiOperationSupport(order = 5)
+	@ApiOperation(value = "新增或修改", notes = "传入notice")
+	public R submit(@RequestBody Notice notice) {
+		return R.status(noticeService.saveOrUpdate(notice));
+	}
+
+	/**
+	 * 删除
+	 */
+	@PostMapping("/remove")
+	@ApiOperationSupport(order = 6)
+	@ApiOperation(value = "逻辑删除", notes = "传入notice")
+	public R remove(@ApiParam(value = "主键集合") @RequestParam String ids) {
+		boolean temp = noticeService.deleteLogic(Func.toLongList(ids));
+		return R.status(temp);
+	}
+
+}

+ 75 - 0
src/main/java/org/springblade/modules/desk/entity/Notice.java

@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.desk.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModelProperty;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.core.mp.base.BaseEntity;
+
+import java.util.Date;
+
+/**
+ * 实体类
+ *
+ * @author Chill
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("blade_notice")
+public class Notice extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 主键id
+	 */
+	@ApiModelProperty(value = "主键")
+	@TableId(value = "id", type = IdType.ASSIGN_ID)
+	@JsonSerialize(using = ToStringSerializer.class)
+	private Long id;
+
+	/**
+	 * 标题
+	 */
+	@ApiModelProperty(value = "标题")
+	private String title;
+
+	/**
+	 * 通知类型
+	 */
+	@ApiModelProperty(value = "通知类型")
+	private Integer category;
+
+	/**
+	 * 发布日期
+	 */
+	@ApiModelProperty(value = "发布日期")
+	private Date releaseTime;
+
+	/**
+	 * 内容
+	 */
+	@ApiModelProperty(value = "内容")
+	private String content;
+
+
+}

+ 46 - 0
src/main/java/org/springblade/modules/desk/mapper/NoticeMapper.java

@@ -0,0 +1,46 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.desk.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springblade.modules.desk.entity.Notice;
+
+import java.util.List;
+
+/**
+ * Mapper 接口
+ *
+ * @author Chill
+ */
+public interface NoticeMapper extends BaseMapper<Notice> {
+
+	/**
+	 * 前N条数据
+	 * @param number
+	 * @return
+	 */
+	List<Notice> topList(Integer number);
+
+	/**
+	 * 自定义分页
+	 * @param page
+	 * @param notice
+	 * @return
+	 */
+	List<Notice> selectNoticePage(IPage page, Notice notice);
+
+}

+ 39 - 0
src/main/java/org/springblade/modules/desk/mapper/NoticeMapper.xml

@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.springblade.modules.desk.mapper.NoticeMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="noticeResultMap" type="org.springblade.modules.desk.entity.Notice">
+        <result column="id" property="id"/>
+        <result column="create_user" property="createUser"/>
+        <result column="create_time" property="createTime"/>
+        <result column="update_user" property="updateUser"/>
+        <result column="update_time" property="updateTime"/>
+        <result column="status" property="status"/>
+        <result column="is_deleted" property="isDeleted"/>
+        <result column="release_time" property="releaseTime"/>
+        <result column="title" property="title"/>
+        <result column="content" property="content"/>
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="baseColumnList">
+        select id,
+        create_user AS createUser,
+        create_time AS createTime,
+        update_user AS updateUser,
+        update_time AS updateTime,
+        status,
+        is_deleted AS isDeleted,
+        title, content
+    </sql>
+
+    <select id="topList" resultMap="noticeResultMap">
+        select * from blade_notice limit #{number}
+    </select>
+
+    <select id="selectNoticePage" resultMap="noticeResultMap">
+        select * from blade_notice where title like concat('%', #{notice.title}, '%') and is_deleted = 0
+    </select>
+
+</mapper>

+ 37 - 0
src/main/java/org/springblade/modules/desk/service/INoticeService.java

@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.desk.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springblade.core.mp.base.BaseService;
+import org.springblade.modules.desk.entity.Notice;
+
+/**
+ * 服务类
+ *
+ * @author Chill
+ */
+public interface INoticeService extends BaseService<Notice> {
+
+	/**
+	 * 自定义分页
+	 * @param page
+	 * @param notice
+	 * @return
+	 */
+	IPage<Notice> selectNoticePage(IPage<Notice> page, Notice notice);
+
+}

+ 38 - 0
src/main/java/org/springblade/modules/desk/service/impl/NoticeServiceImpl.java

@@ -0,0 +1,38 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.desk.service.impl;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springblade.core.mp.base.BaseServiceImpl;
+import org.springblade.modules.desk.entity.Notice;
+import org.springblade.modules.desk.mapper.NoticeMapper;
+import org.springblade.modules.desk.service.INoticeService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 服务实现类
+ *
+ * @author Chill
+ */
+@Service
+public class NoticeServiceImpl extends BaseServiceImpl<NoticeMapper, Notice> implements INoticeService {
+
+	@Override
+	public IPage<Notice> selectNoticePage(IPage<Notice> page, Notice notice) {
+		return page.setRecords(baseMapper.selectNoticePage(page, notice));
+	}
+
+}

+ 20 - 0
src/main/java/org/springblade/modules/desk/vo/NoticeVO.java

@@ -0,0 +1,20 @@
+package org.springblade.modules.desk.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.modules.desk.entity.Notice;
+
+/**
+ * 通知公告视图类
+ *
+ * @author Chill
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class NoticeVO extends Notice {
+
+	@ApiModelProperty(value = "通知类型名")
+	private String categoryName;
+
+}

+ 50 - 0
src/main/java/org/springblade/modules/desk/wrapper/NoticeWrapper.java

@@ -0,0 +1,50 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.desk.wrapper;
+
+import org.springblade.core.mp.support.BaseEntityWrapper;
+import org.springblade.core.tool.utils.BeanUtil;
+import org.springblade.core.tool.utils.SpringUtil;
+import org.springblade.modules.desk.entity.Notice;
+import org.springblade.modules.desk.vo.NoticeVO;
+import org.springblade.modules.system.service.IDictService;
+
+/**
+ * Notice包装类,返回视图层所需的字段
+ *
+ * @author Chill
+ */
+public class NoticeWrapper extends BaseEntityWrapper<Notice, NoticeVO> {
+
+	private static IDictService dictService;
+
+	static {
+		dictService = SpringUtil.getBean(IDictService.class);
+	}
+
+	public static NoticeWrapper build() {
+		return new NoticeWrapper();
+	}
+
+	@Override
+	public NoticeVO entityVO(Notice notice) {
+		NoticeVO noticeVO = BeanUtil.copy(notice, NoticeVO.class);
+		String categoryName = dictService.getValue("notice", noticeVO.getCategory());
+		noticeVO.setCategoryName(categoryName);
+		return noticeVO;
+	}
+
+}

+ 154 - 0
src/main/java/org/springblade/modules/develop/controller/CodeController.java

@@ -0,0 +1,154 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.develop.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.annotations.*;
+import lombok.AllArgsConstructor;
+import org.springblade.core.boot.ctrl.BladeController;
+import org.springblade.core.launch.constant.AppConstant;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.secure.annotation.PreAuth;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.constant.RoleConstant;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.develop.support.BladeCodeGenerator;
+import org.springblade.modules.develop.entity.Code;
+import org.springblade.modules.develop.entity.Datasource;
+import org.springblade.modules.develop.service.ICodeService;
+import org.springblade.modules.develop.service.IDatasourceService;
+import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.validation.Valid;
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * 控制器
+ *
+ * @author Chill
+ */
+@ApiIgnore
+@RestController
+@AllArgsConstructor
+@RequestMapping(AppConstant.APPLICATION_DEVELOP_NAME + "/code")
+@Api(value = "代码生成", tags = "代码生成")
+@PreAuth(RoleConstant.HAS_ROLE_ADMIN)
+public class CodeController extends BladeController {
+
+	private ICodeService codeService;
+	private IDatasourceService datasourceService;
+
+	/**
+	 * 详情
+	 */
+	@GetMapping("/detail")
+	@ApiOperationSupport(order = 1)
+	@ApiOperation(value = "详情", notes = "传入code")
+	public R<Code> detail(Code code) {
+		Code detail = codeService.getOne(Condition.getQueryWrapper(code));
+		return R.data(detail);
+	}
+
+	/**
+	 * 分页
+	 */
+	@GetMapping("/list")
+	@ApiImplicitParams({
+		@ApiImplicitParam(name = "codeName", value = "模块名", paramType = "query", dataType = "string"),
+		@ApiImplicitParam(name = "tableName", value = "表名", paramType = "query", dataType = "string"),
+		@ApiImplicitParam(name = "modelName", value = "实体名", paramType = "query", dataType = "string")
+	})
+	@ApiOperationSupport(order = 2)
+	@ApiOperation(value = "分页", notes = "传入code")
+	public R<IPage<Code>> list(@ApiIgnore @RequestParam Map<String, Object> code, Query query) {
+		IPage<Code> pages = codeService.page(Condition.getPage(query), Condition.getQueryWrapper(code, Code.class));
+		return R.data(pages);
+	}
+
+	/**
+	 * 新增或修改
+	 */
+	@PostMapping("/submit")
+	@ApiOperationSupport(order = 3)
+	@ApiOperation(value = "新增或修改", notes = "传入code")
+	public R submit(@Valid @RequestBody Code code) {
+		return R.status(codeService.submit(code));
+	}
+
+
+	/**
+	 * 删除
+	 */
+	@PostMapping("/remove")
+	@ApiOperationSupport(order = 4)
+	@ApiOperation(value = "删除", notes = "传入ids")
+	public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
+		return R.status(codeService.removeByIds(Func.toLongList(ids)));
+	}
+
+	/**
+	 * 复制
+	 */
+	@PostMapping("/copy")
+	@ApiOperationSupport(order = 5)
+	@ApiOperation(value = "复制", notes = "传入id")
+	public R copy(@ApiParam(value = "主键", required = true) @RequestParam Long id) {
+		Code code = codeService.getById(id);
+		code.setId(null);
+		code.setCodeName(code.getCodeName() + "-copy");
+		return R.status(codeService.save(code));
+	}
+
+	/**
+	 * 代码生成
+	 */
+	@PostMapping("/gen-code")
+	@ApiOperationSupport(order = 6)
+	@ApiOperation(value = "代码生成", notes = "传入ids")
+	public R genCode(@ApiParam(value = "主键集合", required = true) @RequestParam String ids, @RequestParam(defaultValue = "sword") String system) {
+		Collection<Code> codes = codeService.listByIds(Func.toLongList(ids));
+		codes.forEach(code -> {
+			BladeCodeGenerator generator = new BladeCodeGenerator();
+			// 设置数据源
+			Datasource datasource = datasourceService.getById(code.getDatasourceId());
+			generator.setDriverName(datasource.getDriverClass());
+			generator.setUrl(datasource.getUrl());
+			generator.setUsername(datasource.getUsername());
+			generator.setPassword(datasource.getPassword());
+			// 设置基础配置
+			generator.setSystemName(system);
+			generator.setServiceName(code.getServiceName());
+			generator.setPackageName(code.getPackageName());
+			generator.setPackageDir(code.getApiPath());
+			generator.setPackageWebDir(code.getWebPath());
+			generator.setTablePrefix(Func.toStrArray(code.getTablePrefix()));
+			generator.setIncludeTables(Func.toStrArray(code.getTableName()));
+			// 设置是否继承基础业务字段
+			generator.setHasSuperEntity(code.getBaseMode() == 2);
+			// 控制器添加服务名前缀
+			generator.setHasServiceName(Boolean.TRUE);
+			// 设置是否开启包装器模式
+			generator.setHasWrapper(code.getWrapMode() == 2);
+			generator.run();
+		});
+		return R.success("代码生成成功");
+	}
+
+}

+ 126 - 0
src/main/java/org/springblade/modules/develop/controller/DatasourceController.java

@@ -0,0 +1,126 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.develop.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.annotations.ApiParam;
+import lombok.AllArgsConstructor;
+import org.springblade.core.boot.ctrl.BladeController;
+import org.springblade.core.launch.constant.AppConstant;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.modules.develop.entity.Datasource;
+import org.springblade.modules.develop.service.IDatasourceService;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * 数据源配置表 控制器
+ *
+ * @author Chill
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping(AppConstant.APPLICATION_DEVELOP_NAME + "/datasource")
+@Api(value = "数据源配置表", tags = "数据源配置表接口")
+public class DatasourceController extends BladeController {
+
+	private IDatasourceService datasourceService;
+
+	/**
+	 * 详情
+	 */
+	@GetMapping("/detail")
+	@ApiOperationSupport(order = 1)
+	@ApiOperation(value = "详情", notes = "传入datasource")
+	public R<Datasource> detail(Datasource datasource) {
+		Datasource detail = datasourceService.getOne(Condition.getQueryWrapper(datasource));
+		return R.data(detail);
+	}
+
+	/**
+	 * 分页 数据源配置表
+	 */
+	@GetMapping("/list")
+	@ApiOperationSupport(order = 2)
+	@ApiOperation(value = "分页", notes = "传入datasource")
+	public R<IPage<Datasource>> list(Datasource datasource, Query query) {
+		IPage<Datasource> pages = datasourceService.page(Condition.getPage(query), Condition.getQueryWrapper(datasource));
+		return R.data(pages);
+	}
+
+	/**
+	 * 新增 数据源配置表
+	 */
+	@PostMapping("/save")
+	@ApiOperationSupport(order = 4)
+	@ApiOperation(value = "新增", notes = "传入datasource")
+	public R save(@Valid @RequestBody Datasource datasource) {
+		return R.status(datasourceService.save(datasource));
+	}
+
+	/**
+	 * 修改 数据源配置表
+	 */
+	@PostMapping("/update")
+	@ApiOperationSupport(order = 5)
+	@ApiOperation(value = "修改", notes = "传入datasource")
+	public R update(@Valid @RequestBody Datasource datasource) {
+		return R.status(datasourceService.updateById(datasource));
+	}
+
+	/**
+	 * 新增或修改 数据源配置表
+	 */
+	@PostMapping("/submit")
+	@ApiOperationSupport(order = 6)
+	@ApiOperation(value = "新增或修改", notes = "传入datasource")
+	public R submit(@Valid @RequestBody Datasource datasource) {
+		datasource.setUrl(datasource.getUrl().replace("&amp;", "&"));
+		return R.status(datasourceService.saveOrUpdate(datasource));
+	}
+
+
+	/**
+	 * 删除 数据源配置表
+	 */
+	@PostMapping("/remove")
+	@ApiOperationSupport(order = 7)
+	@ApiOperation(value = "逻辑删除", notes = "传入ids")
+	public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
+		return R.status(datasourceService.deleteLogic(Func.toLongList(ids)));
+	}
+
+	/**
+	 * 数据源列表
+	 */
+	@GetMapping("/select")
+	@ApiOperationSupport(order = 8)
+	@ApiOperation(value = "下拉数据源", notes = "查询列表")
+	public R<List<Datasource>> select() {
+		List<Datasource> list = datasourceService.list();
+		return R.data(list);
+	}
+
+}

+ 125 - 0
src/main/java/org/springblade/modules/develop/entity/Code.java

@@ -0,0 +1,125 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.develop.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 实体类
+ *
+ * @author Chill
+ */
+@Data
+@TableName("blade_code")
+@ApiModel(value = "Code对象", description = "Code对象")
+public class Code implements Serializable {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 主键
+	 */
+	@ApiModelProperty(value = "主键")
+	@TableId(value = "id", type = IdType.ASSIGN_ID)
+	@JsonSerialize(using = ToStringSerializer.class)
+	private Long id;
+
+	/**
+	 * 数据源主键
+	 */
+	@ApiModelProperty(value = "数据源主键")
+	@JsonSerialize(using = ToStringSerializer.class)
+	private Long datasourceId;
+
+	/**
+	 * 模块名称
+	 */
+	@ApiModelProperty(value = "服务名称")
+	private String serviceName;
+
+	/**
+	 * 模块名称
+	 */
+	@ApiModelProperty(value = "模块名称")
+	private String codeName;
+
+	/**
+	 * 表名
+	 */
+	@ApiModelProperty(value = "表名")
+	private String tableName;
+
+	/**
+	 * 实体名
+	 */
+	@ApiModelProperty(value = "表前缀")
+	private String tablePrefix;
+
+	/**
+	 * 主键名
+	 */
+	@ApiModelProperty(value = "主键名")
+	private String pkName;
+
+	/**
+	 * 基础业务模式
+	 */
+	@ApiModelProperty(value = "基础业务模式")
+	private Integer baseMode;
+
+	/**
+	 * 包装器模式
+	 */
+	@ApiModelProperty(value = "包装器模式")
+	private Integer wrapMode;
+
+	/**
+	 * 后端包名
+	 */
+	@ApiModelProperty(value = "后端包名")
+	private String packageName;
+
+	/**
+	 * 后端路径
+	 */
+	@ApiModelProperty(value = "后端路径")
+	private String apiPath;
+
+	/**
+	 * 前端路径
+	 */
+	@ApiModelProperty(value = "前端路径")
+	private String webPath;
+
+	/**
+	 * 是否已删除
+	 */
+	@TableLogic
+	@ApiModelProperty(value = "是否已删除")
+	private Integer isDeleted;
+
+
+}

+ 82 - 0
src/main/java/org/springblade/modules/develop/entity/Datasource.java

@@ -0,0 +1,82 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.develop.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.core.mp.base.BaseEntity;
+
+/**
+ * 数据源配置表实体类
+ *
+ * @author Chill
+ */
+@Data
+@TableName("blade_datasource")
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "Datasource对象", description = "数据源配置表")
+public class Datasource extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 主键
+	 */
+	@ApiModelProperty(value = "主键")
+	@TableId(value = "id", type = IdType.ASSIGN_ID)
+	@JsonSerialize(using = ToStringSerializer.class)
+	private Long id;
+
+	/**
+	 * 名称
+	 */
+	@ApiModelProperty(value = "名称")
+	private String name;
+	/**
+	 * 驱动类
+	 */
+	@ApiModelProperty(value = "驱动类")
+	private String driverClass;
+	/**
+	 * 连接地址
+	 */
+	@ApiModelProperty(value = "连接地址")
+	private String url;
+	/**
+	 * 用户名
+	 */
+	@ApiModelProperty(value = "用户名")
+	private String username;
+	/**
+	 * 密码
+	 */
+	@ApiModelProperty(value = "密码")
+	private String password;
+	/**
+	 * 备注
+	 */
+	@ApiModelProperty(value = "备注")
+	private String remark;
+
+
+}

+ 28 - 0
src/main/java/org/springblade/modules/develop/mapper/CodeMapper.java

@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.develop.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.springblade.modules.develop.entity.Code;
+
+/**
+ * Mapper 接口
+ *
+ * @author Chill
+ */
+public interface CodeMapper extends BaseMapper<Code> {
+
+}

+ 22 - 0
src/main/java/org/springblade/modules/develop/mapper/CodeMapper.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.springblade.modules.develop.mapper.CodeMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="codeResultMap" type="org.springblade.modules.develop.entity.Code">
+        <id column="id" property="id"/>
+        <result column="datasource_id" property="datasourceId"/>
+        <result column="service_name" property="serviceName"/>
+        <result column="code_name" property="codeName"/>
+        <result column="table_name" property="tableName"/>
+        <result column="pk_name" property="pkName"/>
+        <result column="base_mode" property="baseMode"/>
+        <result column="wrap_mode" property="wrapMode"/>
+        <result column="table_prefix" property="tablePrefix"/>
+        <result column="package_name" property="packageName"/>
+        <result column="api_path" property="apiPath"/>
+        <result column="web_path" property="webPath"/>
+        <result column="is_deleted" property="isDeleted"/>
+    </resultMap>
+
+</mapper>

+ 28 - 0
src/main/java/org/springblade/modules/develop/mapper/DatasourceMapper.java

@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.develop.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.springblade.modules.develop.entity.Datasource;
+
+/**
+ * 数据源配置表 Mapper 接口
+ *
+ * @author Chill
+ */
+public interface DatasourceMapper extends BaseMapper<Datasource> {
+
+}

+ 22 - 0
src/main/java/org/springblade/modules/develop/mapper/DatasourceMapper.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.springblade.modules.develop.mapper.DatasourceMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="datasourceResultMap" type="org.springblade.modules.develop.entity.Datasource">
+        <result column="id" property="id"/>
+        <result column="create_user" property="createUser"/>
+        <result column="create_dept" property="createDept"/>
+        <result column="create_time" property="createTime"/>
+        <result column="update_user" property="updateUser"/>
+        <result column="update_time" property="updateTime"/>
+        <result column="status" property="status"/>
+        <result column="is_deleted" property="isDeleted"/>
+        <result column="driver_class" property="driverClass"/>
+        <result column="url" property="url"/>
+        <result column="username" property="username"/>
+        <result column="password" property="password"/>
+        <result column="remark" property="remark"/>
+    </resultMap>
+
+</mapper>

+ 37 - 0
src/main/java/org/springblade/modules/develop/service/ICodeService.java

@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.develop.service;
+
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.springblade.modules.develop.entity.Code;
+
+/**
+ * 服务类
+ *
+ * @author Chill
+ */
+public interface ICodeService extends IService<Code> {
+
+	/**
+	 * 提交
+	 *
+	 * @param code
+	 * @return
+	 */
+	boolean submit(Code code);
+
+}

+ 28 - 0
src/main/java/org/springblade/modules/develop/service/IDatasourceService.java

@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.develop.service;
+
+import org.springblade.core.mp.base.BaseService;
+import org.springblade.modules.develop.entity.Datasource;
+
+/**
+ * 数据源配置表 服务类
+ *
+ * @author Chill
+ */
+public interface IDatasourceService extends BaseService<Datasource> {
+
+}

+ 39 - 0
src/main/java/org/springblade/modules/develop/service/impl/CodeServiceImpl.java

@@ -0,0 +1,39 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.develop.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springblade.core.tool.constant.BladeConstant;
+import org.springblade.modules.develop.entity.Code;
+import org.springblade.modules.develop.mapper.CodeMapper;
+import org.springblade.modules.develop.service.ICodeService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 服务实现类
+ *
+ * @author Chill
+ */
+@Service
+public class CodeServiceImpl extends ServiceImpl<CodeMapper, Code> implements ICodeService {
+
+	@Override
+	public boolean submit(Code code) {
+		code.setIsDeleted(BladeConstant.DB_NOT_DELETED);
+		return saveOrUpdate(code);
+	}
+
+}

+ 32 - 0
src/main/java/org/springblade/modules/develop/service/impl/DatasourceServiceImpl.java

@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.develop.service.impl;
+
+import org.springblade.core.mp.base.BaseServiceImpl;
+import org.springblade.modules.develop.entity.Datasource;
+import org.springblade.modules.develop.mapper.DatasourceMapper;
+import org.springblade.modules.develop.service.IDatasourceService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 数据源配置表 服务实现类
+ *
+ * @author Chill
+ */
+@Service
+public class DatasourceServiceImpl extends BaseServiceImpl<DatasourceMapper, Datasource> implements IDatasourceService {
+
+}

+ 173 - 0
src/main/java/org/springblade/modules/resource/OssEndpoint.java

@@ -0,0 +1,173 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.resource;
+
+import io.swagger.annotations.Api;
+import lombok.AllArgsConstructor;
+import lombok.SneakyThrows;
+import org.springblade.core.oss.QiniuTemplate;
+import org.springblade.core.oss.model.BladeFile;
+import org.springblade.core.oss.model.OssFile;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.Func;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * 对象存储端点
+ *
+ * @author Chill
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/blade-resource/oss/endpoint")
+@Api(value = "对象存储端点", tags = "对象存储端点")
+public class OssEndpoint {
+
+	private QiniuTemplate qiniuTemplate;
+
+	/**
+	 * 创建存储桶
+	 *
+	 * @param bucketName 存储桶名称
+	 * @return Bucket
+	 */
+	@SneakyThrows
+	@PostMapping("/make-bucket")
+	public R makeBucket(@RequestParam String bucketName) {
+		qiniuTemplate.makeBucket(bucketName);
+		return R.success("创建成功");
+	}
+
+	/**
+	 * 创建存储桶
+	 *
+	 * @param bucketName 存储桶名称
+	 * @return R
+	 */
+	@SneakyThrows
+	@PostMapping("/remove-bucket")
+	public R removeBucket(@RequestParam String bucketName) {
+		qiniuTemplate.removeBucket(bucketName);
+		return R.success("删除成功");
+	}
+
+	/**
+	 * 拷贝文件
+	 *
+	 * @param fileName       存储桶对象名称
+	 * @param destBucketName 目标存储桶名称
+	 * @param destFileName   目标存储桶对象名称
+	 * @return R
+	 */
+	@SneakyThrows
+	@PostMapping("/copy-file")
+	public R copyFile(@RequestParam String fileName, @RequestParam String destBucketName, String destFileName) {
+		qiniuTemplate.copyFile(fileName, destBucketName, destFileName);
+		return R.success("操作成功");
+	}
+
+	/**
+	 * 获取文件信息
+	 *
+	 * @param fileName 存储桶对象名称
+	 * @return InputStream
+	 */
+	@SneakyThrows
+	@GetMapping("/stat-file")
+	public R<OssFile> statFile(@RequestParam String fileName) {
+		return R.data(qiniuTemplate.statFile(fileName));
+	}
+
+	/**
+	 * 获取文件相对路径
+	 *
+	 * @param fileName 存储桶对象名称
+	 * @return String
+	 */
+	@SneakyThrows
+	@GetMapping("/file-path")
+	public R<String> filePath(@RequestParam String fileName) {
+		return R.data(qiniuTemplate.filePath(fileName));
+	}
+
+
+	/**
+	 * 获取文件外链
+	 *
+	 * @param fileName 存储桶对象名称
+	 * @return String
+	 */
+	@SneakyThrows
+	@GetMapping("/file-link")
+	public R<String> fileLink(@RequestParam String fileName) {
+		return R.data(qiniuTemplate.fileLink(fileName));
+	}
+
+	/**
+	 * 上传文件
+	 *
+	 * @param file 文件
+	 * @return ObjectStat
+	 */
+	@SneakyThrows
+	@PostMapping("/put-file")
+	public R<BladeFile> putFile(@RequestParam MultipartFile file) {
+		BladeFile bladeFile = qiniuTemplate.putFile(file.getOriginalFilename(), file.getInputStream());
+		return R.data(bladeFile);
+	}
+
+	/**
+	 * 上传文件
+	 *
+	 * @param fileName 存储桶对象名称
+	 * @param file     文件
+	 * @return ObjectStat
+	 */
+	@SneakyThrows
+	@PostMapping("/put-file-by-name")
+	public R<BladeFile> putFile(@RequestParam String fileName, @RequestParam MultipartFile file) {
+		BladeFile bladeFile = qiniuTemplate.putFile(fileName, file.getInputStream());
+		return R.data(bladeFile);
+	}
+
+	/**
+	 * 删除文件
+	 *
+	 * @param fileName 存储桶对象名称
+	 * @return R
+	 */
+	@SneakyThrows
+	@PostMapping("/remove-file")
+	public R removeFile(@RequestParam String fileName) {
+		qiniuTemplate.removeFile(fileName);
+		return R.success("操作成功");
+	}
+
+	/**
+	 * 批量删除文件
+	 *
+	 * @param fileNames 存储桶对象名称集合
+	 * @return R
+	 */
+	@SneakyThrows
+	@PostMapping("/remove-files")
+	public R removeFiles(@RequestParam String fileNames) {
+		qiniuTemplate.removeFiles(Func.toStrList(fileNames));
+		return R.success("操作成功");
+	}
+
+}

+ 118 - 0
src/main/java/org/springblade/modules/system/controller/AuthClientController.java

@@ -0,0 +1,118 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.annotations.ApiParam;
+import lombok.AllArgsConstructor;
+import org.springblade.core.boot.ctrl.BladeController;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.secure.annotation.PreAuth;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.constant.RoleConstant;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.modules.system.entity.AuthClient;
+import org.springblade.modules.system.service.IAuthClientService;
+import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.validation.Valid;
+
+/**
+ * 应用管理控制器
+ *
+ * @author Chill
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/blade-system/client")
+@ApiIgnore
+@Api(value = "应用管理", tags = "接口")
+@PreAuth(RoleConstant.HAS_ROLE_ADMIN)
+public class AuthClientController extends BladeController {
+
+	private IAuthClientService clientService;
+
+	/**
+	 * 详情
+	 */
+	@GetMapping("/detail")
+	@ApiOperationSupport(order = 1)
+	@ApiOperation(value = "详情", notes = "传入client")
+	public R<AuthClient> detail(AuthClient authClient) {
+		AuthClient detail = clientService.getOne(Condition.getQueryWrapper(authClient));
+		return R.data(detail);
+	}
+
+	/**
+	 * 分页
+	 */
+	@GetMapping("/list")
+	@ApiOperationSupport(order = 2)
+	@ApiOperation(value = "分页", notes = "传入client")
+	public R<IPage<AuthClient>> list(AuthClient authClient, Query query) {
+		IPage<AuthClient> pages = clientService.page(Condition.getPage(query), Condition.getQueryWrapper(authClient));
+		return R.data(pages);
+	}
+
+	/**
+	 * 新增
+	 */
+	@PostMapping("/save")
+	@ApiOperationSupport(order = 3)
+	@ApiOperation(value = "新增", notes = "传入client")
+	public R save(@Valid @RequestBody AuthClient authClient) {
+		return R.status(clientService.save(authClient));
+	}
+
+	/**
+	 * 修改
+	 */
+	@PostMapping("/update")
+	@ApiOperationSupport(order = 4)
+	@ApiOperation(value = "修改", notes = "传入client")
+	public R update(@Valid @RequestBody AuthClient authClient) {
+		return R.status(clientService.updateById(authClient));
+	}
+
+	/**
+	 * 新增或修改
+	 */
+	@PostMapping("/submit")
+	@ApiOperationSupport(order = 5)
+	@ApiOperation(value = "新增或修改", notes = "传入client")
+	public R submit(@Valid @RequestBody AuthClient authClient) {
+		return R.status(clientService.saveOrUpdate(authClient));
+	}
+
+
+	/**
+	 * 删除
+	 */
+	@PostMapping("/remove")
+	@ApiOperationSupport(order = 6)
+	@ApiOperation(value = "逻辑删除", notes = "传入ids")
+	public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
+		return R.status(clientService.deleteLogic(Func.toLongList(ids)));
+	}
+
+
+}

+ 121 - 0
src/main/java/org/springblade/modules/system/controller/DataScopeController.java

@@ -0,0 +1,121 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.AllArgsConstructor;
+import org.springblade.core.boot.ctrl.BladeController;
+import org.springblade.core.launch.constant.AppConstant;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.CacheUtil;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.modules.system.entity.DataScope;
+import org.springblade.modules.system.service.IDataScopeService;
+import org.springblade.modules.system.vo.DataScopeVO;
+import org.springblade.modules.system.wrapper.DataScopeWrapper;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+
+import static org.springblade.core.tool.utils.CacheUtil.SYS_CACHE;
+
+/**
+ * 数据权限控制器
+ *
+ * @author BladeX
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping(AppConstant.APPLICATION_SYSTEM_NAME + "/data-scope")
+@Api(value = "数据权限", tags = "数据权限")
+public class DataScopeController extends BladeController {
+
+	private final IDataScopeService dataScopeService;
+
+	/**
+	 * 详情
+	 */
+	@GetMapping("/detail")
+	@ApiOperationSupport(order = 1)
+	@ApiOperation(value = "详情", notes = "传入dataScope")
+	public R<DataScope> detail(DataScope dataScope) {
+		DataScope detail = dataScopeService.getOne(Condition.getQueryWrapper(dataScope));
+		return R.data(detail);
+	}
+
+	/**
+	 * 分页
+	 */
+	@GetMapping("/list")
+	@ApiOperationSupport(order = 2)
+	@ApiOperation(value = "分页", notes = "传入dataScope")
+	public R<IPage<DataScopeVO>> list(DataScope dataScope, Query query) {
+		IPage<DataScope> pages = dataScopeService.page(Condition.getPage(query), Condition.getQueryWrapper(dataScope));
+		return R.data(DataScopeWrapper.build().pageVO(pages));
+	}
+
+	/**
+	 * 新增
+	 */
+	@PostMapping("/save")
+	@ApiOperationSupport(order = 3)
+	@ApiOperation(value = "新增", notes = "传入dataScope")
+	public R save(@Valid @RequestBody DataScope dataScope) {
+		CacheUtil.clear(SYS_CACHE);
+		return R.status(dataScopeService.save(dataScope));
+	}
+
+	/**
+	 * 修改
+	 */
+	@PostMapping("/update")
+	@ApiOperationSupport(order = 4)
+	@ApiOperation(value = "修改", notes = "传入dataScope")
+	public R update(@Valid @RequestBody DataScope dataScope) {
+		CacheUtil.clear(SYS_CACHE);
+		return R.status(dataScopeService.updateById(dataScope));
+	}
+
+	/**
+	 * 新增或修改
+	 */
+	@PostMapping("/submit")
+	@ApiOperationSupport(order = 5)
+	@ApiOperation(value = "新增或修改", notes = "传入dataScope")
+	public R submit(@Valid @RequestBody DataScope dataScope) {
+		CacheUtil.clear(SYS_CACHE);
+		return R.status(dataScopeService.saveOrUpdate(dataScope));
+	}
+
+
+	/**
+	 * 删除
+	 */
+	@PostMapping("/remove")
+	@ApiOperationSupport(order = 6)
+	@ApiOperation(value = "逻辑删除", notes = "传入ids")
+	public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
+		CacheUtil.clear(SYS_CACHE);
+		return R.status(dataScopeService.deleteLogic(Func.toLongList(ids)));
+	}
+
+}

+ 114 - 0
src/main/java/org/springblade/modules/system/controller/DeptController.java

@@ -0,0 +1,114 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.annotations.*;
+import lombok.AllArgsConstructor;
+import org.springblade.core.boot.ctrl.BladeController;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.secure.BladeUser;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.constant.BladeConstant;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.modules.system.entity.Dept;
+import org.springblade.modules.system.service.IDeptService;
+import org.springblade.modules.system.vo.DeptVO;
+import org.springblade.modules.system.wrapper.DeptWrapper;
+import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.validation.Valid;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 控制器
+ *
+ * @author Chill
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/blade-system/dept")
+@ApiIgnore
+@Api(value = "部门", tags = "部门")
+public class DeptController extends BladeController {
+
+	private IDeptService deptService;
+
+	/**
+	 * 详情
+	 */
+	@GetMapping("/detail")
+	@ApiOperationSupport(order = 1)
+	@ApiOperation(value = "详情", notes = "传入dept")
+	public R<DeptVO> detail(Dept dept) {
+		Dept detail = deptService.getOne(Condition.getQueryWrapper(dept));
+		return R.data(DeptWrapper.build().entityVO(detail));
+	}
+
+	/**
+	 * 列表
+	 */
+	@GetMapping("/list")
+	@ApiImplicitParams({
+		@ApiImplicitParam(name = "deptName", value = "部门名称", paramType = "query", dataType = "string"),
+		@ApiImplicitParam(name = "fullName", value = "部门全称", paramType = "query", dataType = "string")
+	})
+	@ApiOperationSupport(order = 2)
+	@ApiOperation(value = "列表", notes = "传入dept")
+	public R<List<DeptVO>> list(@ApiIgnore @RequestParam Map<String, Object> dept, BladeUser bladeUser) {
+		QueryWrapper<Dept> queryWrapper = Condition.getQueryWrapper(dept, Dept.class);
+		List<Dept> list = deptService.list((!bladeUser.getTenantId().equals(BladeConstant.ADMIN_TENANT_ID)) ? queryWrapper.lambda().eq(Dept::getTenantId, bladeUser.getTenantId()) : queryWrapper);
+		return R.data(DeptWrapper.build().listNodeVO(list));
+	}
+
+	/**
+	 * 获取部门树形结构
+	 *
+	 * @return
+	 */
+	@GetMapping("/tree")
+	@ApiOperationSupport(order = 3)
+	@ApiOperation(value = "树形结构", notes = "树形结构")
+	public R<List<DeptVO>> tree(String tenantId, BladeUser bladeUser) {
+		List<DeptVO> tree = deptService.tree(Func.toStr(tenantId, bladeUser.getTenantId()));
+		return R.data(tree);
+	}
+
+	/**
+	 * 新增或修改
+	 */
+	@PostMapping("/submit")
+	@ApiOperationSupport(order = 4)
+	@ApiOperation(value = "新增或修改", notes = "传入dept")
+	public R submit(@Valid @RequestBody Dept dept) {
+		return R.status(deptService.submit(dept));
+	}
+
+	/**
+	 * 删除
+	 */
+	@PostMapping("/remove")
+	@ApiOperationSupport(order = 5)
+	@ApiOperation(value = "删除", notes = "传入ids")
+	public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
+		return R.status(deptService.removeByIds(Func.toLongList(ids)));
+	}
+
+
+}

+ 129 - 0
src/main/java/org/springblade/modules/system/controller/DictController.java

@@ -0,0 +1,129 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.controller;
+
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.annotations.*;
+import lombok.AllArgsConstructor;
+import org.springblade.core.boot.ctrl.BladeController;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.modules.system.entity.Dict;
+import org.springblade.modules.system.service.IDictService;
+import org.springblade.modules.system.vo.DictVO;
+import org.springblade.modules.system.wrapper.DictWrapper;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.validation.Valid;
+import java.util.List;
+import java.util.Map;
+
+import static org.springblade.common.cache.CacheNames.DICT_LIST;
+import static org.springblade.common.cache.CacheNames.DICT_VALUE;
+
+/**
+ * 控制器
+ *
+ * @author Chill
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/blade-system/dict")
+@ApiIgnore
+@Api(value = "字典", tags = "字典")
+public class DictController extends BladeController {
+
+	private IDictService dictService;
+
+	/**
+	 * 详情
+	 */
+	@GetMapping("/detail")
+	@ApiOperationSupport(order = 1)
+	@ApiOperation(value = "详情", notes = "传入dict")
+	public R<DictVO> detail(Dict dict) {
+		Dict detail = dictService.getOne(Condition.getQueryWrapper(dict));
+		return R.data(DictWrapper.build().entityVO(detail));
+	}
+
+	/**
+	 * 列表
+	 */
+	@GetMapping("/list")
+	@ApiImplicitParams({
+		@ApiImplicitParam(name = "code", value = "字典编号", paramType = "query", dataType = "string"),
+		@ApiImplicitParam(name = "dictValue", value = "字典名称", paramType = "query", dataType = "string")
+	})
+	@ApiOperationSupport(order = 2)
+	@ApiOperation(value = "列表", notes = "传入dict")
+	public R<List<DictVO>> list(@ApiIgnore @RequestParam Map<String, Object> dict) {
+		List<Dict> list = dictService.list(Condition.getQueryWrapper(dict, Dict.class).lambda().orderByAsc(Dict::getSort));
+		return R.data(DictWrapper.build().listNodeVO(list));
+	}
+
+	/**
+	 * 获取字典树形结构
+	 *
+	 * @return
+	 */
+	@GetMapping("/tree")
+	@ApiOperationSupport(order = 3)
+	@ApiOperation(value = "树形结构", notes = "树形结构")
+	public R<List<DictVO>> tree() {
+		List<DictVO> tree = dictService.tree();
+		return R.data(tree);
+	}
+
+	/**
+	 * 新增或修改
+	 */
+	@PostMapping("/submit")
+	@ApiOperationSupport(order = 4)
+	@ApiOperation(value = "新增或修改", notes = "传入dict")
+	public R submit(@Valid @RequestBody Dict dict) {
+		return R.status(dictService.submit(dict));
+	}
+
+
+	/**
+	 * 删除
+	 */
+	@PostMapping("/remove")
+	@ApiOperationSupport(order = 5)
+	@CacheEvict(cacheNames = {DICT_LIST, DICT_VALUE}, allEntries = true)
+	@ApiOperation(value = "删除", notes = "传入ids")
+	public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
+		return R.status(dictService.removeByIds(Func.toLongList(ids)));
+	}
+
+	/**
+	 * 获取字典
+	 *
+	 * @return
+	 */
+	@GetMapping("/dictionary")
+	@ApiOperationSupport(order = 6)
+	@ApiOperation(value = "获取字典", notes = "获取字典")
+	public R<List<Dict>> dictionary(String code) {
+		List<Dict> tree = dictService.getList(code);
+		return R.data(tree);
+	}
+
+
+}

+ 80 - 0
src/main/java/org/springblade/modules/system/controller/LogApiController.java

@@ -0,0 +1,80 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.controller;
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.AllArgsConstructor;
+import org.springblade.core.log.model.LogApi;
+import org.springblade.core.log.model.LogApiVo;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.BeanUtil;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.StringPool;
+import org.springblade.modules.system.service.ILogApiService;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import springfox.documentation.annotations.ApiIgnore;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 控制器
+ *
+ * @author Chill
+ */
+@ApiIgnore
+@RestController
+@AllArgsConstructor
+@RequestMapping("/blade-log/api")
+public class LogApiController {
+
+	private ILogApiService logService;
+
+	/**
+	 * 查询单条
+	 */
+	@GetMapping("/detail")
+	public R<LogApi> detail(LogApi log) {
+		return R.data(logService.getOne(Condition.getQueryWrapper(log)));
+	}
+
+	/**
+	 * 查询多条(分页)
+	 */
+	@GetMapping("/list")
+	public R<IPage<LogApiVo>> list(@ApiIgnore @RequestParam Map<String, Object> log, Query query) {
+		query.setAscs("create_time");
+		query.setDescs(StringPool.EMPTY);
+		IPage<LogApi> pages = logService.page(Condition.getPage(query), Condition.getQueryWrapper(log, LogApi.class));
+		List<LogApiVo> records = pages.getRecords().stream().map(logApi -> {
+			LogApiVo vo = BeanUtil.copy(logApi, LogApiVo.class);
+			vo.setStrId(Func.toStr(logApi.getId()));
+			return vo;
+		}).collect(Collectors.toList());
+		IPage<LogApiVo> pageVo = new Page<>(pages.getCurrent(), pages.getSize(), pages.getTotal());
+		pageVo.setRecords(records);
+		return R.data(pageVo);
+	}
+
+}

+ 80 - 0
src/main/java/org/springblade/modules/system/controller/LogErrorController.java

@@ -0,0 +1,80 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.controller;
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.AllArgsConstructor;
+import org.springblade.core.log.model.LogError;
+import org.springblade.core.log.model.LogErrorVo;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.BeanUtil;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.StringPool;
+import org.springblade.modules.system.service.ILogErrorService;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import springfox.documentation.annotations.ApiIgnore;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 控制器
+ *
+ * @author Chill
+ */
+@ApiIgnore
+@RestController
+@AllArgsConstructor
+@RequestMapping("/blade-log/error")
+public class LogErrorController {
+
+	private ILogErrorService errorLogService;
+
+	/**
+	 * 查询单条
+	 */
+	@GetMapping("/detail")
+	public R<LogError> detail(LogError logError) {
+		return R.data(errorLogService.getOne(Condition.getQueryWrapper(logError)));
+	}
+
+	/**
+	 * 查询多条(分页)
+	 */
+	@GetMapping("/list")
+	public R<IPage<LogErrorVo>> list(@ApiIgnore @RequestParam Map<String, Object> logError, Query query) {
+		query.setAscs("create_time");
+		query.setDescs(StringPool.EMPTY);
+		IPage<LogError> pages = errorLogService.page(Condition.getPage(query), Condition.getQueryWrapper(logError, LogError.class));
+		List<LogErrorVo> records = pages.getRecords().stream().map(logApi -> {
+			LogErrorVo vo = BeanUtil.copy(logApi, LogErrorVo.class);
+			vo.setStrId(Func.toStr(logApi.getId()));
+			return vo;
+		}).collect(Collectors.toList());
+		IPage<LogErrorVo> pageVo = new Page<>(pages.getCurrent(), pages.getSize(), pages.getTotal());
+		pageVo.setRecords(records);
+		return R.data(pageVo);
+	}
+
+}

+ 80 - 0
src/main/java/org/springblade/modules/system/controller/LogUsualController.java

@@ -0,0 +1,80 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.controller;
+
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.AllArgsConstructor;
+import org.springblade.core.log.model.LogUsual;
+import org.springblade.core.log.model.LogUsualVo;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.BeanUtil;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.core.tool.utils.StringPool;
+import org.springblade.modules.system.service.ILogUsualService;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import springfox.documentation.annotations.ApiIgnore;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 控制器
+ *
+ * @author Chill
+ */
+@ApiIgnore
+@RestController
+@AllArgsConstructor
+@RequestMapping("/blade-log/usual")
+public class LogUsualController {
+
+	private ILogUsualService logService;
+
+	/**
+	 * 查询单条
+	 */
+	@GetMapping("/detail")
+	public R<LogUsual> detail(LogUsual log) {
+		return R.data(logService.getOne(Condition.getQueryWrapper(log)));
+	}
+
+	/**
+	 * 查询多条(分页)
+	 */
+	@GetMapping("/list")
+	public R<IPage<LogUsualVo>> list(@ApiIgnore @RequestParam Map<String, Object> log, Query query) {
+		query.setAscs("create_time");
+		query.setDescs(StringPool.EMPTY);
+		IPage<LogUsual> pages = logService.page(Condition.getPage(query), Condition.getQueryWrapper(log, LogUsual.class));
+		List<LogUsualVo> records = pages.getRecords().stream().map(logApi -> {
+			LogUsualVo vo = BeanUtil.copy(logApi, LogUsualVo.class);
+			vo.setStrId(Func.toStr(logApi.getId()));
+			return vo;
+		}).collect(Collectors.toList());
+		IPage<LogUsualVo> pageVo = new Page<>(pages.getCurrent(), pages.getSize(), pages.getTotal());
+		pageVo.setRecords(records);
+		return R.data(pageVo);
+	}
+
+}

+ 211 - 0
src/main/java/org/springblade/modules/system/controller/MenuController.java

@@ -0,0 +1,211 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.controller;
+
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.annotations.*;
+import lombok.AllArgsConstructor;
+import org.springblade.core.boot.ctrl.BladeController;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.secure.BladeUser;
+import org.springblade.core.secure.annotation.PreAuth;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.constant.RoleConstant;
+import org.springblade.core.tool.support.Kv;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.modules.system.entity.Menu;
+import org.springblade.modules.system.service.IMenuService;
+import org.springblade.modules.system.vo.CheckedTreeVO;
+import org.springblade.modules.system.vo.GrantTreeVO;
+import org.springblade.modules.system.vo.MenuVO;
+import org.springblade.modules.system.wrapper.MenuWrapper;
+import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.validation.Valid;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 控制器
+ *
+ * @author Chill
+ */
+@ApiIgnore
+@RestController
+@AllArgsConstructor
+@RequestMapping("/blade-system/menu")
+@Api(value = "菜单", tags = "菜单")
+public class MenuController extends BladeController {
+
+	private IMenuService menuService;
+
+	/**
+	 * 详情
+	 */
+	@GetMapping("/detail")
+	@PreAuth(RoleConstant.HAS_ROLE_ADMIN)
+	@ApiOperationSupport(order = 1)
+	@ApiOperation(value = "详情", notes = "传入menu")
+	public R<MenuVO> detail(Menu menu) {
+		Menu detail = menuService.getOne(Condition.getQueryWrapper(menu));
+		return R.data(MenuWrapper.build().entityVO(detail));
+	}
+
+	/**
+	 * 列表
+	 */
+	@GetMapping("/list")
+	@ApiImplicitParams({
+		@ApiImplicitParam(name = "code", value = "菜单编号", paramType = "query", dataType = "string"),
+		@ApiImplicitParam(name = "name", value = "菜单名称", paramType = "query", dataType = "string")
+	})
+	@PreAuth(RoleConstant.HAS_ROLE_ADMIN)
+	@ApiOperationSupport(order = 2)
+	@ApiOperation(value = "列表", notes = "传入menu")
+	public R<List<MenuVO>> list(@ApiIgnore @RequestParam Map<String, Object> menu) {
+		List<Menu> list = menuService.list(Condition.getQueryWrapper(menu, Menu.class).lambda().orderByAsc(Menu::getSort));
+		return R.data(MenuWrapper.build().listNodeVO(list));
+	}
+
+	/**
+	 * 菜单列表
+	 */
+	@GetMapping("/menu-list")
+	@ApiImplicitParams({
+		@ApiImplicitParam(name = "code", value = "菜单编号", paramType = "query", dataType = "string"),
+		@ApiImplicitParam(name = "name", value = "菜单名称", paramType = "query", dataType = "string")
+	})
+	@PreAuth(RoleConstant.HAS_ROLE_ADMIN)
+	@ApiOperationSupport(order = 3)
+	@ApiOperation(value = "菜单列表", notes = "传入menu")
+	public R<List<MenuVO>> menuList(@ApiIgnore @RequestParam Map<String, Object> menu) {
+		List<Menu> list = menuService.list(Condition.getQueryWrapper(menu, Menu.class).lambda().eq(Menu::getCategory, 1).orderByAsc(Menu::getSort));
+		return R.data(MenuWrapper.build().listNodeVO(list));
+	}
+
+	/**
+	 * 懒加载菜单列表
+	 */
+	@GetMapping("/lazy-menu-list")
+	@ApiImplicitParams({
+		@ApiImplicitParam(name = "code", value = "菜单编号", paramType = "query", dataType = "string"),
+		@ApiImplicitParam(name = "name", value = "菜单名称", paramType = "query", dataType = "string")
+	})
+	@PreAuth(RoleConstant.HAS_ROLE_ADMIN)
+	@ApiOperationSupport(order = 4)
+	@ApiOperation(value = "懒加载菜单列表", notes = "传入menu")
+	public R<List<MenuVO>> lazyMenuList(Long parentId, @ApiIgnore @RequestParam Map<String, Object> menu) {
+		List<MenuVO> list = menuService.lazyMenuList(parentId, menu);
+		return R.data(MenuWrapper.build().listNodeLazyVO(list));
+	}
+
+	/**
+	 * 新增或修改
+	 */
+	@PostMapping("/submit")
+	@PreAuth(RoleConstant.HAS_ROLE_ADMIN)
+	@ApiOperationSupport(order = 5)
+	@ApiOperation(value = "新增或修改", notes = "传入menu")
+	public R submit(@Valid @RequestBody Menu menu) {
+		return R.status(menuService.saveOrUpdate(menu));
+	}
+
+
+	/**
+	 * 删除
+	 */
+	@PostMapping("/remove")
+	@PreAuth(RoleConstant.HAS_ROLE_ADMIN)
+	@ApiOperationSupport(order = 6)
+	@ApiOperation(value = "删除", notes = "传入ids")
+	public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
+		return R.status(menuService.removeByIds(Func.toLongList(ids)));
+	}
+
+	/**
+	 * 前端菜单数据
+	 */
+	@GetMapping("/routes")
+	@ApiOperationSupport(order = 7)
+	@ApiOperation(value = "前端菜单数据", notes = "前端菜单数据")
+	public R<List<MenuVO>> routes(BladeUser user) {
+		List<MenuVO> list = menuService.routes((user == null || user.getUserId() == 0L) ? null : user.getRoleId());
+		return R.data(list);
+	}
+
+	/**
+	 * 前端按钮数据
+	 */
+	@GetMapping("/buttons")
+	@ApiOperationSupport(order = 8)
+	@ApiOperation(value = "前端按钮数据", notes = "前端按钮数据")
+	public R<List<MenuVO>> buttons(BladeUser user) {
+		List<MenuVO> list = menuService.buttons(user.getRoleId());
+		return R.data(list);
+	}
+
+	/**
+	 * 获取菜单树形结构
+	 */
+	@GetMapping("/tree")
+	@ApiOperationSupport(order = 9)
+	@ApiOperation(value = "树形结构", notes = "树形结构")
+	public R<List<MenuVO>> tree() {
+		List<MenuVO> tree = menuService.tree();
+		return R.data(tree);
+	}
+
+	/**
+	 * 获取权限分配树形结构
+	 */
+	@GetMapping("/grant-tree")
+	@ApiOperationSupport(order = 10)
+	@ApiOperation(value = "权限分配树形结构", notes = "权限分配树形结构")
+	public R<GrantTreeVO> grantTree(BladeUser user) {
+		GrantTreeVO vo = new GrantTreeVO();
+		vo.setMenu(menuService.grantTree(user));
+		vo.setDataScope(menuService.grantDataScopeTree(user));
+		return R.data(vo);
+	}
+
+	/**
+	 * 获取权限分配树形结构
+	 */
+	@GetMapping("/role-tree-keys")
+	@ApiOperationSupport(order = 11)
+	@ApiOperation(value = "角色所分配的树", notes = "角色所分配的树")
+	public R<CheckedTreeVO> roleTreeKeys(String roleIds) {
+		CheckedTreeVO vo = new CheckedTreeVO();
+		vo.setMenu(menuService.roleTreeKeys(roleIds));
+		vo.setDataScope(menuService.dataScopeTreeKeys(roleIds));
+		return R.data(vo);
+	}
+
+	/**
+	 * 获取配置的角色权限
+	 */
+	@GetMapping("auth-routes")
+	@ApiOperationSupport(order = 12)
+	@ApiOperation(value = "菜单的角色权限")
+	public R<List<Kv>> authRoutes(BladeUser user) {
+		if (Func.isEmpty(user) || user.getUserId() == 0L) {
+			return null;
+		}
+		return R.data(menuService.authRoutes(user));
+	}
+
+}

+ 93 - 0
src/main/java/org/springblade/modules/system/controller/ParamController.java

@@ -0,0 +1,93 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import io.swagger.annotations.*;
+import lombok.AllArgsConstructor;
+import org.springblade.core.boot.ctrl.BladeController;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.modules.system.entity.Param;
+import org.springblade.modules.system.service.IParamService;
+import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.validation.Valid;
+import java.util.Map;
+
+/**
+ * 控制器
+ *
+ * @author Chill
+ */
+@ApiIgnore
+@RestController
+@AllArgsConstructor
+@RequestMapping("/blade-system/param")
+@Api(value = "参数管理", tags = "接口")
+public class ParamController extends BladeController {
+
+	private IParamService paramService;
+
+	/**
+	 * 详情
+	 */
+	@GetMapping("/detail")
+	@ApiOperation(value = "详情", notes = "传入param")
+	public R<Param> detail(Param param) {
+		Param detail = paramService.getOne(Condition.getQueryWrapper(param));
+		return R.data(detail);
+	}
+
+	/**
+	 * 分页
+	 */
+	@GetMapping("/list")
+	@ApiImplicitParams({
+		@ApiImplicitParam(name = "paramName", value = "参数名称", paramType = "query", dataType = "string"),
+		@ApiImplicitParam(name = "paramKey", value = "参数键名", paramType = "query", dataType = "string"),
+		@ApiImplicitParam(name = "paramValue", value = "参数键值", paramType = "query", dataType = "string")
+	})
+	@ApiOperation(value = "分页", notes = "传入param")
+	public R<IPage<Param>> list(@ApiIgnore @RequestParam Map<String, Object> param, Query query) {
+		IPage<Param> pages = paramService.page(Condition.getPage(query), Condition.getQueryWrapper(param, Param.class));
+		return R.data(pages);
+	}
+
+	/**
+	 * 新增或修改
+	 */
+	@PostMapping("/submit")
+	@ApiOperation(value = "新增或修改", notes = "传入param")
+	public R submit(@Valid @RequestBody Param param) {
+		return R.status(paramService.saveOrUpdate(param));
+	}
+
+
+	/**
+	 * 删除
+	 */
+	@PostMapping("/remove")
+	@ApiOperation(value = "逻辑删除", notes = "传入ids")
+	public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
+		return R.status(paramService.deleteLogic(Func.toLongList(ids)));
+	}
+
+
+}

+ 142 - 0
src/main/java/org/springblade/modules/system/controller/PostController.java

@@ -0,0 +1,142 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.AllArgsConstructor;
+import org.springblade.core.boot.ctrl.BladeController;
+import org.springblade.core.launch.constant.AppConstant;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.secure.BladeUser;
+import org.springblade.core.secure.utils.SecureUtil;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.modules.system.entity.Post;
+import org.springblade.modules.system.service.IPostService;
+import org.springblade.modules.system.vo.PostVO;
+import org.springblade.modules.system.wrapper.PostWrapper;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+import java.util.List;
+
+/**
+ * 岗位表 控制器
+ *
+ * @author Chill
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping(AppConstant.APPLICATION_SYSTEM_NAME + "/post")
+@Api(value = "岗位表", tags = "岗位表接口")
+public class PostController extends BladeController {
+
+	private IPostService postService;
+
+	/**
+	 * 详情
+	 */
+	@GetMapping("/detail")
+	@ApiOperationSupport(order = 1)
+	@ApiOperation(value = "详情", notes = "传入post")
+	public R<PostVO> detail(Post post) {
+		Post detail = postService.getOne(Condition.getQueryWrapper(post));
+		return R.data(PostWrapper.build().entityVO(detail));
+	}
+
+	/**
+	 * 分页 岗位表
+	 */
+	@GetMapping("/list")
+	@ApiOperationSupport(order = 2)
+	@ApiOperation(value = "分页", notes = "传入post")
+	public R<IPage<PostVO>> list(Post post, Query query) {
+		IPage<Post> pages = postService.page(Condition.getPage(query), Condition.getQueryWrapper(post));
+		return R.data(PostWrapper.build().pageVO(pages));
+	}
+
+
+	/**
+	 * 自定义分页 岗位表
+	 */
+	@GetMapping("/page")
+	@ApiOperationSupport(order = 3)
+	@ApiOperation(value = "分页", notes = "传入post")
+	public R<IPage<PostVO>> page(PostVO post, Query query) {
+		IPage<PostVO> pages = postService.selectPostPage(Condition.getPage(query), post);
+		return R.data(pages);
+	}
+
+	/**
+	 * 新增 岗位表
+	 */
+	@PostMapping("/save")
+	@ApiOperationSupport(order = 4)
+	@ApiOperation(value = "新增", notes = "传入post")
+	public R save(@Valid @RequestBody Post post) {
+		return R.status(postService.save(post));
+	}
+
+	/**
+	 * 修改 岗位表
+	 */
+	@PostMapping("/update")
+	@ApiOperationSupport(order = 5)
+	@ApiOperation(value = "修改", notes = "传入post")
+	public R update(@Valid @RequestBody Post post) {
+		return R.status(postService.updateById(post));
+	}
+
+	/**
+	 * 新增或修改 岗位表
+	 */
+	@PostMapping("/submit")
+	@ApiOperationSupport(order = 6)
+	@ApiOperation(value = "新增或修改", notes = "传入post")
+	public R submit(@Valid @RequestBody Post post) {
+		post.setTenantId(SecureUtil.getTenantId());
+		return R.status(postService.saveOrUpdate(post));
+	}
+
+
+	/**
+	 * 删除 岗位表
+	 */
+	@PostMapping("/remove")
+	@ApiOperationSupport(order = 7)
+	@ApiOperation(value = "逻辑删除", notes = "传入ids")
+	public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
+		return R.status(postService.deleteLogic(Func.toLongList(ids)));
+	}
+
+	/**
+	 * 下拉数据源
+	 */
+	@GetMapping("/select")
+	@ApiOperationSupport(order = 8)
+	@ApiOperation(value = "下拉数据源", notes = "传入post")
+	public R<List<Post>> select(String tenantId, BladeUser bladeUser) {
+		List<Post> list = postService.list(Wrappers.<Post>query().lambda().eq(Post::getTenantId, Func.toStr(tenantId, bladeUser.getTenantId())));
+		return R.data(list);
+	}
+
+}

+ 159 - 0
src/main/java/org/springblade/modules/system/controller/RegionController.java

@@ -0,0 +1,159 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.controller;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.annotations.*;
+import lombok.AllArgsConstructor;
+import org.springblade.core.boot.ctrl.BladeController;
+import org.springblade.core.launch.constant.AppConstant;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.node.INode;
+import org.springblade.modules.system.entity.Region;
+import org.springblade.modules.system.service.IRegionService;
+import org.springblade.modules.system.vo.RegionVO;
+import org.springblade.modules.system.vo.RoleVO;
+import org.springblade.modules.system.wrapper.RegionWrapper;
+import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.validation.Valid;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 行政区划表 控制器
+ *
+ * @author Chill
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping(AppConstant.APPLICATION_SYSTEM_NAME + "/region")
+@Api(value = "行政区划表", tags = "行政区划表接口")
+public class RegionController extends BladeController {
+
+	private final IRegionService regionService;
+
+	/**
+	 * 详情
+	 */
+	@GetMapping("/detail")
+	@ApiOperationSupport(order = 1)
+	@ApiOperation(value = "详情", notes = "传入region")
+	public R<RegionVO> detail(Region region) {
+		Region detail = regionService.getOne(Condition.getQueryWrapper(region));
+		return R.data(RegionWrapper.build().entityVO(detail));
+	}
+
+	/**
+	 * 分页 行政区划表
+	 */
+	@GetMapping("/list")
+	@ApiOperationSupport(order = 2)
+	@ApiOperation(value = "分页", notes = "传入region")
+	public R<IPage<Region>> list(Region region, Query query) {
+		IPage<Region> pages = regionService.page(Condition.getPage(query), Condition.getQueryWrapper(region));
+		return R.data(pages);
+	}
+
+	/**
+	 * 懒加载列表
+	 */
+	@GetMapping("/lazy-list")
+	@ApiImplicitParams({
+		@ApiImplicitParam(name = "code", value = "区划编号", paramType = "query", dataType = "string"),
+		@ApiImplicitParam(name = "name", value = "区划名称", paramType = "query", dataType = "string")
+	})
+	@ApiOperationSupport(order = 3)
+	@ApiOperation(value = "懒加载列表", notes = "传入menu")
+	public R<List<RoleVO>> lazyList(String parentCode, @ApiIgnore @RequestParam Map<String, Object> menu) {
+		List<RoleVO> list = regionService.lazyList(parentCode, menu);
+		return R.data(RegionWrapper.build().listNodeLazyVO(list));
+	}
+
+	/**
+	 * 懒加载列表
+	 */
+	@GetMapping("/lazy-tree")
+	@ApiImplicitParams({
+		@ApiImplicitParam(name = "code", value = "区划编号", paramType = "query", dataType = "string"),
+		@ApiImplicitParam(name = "name", value = "区划名称", paramType = "query", dataType = "string")
+	})
+	@ApiOperationSupport(order = 4)
+	@ApiOperation(value = "懒加载列表", notes = "传入menu")
+	public R<List<RoleVO>> lazyTree(String parentCode, @ApiIgnore @RequestParam Map<String, Object> menu) {
+		List<RoleVO> list = regionService.lazyTree(parentCode, menu);
+		return R.data(RegionWrapper.build().listNodeLazyVO(list));
+	}
+
+	/**
+	 * 新增 行政区划表
+	 */
+	@PostMapping("/save")
+	@ApiOperationSupport(order = 5)
+	@ApiOperation(value = "新增", notes = "传入region")
+	public R save(@Valid @RequestBody Region region) {
+		return R.status(regionService.save(region));
+	}
+
+	/**
+	 * 修改 行政区划表
+	 */
+	@PostMapping("/update")
+	@ApiOperationSupport(order = 6)
+	@ApiOperation(value = "修改", notes = "传入region")
+	public R update(@Valid @RequestBody Region region) {
+		return R.status(regionService.updateById(region));
+	}
+
+	/**
+	 * 新增或修改 行政区划表
+	 */
+	@PostMapping("/submit")
+	@ApiOperationSupport(order = 7)
+	@ApiOperation(value = "新增或修改", notes = "传入region")
+	public R submit(@Valid @RequestBody Region region) {
+		return R.status(regionService.submit(region));
+	}
+
+
+	/**
+	 * 删除 行政区划表
+	 */
+	@PostMapping("/remove")
+	@ApiOperationSupport(order = 8)
+	@ApiOperation(value = "删除", notes = "传入主键")
+	public R remove(@ApiParam(value = "主键", required = true) @RequestParam String id) {
+		return R.status(regionService.removeRegion(id));
+	}
+
+	/**
+	 * 行政区划下拉数据源
+	 */
+	@GetMapping("/select")
+	@ApiOperationSupport(order = 9)
+	@ApiOperation(value = "下拉数据源", notes = "传入tenant")
+	public R<List<Region>> select(@RequestParam(required = false, defaultValue = "00") String code) {
+		List<Region> list = regionService.list(Wrappers.<Region>query().lambda().eq(Region::getParentCode, code));
+		return R.data(list);
+	}
+
+
+}

+ 144 - 0
src/main/java/org/springblade/modules/system/controller/RoleController.java

@@ -0,0 +1,144 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.annotations.*;
+import lombok.AllArgsConstructor;
+import org.springblade.core.boot.ctrl.BladeController;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.secure.BladeUser;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.constant.BladeConstant;
+import org.springblade.core.tool.utils.CacheUtil;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.modules.system.entity.Role;
+import org.springblade.modules.system.service.IRoleService;
+import org.springblade.modules.system.vo.GrantVO;
+import org.springblade.modules.system.vo.RoleVO;
+import org.springblade.modules.system.wrapper.RoleWrapper;
+import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.validation.Valid;
+import java.util.List;
+import java.util.Map;
+
+import static org.springblade.core.tool.utils.CacheUtil.SYS_CACHE;
+
+/**
+ * 控制器
+ *
+ * @author Chill
+ */
+@ApiIgnore
+@RestController
+@AllArgsConstructor
+@RequestMapping("/blade-system/role")
+@Api(value = "角色", tags = "角色")
+public class RoleController extends BladeController {
+
+	private IRoleService roleService;
+
+	/**
+	 * 详情
+	 */
+	@GetMapping("/detail")
+	@ApiOperationSupport(order = 1)
+	@ApiOperation(value = "详情", notes = "传入role")
+	public R<RoleVO> detail(Role role) {
+		Role detail = roleService.getOne(Condition.getQueryWrapper(role));
+		return R.data(RoleWrapper.build().entityVO(detail));
+	}
+
+	/**
+	 * 列表
+	 */
+	@GetMapping("/list")
+	@ApiImplicitParams({
+		@ApiImplicitParam(name = "roleName", value = "参数名称", paramType = "query", dataType = "string"),
+		@ApiImplicitParam(name = "roleAlias", value = "角色别名", paramType = "query", dataType = "string")
+	})
+	@ApiOperationSupport(order = 2)
+	@ApiOperation(value = "列表", notes = "传入role")
+	public R<List<RoleVO>> list(@ApiIgnore @RequestParam Map<String, Object> role, BladeUser bladeUser) {
+		QueryWrapper<Role> queryWrapper = Condition.getQueryWrapper(role, Role.class);
+		List<Role> list = roleService.list((!bladeUser.getTenantId().equals(BladeConstant.ADMIN_TENANT_ID)) ? queryWrapper.lambda().eq(Role::getTenantId, bladeUser.getTenantId()) : queryWrapper);
+		return R.data(RoleWrapper.build().listNodeVO(list));
+	}
+
+	/**
+	 * 获取角色树形结构
+	 */
+	@GetMapping("/tree")
+	@ApiOperationSupport(order = 3)
+	@ApiOperation(value = "树形结构", notes = "树形结构")
+	public R<List<RoleVO>> tree(String tenantId, BladeUser bladeUser) {
+		List<RoleVO> tree = roleService.tree(Func.toStr(tenantId, bladeUser.getTenantId()));
+		return R.data(tree);
+	}
+
+	/**
+	 * 获取指定角色树形结构
+	 */
+	@GetMapping("/tree-by-id")
+	@ApiOperationSupport(order = 4)
+	@ApiOperation(value = "树形结构", notes = "树形结构")
+	public R<List<RoleVO>> treeById(Long roleId, BladeUser bladeUser) {
+		Role role = roleService.getById(roleId);
+		List<RoleVO> tree = roleService.tree(Func.notNull(role) ? role.getTenantId() : bladeUser.getTenantId());
+		return R.data(tree);
+	}
+
+	/**
+	 * 新增或修改
+	 */
+	@PostMapping("/submit")
+	@ApiOperationSupport(order = 5)
+	@ApiOperation(value = "新增或修改", notes = "传入role")
+	public R submit(@Valid @RequestBody Role role, BladeUser user) {
+		CacheUtil.clear(SYS_CACHE);
+		if (Func.isEmpty(role.getId())) {
+			role.setTenantId(user.getTenantId());
+		}
+		return R.status(roleService.saveOrUpdate(role));
+	}
+
+	/**
+	 * 删除
+	 */
+	@PostMapping("/remove")
+	@ApiOperationSupport(order = 6)
+	@ApiOperation(value = "删除", notes = "传入ids")
+	public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
+		CacheUtil.clear(SYS_CACHE);
+		return R.status(roleService.removeByIds(Func.toLongList(ids)));
+	}
+
+	/**
+	 * 设置菜单权限
+	 */
+	@PostMapping("/grant")
+	@ApiOperationSupport(order = 7)
+	@ApiOperation(value = "权限设置", notes = "传入roleId集合以及menuId集合")
+	public R grant(@RequestBody GrantVO grantVO) {
+		CacheUtil.clear(SYS_CACHE);
+		boolean temp = roleService.grant(grantVO.getRoleIds(), grantVO.getMenuIds(), grantVO.getDataScopeIds());
+		return R.status(temp);
+	}
+
+}

+ 137 - 0
src/main/java/org/springblade/modules/system/controller/TenantController.java

@@ -0,0 +1,137 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import io.swagger.annotations.*;
+import lombok.AllArgsConstructor;
+import org.springblade.core.boot.ctrl.BladeController;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.secure.BladeUser;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.constant.BladeConstant;
+import org.springblade.core.tool.support.Kv;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.modules.system.entity.Tenant;
+import org.springblade.modules.system.service.ITenantService;
+import org.springframework.web.bind.annotation.*;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.validation.Valid;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 控制器
+ *
+ * @author Chill
+ */
+@RestController
+@AllArgsConstructor
+@RequestMapping("/blade-system/tenant")
+@ApiIgnore
+@Api(value = "租户管理", tags = "接口")
+public class TenantController extends BladeController {
+
+	private ITenantService tenantService;
+
+	/**
+	 * 详情
+	 */
+	@GetMapping("/detail")
+	@ApiOperation(value = "详情", notes = "传入tenant")
+	public R<Tenant> detail(Tenant tenant) {
+		Tenant detail = tenantService.getOne(Condition.getQueryWrapper(tenant));
+		return R.data(detail);
+	}
+
+	/**
+	 * 分页
+	 */
+	@GetMapping("/list")
+	@ApiImplicitParams({
+		@ApiImplicitParam(name = "tenantId", value = "参数名称", paramType = "query", dataType = "string"),
+		@ApiImplicitParam(name = "tenantName", value = "角色别名", paramType = "query", dataType = "string"),
+		@ApiImplicitParam(name = "contactNumber", value = "联系电话", paramType = "query", dataType = "string")
+	})
+	@ApiOperation(value = "分页", notes = "传入tenant")
+	public R<IPage<Tenant>> list(@ApiIgnore @RequestParam Map<String, Object> tenant, Query query, BladeUser bladeUser) {
+		QueryWrapper<Tenant> queryWrapper = Condition.getQueryWrapper(tenant, Tenant.class);
+		IPage<Tenant> pages = tenantService.page(Condition.getPage(query), (!bladeUser.getTenantId().equals(BladeConstant.ADMIN_TENANT_ID)) ? queryWrapper.lambda().eq(Tenant::getTenantId, bladeUser.getTenantId()) : queryWrapper);
+		return R.data(pages);
+	}
+
+	/**
+	 * 下拉数据源
+	 */
+	@GetMapping("/select")
+	@ApiOperation(value = "下拉数据源", notes = "传入tenant")
+	public R<List<Tenant>> select(Tenant tenant, BladeUser bladeUser) {
+		QueryWrapper<Tenant> queryWrapper = Condition.getQueryWrapper(tenant);
+		List<Tenant> list = tenantService.list((!bladeUser.getTenantId().equals(BladeConstant.ADMIN_TENANT_ID)) ? queryWrapper.lambda().eq(Tenant::getTenantId, bladeUser.getTenantId()) : queryWrapper);
+		return R.data(list);
+	}
+
+	/**
+	 * 自定义分页
+	 */
+	@GetMapping("/page")
+	@ApiOperation(value = "分页", notes = "传入tenant")
+	public R<IPage<Tenant>> page(Tenant tenant, Query query) {
+		IPage<Tenant> pages = tenantService.selectTenantPage(Condition.getPage(query), tenant);
+		return R.data(pages);
+	}
+
+	/**
+	 * 新增或修改
+	 */
+	@PostMapping("/submit")
+	@ApiOperation(value = "新增或修改", notes = "传入tenant")
+	public R submit(@Valid @RequestBody Tenant tenant) {
+		return R.status(tenantService.saveTenant(tenant));
+	}
+
+
+	/**
+	 * 删除
+	 */
+	@PostMapping("/remove")
+	@ApiOperation(value = "逻辑删除", notes = "传入ids")
+	public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
+		return R.status(tenantService.deleteLogic(Func.toLongList(ids)));
+	}
+
+	/**
+	 * 根据域名查询信息
+	 *
+	 * @param domain 域名
+	 */
+	@GetMapping("/info")
+	@ApiOperation(value = "配置信息", notes = "传入domain")
+	public R<Kv> info(String domain) {
+		Tenant tenant = tenantService.getOne(Wrappers.<Tenant>query().lambda().eq(Tenant::getDomain, domain));
+		Kv kv = Kv.init();
+		if (tenant != null) {
+			kv.set("tenantId", tenant.getTenantId()).set("domain", tenant.getDomain());
+		}
+		return R.data(kv);
+	}
+
+
+}

+ 271 - 0
src/main/java/org/springblade/modules/system/controller/UserController.java

@@ -0,0 +1,271 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.controller;
+
+
+import com.alibaba.excel.EasyExcel;
+import com.alibaba.excel.read.builder.ExcelReaderBuilder;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import lombok.AllArgsConstructor;
+import lombok.SneakyThrows;
+import org.apache.commons.codec.Charsets;
+import org.springblade.core.mp.support.Condition;
+import org.springblade.core.mp.support.Query;
+import org.springblade.core.secure.BladeUser;
+import org.springblade.core.secure.utils.SecureUtil;
+import org.springblade.core.tool.api.R;
+import org.springblade.core.tool.constant.BladeConstant;
+import org.springblade.core.tool.utils.Func;
+import org.springblade.modules.system.entity.User;
+import org.springblade.modules.system.excel.UserExcel;
+import org.springblade.modules.system.excel.UserImportListener;
+import org.springblade.modules.system.service.IUserService;
+import org.springblade.modules.system.vo.UserVO;
+import org.springblade.modules.system.wrapper.UserWrapper;
+import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+import springfox.documentation.annotations.ApiIgnore;
+
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 控制器
+ *
+ * @author Chill
+ */
+@ApiIgnore
+@RestController
+@RequestMapping("blade-user")
+@AllArgsConstructor
+public class UserController {
+
+	private IUserService userService;
+
+	/**
+	 * 查询单条
+	 */
+	@ApiOperationSupport(order = 1)
+	@ApiOperation(value = "查看详情", notes = "传入id")
+	@GetMapping("/detail")
+	public R<UserVO> detail(User user) {
+		User detail = userService.getOne(Condition.getQueryWrapper(user));
+		return R.data(UserWrapper.build().entityVO(detail));
+	}
+
+	/**
+	 * 查询单条
+	 */
+	@ApiOperationSupport(order = 2)
+	@ApiOperation(value = "查看详情", notes = "传入id")
+	@GetMapping("/info")
+	public R<UserVO> info(BladeUser user) {
+		User detail = userService.getById(user.getUserId());
+		return R.data(UserWrapper.build().entityVO(detail));
+	}
+
+	/**
+	 * 用户列表
+	 */
+	@GetMapping("/list")
+	@ApiImplicitParams({
+		@ApiImplicitParam(name = "account", value = "账号名", paramType = "query", dataType = "string"),
+		@ApiImplicitParam(name = "realName", value = "姓名", paramType = "query", dataType = "string")
+	})
+	@ApiOperationSupport(order = 3)
+	@ApiOperation(value = "列表", notes = "传入account和realName")
+	public R<IPage<UserVO>> list(@ApiIgnore @RequestParam Map<String, Object> user, Query query, BladeUser bladeUser) {
+		QueryWrapper<User> queryWrapper = Condition.getQueryWrapper(user, User.class);
+		IPage<User> pages = userService.page(Condition.getPage(query), (!bladeUser.getTenantId().equals(BladeConstant.ADMIN_TENANT_ID)) ? queryWrapper.lambda().eq(User::getTenantId, bladeUser.getTenantId()) : queryWrapper);
+		return R.data(UserWrapper.build().pageVO(pages));
+	}
+
+	/**
+	 * 新增或修改
+	 */
+	@PostMapping("/submit")
+	@ApiOperationSupport(order = 4)
+	@ApiOperation(value = "新增或修改", notes = "传入User")
+	public R submit(@Valid @RequestBody User user) {
+		return R.status(userService.submit(user));
+	}
+
+	/**
+	 * 修改
+	 */
+	@PostMapping("/update")
+	@ApiOperationSupport(order = 5)
+	@ApiOperation(value = "修改", notes = "传入User")
+	public R update(@Valid @RequestBody User user) {
+		return R.status(userService.updateById(user));
+	}
+
+	/**
+	 * 删除
+	 */
+	@PostMapping("/remove")
+	@ApiOperationSupport(order = 6)
+	@ApiOperation(value = "删除", notes = "传入地基和")
+	public R remove(@RequestParam String ids) {
+		return R.status(userService.deleteLogic(Func.toLongList(ids)));
+	}
+
+
+	/**
+	 * 设置菜单权限
+	 *
+	 * @param userIds
+	 * @param roleIds
+	 * @return
+	 */
+	@PostMapping("/grant")
+	@ApiOperationSupport(order = 7)
+	@ApiOperation(value = "权限设置", notes = "传入roleId集合以及menuId集合")
+	public R grant(@ApiParam(value = "userId集合", required = true) @RequestParam String userIds,
+				   @ApiParam(value = "roleId集合", required = true) @RequestParam String roleIds) {
+		boolean temp = userService.grant(userIds, roleIds);
+		return R.status(temp);
+	}
+
+	@PostMapping("/reset-password")
+	@ApiOperationSupport(order = 8)
+	@ApiOperation(value = "初始化密码", notes = "传入userId集合")
+	public R resetPassword(@ApiParam(value = "userId集合", required = true) @RequestParam String userIds) {
+		boolean temp = userService.resetPassword(userIds);
+		return R.status(temp);
+	}
+
+	/**
+	 * 修改密码
+	 *
+	 * @param oldPassword
+	 * @param newPassword
+	 * @param newPassword1
+	 * @return
+	 */
+	@PostMapping("/update-password")
+	@ApiOperationSupport(order = 9)
+	@ApiOperation(value = "修改密码", notes = "传入密码")
+	public R updatePassword(BladeUser user, @ApiParam(value = "旧密码", required = true) @RequestParam String oldPassword,
+							@ApiParam(value = "新密码", required = true) @RequestParam String newPassword,
+							@ApiParam(value = "新密码", required = true) @RequestParam String newPassword1) {
+		boolean temp = userService.updatePassword(user.getUserId(), oldPassword, newPassword, newPassword1);
+		return R.status(temp);
+	}
+
+	/**
+	 * 用户列表
+	 *
+	 * @param user
+	 * @return
+	 */
+	@GetMapping("/user-list")
+	@ApiOperationSupport(order = 10)
+	@ApiOperation(value = "用户列表", notes = "传入user")
+	public R<List<User>> userList(User user) {
+		List<User> list = userService.list(Condition.getQueryWrapper(user));
+		return R.data(list);
+	}
+
+
+	/**
+	 * 导入用户
+	 */
+	@PostMapping("import-user")
+	@ApiOperationSupport(order = 12)
+	@ApiOperation(value = "导入用户", notes = "传入excel")
+	public R importUser(MultipartFile file, Integer isCovered) {
+		String filename = file.getOriginalFilename();
+		if (StringUtils.isEmpty(filename)) {
+			throw new RuntimeException("请上传文件!");
+		}
+		if ((!StringUtils.endsWithIgnoreCase(filename, ".xls") && !StringUtils.endsWithIgnoreCase(filename, ".xlsx"))) {
+			throw new RuntimeException("请上传正确的excel文件!");
+		}
+		InputStream inputStream;
+		try {
+			UserImportListener importListener = new UserImportListener(userService);
+			inputStream = new BufferedInputStream(file.getInputStream());
+			ExcelReaderBuilder builder = EasyExcel.read(inputStream, UserExcel.class, importListener);
+			builder.doReadAll();
+		} catch (IOException e) {
+			e.printStackTrace();
+		}
+		return R.success("操作成功");
+	}
+
+	/**
+	 * 导出用户
+	 */
+	@SneakyThrows
+	@GetMapping("export-user")
+	@ApiOperationSupport(order = 13)
+	@ApiOperation(value = "导出用户", notes = "传入user")
+	public void exportUser(@ApiIgnore @RequestParam Map<String, Object> user, BladeUser bladeUser, HttpServletResponse response) {
+		QueryWrapper<User> queryWrapper = Condition.getQueryWrapper(user, User.class);
+		if (!SecureUtil.isAdministrator()){
+			queryWrapper.lambda().eq(User::getTenantId, bladeUser.getTenantId());
+		}
+		queryWrapper.lambda().eq(User::getIsDeleted, BladeConstant.DB_NOT_DELETED);
+		List<UserExcel> list = userService.exportUser(queryWrapper);
+		response.setContentType("application/vnd.ms-excel");
+		response.setCharacterEncoding(Charsets.UTF_8.name());
+		String fileName = URLEncoder.encode("用户数据导出", Charsets.UTF_8.name());
+		response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
+		EasyExcel.write(response.getOutputStream(), UserExcel.class).sheet("用户数据表").doWrite(list);
+	}
+
+	/**
+	 * 导出模板
+	 */
+	@SneakyThrows
+	@GetMapping("export-template")
+	@ApiOperationSupport(order = 14)
+	@ApiOperation(value = "导出模板")
+	public void exportUser(HttpServletResponse response) {
+		List<UserExcel> list = new ArrayList<>();
+		response.setContentType("application/vnd.ms-excel");
+		response.setCharacterEncoding(Charsets.UTF_8.name());
+		String fileName = URLEncoder.encode("用户数据模板", Charsets.UTF_8.name());
+		response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
+		EasyExcel.write(response.getOutputStream(), UserExcel.class).sheet("用户数据表").doWrite(list);
+	}
+
+	/**
+	 * 第三方注册用户
+	 */
+	@PostMapping("/register-guest")
+	@ApiOperationSupport(order = 15)
+	@ApiOperation(value = "第三方注册用户", notes = "传入user")
+	public R registerGuest(User user, Long oauthId) {
+		return R.status(userService.registerGuest(user, oauthId));
+	}
+
+}

+ 32 - 0
src/main/java/org/springblade/modules/system/dto/DeptDTO.java

@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.dto;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.modules.system.entity.Dept;
+
+/**
+ * 数据传输对象实体类
+ *
+ * @author Chill
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class DeptDTO extends Dept {
+	private static final long serialVersionUID = 1L;
+
+}

+ 32 - 0
src/main/java/org/springblade/modules/system/dto/DictDTO.java

@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.dto;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.modules.system.entity.Dict;
+
+/**
+ * 数据传输对象实体类
+ *
+ * @author Chill
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class DictDTO extends Dict {
+	private static final long serialVersionUID = 1L;
+
+}

+ 32 - 0
src/main/java/org/springblade/modules/system/dto/MenuDTO.java

@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 数据传输对象实体类
+ *
+ * @author Chill
+ */
+@Data
+public class MenuDTO implements Serializable {
+	private static final long serialVersionUID = 1L;
+	private String alias;
+	private String path;
+}

+ 32 - 0
src/main/java/org/springblade/modules/system/dto/ParamDTO.java

@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.dto;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.modules.system.entity.Param;
+
+/**
+ * 数据传输对象实体类
+ *
+ * @author Chill
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class ParamDTO extends Param {
+	private static final long serialVersionUID = 1L;
+
+}

+ 32 - 0
src/main/java/org/springblade/modules/system/dto/RoleDTO.java

@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.dto;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.modules.system.entity.Role;
+
+/**
+ * 数据传输对象实体类
+ *
+ * @author Chill
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class RoleDTO extends Role {
+	private static final long serialVersionUID = 1L;
+
+}

+ 32 - 0
src/main/java/org/springblade/modules/system/dto/RoleMenuDTO.java

@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.dto;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.modules.system.entity.RoleMenu;
+
+/**
+ * 数据传输对象实体类
+ *
+ * @author Chill
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class RoleMenuDTO extends RoleMenu {
+	private static final long serialVersionUID = 1L;
+
+}

+ 108 - 0
src/main/java/org/springblade/modules/system/entity/AuthClient.java

@@ -0,0 +1,108 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.core.mp.base.BaseEntity;
+
+/**
+ * 实体类
+ *
+ * @author BladeX
+ * @since 2019-03-24
+ */
+@Data
+@TableName("blade_client")
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "Client对象", description = "Client对象")
+public class AuthClient extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 主键id
+	 */
+	@ApiModelProperty(value = "主键")
+	@TableId(value = "id", type = IdType.ASSIGN_ID)
+	@JsonSerialize(using = ToStringSerializer.class)
+	private Long id;
+
+	/**
+	 * 客户端id
+	 */
+	@ApiModelProperty(value = "客户端id")
+	private String clientId;
+	/**
+	 * 客户端密钥
+	 */
+	@ApiModelProperty(value = "客户端密钥")
+	private String clientSecret;
+	/**
+	 * 资源集合
+	 */
+	@ApiModelProperty(value = "资源集合")
+	private String resourceIds;
+	/**
+	 * 授权范围
+	 */
+	@ApiModelProperty(value = "授权范围")
+	private String scope;
+	/**
+	 * 授权类型
+	 */
+	@ApiModelProperty(value = "授权类型")
+	private String authorizedGrantTypes;
+	/**
+	 * 回调地址
+	 */
+	@ApiModelProperty(value = "回调地址")
+	private String webServerRedirectUri;
+	/**
+	 * 权限
+	 */
+	@ApiModelProperty(value = "权限")
+	private String authorities;
+	/**
+	 * 令牌过期秒数
+	 */
+	@ApiModelProperty(value = "令牌过期秒数")
+	private Integer accessTokenValidity;
+	/**
+	 * 刷新令牌过期秒数
+	 */
+	@ApiModelProperty(value = "刷新令牌过期秒数")
+	private Integer refreshTokenValidity;
+	/**
+	 * 附加说明
+	 */
+	@ApiModelProperty(value = "附加说明")
+	private String additionalInformation;
+	/**
+	 * 自动授权
+	 */
+	@ApiModelProperty(value = "自动授权")
+	private String autoapprove;
+
+
+}

+ 97 - 0
src/main/java/org/springblade/modules/system/entity/DataScope.java

@@ -0,0 +1,97 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.core.mp.base.BaseEntity;
+
+/**
+ * 实体类
+ *
+ * @author BladeX
+ */
+@Data
+@TableName("blade_scope_data")
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "DataScope对象", description = "DataScope对象")
+public class DataScope extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 主键
+	 */
+	@ApiModelProperty(value = "主键")
+	@TableId(value = "id", type = IdType.ASSIGN_ID)
+	@JsonSerialize(using = ToStringSerializer.class)
+	private Long id;
+
+	/**
+	 * 菜单主键
+	 */
+	@ApiModelProperty(value = "菜单主键")
+	private Long menuId;
+	/**
+	 * 资源编号
+	 */
+	@ApiModelProperty(value = "资源编号")
+	private String resourceCode;
+	/**
+	 * 数据权限名称
+	 */
+	@ApiModelProperty(value = "数据权限名称")
+	private String scopeName;
+	/**
+	 * 数据权限可见字段
+	 */
+	@ApiModelProperty(value = "数据权限可见字段")
+	private String scopeField;
+	/**
+	 * 数据权限类名
+	 */
+	@ApiModelProperty(value = "数据权限类名")
+	private String scopeClass;
+	/**
+	 * 数据权限字段
+	 */
+	@ApiModelProperty(value = "数据权限字段")
+	private String scopeColumn;
+	/**
+	 * 数据权限类型
+	 */
+	@ApiModelProperty(value = "数据权限类型")
+	private Integer scopeType;
+	/**
+	 * 数据权限值域
+	 */
+	@ApiModelProperty(value = "数据权限值域")
+	private String scopeValue;
+	/**
+	 * 数据权限备注
+	 */
+	@ApiModelProperty(value = "数据权限备注")
+	private String remark;
+
+
+}

+ 101 - 0
src/main/java/org/springblade/modules/system/entity/Dept.java

@@ -0,0 +1,101 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 实体类
+ *
+ * @author Chill
+ */
+@Data
+@TableName("blade_dept")
+@ApiModel(value = "Dept对象", description = "Dept对象")
+public class Dept implements Serializable {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 主键
+	 */
+	@ApiModelProperty(value = "主键")
+	@TableId(value = "id", type = IdType.ASSIGN_ID)
+	@JsonSerialize(using = ToStringSerializer.class)
+	private Long id;
+
+	/**
+	 * 租户ID
+	 */
+	@ApiModelProperty(value = "租户ID")
+	private String tenantId;
+
+	/**
+	 * 父主键
+	 */
+	@ApiModelProperty(value = "父主键")
+	@JsonSerialize(using = ToStringSerializer.class)
+	private Long parentId;
+
+	/**
+	 * 祖级机构主键
+	 */
+	@ApiModelProperty(value = "祖级机构主键")
+	private String ancestors;
+
+	/**
+	 * 部门名
+	 */
+	@ApiModelProperty(value = "部门名")
+	private String deptName;
+
+	/**
+	 * 部门全称
+	 */
+	@ApiModelProperty(value = "部门全称")
+	private String fullName;
+
+	/**
+	 * 排序
+	 */
+	@ApiModelProperty(value = "排序")
+	private Integer sort;
+
+	/**
+	 * 备注
+	 */
+	@ApiModelProperty(value = "备注")
+	private String remark;
+
+	/**
+	 * 是否已删除
+	 */
+	@TableLogic
+	@ApiModelProperty(value = "是否已删除")
+	private Integer isDeleted;
+
+
+}

+ 95 - 0
src/main/java/org/springblade/modules/system/entity/Dict.java

@@ -0,0 +1,95 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 实体类
+ *
+ * @author Chill
+ */
+@Data
+@TableName("blade_dict")
+@ApiModel(value = "Dict对象", description = "Dict对象")
+public class Dict implements Serializable {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 主键
+	 */
+	@ApiModelProperty(value = "主键")
+	@TableId(value = "id", type = IdType.ASSIGN_ID)
+	@JsonSerialize(using = ToStringSerializer.class)
+	private Long id;
+
+	/**
+	 * 父主键
+	 */
+	@ApiModelProperty(value = "父主键")
+	@JsonSerialize(using = ToStringSerializer.class)
+	private Long parentId;
+
+	/**
+	 * 字典码
+	 */
+	@ApiModelProperty(value = "字典码")
+	private String code;
+
+	/**
+	 * 字典值
+	 */
+	@ApiModelProperty(value = "字典值")
+	private Integer dictKey;
+
+	/**
+	 * 字典名称
+	 */
+	@ApiModelProperty(value = "字典名称")
+	private String dictValue;
+
+	/**
+	 * 排序
+	 */
+	@ApiModelProperty(value = "排序")
+	private Integer sort;
+
+	/**
+	 * 字典备注
+	 */
+	@ApiModelProperty(value = "字典备注")
+	private String remark;
+
+	/**
+	 * 是否已删除
+	 */
+	@TableLogic
+	@ApiModelProperty(value = "是否已删除")
+	private Integer isDeleted;
+
+
+}

+ 141 - 0
src/main/java/org/springblade/modules/system/entity/Menu.java

@@ -0,0 +1,141 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springblade.core.tool.utils.Func;
+
+import java.io.Serializable;
+
+/**
+ * 实体类
+ *
+ * @author Chill
+ */
+@Data
+@TableName("blade_menu")
+@ApiModel(value = "Menu对象", description = "Menu对象")
+public class Menu implements Serializable {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 主键
+	 */
+	@ApiModelProperty(value = "主键")
+	@TableId(value = "id", type = IdType.ASSIGN_ID)
+	@JsonSerialize(using = ToStringSerializer.class)
+	private Long id;
+
+	/**
+	 * 菜单父主键
+	 */
+	@ApiModelProperty(value = "父主键")
+	@JsonSerialize(using = ToStringSerializer.class)
+	private Long parentId;
+
+	/**
+	 * 菜单编号
+	 */
+	@ApiModelProperty(value = "菜单编号")
+	private String code;
+
+	/**
+	 * 菜单名称
+	 */
+	@ApiModelProperty(value = "菜单名称")
+	private String name;
+
+	/**
+	 * 菜单别名
+	 */
+	@ApiModelProperty(value = "菜单别名")
+	private String alias;
+
+	/**
+	 * 请求地址
+	 */
+	@ApiModelProperty(value = "请求地址")
+	private String path;
+
+	/**
+	 * 菜单资源
+	 */
+	@ApiModelProperty(value = "菜单资源")
+	private String source;
+
+	/**
+	 * 排序
+	 */
+	@ApiModelProperty(value = "排序")
+	private Integer sort;
+
+	/**
+	 * 菜单类型
+	 */
+	@ApiModelProperty(value = "菜单类型")
+	private Integer category;
+
+	/**
+	 * 操作按钮类型
+	 */
+	@ApiModelProperty(value = "操作按钮类型")
+	private Integer action;
+
+	/**
+	 * 是否打开新页面
+	 */
+	@ApiModelProperty(value = "是否打开新页面")
+	private Integer isOpen;
+
+	/**
+	 * 备注
+	 */
+	@ApiModelProperty(value = "备注")
+	private String remark;
+
+	/**
+	 * 是否已删除
+	 */
+	@TableLogic
+	@ApiModelProperty(value = "是否已删除")
+	private Integer isDeleted;
+
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj) {
+			return true;
+		}
+		if (obj == null) {
+			return false;
+		}
+		Menu other = (Menu) obj;
+		if (Func.equals(this.getId(), other.getId())) {
+			return true;
+		}
+		return false;
+	}
+
+}

+ 75 - 0
src/main/java/org/springblade/modules/system/entity/Param.java

@@ -0,0 +1,75 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.core.mp.base.BaseEntity;
+
+/**
+ * 实体类
+ *
+ * @author Chill
+ */
+@Data
+@TableName("blade_param")
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "Param对象", description = "Param对象")
+public class Param extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 主键id
+	 */
+	@ApiModelProperty(value = "主键")
+	@TableId(value = "id", type = IdType.ASSIGN_ID)
+	@JsonSerialize(using = ToStringSerializer.class)
+	private Long id;
+
+	/**
+	 * 参数名
+	 */
+	@ApiModelProperty(value = "参数名")
+	private String paramName;
+
+	/**
+	 * 参数键
+	 */
+	@ApiModelProperty(value = "参数键")
+	private String paramKey;
+
+	/**
+	 * 参数值
+	 */
+	@ApiModelProperty(value = "参数值")
+	private String paramValue;
+
+	/**
+	 * 备注
+	 */
+	@ApiModelProperty(value = "备注")
+	private String remark;
+
+
+}

+ 77 - 0
src/main/java/org/springblade/modules/system/entity/Post.java

@@ -0,0 +1,77 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.core.mp.base.TenantEntity;
+
+/**
+ * 岗位表实体类
+ *
+ * @author Chill
+ */
+@Data
+@TableName("blade_post")
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "Post对象", description = "岗位表")
+public class Post extends TenantEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 主键id
+	 */
+	@ApiModelProperty(value = "主键")
+	@TableId(value = "id", type = IdType.ASSIGN_ID)
+	@JsonSerialize(using = ToStringSerializer.class)
+	private Long id;
+
+	/**
+	 * 类型
+	 */
+	@ApiModelProperty(value = "类型")
+	private Integer category;
+	/**
+	 * 岗位编号
+	 */
+	@ApiModelProperty(value = "岗位编号")
+	private String postCode;
+	/**
+	 * 岗位名称
+	 */
+	@ApiModelProperty(value = "岗位名称")
+	private String postName;
+	/**
+	 * 岗位排序
+	 */
+	@ApiModelProperty(value = "岗位排序")
+	private Integer sort;
+	/**
+	 * 岗位描述
+	 */
+	@ApiModelProperty(value = "岗位描述")
+	private String remark;
+
+
+}

+ 127 - 0
src/main/java/org/springblade/modules/system/entity/Region.java

@@ -0,0 +1,127 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 行政区划表实体类
+ *
+ * @author Chill
+ */
+@Data
+@TableName("blade_region")
+@ApiModel(value = "Region对象", description = "行政区划表")
+public class Region implements Serializable {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 区划编号
+	 */
+	@TableId(value = "code", type = IdType.INPUT)
+	@ApiModelProperty(value = "区划编号")
+	private String code;
+	/**
+	 * 父区划编号
+	 */
+	@ApiModelProperty(value = "父区划编号")
+	private String parentCode;
+	/**
+	 * 祖区划编号
+	 */
+	@ApiModelProperty(value = "祖区划编号")
+	private String ancestors;
+	/**
+	 * 区划名称
+	 */
+	@ApiModelProperty(value = "区划名称")
+	private String name;
+	/**
+	 * 省级区划编号
+	 */
+	@ApiModelProperty(value = "省级区划编号")
+	private String provinceCode;
+	/**
+	 * 省级名称
+	 */
+	@ApiModelProperty(value = "省级名称")
+	private String provinceName;
+	/**
+	 * 市级区划编号
+	 */
+	@ApiModelProperty(value = "市级区划编号")
+	private String cityCode;
+	/**
+	 * 市级名称
+	 */
+	@ApiModelProperty(value = "市级名称")
+	private String cityName;
+	/**
+	 * 区级区划编号
+	 */
+	@ApiModelProperty(value = "区级区划编号")
+	private String districtCode;
+	/**
+	 * 区级名称
+	 */
+	@ApiModelProperty(value = "区级名称")
+	private String districtName;
+	/**
+	 * 镇级区划编号
+	 */
+	@ApiModelProperty(value = "镇级区划编号")
+	private String townCode;
+	/**
+	 * 镇级名称
+	 */
+	@ApiModelProperty(value = "镇级名称")
+	private String townName;
+	/**
+	 * 村级区划编号
+	 */
+	@ApiModelProperty(value = "村级区划编号")
+	private String villageCode;
+	/**
+	 * 村级名称
+	 */
+	@ApiModelProperty(value = "村级名称")
+	private String villageName;
+	/**
+	 * 层级
+	 */
+	@ApiModelProperty(value = "层级")
+	private Integer level;
+	/**
+	 * 排序
+	 */
+	@ApiModelProperty(value = "排序")
+	private Integer sort;
+	/**
+	 * 备注
+	 */
+	@ApiModelProperty(value = "备注")
+	private String remark;
+
+
+}

+ 89 - 0
src/main/java/org/springblade/modules/system/entity/Role.java

@@ -0,0 +1,89 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 实体类
+ *
+ * @author Chill
+ */
+@Data
+@TableName("blade_role")
+@ApiModel(value = "Role对象", description = "Role对象")
+public class Role implements Serializable {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 主键
+	 */
+	@ApiModelProperty(value = "主键")
+	@TableId(value = "id", type = IdType.ASSIGN_ID)
+	@JsonSerialize(using = ToStringSerializer.class)
+	private Long id;
+
+	/**
+	 * 租户ID
+	 */
+	@ApiModelProperty(value = "租户ID")
+	private String tenantId;
+
+	/**
+	 * 父主键
+	 */
+	@ApiModelProperty(value = "父主键")
+	@JsonSerialize(using = ToStringSerializer.class)
+	private Long parentId;
+
+	/**
+	 * 角色名
+	 */
+	@ApiModelProperty(value = "角色名")
+	private String roleName;
+
+	/**
+	 * 排序
+	 */
+	@ApiModelProperty(value = "排序")
+	private Integer sort;
+
+	/**
+	 * 角色别名
+	 */
+	@ApiModelProperty(value = "角色别名")
+	private String roleAlias;
+
+	/**
+	 * 是否已删除
+	 */
+	@TableLogic
+	@ApiModelProperty(value = "是否已删除")
+	private Integer isDeleted;
+
+
+}

+ 64 - 0
src/main/java/org/springblade/modules/system/entity/RoleMenu.java

@@ -0,0 +1,64 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 实体类
+ *
+ * @author Chill
+ */
+@Data
+@TableName("blade_role_menu")
+@ApiModel(value = "RoleMenu对象", description = "RoleMenu对象")
+public class RoleMenu implements Serializable {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 主键
+	 */
+	@ApiModelProperty(value = "主键")
+	@TableId(value = "id", type = IdType.ASSIGN_ID)
+	@JsonSerialize(using = ToStringSerializer.class)
+	private Long id;
+
+	/**
+	 * 菜单id
+	 */
+	@ApiModelProperty(value = "菜单id")
+	@JsonSerialize(using = ToStringSerializer.class)
+	private Long menuId;
+
+	/**
+	 * 角色id
+	 */
+	@ApiModelProperty(value = "角色id")
+	@JsonSerialize(using = ToStringSerializer.class)
+	private Long roleId;
+
+
+}

+ 64 - 0
src/main/java/org/springblade/modules/system/entity/RoleScope.java

@@ -0,0 +1,64 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 实体类
+ *
+ * @author Chill
+ */
+@Data
+@TableName("blade_role_scope")
+@ApiModel(value = "RoleScope对象", description = "RoleScope对象")
+public class RoleScope implements Serializable {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 主键
+	 */
+	@JsonSerialize(using = ToStringSerializer.class)
+	@ApiModelProperty(value = "主键")
+	@TableId(value = "id", type = IdType.ASSIGN_ID)
+	private Long id;
+
+	/**
+	 * 权限id
+	 */
+	@JsonSerialize(using = ToStringSerializer.class)
+	@ApiModelProperty(value = "权限id")
+	private Long scopeId;
+
+	/**
+	 * 角色id
+	 */
+	@JsonSerialize(using = ToStringSerializer.class)
+	@ApiModelProperty(value = "角色id")
+	private Long roleId;
+
+
+}

+ 82 - 0
src/main/java/org/springblade/modules/system/entity/Tenant.java

@@ -0,0 +1,82 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.core.mp.base.BaseEntity;
+
+/**
+ * 实体类
+ *
+ * @author Chill
+ */
+@Data
+@TableName("blade_tenant")
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "Tenant对象", description = "Tenant对象")
+public class Tenant extends BaseEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 主键id
+	 */
+	@ApiModelProperty(value = "主键")
+	@TableId(value = "id", type = IdType.ASSIGN_ID)
+	@JsonSerialize(using = ToStringSerializer.class)
+	private Long id;
+
+	/**
+	 * 租户ID
+	 */
+	@ApiModelProperty(value = "租户ID")
+	private String tenantId;
+	/**
+	 * 租户名称
+	 */
+	@ApiModelProperty(value = "租户名称")
+	private String tenantName;
+	/**
+	 * 域名地址
+	 */
+	@ApiModelProperty(value = "域名地址")
+	private String domain;
+	/**
+	 * 联系人
+	 */
+	@ApiModelProperty(value = "联系人")
+	private String linkman;
+	/**
+	 * 联系电话
+	 */
+	@ApiModelProperty(value = "联系电话")
+	private String contactNumber;
+	/**
+	 * 联系地址
+	 */
+	@ApiModelProperty(value = "联系地址")
+	private String address;
+
+
+}

+ 104 - 0
src/main/java/org/springblade/modules/system/entity/User.java

@@ -0,0 +1,104 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModelProperty;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springblade.core.mp.base.TenantEntity;
+
+import java.util.Date;
+
+/**
+ * 实体类
+ *
+ * @author Chill
+ */
+@Data
+@TableName("blade_user")
+@EqualsAndHashCode(callSuper = true)
+public class User extends TenantEntity {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 主键id
+	 */
+	@ApiModelProperty(value = "主键")
+	@TableId(value = "id", type = IdType.ASSIGN_ID)
+	@JsonSerialize(using = ToStringSerializer.class)
+	private Long id;
+
+	/**
+	 * 编号
+	 */
+	private String code;
+	/**
+	 * 账号
+	 */
+	private String account;
+	/**
+	 * 密码
+	 */
+	private String password;
+	/**
+	 * 昵称
+	 */
+	private String name;
+	/**
+	 * 真名
+	 */
+	private String realName;
+	/**
+	 * 头像
+	 */
+	private String avatar;
+	/**
+	 * 邮箱
+	 */
+	private String email;
+	/**
+	 * 手机
+	 */
+	private String phone;
+	/**
+	 * 生日
+	 */
+	private Date birthday;
+	/**
+	 * 性别
+	 */
+	private Integer sex;
+	/**
+	 * 角色id
+	 */
+	private String roleId;
+	/**
+	 * 部门id
+	 */
+	private String deptId;
+	/**
+	 * 部门id
+	 */
+	private String postId;
+
+
+}

+ 60 - 0
src/main/java/org/springblade/modules/system/entity/UserInfo.java

@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.entity;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 用户信息
+ *
+ * @author Chill
+ */
+@Data
+@ApiModel(description = "用户信息")
+public class UserInfo implements Serializable {
+
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * 用户基础信息
+	 */
+	@ApiModelProperty(value = "用户")
+	private User user;
+
+	/**
+	 * 权限标识集合
+	 */
+	@ApiModelProperty(value = "权限集合")
+	private List<String> permissions;
+
+	/**
+	 * 角色集合
+	 */
+	@ApiModelProperty(value = "角色集合")
+	private List<String> roles;
+
+	/**
+	 * 第三方授权id
+	 */
+	@ApiModelProperty(value = "第三方授权id")
+	private String oauthId;
+
+}

+ 107 - 0
src/main/java/org/springblade/modules/system/entity/UserOauth.java

@@ -0,0 +1,107 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 实体类
+ *
+ * @author Chill
+ */
+@Data
+@TableName("blade_user_oauth")
+public class UserOauth implements Serializable {
+
+	private static final long serialVersionUID = 1L;
+
+
+	/**
+	 * 主键
+	 */
+	@JsonSerialize(using = ToStringSerializer.class)
+	@ApiModelProperty(value = "主键")
+	@TableId(value = "id", type = IdType.ASSIGN_ID)
+	private Long id;
+
+	/**
+	 * 租户ID
+	 */
+	private String tenantId;
+
+	/**
+	 * 第三方系统用户ID
+	 */
+	private String uuid;
+
+	/**
+	 * 用户ID
+	 */
+	@JsonSerialize(using = ToStringSerializer.class)
+	@ApiModelProperty(value = "用户主键")
+	private Long userId;
+
+	/**
+	 * 用户名
+	 */
+	private String username;
+	/**
+	 * 用户昵称
+	 */
+	private String nickname;
+	/**
+	 * 用户头像
+	 */
+	private String avatar;
+	/**
+	 * 用户网址
+	 */
+	private String blog;
+	/**
+	 * 所在公司
+	 */
+	private String company;
+	/**
+	 * 位置
+	 */
+	private String location;
+	/**
+	 * 用户邮箱
+	 */
+	private String email;
+	/**
+	 * 用户备注(各平台中的用户个人介绍)
+	 */
+	private String remark;
+	/**
+	 * 性别
+	 */
+	private String gender;
+	/**
+	 * 用户来源
+	 */
+	private String source;
+
+
+}

+ 88 - 0
src/main/java/org/springblade/modules/system/excel/UserExcel.java

@@ -0,0 +1,88 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.excel;
+
+import com.alibaba.excel.annotation.ExcelIgnore;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.write.style.ColumnWidth;
+import com.alibaba.excel.annotation.write.style.ContentRowHeight;
+import com.alibaba.excel.annotation.write.style.HeadRowHeight;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * UserDTO
+ *
+ * @author Chill
+ */
+@Data
+@ColumnWidth(25)
+@HeadRowHeight(20)
+@ContentRowHeight(18)
+public class UserExcel implements Serializable {
+	private static final long serialVersionUID = 1L;
+
+	@ColumnWidth(15)
+	@ExcelProperty("租户编号")
+	private String tenantId;
+
+	@ColumnWidth(15)
+	@ExcelProperty("账户")
+	private String account;
+
+	@ColumnWidth(10)
+	@ExcelProperty("昵称")
+	private String name;
+
+	@ColumnWidth(10)
+	@ExcelProperty("姓名")
+	private String realName;
+
+	@ExcelProperty("邮箱")
+	private String email;
+
+	@ColumnWidth(15)
+	@ExcelProperty("手机")
+	private String phone;
+
+	@ExcelIgnore
+	@ExcelProperty("角色ID")
+	private String roleId;
+
+	@ExcelIgnore
+	@ExcelProperty("部门ID")
+	private String deptId;
+
+	@ExcelIgnore
+	@ExcelProperty("岗位ID")
+	private String postId;
+
+	@ExcelProperty("角色名称")
+	private String roleName;
+
+	@ExcelProperty("部门名称")
+	private String deptName;
+
+	@ExcelProperty("岗位名称")
+	private String postName;
+
+	@ColumnWidth(20)
+	@ExcelProperty("生日")
+	private Date birthday;
+
+}

+ 56 - 0
src/main/java/org/springblade/modules/system/excel/UserImportListener.java

@@ -0,0 +1,56 @@
+package org.springblade.modules.system.excel;
+
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.event.AnalysisEventListener;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.RequiredArgsConstructor;
+import org.springblade.modules.system.service.IUserService;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * UserImportListener
+ *
+ * @author Chill
+ */
+@Data
+@RequiredArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class UserImportListener extends AnalysisEventListener<UserExcel> {
+
+	/**
+	 * 默认每隔3000条存储数据库
+	 */
+	private int batchCount = 3000;
+	/**
+	 * 缓存的数据列表
+	 */
+	private List<UserExcel> list = new ArrayList<>();
+	/**
+	 * 用户service
+	 */
+	private final IUserService userService;
+
+	@Override
+	public void invoke(UserExcel data, AnalysisContext context) {
+		list.add(data);
+		// 达到BATCH_COUNT,则调用importer方法入库,防止数据几万条数据在内存,容易OOM
+		if (list.size() >= batchCount) {
+			// 调用importer方法
+			userService.importUser(list);
+			// 存储完成清理list
+			list.clear();
+		}
+	}
+
+	@Override
+	public void doAfterAllAnalysed(AnalysisContext analysisContext) {
+		// 调用importer方法
+		userService.importUser(list);
+		// 存储完成清理list
+		list.clear();
+	}
+
+}

+ 28 - 0
src/main/java/org/springblade/modules/system/mapper/AuthClientMapper.java

@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.springblade.modules.system.entity.AuthClient;
+
+/**
+ * Mapper 接口
+ *
+ * @author Chill
+ */
+public interface AuthClientMapper extends BaseMapper<AuthClient> {
+
+}

+ 27 - 0
src/main/java/org/springblade/modules/system/mapper/AuthClientMapper.xml

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.springblade.modules.system.mapper.AuthClientMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="clientResultMap" type="org.springblade.modules.system.entity.AuthClient">
+        <result column="id" property="id"/>
+        <result column="create_user" property="createUser"/>
+        <result column="create_time" property="createTime"/>
+        <result column="update_user" property="updateUser"/>
+        <result column="update_time" property="updateTime"/>
+        <result column="status" property="status"/>
+        <result column="is_deleted" property="isDeleted"/>
+        <result column="client_id" property="clientId"/>
+        <result column="client_secret" property="clientSecret"/>
+        <result column="resources_ids" property="resourceIds"/>
+        <result column="scope" property="scope"/>
+        <result column="authorized_grant_types" property="authorizedGrantTypes"/>
+        <result column="web_server_redirect_uri" property="webServerRedirectUri"/>
+        <result column="authorities" property="authorities"/>
+        <result column="access_token_validity" property="accessTokenValidity"/>
+        <result column="refresh_token_validity" property="refreshTokenValidity"/>
+        <result column="additional_information" property="additionalInformation"/>
+        <result column="autoapprove" property="autoapprove"/>
+    </resultMap>
+
+</mapper>

+ 28 - 0
src/main/java/org/springblade/modules/system/mapper/DataScopeMapper.java

@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.springblade.modules.system.entity.DataScope;
+
+/**
+ *  Mapper 接口
+ *
+ * @author BladeX
+ */
+public interface DataScopeMapper extends BaseMapper<DataScope> {
+
+}

+ 5 - 0
src/main/java/org/springblade/modules/system/mapper/DataScopeMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.springblade.modules.system.mapper.DataScopeMapper">
+
+</mapper>

+ 57 - 0
src/main/java/org/springblade/modules/system/mapper/DeptMapper.java

@@ -0,0 +1,57 @@
+/**
+ * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.modules.system.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import org.springblade.modules.system.entity.Dept;
+import org.springblade.modules.system.vo.DeptVO;
+
+import java.util.List;
+
+/**
+ * Mapper 接口
+ *
+ * @author Chill
+ */
+public interface DeptMapper extends BaseMapper<Dept> {
+
+	/**
+	 * 自定义分页
+	 *
+	 * @param page
+	 * @param dept
+	 * @return
+	 */
+	List<DeptVO> selectDeptPage(IPage page, DeptVO dept);
+
+	/**
+	 * 获取树形节点
+	 *
+	 * @param tenantId
+	 * @return
+	 */
+	List<DeptVO> tree(String tenantId);
+
+	/**
+	 * 获取部门名
+	 *
+	 * @param ids
+	 * @return
+	 */
+	List<String> getDeptNames(Long[] ids);
+
+}

+ 55 - 0
src/main/java/org/springblade/modules/system/mapper/DeptMapper.xml

@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.springblade.modules.system.mapper.DeptMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="deptResultMap" type="org.springblade.modules.system.entity.Dept">
+        <id column="id" property="id"/>
+        <result column="parent_id" property="parentId"/>
+        <result column="ancestors" property="ancestors"/>
+        <result column="dept_name" property="deptName"/>
+        <result column="full_name" property="fullName"/>
+        <result column="sort" property="sort"/>
+        <result column="remark" property="remark"/>
+        <result column="is_deleted" property="isDeleted"/>
+    </resultMap>
+
+    <resultMap id="treeNodeResultMap" type="org.springblade.core.tool.node.TreeNode">
+        <id column="id" property="id"/>
+        <result column="parent_id" property="parentId"/>
+        <result column="title" property="title"/>
+        <result column="value" property="value"/>
+        <result column="key" property="key"/>
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="baseColumnList">
+        select
+        id, parent_id, ancestors, dept_name, full_name, sort, remark, is_deleted
+    </sql>
+
+    <select id="selectDeptPage" resultMap="deptResultMap">
+        select * from blade_dept where is_deleted = 0
+    </select>
+
+    <select id="tree" resultMap="treeNodeResultMap">
+        select id, parent_id, dept_name as title, id as 'value', id as 'key' from blade_dept where is_deleted = 0
+        <if test="_parameter!=null">
+            and tenant_id = #{_parameter}
+        </if>
+    </select>
+
+    <select id="getDeptNames" resultType="java.lang.String">
+        SELECT
+        dept_name
+        FROM
+        blade_dept
+        WHERE
+        id IN
+        <foreach collection="array" item="ids" index="index" open="(" close=")" separator=",">
+            #{ids}
+        </foreach>
+        and is_deleted = 0
+    </select>
+
+</mapper>

Некоторые файлы не были показаны из-за большого количества измененных файлов