Browse Source

代码初始化

zhongwei
Jone 2 years ago
commit
51ff842853
  1. 21
      .editorconfig
  2. 53
      1.md
  3. 20
      HZIMS.iml
  4. 34
      LICENSE
  5. 43
      README.md
  6. 15
      blade-gateway/Dockerfile
  7. 130
      blade-gateway/pom.xml
  8. 39
      blade-gateway/src/main/java/org/springblade/gateway/GateWayApplication.java
  9. 86
      blade-gateway/src/main/java/org/springblade/gateway/config/ErrorHandlerConfiguration.java
  10. 103
      blade-gateway/src/main/java/org/springblade/gateway/config/RouterFunctionConfiguration.java
  11. 101
      blade-gateway/src/main/java/org/springblade/gateway/dynamic/DynamicRouteService.java
  12. 94
      blade-gateway/src/main/java/org/springblade/gateway/dynamic/DynamicRouteServiceListener.java
  13. 41
      blade-gateway/src/main/java/org/springblade/gateway/dynamic/GatewayFilter.java
  14. 41
      blade-gateway/src/main/java/org/springblade/gateway/dynamic/GatewayPredicate.java
  15. 57
      blade-gateway/src/main/java/org/springblade/gateway/dynamic/GatewayRoute.java
  16. 101
      blade-gateway/src/main/java/org/springblade/gateway/filter/AuthFilter.java
  17. 112
      blade-gateway/src/main/java/org/springblade/gateway/filter/GlobalRequestLogFilter.java
  18. 99
      blade-gateway/src/main/java/org/springblade/gateway/filter/GlobalResponseLogFilter.java
  19. 63
      blade-gateway/src/main/java/org/springblade/gateway/filter/RequestFilter.java
  20. 101
      blade-gateway/src/main/java/org/springblade/gateway/handler/ErrorExceptionHandler.java
  21. 55
      blade-gateway/src/main/java/org/springblade/gateway/handler/SwaggerResourceHandler.java
  22. 52
      blade-gateway/src/main/java/org/springblade/gateway/handler/SwaggerSecurityHandler.java
  23. 52
      blade-gateway/src/main/java/org/springblade/gateway/handler/SwaggerUiHandler.java
  24. 41
      blade-gateway/src/main/java/org/springblade/gateway/props/AuthProperties.java
  25. 38
      blade-gateway/src/main/java/org/springblade/gateway/props/RouteProperties.java
  26. 45
      blade-gateway/src/main/java/org/springblade/gateway/props/RouteResource.java
  27. 70
      blade-gateway/src/main/java/org/springblade/gateway/provider/AuthProvider.java
  28. 53
      blade-gateway/src/main/java/org/springblade/gateway/provider/RequestProvider.java
  29. 88
      blade-gateway/src/main/java/org/springblade/gateway/provider/ResponseProvider.java
  30. 59
      blade-gateway/src/main/java/org/springblade/gateway/provider/SwaggerProvider.java
  31. 10
      blade-gateway/src/main/resources/application-dev.yml
  32. 23
      blade-gateway/src/main/resources/bootstrap.yml
  33. 109
      doc/docker/README.md
  34. 3
      doc/mvn/mvn命令.md
  35. 3
      doc/nacos/README.md
  36. 19
      doc/nacos/blade-demo-dev.yaml
  37. 57
      doc/nacos/blade-dev.yaml
  38. 40
      doc/nacos/blade-prod.yaml
  39. 38
      doc/nacos/blade-test.yaml
  40. 134
      doc/nacos/blade.yaml
  41. 1
      doc/nacos/routes/README.md
  42. 28
      doc/nacos/routes/blade-gateway-dev.json
  43. 29
      doc/other/env.md
  44. 57
      doc/other/http-code.md
  45. 16
      doc/other/系统使用websocket需要修改pom.md
  46. 61
      hzims-biz-common/pom.xml
  47. 28
      hzims-biz-common/src/main/java/com/hnac/hzims/common/cache/CacheNames.java
  48. 32
      hzims-biz-common/src/main/java/com/hnac/hzims/common/config/BladeCommonConfiguration.java
  49. 52
      hzims-biz-common/src/main/java/com/hnac/hzims/common/constant/CommonConstant.java
  50. 206
      hzims-biz-common/src/main/java/com/hnac/hzims/common/constant/LauncherConstant.java
  51. 33
      hzims-biz-common/src/main/java/com/hnac/hzims/common/invalid/DictInvalid.java
  52. 64
      hzims-biz-common/src/main/java/com/hnac/hzims/common/invalid/DictInvalidator.java
  53. 27
      hzims-biz-common/src/main/java/com/hnac/hzims/common/invalid/ObjectRequiredInvalid.java
  54. 66
      hzims-biz-common/src/main/java/com/hnac/hzims/common/invalid/ObjectRequiredInvalidator.java
  55. 66
      hzims-biz-common/src/main/java/com/hnac/hzims/common/launch/LauncherServiceImpl.java
  56. 22
      hzims-biz-common/src/main/java/com/hnac/hzims/common/pojo/Tree.java
  57. 84
      hzims-biz-common/src/main/java/com/hnac/hzims/common/service/UserAuthDataService.java
  58. 171
      hzims-biz-common/src/main/java/com/hnac/hzims/common/utils/CacheUtil.java
  59. 26
      hzims-biz-common/src/main/java/com/hnac/hzims/common/utils/CommonUtil.java
  60. 142
      hzims-biz-common/src/main/java/com/hnac/hzims/common/utils/Condition.java
  61. 123
      hzims-biz-common/src/main/java/com/hnac/hzims/common/utils/DateUtil.java
  62. 80
      hzims-biz-common/src/main/java/com/hnac/hzims/common/utils/TreeUtil.java
  63. 8
      hzims-biz-common/src/main/resources/banner.txt
  64. 35
      hzims-service-api/assets-api/pom.xml
  65. 175
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/AssetsConstants.java
  66. 38
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/chche/AssetsNumCache.java
  67. 43
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/constants/AssetsConstant.java
  68. 10
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/constants/ScheduledConstant.java
  69. 58
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/SpAllocationEntity.java
  70. 56
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/SpReceiveEntity.java
  71. 59
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/SpReceivesEntity.java
  72. 55
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/SpRecordEntity.java
  73. 67
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/SpRevertEntity.java
  74. 29
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/SpTemporaryStockDetailEntity.java
  75. 70
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/SpTemporaryStockEntity.java
  76. 40
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/SpTicketRelationEntity.java
  77. 63
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/SpWarehouseInEntity.java
  78. 63
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/SpWarehouseOutEntity.java
  79. 97
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/WtSpBasicEntity.java
  80. 64
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/WtSpManagementEntity.java
  81. 27
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/WtSpManagementeExcelEntity.java
  82. 101
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/WtSpProviderEntity.java
  83. 55
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/WtSpToolBasicEntity.java
  84. 96
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/WtSpTotalEntity.java
  85. 87
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/WtSpWarehouseEntity.java
  86. 32
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/enume/BusinessType.java
  87. 46
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/enume/WarehouseInType.java
  88. 46
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/enume/WarehouseOutType.java
  89. 29
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/feign/ISpareClient.java
  90. 20
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/feign/ISpareClientFallback.java
  91. 35
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/feign/ISpareOutServiceClient.java
  92. 33
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/feign/ISpareOutServiceFallback.java
  93. 54
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/vo/SpAllocationVO.java
  94. 50
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/vo/SpReceiveVO.java
  95. 50
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/vo/SpReceivesVO.java
  96. 18
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/vo/SpRevertVO.java
  97. 53
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/vo/SpWarehouseInVO.java
  98. 57
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/vo/SpWarehouseOutVO.java
  99. 34
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/vo/StockVo.java
  100. 60
      hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/vo/WtSpBasicVO.java
  101. Some files were not shown because too many files have changed in this diff Show More

21
.editorconfig

@ -0,0 +1,21 @@
# http://editorconfig.org
root = true
# 空格替代Tab缩进在各种编辑工具下效果一致
[*]
indent_style = space
indent_size = 4
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
[*.java]
indent_style = tab
[*.{json,yml}]
indent_size = 2
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false

53
1.md

@ -0,0 +1,53 @@
## 硬件资源
由于微服务是将一套整体的项目拆分为 N 个子服务,每个服务作为一个独立的项目存在,保证了每一个子服务的启动/关闭不会影响到整个系统,但是因此也带来了硬件资源的消耗,以下为 15-20 个微服务应用下的最佳推荐,各个项目组可结合此配置自行扩展或缩减。
* 标配方案
服务器类型 | 配置 | 台数
---------|----------|---------
服务器 | 16CPU,32GB 内存,512GB 固态硬盘 | 2 台 所有服务部署在一起
>此标准配置可以做支持 10 个并发访问,10 并发理论上支持 200 到 500 同时在线
* 推荐方案
服务器类型 | 配置 | 台数
---------|----------|---------
数据库 | 32CPU,32GB 内存,512GB 固态硬盘 / 16CPU,16GB 内存 1T 机械硬盘 | 2 台,固态硬盘这台服务器为主数据库,机械硬盘的服务器为备用服务
内存数据库 | 16CPU,32GB 内存,256GB 固态硬盘 | 1+ 台,如需要大量访问内存数据库,请尽可能采用集群部署,建议 3 台起步
静态资源 | 16CPU,16GB 内存,128GB 机械/固态硬盘 | 1 台,用于部署微前端
微服务服务器 | 16CPU,32GB+ 内存,512GB 机械硬盘 | 1+ 台,为保证高可用,尽可能采用分布式部署方式,建议 3 台起步(分布式部署可以根据各服务的访问量,酌情减少服务器配置)
文件服务器 | 8CPU,16GB 内存,1T 固态硬盘/1T 机械硬盘 | 1+ 台,为保证高可用,尽可能采用分布式部署方式,建议 3 台起步,如果都是固态硬盘,则请至少配置一台机械硬盘作为备份使用(非必备,可以外购 OSS 服务)
>此推荐配置采用集群部署,也就是所有建议 3 台起步的,按照 3 台的方案部署,可以支持 100 个并发访问,100 并发理论上支持 2000 到 5000 同时在线
<br>
> <font color="red">在极端情况(16GB 内存,8CPU)下也可使用平台组进过测试后的结合 tomcat 的模式进行部署,且这种模式下项目的并发数量将大大降低,但此模式为禁用方案,请各项目组在技术询价报价前请明确告知</font>
* 内存计算
对象名 | 内存推荐(GB) | 备注
---------|----------|---------
blade-system | 1+ | 系统服务
blade-auth | 1+ | 认证服务
blade-gateway | 2+ | 网关服务 所有微服务都将经过他进行转换
blade-flow | 4+ | 工作流服务
blade-resource | 1+ | 资源管理服务
blade-report | 1+ | 报表服务
blade-xxljob | 1+ | 任务调度
redis | 4+ | 推荐使用所选微服务的内存消耗的1/2作为最终内存
nacos | 2+ | 配置中心
mysql | 2+ | 数据库
数据采集 | 4+ | 数据采集 单机支持每分钟1000条
数据处理 | 4+ | 数据清理服务
数据展示 | 8+ | 数据渲染展示
采集数据库 | 16+ | 采集为了保持高性能,最好使用8CPU+ 16GB+ 固态硬盘作为服务器
## 环境准备
名称 | 版本 | 备注
---------|----------|----------
JAVA 环境 | JRE1.8+ | JDK 为开发调试时的运行环境,实际运行时可以使用 JRE
数据库 | MySql5.7+ | 数据库和 HZ3000 数据库配置一致
Redis | 4.0+ | 内存数据库,在硬件资源配置 redis 尽可能使用最新最稳定版本
Nacos | 1.3.1 | 参考下文进行安装

20
HZIMS.iml

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="Spring" name="Spring">
<configuration />
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/hzims-service/spare/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/hzims-service-api/spare-api/src/main/java" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" scope="PROVIDED" name="Maven: org.projectlombok:lombok:1.18.12" level="project" />
</component>
</module>

34
LICENSE

@ -0,0 +1,34 @@
BladeX商业授权许可协议
一、 知识产权:
BladeX系列产品知识产权归上海布雷德网络科技独立所有
二、 许可:
1. 在您完全接受并遵守本协议的基础上,本协议授予您使用BladeX的某些权利和非独占性许可。
2. 本协议中,将本产品使用用途分为“专业版用途”和“企业版用途”。
3. “专业版用途”定义:指个人在非团体机构中出于任何目的使用本产品(任何目的包括商业目的或非盈利目的)。
4. “企业版用途”定义:指团体机构(例如公司企业、政府、学校、军队、医院、社会团体等各类组织)(不包含集团,若集团使用则需为各个子公司分别购买企业授权)出于任何目的使用本产品(任何目的包括商业目的或非盈利目的)。
三、 约束和限制:
1. 本产品只能由您为本协议许可的目的而使用,您不得透露给任何第三方;
2. 从本产品取得的任何信息、软件、产品或服务,您不得对其进行修改、改编或基于以上内容创建同种类别的衍生产品并售卖。
3. 您不得对本产品以及与之关联的商业授权进行发布、出租、销售、分销、抵押、转让、许可或发放子许可证。
4. 本产品商业授权版可能包含一些独立功能或特性,这些功能只有在您购买商业授权后才可以使用。在未取得商业授权的情况下,您不得使用、尝试使用或复制这些授权版独立功能。
5. 若您的客户要求以源码方式交付软件,需缴纳企业版授权费用,否则本产品部分不得提供源码。
四、 不得用于非法或禁止的用途:
您在使用本产品或服务时,不得将本产品产品或服务用于任何非法用途或本协议条款、条件和声明禁止的用途。
五、 免责说明:
1. 本产品按“现状”授予许可,您须自行承担使用本产品的风险。BladeX团队不对此提供任何明示、暗示或任何其它形式的担保和表示。在任何情况下,对于因使用或无法使用本软件而导致的任何损失(包括但不仅限于商业利润损失、业务中断或业务信息丢失),BladeX团队无需向您或任何第三方负责,即使BladeX团队已被告知可能会造成此类损失。在任何情况下, BladeX团队均不就任何直接的、间接的、附带的、后果性的、特别的、惩戒性的和处罚性的损害赔偿承担任何责任,无论该主张是基于保证、合同、侵权(包括疏忽)或是基于其他原因作出。
2. 本产品可能内置有第三方服务,您应自行评估使用这些第三方服务的风险,由使用此类第三方服务而产生的纠纷,全部责任由您自行承担。
3. BladeX团队不对使用本产品构建的网站中任何信息内容以及导致的任何版权纠纷、法律争议和后果承担任何责任,全部责任由您自行承担。
4. BladeX团队可能会经常提供产品更新或升级,但BladeX团队没有为根据本协议许可的产品提供维护或更新的责任。
5. BladeX团队可能会按照官方制定的答疑规则为您进行答疑,但BladeX团队没有为根据本协议许可的产品提供技术支持的义务或责任。
六、 权利和所有权的保留:
BladeX团队保留所有未在本协议中明确授予您的所有权利。BladeX团队保留随时更新本协议的权利,并只需公示于对应产品项目的LICENSE文件,无需征得您的事先同意且无需另行通知,更新后的内容应于公示即时生效。您可以随时访问产品地址并查阅最新版许可条款,在更新生效后您继续使用本产品则被视作您已接受了新的条款。
七、 协议终止
1. 您一旦开始复制、下载、安装或者使用本产品,即被视为完全理解并接受本协议的各项条款,在享有上述条款授予的许可权力同时,也受到相关的约束和限制,本协议许可范围以外的行为,将直接违反本协议并构成侵权。
2. 一旦您违反本协议的条款,BladeX团队随时可能终止本协议、收回许可和授权,并要求您承担相应法律和经济责任。

43
README.md

@ -0,0 +1,43 @@
## 版权声明
* BladeX是一个商业化软件,系列产品知识产权归**上海布雷德网络科技**独立所有
* 您一旦开始复制、下载、安装或者使用本产品,即被视为完全理解并接受本协议的各项条款
* 更多详情请看:[BladeX商业授权许可协议](/LICENSE)
## 答疑流程
>1. 遇到问题或Bug
>2. 业务型问题打断点调试尝试找出问题所在
>3. 系统型问题通过百度、谷歌、社区查找解决方案
>4. 未解决问题则进入技术社区进行发帖提问:[https://sns.bladex.vip/](https://sns.bladex.vip/)
>5. 将帖子地址发至商业群,特别简单三言两语就能描述清楚的也可在答疑时间内发至商业群提问
>6. 发帖的时候一定要描述清楚,详细描述遇到问题的**重现步骤**、**报错详细信息**、**相关代码与逻辑**、**使用软件版本**以及**操作系统版本**,否则随意发帖提问将会提高我们的答疑难度。
## 答疑时间
* 工作日:9:00 ~ 17:00 提供答疑,周末、节假日休息,暂停答疑
* 请勿**私聊提问**,以免被其他用户的消息覆盖从而无法获得答疑
* 答疑时间外遇到问题可以将问题发帖至[技术社区](https://sns.bladex.vip/),我们后续会逐个回复
## 授权范围
* 专业版:只可用于**个人学习**及**个人私活**项目,不可用于公司或团队,不可泄露给任何第三方
* 企业版:可用于**企业名下**的任何项目,企业版员工在**未购买**专业版授权前,只授权开发**所在授权企业名下**的项目,**不得将BladeX用于个人私活**
* 共同遵守:若甲方需要您提供项目源码,则需代为甲方购买BladeX企业授权,甲方购买后续的所有项目都无需再次购买授权
## 商用权益
* ✔ 遵守[商业协议](/LICENSE)的前提下,将BladeX系列产品用于授权范围内的商用项目,并上线运营
* ✔ 遵守[商业协议](/LICENSE)的前提下,不限制项目数,不限制服务器数
* ✔ 遵守[商业协议](/LICENSE)的前提下,将自行编写的业务代码申请软件著作权
## 何为侵权
* ❌ 不遵守商业协议,私自销售商业源码
* ❌ 以任何理由将BladeX源码用于申请软件著作权
* ❌ 将商业源码以任何途径任何理由泄露给未授权的单位或个人
* ❌ 开发完毕项目,没有为甲方购买企业授权,向甲方提供了BladeX代码
* ❌ 基于BladeX拓展研发与BladeX有竞争关系的衍生框架,并将其开源或销售
## 侵权后果
* 情节较轻:第一次发现警告处理
* 情节较重:封禁账号,踢出商业群,并保留追究法律责任的权利
* 情节严重:与本地律师事务所合作,以公司名义起诉侵犯计算机软件著作权
## 举报有奖
* 向官方提供有用线索并成功捣毁盗版个人或窝点,将会看成果给予 500~10000 不等的现金奖励
* 官方唯一指定QQ:1272154962

15
blade-gateway/Dockerfile

@ -0,0 +1,15 @@
FROM adoptopenjdk/openjdk8-openj9:alpine-slim
MAINTAINER smallchill@163.com
RUN mkdir -p /blade/gateway
WORKDIR /blade/gateway
EXPOSE 80
ADD ./target/blade-gateway.jar ./app.jar
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
CMD ["--spring.profiles.active=test"]

130
blade-gateway/pom.xml

@ -0,0 +1,130 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>main</artifactId>
<groupId>com.hnac.hzims</groupId>
<version>2.5.1.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>blade-gateway</artifactId>
<name>${project.artifactId}</name>
<version>${bladex.project.version}</version>
<packaging>jar</packaging>
<dependencies>
<!--Blade-->
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-core-launch</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.hnac.hzims</groupId>
<artifactId>hzims-biz-common</artifactId>
<version>2.5.1.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.springblade</groupId>
<artifactId>blade-core-launch</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-jwt</artifactId>
</dependency>
<!--Spring-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
<!--Hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Nacos -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!--Swagger-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<exclusions>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-ui</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<configuration>
<username>${docker.username}</username>
<password>${docker.password}</password>
<repository>${docker.registry.url}/${docker.namespace}/${project.artifactId}</repository>
<tag>${project.version}</tag>
<useMavenSettingsForAuth>true</useMavenSettingsForAuth>
<buildArgs>
<JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
<skip>false</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

39
blade-gateway/src/main/java/org/springblade/gateway/GateWayApplication.java

@ -0,0 +1,39 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.gateway;
import org.springblade.core.launch.constant.AppConstant;
import org.springblade.core.launch.BladeApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* 项目启动
*
* @author Chill
*/
@EnableHystrix
@EnableScheduling
@SpringCloudApplication
public class GateWayApplication {
public static void main(String[] args) {
BladeApplication.run(AppConstant.APPLICATION_GATEWAY_NAME, GateWayApplication.class, args);
}
}

86
blade-gateway/src/main/java/org/springblade/gateway/config/ErrorHandlerConfiguration.java

@ -0,0 +1,86 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.gateway.config;
import org.springblade.gateway.handler.ErrorExceptionHandler;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.result.view.ViewResolver;
import java.util.Collections;
import java.util.List;
/**
* 异常处理配置类
*
* @author Chill
*/
@Configuration
@AutoConfigureBefore(ErrorWebFluxAutoConfiguration.class)
@EnableConfigurationProperties({ServerProperties.class, ResourceProperties.class})
public class ErrorHandlerConfiguration {
private final ServerProperties serverProperties;
private final ApplicationContext applicationContext;
private final ResourceProperties resourceProperties;
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public ErrorHandlerConfiguration(ServerProperties serverProperties,
ResourceProperties resourceProperties,
ObjectProvider<List<ViewResolver>> viewResolversProvider,
ServerCodecConfigurer serverCodecConfigurer,
ApplicationContext applicationContext) {
this.serverProperties = serverProperties;
this.applicationContext = applicationContext;
this.resourceProperties = resourceProperties;
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) {
ErrorExceptionHandler exceptionHandler = new ErrorExceptionHandler(
errorAttributes,
this.resourceProperties,
this.serverProperties.getError(),
this.applicationContext);
exceptionHandler.setViewResolvers(this.viewResolvers);
exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());
exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());
return exceptionHandler;
}
}

103
blade-gateway/src/main/java/org/springblade/gateway/config/RouterFunctionConfiguration.java

@ -0,0 +1,103 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.gateway.config;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.gateway.handler.SwaggerResourceHandler;
import org.springblade.gateway.handler.SwaggerSecurityHandler;
import org.springblade.gateway.handler.SwaggerUiHandler;
import org.springblade.gateway.props.AuthProperties;
import org.springblade.gateway.props.RouteProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
/**
* 路由配置信息
*
* @author Chill
*/
@Slf4j
@Configuration
@AllArgsConstructor
@EnableConfigurationProperties({RouteProperties.class, AuthProperties.class})
public class RouterFunctionConfiguration {
private final SwaggerResourceHandler swaggerResourceHandler;
private final SwaggerSecurityHandler swaggerSecurityHandler;
private final SwaggerUiHandler swaggerUiHandler;
/**
* 这里为支持的请求头如果有自定义的header字段请自己添加
*/
private static final String ALLOWED_HEADERS = "X-Requested-With, Tenant-Id, Blade-Auth, Content-Type, Authorization, credential, X-XSRF-TOKEN, token, username, client";
private static final String ALLOWED_METHODS = "GET,POST,PUT,DELETE,OPTIONS,HEAD";
private static final String ALLOWED_ORIGIN = "*";
private static final String ALLOWED_EXPOSE = "*";
private static final String MAX_AGE = "18000L";
/**
* 跨域配置
*/
@Bean
public WebFilter corsFilter() {
return (ServerWebExchange ctx, WebFilterChain chain) -> {
ServerHttpRequest request = ctx.getRequest();
if (CorsUtils.isCorsRequest(request)) {
ServerHttpResponse response = ctx.getResponse();
HttpHeaders headers = response.getHeaders();
headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
headers.add("Access-Control-Expose-Headers", ALLOWED_EXPOSE);
headers.add("Access-Control-Max-Age", MAX_AGE);
headers.add("Access-Control-Allow-Credentials", "true");
if (request.getMethod() == HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
return Mono.empty();
}
}
return chain.filter(ctx);
};
}
@Bean
public RouterFunction routerFunction() {
return RouterFunctions.route(RequestPredicates.GET("/swagger-resources")
.and(RequestPredicates.accept(MediaType.ALL)), swaggerResourceHandler)
.andRoute(RequestPredicates.GET("/swagger-resources/configuration/ui")
.and(RequestPredicates.accept(MediaType.ALL)), swaggerUiHandler)
.andRoute(RequestPredicates.GET("/swagger-resources/configuration/security")
.and(RequestPredicates.accept(MediaType.ALL)), swaggerSecurityHandler);
}
}

101
blade-gateway/src/main/java/org/springblade/gateway/dynamic/DynamicRouteService.java

@ -0,0 +1,101 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.gateway.dynamic;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
import java.util.List;
/**
* 动态路由业务类
*
* @author Chill
*/
@Service
public class DynamicRouteService implements ApplicationEventPublisherAware {
private final RouteDefinitionWriter routeDefinitionWriter;
private ApplicationEventPublisher publisher;
public DynamicRouteService(RouteDefinitionWriter routeDefinitionWriter) {
this.routeDefinitionWriter = routeDefinitionWriter;
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.publisher = applicationEventPublisher;
}
/**
* 增加路由
*/
public String save(RouteDefinition definition) {
try {
routeDefinitionWriter.save(Mono.just(definition)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return "save success";
} catch (Exception e) {
e.printStackTrace();
return "save failure";
}
}
/**
* 更新路由
*/
public String update(RouteDefinition definition) {
try {
this.routeDefinitionWriter.delete(Mono.just(definition.getId()));
this.routeDefinitionWriter.save(Mono.just(definition)).subscribe();
this.publisher.publishEvent(new RefreshRoutesEvent(this));
return "update success";
} catch (Exception e) {
e.printStackTrace();
return "update failure";
}
}
/**
* 更新路由
*/
public String updateList(List<RouteDefinition> routeDefinitions) {
routeDefinitions.forEach(this::update);
return "update done";
}
/**
* 删除路由
*/
public String delete(String id) {
try {
this.routeDefinitionWriter.delete(Mono.just(id));
return "delete success";
} catch (Exception e) {
e.printStackTrace();
return "delete failure";
}
}
}

94
blade-gateway/src/main/java/org/springblade/gateway/dynamic/DynamicRouteServiceListener.java

@ -0,0 +1,94 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.gateway.dynamic;
import com.alibaba.cloud.nacos.NacosConfigProperties;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.launch.constant.NacosConstant;
import org.springblade.core.launch.props.BladeProperties;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.Executor;
/**
* 动态路由监听器
*
* @author Chill
*/
@Order
@Slf4j
@Component
public class DynamicRouteServiceListener {
private final DynamicRouteService dynamicRouteService;
private final NacosDiscoveryProperties nacosDiscoveryProperties;
private final NacosConfigProperties nacosConfigProperties;
private final BladeProperties bladeProperties;
public DynamicRouteServiceListener(DynamicRouteService dynamicRouteService, NacosDiscoveryProperties nacosDiscoveryProperties, NacosConfigProperties nacosConfigProperties, BladeProperties bladeProperties) {
this.dynamicRouteService = dynamicRouteService;
this.nacosDiscoveryProperties = nacosDiscoveryProperties;
this.nacosConfigProperties = nacosConfigProperties;
this.bladeProperties = bladeProperties;
dynamicRouteServiceListener();
}
/**
* 监听Nacos下发的动态路由配置
*/
private void dynamicRouteServiceListener() {
try {
String dataId = NacosConstant.dataId(bladeProperties.getName(), bladeProperties.getEnv(), NacosConstant.NACOS_CONFIG_JSON_FORMAT);
String group = nacosConfigProperties.getGroup();
Properties properties = new Properties();
properties.setProperty(PropertyKeyConst.SERVER_ADDR, nacosDiscoveryProperties.getServerAddr());
properties.setProperty(PropertyKeyConst.NAMESPACE, nacosDiscoveryProperties.getNamespace());
ConfigService configService = NacosFactory.createConfigService(properties);
configService.addListener(dataId, group, new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
List<RouteDefinition> routeDefinitions = JSON.parseArray(configInfo, RouteDefinition.class);
dynamicRouteService.updateList(routeDefinitions);
}
@Override
public Executor getExecutor() {
return null;
}
});
String configInfo = configService.getConfig(dataId, group, 5000);
if (configInfo != null) {
List<RouteDefinition> routeDefinitions = JSON.parseArray(configInfo, RouteDefinition.class);
dynamicRouteService.updateList(routeDefinitions);
}
} catch (NacosException ignored) {
log.info(ignored.getMessage());
}
}
}

41
blade-gateway/src/main/java/org/springblade/gateway/dynamic/GatewayFilter.java

@ -0,0 +1,41 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.gateway.dynamic;
import lombok.Data;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 过滤器定义模型
*
* @author Chill
*/
@Data
public class GatewayFilter {
/**
* 过滤器对应的Name
*/
private String name;
/**
* 对应的路由规则
*/
private Map<String, String> args = new LinkedHashMap<>();
}

41
blade-gateway/src/main/java/org/springblade/gateway/dynamic/GatewayPredicate.java

@ -0,0 +1,41 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.gateway.dynamic;
import lombok.Data;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 路由断言定义模型
*
* @author Chill
*/
@Data
public class GatewayPredicate {
/**
* 断言对应的Name
*/
private String name;
/**
* 配置的断言规则
*/
private Map<String, String> args = new LinkedHashMap<>();
}

57
blade-gateway/src/main/java/org/springblade/gateway/dynamic/GatewayRoute.java

@ -0,0 +1,57 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.gateway.dynamic;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* Gateway的路由定义模型
*
* @author Chill
*/
@Data
public class GatewayRoute {
/**
* 路由的id
*/
private String id;
/**
* 路由断言集合配置
*/
private List<GatewayPredicate> predicates = new ArrayList<>();
/**
* 路由过滤器集合配置
*/
private List<GatewayFilter> filters = new ArrayList<>();
/**
* 路由规则转发的目标uri
*/
private String uri;
/**
* 路由执行的顺序
*/
private int order = 0;
}

101
blade-gateway/src/main/java/org/springblade/gateway/filter/AuthFilter.java

@ -0,0 +1,101 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.gateway.filter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.jsonwebtoken.Claims;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springblade.core.jwt.JwtUtil;
import org.springblade.gateway.props.AuthProperties;
import org.springblade.gateway.provider.AuthProvider;
import org.springblade.gateway.provider.RequestProvider;
import org.springblade.gateway.provider.ResponseProvider;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
/**
* 鉴权认证
*
* @author Chill
*/
@Slf4j
@Component
@AllArgsConstructor
public class AuthFilter implements GlobalFilter, Ordered {
private final AuthProperties authProperties;
private final ObjectMapper objectMapper;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String originalRequestUrl = RequestProvider.getOriginalRequestUrl(exchange);
String path = exchange.getRequest().getURI().getPath();
if (isSkip(path) || isSkip(originalRequestUrl)) {
return chain.filter(exchange);
}
ServerHttpResponse resp = exchange.getResponse();
String headerToken = exchange.getRequest().getHeaders().getFirst(AuthProvider.AUTH_KEY);
String paramToken = exchange.getRequest().getQueryParams().getFirst(AuthProvider.AUTH_KEY);
if (StringUtils.isAllBlank(headerToken, paramToken)) {
return unAuth(resp, "缺失令牌,鉴权失败");
}
String auth = StringUtils.isBlank(headerToken) ? paramToken : headerToken;
String token = JwtUtil.getToken(auth);
Claims claims = JwtUtil.parseJWT(token);
if (claims == null) {
return unAuth(resp, "请求未授权");
}
return chain.filter(exchange);
}
private boolean isSkip(String path) {
return AuthProvider.getDefaultSkipUrl().stream().map(url -> url.replace(AuthProvider.TARGET, AuthProvider.REPLACEMENT)).anyMatch(path::startsWith)
|| authProperties.getSkipUrl().stream().map(url -> url.replace(AuthProvider.TARGET, AuthProvider.REPLACEMENT)).anyMatch(path::startsWith);
}
private Mono<Void> unAuth(ServerHttpResponse resp, String msg) {
resp.setStatusCode(HttpStatus.UNAUTHORIZED);
resp.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
String result = "";
try {
result = objectMapper.writeValueAsString(ResponseProvider.unAuth(msg));
} catch (JsonProcessingException e) {
log.error(e.getMessage(), e);
}
DataBuffer buffer = resp.bufferFactory().wrap(result.getBytes(StandardCharsets.UTF_8));
return resp.writeWith(Flux.just(buffer));
}
@Override
public int getOrder() {
return -100;
}
}

112
blade-gateway/src/main/java/org/springblade/gateway/filter/GlobalRequestLogFilter.java

@ -0,0 +1,112 @@
/*
* Copyright (c) 2018-2028, DreamLu All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: DreamLu 卢春梦 (596392912@qq.com)
*/
package org.springblade.gateway.filter;
import io.jsonwebtoken.Claims;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springblade.core.jwt.JwtUtil;
import org.springblade.gateway.provider.AuthProvider;
import org.springblade.gateway.provider.RequestProvider;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.ArrayList;
import java.util.List;
/**
* webflux 日志请求记录方便开发调试请求日志过滤器排序尽量低
*
* <p>
* 注意暂时不支持结构体打印想实现请看下面的链接
* https://stackoverflow.com/questions/45240005/how-to-log-request-and-response-bodies-in-spring-webflux
* https://github.com/Silvmike/webflux-demo/blob/master/tests/src/test/java/ru/hardcoders/demo/webflux/web_handler/filters/logging
* </p>
*
* @author dream.lu
*/
@Slf4j
@Configuration
@RequiredArgsConstructor
@ConditionalOnProperty(value = "blade.log.request.enabled", havingValue = "true", matchIfMissing = true)
public class GlobalRequestLogFilter implements GlobalFilter, Ordered {
private final WebEndpointProperties endpointProperties;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
// 打印请求路径
String path = request.getPath().pathWithinApplication().value();
// 忽略 endpoint 请求
String endpointBasePath = endpointProperties.getBasePath();
if (StringUtils.isNotBlank(endpointBasePath) && path.startsWith(endpointBasePath)) {
return chain.filter(exchange);
}
String requestUrl = RequestProvider.getOriginalRequestUrl(exchange);
// 构建成一条长 日志,避免并发下日志错乱
StringBuilder beforeReqLog = new StringBuilder(300);
// 日志参数
List<Object> beforeReqArgs = new ArrayList<>();
beforeReqLog.append("\n\n================ Gateway Request Start ================\n");
// 打印路由
beforeReqLog.append("===> {}: {}\n");
// 参数
String requestMethod = request.getMethodValue();
beforeReqArgs.add(requestMethod);
beforeReqArgs.add(requestUrl);
// 打印请求头
HttpHeaders headers = request.getHeaders();
headers.forEach((headerName, headerValue) -> {
beforeReqLog.append("===Headers=== {}: {}\n");
beforeReqArgs.add(headerName);
if (AuthProvider.AUTH_KEY.toLowerCase().equals(headerName)) {
String value = headerValue.get(0);
String token = JwtUtil.getToken(value);
Claims claims = JwtUtil.parseJWT(token);
beforeReqArgs.add((claims == null) ? "" : claims.toString());
beforeReqLog.append("===Headers=== {}: {}\n");
beforeReqArgs.add(headerName.concat("-original"));
beforeReqArgs.add(StringUtils.join(headerValue));
} else {
beforeReqArgs.add(StringUtils.join(headerValue));
}
});
beforeReqLog.append("================ Gateway Request End =================\n");
// 打印执行时间
log.info(beforeReqLog.toString(), beforeReqArgs.toArray());
return chain.filter(exchange);
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}

99
blade-gateway/src/main/java/org/springblade/gateway/filter/GlobalResponseLogFilter.java

@ -0,0 +1,99 @@
/*
* Copyright (c) 2018-2028, DreamLu All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: DreamLu 卢春梦 (596392912@qq.com)
*/
package org.springblade.gateway.filter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;
import reactor.core.publisher.Mono;
import java.util.ArrayList;
import java.util.List;
/**
* webflux 相应日志方便开发调试注意排序要优先
*
* @author dream.lu
*/
@Slf4j
@Configuration
@RequiredArgsConstructor
@ConditionalOnProperty(value = "blade.log.request.enabled", havingValue = "true", matchIfMissing = true)
public class GlobalResponseLogFilter implements GlobalFilter, Ordered {
private final WebEndpointProperties endpointProperties;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
// 打印请求路径
String path = request.getPath().pathWithinApplication().value();
// 忽略 endpoint 请求
String endpointBasePath = endpointProperties.getBasePath();
if (StringUtils.isNotBlank(endpointBasePath) && path.startsWith(endpointBasePath)) {
return chain.filter(exchange);
}
return chain.filter(exchange).then(
Mono.fromRunnable(() -> {
MultiValueMap<String, String> queryParams = request.getQueryParams();
String requestUrl = UriComponentsBuilder.fromPath(path).queryParams(queryParams).build().toUriString();
// 构建成一条长 日志,避免并发下日志错乱
StringBuilder responseLog = new StringBuilder(300);
// 日志参数
List<Object> responseArgs = new ArrayList<>();
responseLog.append("\n\n================ Gateway Response Start ================\n");
ServerHttpResponse response = exchange.getResponse();
// 打印路由 200 get: /api/xxx/xxx
responseLog.append("<=== {} {}: {}\n");
// 参数
String requestMethod = request.getMethodValue();
responseArgs.add(response.getStatusCode().value());
responseArgs.add(requestMethod);
responseArgs.add(requestUrl);
// 打印请求头
HttpHeaders headers = response.getHeaders();
headers.forEach((headerName, headerValue) -> {
responseLog.append("===Headers=== {}: {}\n");
responseArgs.add(headerName);
responseArgs.add(StringUtils.join(headerValue));
});
responseLog.append("================ Gateway Response End =================\n");
// 打印执行时间
log.info(responseLog.toString(), responseArgs.toArray());
})
);
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}

63
blade-gateway/src/main/java/org/springblade/gateway/filter/RequestFilter.java

@ -0,0 +1,63 @@
package org.springblade.gateway.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Arrays;
import java.util.stream.Collectors;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.addOriginalRequestUrl;
/**
* <p>
* 全局拦截器作用所有的微服务
* <p>
* 1. 对请求头中参数进行处理 from 参数进行清洗
* 2. 重写StripPrefix = 1,支持全局
*
* @author lengleng
*/
@Component
public class RequestFilter implements GlobalFilter, Ordered {
/**
* Process the Web request and (optionally) delegate to the next
* {@code WebFilter} through the given {@link GatewayFilterChain}.
*
* @param exchange the current server exchange
* @param chain provides a way to delegate to the next filter
* @return {@code Mono<Void>} to indicate when request processing is complete
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1. 清洗请求头中from 参数
ServerHttpRequest request = exchange.getRequest().mutate()
.headers(httpHeaders -> httpHeaders.remove("X"))
.build();
// 2. 重写StripPrefix
addOriginalRequestUrl(exchange, request.getURI());
String rawPath = request.getURI().getRawPath();
String newPath = "/" + Arrays.stream(StringUtils.tokenizeToStringArray(rawPath, "/"))
.skip(1L).collect(Collectors.joining("/"));
ServerHttpRequest newRequest = request.mutate()
.path(newPath)
.build();
exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, newRequest.getURI());
return chain.filter(exchange.mutate().request(newRequest.mutate().build()).build());
}
@Override
public int getOrder() {
return -1000;
}
}

101
blade-gateway/src/main/java/org/springblade/gateway/handler/ErrorExceptionHandler.java

@ -0,0 +1,101 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.gateway.handler;
import org.springblade.gateway.provider.ResponseProvider;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.web.reactive.function.server.*;
import org.springframework.web.server.ResponseStatusException;
import java.util.Map;
/**
* 异常处理
*
* @author Chill
*/
public class ErrorExceptionHandler extends DefaultErrorWebExceptionHandler {
public ErrorExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties,
ErrorProperties errorProperties, ApplicationContext applicationContext) {
super(errorAttributes, resourceProperties, errorProperties, applicationContext);
}
/**
* 获取异常属性
*/
@Override
protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
int code = 500;
Throwable error = super.getError(request);
if (error instanceof NotFoundException) {
code = 404;
}
if (error instanceof ResponseStatusException) {
code = ((ResponseStatusException) error).getStatus().value();
}
return ResponseProvider.response(code, this.buildMessage(request, error));
}
/**
* 指定响应处理方法为JSON处理的方法
*
* @param errorAttributes
*/
@Override
protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
}
/**
* 根据code获取对应的HttpStatus
*
* @param errorAttributes
*/
@Override
protected HttpStatus getHttpStatus(Map<String, Object> errorAttributes) {
int statusCode = (int) errorAttributes.get("code");
return HttpStatus.valueOf(statusCode);
}
/**
* 构建异常信息
*
* @param request
* @param ex
* @return
*/
private String buildMessage(ServerRequest request, Throwable ex) {
StringBuilder message = new StringBuilder("Failed to handle request [");
message.append(request.methodName());
message.append(" ");
message.append(request.uri());
message.append("]");
if (ex != null) {
message.append(": ");
message.append(ex.getMessage());
}
return message.toString();
}
}

55
blade-gateway/src/main/java/org/springblade/gateway/handler/SwaggerResourceHandler.java

@ -0,0 +1,55 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.gateway.handler;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
/**
* SwaggerResourceHandler
*
* @author lengleng
*/
@Slf4j
@Component
@AllArgsConstructor
public class SwaggerResourceHandler implements HandlerFunction<ServerResponse> {
private final SwaggerResourcesProvider swaggerResources;
/**
* Handle the given request.
*
* @param request the request to handler
* @return the response
*/
@Override
public Mono<ServerResponse> handle(ServerRequest request) {
return ServerResponse.status(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(BodyInserters.fromObject(swaggerResources.get()));
}
}

52
blade-gateway/src/main/java/org/springblade/gateway/handler/SwaggerSecurityHandler.java

@ -0,0 +1,52 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.gateway.handler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.SecurityConfigurationBuilder;
/**
* SwaggerSecurityHandler
*
* @author lengleng
*/
@Slf4j
@Component
public class SwaggerSecurityHandler implements HandlerFunction<ServerResponse> {
/**
* Handle the given request.
*
* @param request the request to handler
* @return the response
*/
@Override
public Mono<ServerResponse> handle(ServerRequest request) {
return ServerResponse.status(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(BodyInserters.fromObject(SecurityConfigurationBuilder.builder().build()));
}
}

52
blade-gateway/src/main/java/org/springblade/gateway/handler/SwaggerUiHandler.java

@ -0,0 +1,52 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.gateway.handler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.HandlerFunction;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;
import springfox.documentation.swagger.web.UiConfigurationBuilder;
/**
* SwaggerUiHandler
*
* @author lengleng
*/
@Slf4j
@Component
public class SwaggerUiHandler implements HandlerFunction<ServerResponse> {
/**
* Handle the given request.
*
* @param request the request to handler
* @return the response
*/
@Override
public Mono<ServerResponse> handle(ServerRequest request) {
return ServerResponse.status(HttpStatus.OK)
.contentType(MediaType.APPLICATION_JSON_UTF8)
.body(BodyInserters.fromObject(UiConfigurationBuilder.builder().build()));
}
}

41
blade-gateway/src/main/java/org/springblade/gateway/props/AuthProperties.java

@ -0,0 +1,41 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.gateway.props;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import java.util.ArrayList;
import java.util.List;
/**
* 权限过滤
*
* @author Chill
*/
@Data
@RefreshScope
@ConfigurationProperties("blade.secure")
public class AuthProperties {
/**
* 放行API集合
*/
private final List<String> skipUrl = new ArrayList<>();
}

38
blade-gateway/src/main/java/org/springblade/gateway/props/RouteProperties.java

@ -0,0 +1,38 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.gateway.props;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import java.util.ArrayList;
import java.util.List;
/**
* 路由配置类
*
* @author Chill
*/
@Data
@RefreshScope
@ConfigurationProperties("blade.document")
public class RouteProperties {
private final List<RouteResource> resources = new ArrayList<>();
}

45
blade-gateway/src/main/java/org/springblade/gateway/props/RouteResource.java

@ -0,0 +1,45 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.gateway.props;
import lombok.Data;
import org.springblade.core.launch.constant.AppConstant;
/**
* Swagger聚合文档属性
*
* @author Chill
*/
@Data
public class RouteResource {
/**
* 文档名
*/
private String name;
/**
* 文档所在服务地址
*/
private String location;
/**
* 文档版本
*/
private String version = AppConstant.APPLICATION_VERSION;
}

70
blade-gateway/src/main/java/org/springblade/gateway/provider/AuthProvider.java

@ -0,0 +1,70 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.gateway.provider;
import org.springblade.core.launch.constant.TokenConstant;
import java.util.ArrayList;
import java.util.List;
/**
* 鉴权配置
*
* @author Chill
*/
public class AuthProvider {
AuthProvider(){
}
public static final String TARGET = "/**";
public static final String REPLACEMENT = "";
public static final String AUTH_KEY = TokenConstant.HEADER;
private static final List<String> DEFAULT_SKIP_URL = new ArrayList<>();
static {
DEFAULT_SKIP_URL.add("/example");
DEFAULT_SKIP_URL.add("/oauth/token/**");
DEFAULT_SKIP_URL.add("/oauth/captcha/**");
DEFAULT_SKIP_URL.add("/oauth/clear-cache/**");
DEFAULT_SKIP_URL.add("/oauth/user-info");
DEFAULT_SKIP_URL.add("/token/**");
DEFAULT_SKIP_URL.add("/actuator/health/**");
DEFAULT_SKIP_URL.add("/v2/api-docs/**");
DEFAULT_SKIP_URL.add("/v2/api-docs-ext/**");
DEFAULT_SKIP_URL.add("/auth/**");
DEFAULT_SKIP_URL.add("/log/**");
DEFAULT_SKIP_URL.add("/menu/routes");
DEFAULT_SKIP_URL.add("/menu/auth-routes");
DEFAULT_SKIP_URL.add("/menu/top-menu");
DEFAULT_SKIP_URL.add("/tenant/info");
DEFAULT_SKIP_URL.add("/process/resource-view");
DEFAULT_SKIP_URL.add("/process/diagram-view");
DEFAULT_SKIP_URL.add("/manager/check-upload");
DEFAULT_SKIP_URL.add("/error/**");
DEFAULT_SKIP_URL.add("/assets/**");
}
/**
* 默认无需鉴权的API
*/
public static List<String> getDefaultSkipUrl() {
return DEFAULT_SKIP_URL;
}
}

53
blade-gateway/src/main/java/org/springblade/gateway/provider/RequestProvider.java

@ -0,0 +1,53 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.gateway.provider;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.MultiValueMap;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
import java.util.LinkedHashSet;
/**
* RequestProvider
*
* @author Chill
*/
public class RequestProvider {
RequestProvider(){
}
/**
* 获取原始url
*
* @param exchange
* @return
*/
public static String getOriginalRequestUrl(ServerWebExchange exchange) {
ServerHttpRequest request = exchange.getRequest();
LinkedHashSet<URI> uris = exchange.getRequiredAttribute(ServerWebExchangeUtils.GATEWAY_ORIGINAL_REQUEST_URL_ATTR);
URI requestUri = uris.stream().findFirst().orElse(request.getURI());
MultiValueMap<String, String> queryParams = request.getQueryParams();
return UriComponentsBuilder.fromPath(requestUri.getRawPath()).queryParams(queryParams).build().toUriString();
}
}

88
blade-gateway/src/main/java/org/springblade/gateway/provider/ResponseProvider.java

@ -0,0 +1,88 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.gateway.provider;
import java.util.HashMap;
import java.util.Map;
/**
* 请求响应返回
*
* @author Chill
*/
public class ResponseProvider {
ResponseProvider(){
}
/**
* 成功
*
* @param message 信息
* @return
*/
public static Map<String, Object> success(String message) {
return response(200, message);
}
/**
* 失败
*..
* @param message 信息
* @return
*/
public static Map<String, Object> fail(String message) {
return response(400, message);
}
/**
* 未授权
*
* @param message 信息
* @return
*/
public static Map<String, Object> unAuth(String message) {
return response(401, message);
}
/**
* 服务器异常
*
* @param message 信息
* @return
*/
public static Map<String, Object> error(String message) {
return response(500, message);
}
/**
* 构建返回的JSON数据格式
*
* @param status 状态码
* @param message 信息
* @return
*/
public static Map<String, Object> response(int status, String message) {
Map<String, Object> map = new HashMap<>(16);
map.put("code", status);
map.put("message", message);
map.put("data", null);
return map;
}
}

59
blade-gateway/src/main/java/org/springblade/gateway/provider/SwaggerProvider.java

@ -0,0 +1,59 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package org.springblade.gateway.provider;
import lombok.AllArgsConstructor;
import org.springblade.gateway.props.RouteProperties;
import org.springblade.gateway.props.RouteResource;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
import java.util.ArrayList;
import java.util.List;
/**
* 聚合接口文档注册
*
* @author Chill
*/
@Primary
@Component
@AllArgsConstructor
public class SwaggerProvider implements SwaggerResourcesProvider {
private static final String API_URI = "/v2/api-docs-ext";
private final RouteProperties routeProperties;
@Override
public List<SwaggerResource> get() {
List<SwaggerResource> resources = new ArrayList<>();
List<RouteResource> routeResources = routeProperties.getResources();
routeResources.forEach(routeResource -> resources.add(swaggerResource(routeResource)));
return resources;
}
private SwaggerResource swaggerResource(RouteResource routeResource) {
SwaggerResource swaggerResource = new SwaggerResource();
swaggerResource.setName(routeResource.getName());
swaggerResource.setLocation(routeResource.getLocation().concat(API_URI));
swaggerResource.setSwaggerVersion(routeResource.getVersion());
return swaggerResource;
}
}

10
blade-gateway/src/main/resources/application-dev.yml

@ -0,0 +1,10 @@
blade:
#多团队协作服务配置
ribbon:
rule:
#开启配置
enabled: true
#负载均衡优先调用的ip段
prior-ip-pattern:
- 192.168.0.*
- 127.0.0.1

23
blade-gateway/src/main/resources/bootstrap.yml

@ -0,0 +1,23 @@
server:
port: 80
spring:
cloud:
gateway:
discovery:
locator:
enabled: true
loadbalancer:
retry:
enabled: true
# 聚合文档配置
blade:
document:
resources:
- name: 授权模块
location: /blade-auth
- name: 工作台模块
location: /blade-desk
- name: 系统模块
location: /blade-system

109
doc/docker/README.md

@ -0,0 +1,109 @@
#使用docker构建工程步骤
### 1. 使用harbor作为私有库,需要配置maven,找到setting.xml( `linux可以使用find / -name settings.xml`)加入以下配置
```
<servers>
<server>
<id>192.168.0.157</id>
<username>admin</username>
<password>Harbor12345</password>
<configuration>
<email>smallchill@163.com</email>
</configuration>
</server>
</servers>
<pluginGroups>
<pluginGroup>com.spotify</pluginGroup>
</pluginGroups>
```
### 2. docker开启远程访问
如果没有远程访问,会报 `Connect to 192.168.0.157:2375 [/192.168.0.157] failed: Connection refused: connect`
在`/usr/lib/systemd/system/docker.service`,配置远程访问。主要是在[Service]这个部分,加上下面两个参数:
```
cd /usr/lib/systemd/system
vi docker.service
ExecStart=
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock
```
### 3. 配置http访问
因为docker1.3.2版本开始默认docker registry使用的是https,我们设置Harbor默认http方式,所以当执行用docker login、pull、push等命令操作非https的docker regsitry的时就会报错。
解决办法:配置`/etc/docker/daemon.json`
```
[root@localhost harbor]# vi /etc/docker/daemon.json
{
"registry-mirrors": ["https://3dse7md.mirror.aliyuncs.com"]
}
```
将其修改为:
```
{
"registry-mirrors": ["https://3dse7md.mirror.aliyuncs.com"],
"insecure-registries":["192.168.0.157"]
}
```
### 4. 在每个需要构建子项目的pom.xml下加入配置,内容可参考如下
```
<build>
<plugins>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<configuration>
<username>${docker.username}</username>
<password>${docker.password}</password>
<repository>${docker.registry.url}/${docker.namespace}/${project.artifactId}</repository>
<tag>${project.version}</tag>
<useMavenSettingsForAuth>true</useMavenSettingsForAuth>
<buildArgs>
<JAR_FILE>target/${project.build.finalName}.jar</JAR_FILE>
</buildArgs>
<skip>false</skip>
</configuration>
</plugin>
</plugins>
</build>
```
### 5. 在每个需要构建子项目的根目录下加入Dockerfile,内容可参考如下
```
FROM adoptopenjdk/openjdk8-openj9:alpine-slim
MAINTAINER smallchill@163.com
RUN mkdir -p /blade/gateway
WORKDIR /blade/gateway
EXPOSE 80
ADD ./target/blade-gateway.jar ./app.jar
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "app.jar"]
CMD ["--spring.profiles.active=test"]
```
### 6. 在工程根目录的docker-compose.yml下加入配置,内容可参考如下
```
blade-gateway:
image: "${REGISTER}/blade/blade-gateway:${TAG}"
ports:
- 80:80
networks:
blade_net:
ipv4_address: 192.168.2.1
```

3
doc/mvn/mvn命令.md

@ -0,0 +1,3 @@
mvn install:install-file -Dfile=blade-core-1.0.jar -DgroupId=org.springblade -DartifactId=blade-core -Dversion=1.0 -Dpackaging=jar
mvn deploy:deploy-file -DgroupId=com.zhuozhengsoft -DartifactId=pageoffice -Dversion=4.5.0.2 -Dpackaging=jar -Dfile=pageoffice4.5.0.2.jar -Durl=http://nexus.bladex.vip/repository/maven-releases/ -DrepositoryId=release

3
doc/nacos/README.md

@ -0,0 +1,3 @@
* BladeX的注册中心
* 具体文档详见:https://nacos.io/zh-cn/docs/quick-start.html
* docker部署详见:https://github.com/nacos-group/nacos-docker

19
doc/nacos/blade-demo-dev.yaml

@ -0,0 +1,19 @@
#自定义配置
demo:
name: demo-name
#放行配置
blade:
secure:
skip-url:
- /demo/**
datasource:
demo:
master:
url: jdbc:mysql://localhost:3306/bladex?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&tinyInt1isBit=false&allowMultiQueries=true&serverTimezone=GMT%2B8
username: root
password: root
slave:
url: jdbc:mysql://localhost:3306/bladex_slave?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&tinyInt1isBit=false&allowMultiQueries=true&serverTimezone=GMT%2B8
username: root
password: root

57
doc/nacos/blade-dev.yaml

@ -0,0 +1,57 @@
#spring配置
spring:
redis:
##redis 单机环境配置
host: 127.0.0.1
port: 6379
password:
database: 0
ssl: false
##redis 集群环境配置
#cluster:
# nodes: 127.0.0.1:7001,127.0.0.1:7002,127.0.0.1:7003
# commandTimeout: 5000
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
#driver-class-name: org.postgresql.Driver
#driver-class-name: oracle.jdbc.OracleDriver
druid:
# MySql、PostgreSQL校验
validation-query: select 1
# Oracle校验
#validation-query: select 1 from dual
#项目模块集中配置
blade:
#分布式锁配置
lock:
enabled: false
address: redis://127.0.0.1:6379
#通用开发生产环境数据库地址(特殊情况可在对应的子工程里配置覆盖)
datasource:
dev:
# MySql
url: jdbc:mysql://localhost:3306/bladex?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&tinyInt1isBit=false&allowMultiQueries=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
username: root
password: root
# PostgreSQL
#url: jdbc:postgresql://127.0.0.1:5432/bladex
#username: postgres
#password: 123456
# Oracle
#url: jdbc:oracle:thin:@127.0.0.1:49161:orcl
#username: BLADEX
#password: oracle
document:
resources:
- name: 授权模块
location: /blade-auth
- name: 工作台模块
location: /blade-desk
- name: 系统模块
location: /blade-system
- name: Demo模块
location: /blade-demo
- name: Dubbo模块
location: /blade-dubbo-consumer

40
doc/nacos/blade-prod.yaml

@ -0,0 +1,40 @@
#spring配置
spring:
redis:
##redis 单机环境配置
##将docker脚本部署的redis服务映射为宿主机ip
##生产环境推荐使用阿里云高可用redis服务并设置密码
host: 192.168.0.157
port: 3379
password:
database: 0
ssl: false
##redis 集群环境配置
#cluster:
# nodes: 127.0.0.1:7001,127.0.0.1:7002,127.0.0.1:7003
# commandTimeout: 5000
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
#driver-class-name: org.postgresql.Driver
#driver-class-name: oracle.jdbc.OracleDriver
druid:
# MySql、PostgreSQL校验
validation-query: select 1
# Oracle校验
#validation-query: select 1 from dual
#项目模块集中配置
blade:
#分布式锁配置
lock:
##是否启用分布式锁
enabled: false
##将docker脚本部署的redis服务映射为宿主机ip
##生产环境推荐使用阿里云高可用redis服务并设置密码
address: redis://192.168.0.157:3379
#通用开发生产环境数据库地址(特殊情况可在对应的子工程里配置覆盖)
datasource:
prod:
url: jdbc:mysql://192.168.0.157:3306/bladex?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&tinyInt1isBit=false&allowMultiQueries=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
username: root
password: root

38
doc/nacos/blade-test.yaml

@ -0,0 +1,38 @@
#spring配置
spring:
redis:
##redis 单机环境配置
##将docker脚本部署的redis服务映射为宿主机ip
host: 192.168.0.157
port: 3379
password:
database: 0
ssl: false
##redis 集群环境配置
#cluster:
# nodes: 127.0.0.1:7001,127.0.0.1:7002,127.0.0.1:7003
# commandTimeout: 5000
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
#driver-class-name: org.postgresql.Driver
#driver-class-name: oracle.jdbc.OracleDriver
druid:
# MySql、PostgreSQL校验
validation-query: select 1
# Oracle校验
#validation-query: select 1 from dual
#项目模块集中配置
blade:
#分布式锁配置
lock:
##是否启用分布式锁
enabled: false
##将docker脚本部署的redis服务映射为宿主机ip
address: redis://192.168.0.157:3379
#通用开发生产环境数据库地址(特殊情况可在对应的子工程里配置覆盖)
datasource:
test:
url: jdbc:mysql://192.168.0.157:3306/bladex?useSSL=false&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&tinyInt1isBit=false&allowMultiQueries=true&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
username: root
password: root

134
doc/nacos/blade.yaml

@ -0,0 +1,134 @@
#服务器配置
server:
undertow:
# 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程
io-threads: 16
# 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载
worker-threads: 400
# 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理
buffer-size: 1024
# 是否分配的直接内存
direct-buffers: true
#spring配置
spring:
cloud:
sentinel:
eager: true
devtools:
restart:
log-condition-evaluation-delta: false
livereload:
port: 23333
#feign配置
feign:
hystrix:
enabled: true
okhttp:
enabled: true
httpclient:
enabled: false
#hystrix配置
hystrix:
threadpool:
default:
coreSize: 300
maxQueueSize: 1000
queueSizeRejectionThreshold: 800
command:
default:
execution:
isolation:
thread:
timeoutInMilliseconds: 5000
#ribbon配置
ribbon:
#对当前实例的重试次数
MaxAutoRetries: 1
#切换实例的重试次数
MaxAutoRetriesNextServer: 2
#请求处理的超时时间
ReadTimeout: 60000
#请求连接的超时时间
ConnectTimeout: 60000
#对所有操作请求都进行重试
OkToRetryOnAllOperations: true
#对外暴露端口
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: always
#blade配置
blade:
#token配置
token:
#是否有状态
state: false
#接口配置
api:
#报文加密配置
crypto:
#启用报文加密配置
enabled: false
#使用AesUtil.genAesKey()生成
aes-key: O2BEeIv399qHQNhD6aGW8R8DEj4bqHXm
#使用DesUtil.genDesKey()生成
des-key: jMVCBsFGDQr1USHo
#jackson配置
jackson:
#null自动转空值
null-to-empty: true
#大数字自动转字符串
big-num-to-string: true
#支持text文本请求,与报文加密同时开启
support-text-plain: false
#xss配置
xss:
enabled: true
skip-url:
- /weixin
- /notice/submit
#安全框架配置
secure:
#接口放行
skip-url:
- /test/**
#授权认证配置
auth:
- method: ALL
pattern: /weixin/**
expression: "hasAuth()"
- method: POST
pattern: /dashboard/upload
expression: "hasTimeAuth(9, 17)"
- method: POST
pattern: /dashboard/submit
expression: "hasAnyRole('administrator', 'admin', 'user')"
#多终端认证配置
client:
- client-id: sword
path-patterns:
- /sword/**
- client-id: saber
path-patterns:
- /saber/**
#多租户配置
tenant:
#多租户增强
enhance: true
#多租户授权保护
license: false
#多租户字段名
column: tenant_id
#排除多租户逻辑
exclude-tables:
- blade_user

1
doc/nacos/routes/README.md

@ -0,0 +1 @@
动态网关配置

28
doc/nacos/routes/blade-gateway-dev.json

@ -0,0 +1,28 @@
[
{
"id": "desk-route",
"order": 0,
"predicates": [
{
"name": "Path",
"args": {
"pattern": "/blade-desk/**"
}
}
],
"filters": [],
"uri": "lb://blade-desk-me"
},
{
"id": "example-route",
"order": 0,
"predicates": [{
"name": "Path",
"args": {
"pattern": "/example"
}
}],
"filters": [],
"uri": "http://www.example.com"
}
]

29
doc/other/env.md

@ -0,0 +1,29 @@
## 环境变量
#### 环境划分
> dev(开发)、test(测试)、prod(正式),默认dev
#### 添加环境变量
##### java命令行:
```
java -jar gateWay.jar --spring.profiles.active=dev
```
##### JAVA_OPS
```
set JAVA_OPTS="-Dspring.profiles.active=test"
```
##### 标注方式(代码层面,junit单元测试非常实用)
```
@ActiveProfiles({"junittest","productprofile"})
```
##### ENV方式
```
系统环境变量SPRING_PROFILES_ACTIVE(注意:是大写)
```

57
doc/other/http-code.md

@ -0,0 +1,57 @@
## HTTP 状态码
| 状态码 | 含义 |
| ------ | ------------------------------------------------------------ |
| 100 | 客户端应当继续发送请求。这个临时响应是用来通知客户端它的部分请求已经被服务器接收,且仍未被拒绝。客户端应当继续发送请求的剩余部分,或者如果请求已经完成,忽略这个响应。服务器必须在请求完成后向客户端发送一个最终响应。 |
| 101 | 服务器已经理解了客户端的请求,并将通过Upgrade 消息头通知客户端采用不同的协议来完成这个请求。在发送完这个响应最后的空行后,服务器将会切换到在Upgrade 消息头中定义的那些协议。 只有在切换新的协议更有好处的时候才应该采取类似措施。例如,切换到新的HTTP 版本比旧版本更有优势,或者切换到一个实时且同步的协议以传送利用此类特性的资源。 |
| 102 | 由WebDAV(RFC 2518)扩展的状态码,代表处理将被继续执行。 |
| 200 | 请求已成功,请求所希望的响应头或数据体将随此响应返回。 |
| 201 | 请求已经被实现,而且有一个新的资源已经依据请求的需要而建立,且其 URI 已经随Location 头信息返回。假如需要的资源无法及时建立的话,应当返回 '202 Accepted'。 |
| 202 | 服务器已接受请求,但尚未处理。正如它可能被拒绝一样,最终该请求可能会也可能不会被执行。在异步操作的场合下,没有比发送这个状态码更方便的做法了。 返回202状态码的响应的目的是允许服务器接受其他过程的请求(例如某个每天只执行一次的基于批处理的操作),而不必让客户端一直保持与服务器的连接直到批处理操作全部完成。在接受请求处理并返回202状态码的响应应当在返回的实体中包含一些指示处理当前状态的信息,以及指向处理状态监视器或状态预测的指针,以便用户能够估计操作是否已经完成。 |
| 203 | 服务器已成功处理了请求,但返回的实体头部元信息不是在原始服务器上有效的确定集合,而是来自本地或者第三方的拷贝。当前的信息可能是原始版本的子集或者超集。例如,包含资源的元数据可能导致原始服务器知道元信息的超级。使用此状态码不是必须的,而且只有在响应不使用此状态码便会返回200 OK的情况下才是合适的。 |
| 204 | 服务器成功处理了请求,但不需要返回任何实体内容,并且希望返回更新了的元信息。响应可能通过实体头部的形式,返回新的或更新后的元信息。如果存在这些头部信息,则应当与所请求的变量相呼应。 如果客户端是浏览器的话,那么用户浏览器应保留发送了该请求的页面,而不产生任何文档视图上的变化,即使按照规范新的或更新后的元信息应当被应用到用户浏览器活动视图中的文档。 由于204响应被禁止包含任何消息体,因此它始终以消息头后的第一个空行结尾。 |
| 205 | 服务器成功处理了请求,且没有返回任何内容。但是与204响应不同,返回此状态码的响应要求请求者重置文档视图。该响应主要是被用于接受用户输入后,立即重置表单,以便用户能够轻松地开始另一次输入。 与204响应一样,该响应也被禁止包含任何消息体,且以消息头后的第一个空行结束。 |
| 206 | 服务器已经成功处理了部分 GET 请求。类似于 FlashGet 或者迅雷这类的 HTTP 下载工具都是使用此类响应实现断点续传或者将一个大文档分解为多个下载段同时下载。 该请求必须包含 Range 头信息来指示客户端希望得到的内容范围,并且可能包含 If-Range 来作为请求条件。 响应必须包含如下的头部域: Content-Range 用以指示本次响应中返回的内容的范围;如果是 Content-Type 为 multipart/byteranges 的多段下载,则每一 multipart 段中都应包含 Content-Range 域用以指示本段的内容范围。假如响应中包含 Content-Length,那么它的数值必须匹配它返回的内容范围的真实字节数。 Date ETag 和/或 Content-Location,假如同样的请求本应该返回200响应。 Expires, Cache-Control,和/或 Vary,假如其值可能与之前相同变量的其他响应对应的值不同的话。 假如本响应请求使用了 If-Range 强缓存验证,那么本次响应不应该包含其他实体头;假如本响应的请求使用了 If-Range 弱缓存验证,那么本次响应禁止包含其他实体头;这避免了缓存的实体内容和更新了的实体头信息之间的不一致。否则,本响应就应当包含所有本应该返回200响应中应当返回的所有实体头部域。 假如 ETag 或 Last-Modified 头部不能精确匹配的话,则客户端缓存应禁止将206响应返回的内容与之前任何缓存过的内容组合在一起。 任何不支持 Range 以及 Content-Range 头的缓存都禁止缓存206响应返回的内容。 |
| 207 | 由WebDAV(RFC 2518)扩展的状态码,代表之后的消息体将是一个XML消息,并且可能依照之前子请求数量的不同,包含一系列独立的响应代码。 |
| 300 | 被请求的资源有一系列可供选择的回馈信息,每个都有自己特定的地址和浏览器驱动的商议信息。用户或浏览器能够自行选择一个首选的地址进行重定向。 除非这是一个 HEAD 请求,否则该响应应当包括一个资源特性及地址的列表的实体,以便用户或浏览器从中选择最合适的重定向地址。这个实体的格式由 Content-Type 定义的格式所决定。浏览器可能根据响应的格式以及浏览器自身能力,自动作出最合适的选择。当然,RFC 2616规范并没有规定这样的自动选择该如何进行。 如果服务器本身已经有了首选的回馈选择,那么在 Location 中应当指明这个回馈的 URI;浏览器可能会将这个 Location 值作为自动重定向的地址。此外,除非额外指定,否则这个响应也是可缓存的。 |
| 301 | 被请求的资源已永久移动到新位置,并且将来任何对此资源的引用都应该使用本响应返回的若干个 URI 之一。如果可能,拥有链接编辑功能的客户端应当自动把请求的地址修改为从服务器反馈回来的地址。除非额外指定,否则这个响应也是可缓存的。 新的永久性的 URI 应当在响应的 Location 域中返回。除非这是一个 HEAD 请求,否则响应的实体中应当包含指向新的 URI 的超链接及简短说明。 如果这不是一个 GET 或者 HEAD 请求,因此浏览器禁止自动进行重定向,除非得到用户的确认,因为请求的条件可能因此发生变化。 注意:对于某些使用 HTTP/1.0 协议的浏览器,当它们发送的 POST 请求得到了一个301响应的话,接下来的重定向请求将会变成 GET 方式。 |
| 302 | 请求的资源现在临时从不同的 URI 响应请求。由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。只有在Cache-Control或Expires中进行了指定的情况下,这个响应才是可缓存的。 新的临时性的 URI 应当在响应的 Location 域中返回。除非这是一个 HEAD 请求,否则响应的实体中应当包含指向新的 URI 的超链接及简短说明。 如果这不是一个 GET 或者 HEAD 请求,那么浏览器禁止自动进行重定向,除非得到用户的确认,因为请求的条件可能因此发生变化。 注意:虽然RFC 1945和RFC 2068规范不允许客户端在重定向时改变请求的方法,但是很多现存的浏览器将302响应视作为303响应,并且使用 GET 方式访问在 Location 中规定的 URI,而无视原先请求的方法。状态码303和307被添加了进来,用以明确服务器期待客户端进行何种反应。 |
| 303 | 对应当前请求的响应可以在另一个 URI 上被找到,而且客户端应当采用 GET 的方式访问那个资源。这个方法的存在主要是为了允许由脚本激活的POST请求输出重定向到一个新的资源。这个新的 URI 不是原始资源的替代引用。同时,303响应禁止被缓存。当然,第二个请求(重定向)可能被缓存。 新的 URI 应当在响应的 Location 域中返回。除非这是一个 HEAD 请求,否则响应的实体中应当包含指向新的 URI 的超链接及简短说明。 注意:许多 HTTP/1.1 版以前的 浏览器不能正确理解303状态。如果需要考虑与这些浏览器之间的互动,302状态码应该可以胜任,因为大多数的浏览器处理302响应时的方式恰恰就是上述规范要求客户端处理303响应时应当做的。 |
| 304 | 如果客户端发送了一个带条件的 GET 请求且该请求已被允许,而文档的内容(自上次访问以来或者根据请求的条件)并没有改变,则服务器应当返回这个状态码。304响应禁止包含消息体,因此始终以消息头后的第一个空行结尾。 该响应必须包含以下的头信息: Date,除非这个服务器没有时钟。假如没有时钟的服务器也遵守这些规则,那么代理服务器以及客户端可以自行将 Date 字段添加到接收到的响应头中去(正如RFC 2068中规定的一样),缓存机制将会正常工作。 ETag 和/或 Content-Location,假如同样的请求本应返回200响应。 Expires, Cache-Control,和/或Vary,假如其值可能与之前相同变量的其他响应对应的值不同的话。 假如本响应请求使用了强缓存验证,那么本次响应不应该包含其他实体头;否则(例如,某个带条件的 GET 请求使用了弱缓存验证),本次响应禁止包含其他实体头;这避免了缓存了的实体内容和更新了的实体头信息之间的不一致。 假如某个304响应指明了当前某个实体没有缓存,那么缓存系统必须忽视这个响应,并且重复发送不包含限制条件的请求。 假如接收到一个要求更新某个缓存条目的304响应,那么缓存系统必须更新整个条目以反映所有在响应中被更新的字段的值。 |
| 305 | 被请求的资源必须通过指定的代理才能被访问。Location 域中将给出指定的代理所在的 URI 信息,接收者需要重复发送一个单独的请求,通过这个代理才能访问相应资源。只有原始服务器才能建立305响应。 注意:RFC 2068中没有明确305响应是为了重定向一个单独的请求,而且只能被原始服务器建立。忽视这些限制可能导致严重的安全后果。 |
| 306 | 在最新版的规范中,306状态码已经不再被使用。 |
| 307 | 请求的资源现在临时从不同的URI 响应请求。由于这样的重定向是临时的,客户端应当继续向原有地址发送以后的请求。只有在Cache-Control或Expires中进行了指定的情况下,这个响应才是可缓存的。 新的临时性的URI 应当在响应的 Location 域中返回。除非这是一个HEAD 请求,否则响应的实体中应当包含指向新的URI 的超链接及简短说明。因为部分浏览器不能识别307响应,因此需要添加上述必要信息以便用户能够理解并向新的 URI 发出访问请求。 如果这不是一个GET 或者 HEAD 请求,那么浏览器禁止自动进行重定向,除非得到用户的确认,因为请求的条件可能因此发生变化。 |
| 400 | 1、语义有误,当前请求无法被服务器理解。除非进行修改,否则客户端不应该重复提交这个请求。 2、请求参数有误。 |
| 401 | 当前请求需要用户验证。该响应必须包含一个适用于被请求资源的 WWW-Authenticate 信息头用以询问用户信息。客户端可以重复提交一个包含恰当的 Authorization 头信息的请求。如果当前请求已经包含了 Authorization 证书,那么401响应代表着服务器验证已经拒绝了那些证书。如果401响应包含了与前一个响应相同的身份验证询问,且浏览器已经至少尝试了一次验证,那么浏览器应当向用户展示响应中包含的实体信息,因为这个实体信息中可能包含了相关诊断信息。参见RFC 2617。 |
| 402 | 该状态码是为了将来可能的需求而预留的。 |
| 403 | 服务器已经理解请求,但是拒绝执行它。与401响应不同的是,身份验证并不能提供任何帮助,而且这个请求也不应该被重复提交。如果这不是一个 HEAD 请求,而且服务器希望能够讲清楚为何请求不能被执行,那么就应该在实体内描述拒绝的原因。当然服务器也可以返回一个404响应,假如它不希望让客户端获得任何信息。 |
| 404 | 请求失败,请求所希望得到的资源未被在服务器上发现。没有信息能够告诉用户这个状况到底是暂时的还是永久的。假如服务器知道情况的话,应当使用410状态码来告知旧资源因为某些内部的配置机制问题,已经永久的不可用,而且没有任何可以跳转的地址。404这个状态码被广泛应用于当服务器不想揭示到底为何请求被拒绝或者没有其他适合的响应可用的情况下。 |
| 405 | 请求行中指定的请求方法不能被用于请求相应的资源。该响应必须返回一个Allow 头信息用以表示出当前资源能够接受的请求方法的列表。 鉴于 PUT,DELETE 方法会对服务器上的资源进行写操作,因而绝大部分的网页服务器都不支持或者在默认配置下不允许上述请求方法,对于此类请求均会返回405错误。 |
| 406 | 请求的资源的内容特性无法满足请求头中的条件,因而无法生成响应实体。 除非这是一个 HEAD 请求,否则该响应就应当返回一个包含可以让用户或者浏览器从中选择最合适的实体特性以及地址列表的实体。实体的格式由 Content-Type 头中定义的媒体类型决定。浏览器可以根据格式及自身能力自行作出最佳选择。但是,规范中并没有定义任何作出此类自动选择的标准。 |
| 407 | 与401响应类似,只不过客户端必须在代理服务器上进行身份验证。代理服务器必须返回一个 Proxy-Authenticate 用以进行身份询问。客户端可以返回一个 Proxy-Authorization 信息头用以验证。参见RFC 2617。 |
| 408 | 请求超时。客户端没有在服务器预备等待的时间内完成一个请求的发送。客户端可以随时再次提交这一请求而无需进行任何更改。 |
| 409 | 由于和被请求的资源的当前状态之间存在冲突,请求无法完成。这个代码只允许用在这样的情况下才能被使用:用户被认为能够解决冲突,并且会重新提交新的请求。该响应应当包含足够的信息以便用户发现冲突的源头。 冲突通常发生于对 PUT 请求的处理中。例如,在采用版本检查的环境下,某次 PUT 提交的对特定资源的修改请求所附带的版本信息与之前的某个(第三方)请求向冲突,那么此时服务器就应该返回一个409错误,告知用户请求无法完成。此时,响应实体中很可能会包含两个冲突版本之间的差异比较,以便用户重新提交归并以后的新版本。 |
| 410 | 被请求的资源在服务器上已经不再可用,而且没有任何已知的转发地址。这样的状况应当被认为是永久性的。如果可能,拥有链接编辑功能的客户端应当在获得用户许可后删除所有指向这个地址的引用。如果服务器不知道或者无法确定这个状况是否是永久的,那么就应该使用404状态码。除非额外说明,否则这个响应是可缓存的。 410响应的目的主要是帮助网站管理员维护网站,通知用户该资源已经不再可用,并且服务器拥有者希望所有指向这个资源的远端连接也被删除。这类事件在限时、增值服务中很普遍。同样,410响应也被用于通知客户端在当前服务器站点上,原本属于某个个人的资源已经不再可用。当然,是否需要把所有永久不可用的资源标记为'410 Gone',以及是否需要保持此标记多长时间,完全取决于服务器拥有者。 |
| 411 | 服务器拒绝在没有定义 Content-Length 头的情况下接受请求。在添加了表明请求消息体长度的有效 Content-Length 头之后,客户端可以再次提交该请求。 |
| 412 | 服务器在验证在请求的头字段中给出先决条件时,没能满足其中的一个或多个。这个状态码允许客户端在获取资源时在请求的元信息(请求头字段数据)中设置先决条件,以此避免该请求方法被应用到其希望的内容以外的资源上。 |
| 413 | 服务器拒绝处理当前请求,因为该请求提交的实体数据大小超过了服务器愿意或者能够处理的范围。此种情况下,服务器可以关闭连接以免客户端继续发送此请求。 如果这个状况是临时的,服务器应当返回一个 Retry-After 的响应头,以告知客户端可以在多少时间以后重新尝试。 |
| 414 | 请求的URI 长度超过了服务器能够解释的长度,因此服务器拒绝对该请求提供服务。这比较少见,通常的情况包括: 本应使用POST方法的表单提交变成了GET方法,导致查询字符串(Query String)过长。 重定向URI “黑洞”,例如每次重定向把旧的 URI 作为新的 URI 的一部分,导致在若干次重定向后 URI 超长。 客户端正在尝试利用某些服务器中存在的安全漏洞攻击服务器。这类服务器使用固定长度的缓冲读取或操作请求的 URI,当 GET 后的参数超过某个数值后,可能会产生缓冲区溢出,导致任意代码被执行[1]。没有此类漏洞的服务器,应当返回414状态码。 |
| 415 | 对于当前请求的方法和所请求的资源,请求中提交的实体并不是服务器中所支持的格式,因此请求被拒绝。 |
| 416 | 如果请求中包含了 Range 请求头,并且 Range 中指定的任何数据范围都与当前资源的可用范围不重合,同时请求中又没有定义 If-Range 请求头,那么服务器就应当返回416状态码。 假如 Range 使用的是字节范围,那么这种情况就是指请求指定的所有数据范围的首字节位置都超过了当前资源的长度。服务器也应当在返回416状态码的同时,包含一个 Content-Range 实体头,用以指明当前资源的长度。这个响应也被禁止使用 multipart/byteranges 作为其 Content-Type。 |
| 417 | 在请求头 Expect 中指定的预期内容无法被服务器满足,或者这个服务器是一个代理服务器,它有明显的证据证明在当前路由的下一个节点上,Expect 的内容无法被满足。 |
| 421 | 从当前客户端所在的IP地址到服务器的连接数超过了服务器许可的最大范围。通常,这里的IP地址指的是从服务器上看到的客户端地址(比如用户的网关或者代理服务器地址)。在这种情况下,连接数的计算可能涉及到不止一个终端用户。 |
| 422 | 从当前客户端所在的IP地址到服务器的连接数超过了服务器许可的最大范围。通常,这里的IP地址指的是从服务器上看到的客户端地址(比如用户的网关或者代理服务器地址)。在这种情况下,连接数的计算可能涉及到不止一个终端用户。 |
| 422 | 请求格式正确,但是由于含有语义错误,无法响应。(RFC 4918 WebDAV)423 Locked 当前资源被锁定。(RFC 4918 WebDAV) |
| 424 | 由于之前的某个请求发生的错误,导致当前请求失败,例如 PROPPATCH。(RFC 4918 WebDAV) |
| 425 | 在WebDav Advanced Collections 草案中定义,但是未出现在《WebDAV 顺序集协议》(RFC 3658)中。 |
| 426 | 客户端应当切换到TLS/1.0。(RFC 2817) |
| 449 | 由微软扩展,代表请求应当在执行完适当的操作后进行重试。 |
| 500 | 服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。一般来说,这个问题都会在服务器的程序码出错时出现。 |
| 501 | 服务器不支持当前请求所需要的某个功能。当服务器无法识别请求的方法,并且无法支持其对任何资源的请求。 |
| 502 | 作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。 |
| 503 | 由于临时的服务器维护或者过载,服务器当前无法处理请求。这个状况是临时的,并且将在一段时间以后恢复。如果能够预计延迟时间,那么响应中可以包含一个 Retry-After 头用以标明这个延迟时间。如果没有给出这个 Retry-After 信息,那么客户端应当以处理500响应的方式处理它。 注意:503状态码的存在并不意味着服务器在过载的时候必须使用它。某些服务器只不过是希望拒绝客户端的连接。 |
| 504 | 作为网关或者代理工作的服务器尝试执行请求时,未能及时从上游服务器(URI标识出的服务器,例如HTTP、FTP、LDAP)或者辅助服务器(例如DNS)收到响应。 注意:某些代理服务器在DNS查询超时时会返回400或者500错误 |
| 505 | 服务器不支持,或者拒绝支持在请求中使用的 HTTP 版本。这暗示着服务器不能或不愿使用与客户端相同的版本。响应中应当包含一个描述了为何版本不被支持以及服务器支持哪些协议的实体。 |
| 506 | 由《透明内容协商协议》(RFC 2295)扩展,代表服务器存在内部配置错误:被请求的协商变元资源被配置为在透明内容协商中使用自己,因此在一个协商处理中不是一个合适的重点。 |
| 507 | 服务器无法存储完成请求所必须的内容。这个状况被认为是临时的。WebDAV (RFC 4918) |
| 509 | 服务器达到带宽限制。这不是一个官方的状态码,但是仍被广泛使用。 |
| 510 | 获取资源所需要的策略并没有没满足。(RFC 2774) |

16
doc/other/系统使用websocket需要修改pom.md

@ -0,0 +1,16 @@
# 业务系统开启websocket
业务开启websocket有可能会报错:
No 'javax.websocket.server.ServerContainer' ServletContext attribute. Are you running in a Servlet container that supports JSR-356?
如提示上面的错则需要修改pom.xml文件,去掉undertow的依赖
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-common</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</exclusion>
</exclusions>
</dependency>

61
hzims-biz-common/pom.xml

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>main</artifactId>
<groupId>com.hnac.hzims</groupId>
<version>2.5.1.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>hzims-biz-common</artifactId>
<name>${project.artifactId}</name>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-core-launch</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-core-auto</artifactId>
<scope>provided</scope>
</dependency>
<!--Json 工具 Start-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-user-api</artifactId>
<version>${bladex.project.version}</version>
</dependency>
<!--Json 工具 End-->
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-dict-api</artifactId>
<version>${bladex.project.version}</version>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-datascope</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<skip>true</skip>
<finalName>${project.name}</finalName>
</configuration>
</plugin>
</plugins>
</build>
</project>

28
hzims-biz-common/src/main/java/com/hnac/hzims/common/cache/CacheNames.java vendored

@ -0,0 +1,28 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package com.hnac.hzims.common.cache;
/**
* 缓存名
*
* @author Chill
*/
public interface CacheNames {
String NOTICE_ONE = "blade:notice:one";
}

32
hzims-biz-common/src/main/java/com/hnac/hzims/common/config/BladeCommonConfiguration.java

@ -0,0 +1,32 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package com.hnac.hzims.common.config;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Configuration;
/**
* 公共封装包配置类
*
* @author Chill
*/
@Configuration
@AllArgsConstructor
public class BladeCommonConfiguration {
}

52
hzims-biz-common/src/main/java/com/hnac/hzims/common/constant/CommonConstant.java

@ -0,0 +1,52 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package com.hnac.hzims.common.constant;
/**
* 通用常量
*
* @author Chill
*/
public interface CommonConstant {
/**
* sword 系统名
*/
String SWORD_NAME = "sword";
/**
* saber 系统名
*/
String SABER_NAME = "saber";
/**
* 顶级父节点id
*/
Integer TOP_PARENT_ID = 0;
/**
* 顶级父节点名称
*/
String TOP_PARENT_NAME = "顶级";
/**
* 默认密码
*/
String DEFAULT_PASSWORD = "123456";
}

206
hzims-biz-common/src/main/java/com/hnac/hzims/common/constant/LauncherConstant.java

@ -0,0 +1,206 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package com.hnac.hzims.common.constant;
import org.springblade.core.launch.constant.AppConstant;
import static org.springblade.core.launch.constant.AppConstant.APPLICATION_NAME_PREFIX;
/**
* 通用常量
*
* @author Chill
*/
public interface LauncherConstant {
/**
* nacos namespace id
*/
String NACOS_NAMESPACE = "f447a694-519a-4255-95f9-bcbb5a5d6369";
/**
* nacos dev 地址
*/
String NACOS_DEV_ADDR = "192.168.65.152:8848";
/**
* nacos prod 地址
*/
String NACOS_PROD_ADDR = "192.168.65.152:8848";
/**
* nacos test 地址
*/
String NACOS_TEST_ADDR = "192.168.65.152:8848";
/**
* sentinel dev 地址
*/
String SENTINEL_DEV_ADDR = "192.168.65.152:8858";
/**
* sentinel prod 地址
*/
String SENTINEL_PROD_ADDR = "172.30.0.58:8858";
/**
* sentinel test 地址
*/
String SENTINEL_TEST_ADDR = "192.168.65.152:8858";
/**
* seata dev 地址
*/
String SEATA_DEV_ADDR = "192.168.65.152:8091";
/**
* seata prod 地址
*/
String SEATA_PROD_ADDR = "172.30.0.68:8091";
/**
* seata test 地址
*/
String SEATA_TEST_ADDR = "192.168.65.152:8091";
/**
* dbuuo提供者
*/
String APPLICATION_DUBBO_PROVIDER_NAME = APPLICATION_NAME_PREFIX + "dubbo-provider";
/**
* dbuuo消费者
*/
String APPLICATION_DUBBO_CONSUMER_NAME = APPLICATION_NAME_PREFIX + "dubbo-consumer";
/**
* seata订单
*/
String APPLICATION_SEATA_ORDER_NAME = APPLICATION_NAME_PREFIX + "seata-order";
/**
* seata库存
*/
String APPLICATION_SEATA_STORAGE_NAME = APPLICATION_NAME_PREFIX + "seata-storage";
/**
* easypoi
*/
String APPLICATION_EASYPOI_NAME = APPLICATION_NAME_PREFIX + "easypoi";
/**
* kafka
*/
String APPLICATION_KAFKA_NAME = APPLICATION_NAME_PREFIX + "kafka";
/**
* rabbit
*/
String APPLICATION_RABBIT_NAME = APPLICATION_NAME_PREFIX + "rabbit";
/**
* stream消费者
*/
String APPLICATION_STREAM_CONSUMER_NAME = APPLICATION_NAME_PREFIX + "stream-consumer";
/**
* stream生产者
*/
String APPLICATION_STREAM_PROVIDER_NAME = APPLICATION_NAME_PREFIX + "stream-provider";
/**
* seata file模式
*/
String FILE_MODE = "file";
/**
* seata nacos模式
*/
String NACOS_MODE = "nacos";
/**
* seata default模式
*/
String DEFAULT_MODE = "default";
/**
* seata group后缀
*/
String GROUP_NAME = "-group";
/**
* seata 服务组格式
*
* @param appName 服务名
* @return group
*/
static String seataServiceGroup(String appName) {
return appName.concat(GROUP_NAME);
}
/**
* 动态获取nacos地址
*
* @param profile 环境变量
* @return addr
*/
static String nacosAddr(String profile) {
switch (profile) {
case (AppConstant.PROD_CODE):
return NACOS_PROD_ADDR;
case (AppConstant.TEST_CODE):
return NACOS_TEST_ADDR;
default:
return NACOS_DEV_ADDR;
}
}
/**
* 动态获取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;
}
}
/**
* 动态获取seata地址
*
* @param profile 环境变量
* @return addr
*/
static String seataAddr(String profile) {
switch (profile) {
case (AppConstant.PROD_CODE):
return SEATA_PROD_ADDR;
case (AppConstant.TEST_CODE):
return SEATA_TEST_ADDR;
default:
return SEATA_DEV_ADDR;
}
}
}

33
hzims-biz-common/src/main/java/com/hnac/hzims/common/invalid/DictInvalid.java

@ -0,0 +1,33 @@
package com.hnac.hzims.common.invalid;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
/**
* @author hx
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE,ElementType.PARAMETER})
@Constraint(validatedBy = DictInvalidator.class)
public @interface DictInvalid {
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
String attribute() default "";
/**
* 字典key
* @return
*/
String dictKey() default "";
/**
* 提示信息
* @return
*/
String message() default "传入参数不符合字典状态";
}

64
hzims-biz-common/src/main/java/com/hnac/hzims/common/invalid/DictInvalidator.java

@ -0,0 +1,64 @@
package com.hnac.hzims.common.invalid;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.utils.ObjectUtil;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.system.cache.DictCache;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.lang.reflect.Field;
import java.util.Map;
/**
* @author hx
*/
@Slf4j
public class DictInvalidator implements ConstraintValidator<DictInvalid,Object> {
private String dictKey;
private String attribute;
@Override
public void initialize(DictInvalid constraintAnnotation) {
dictKey = constraintAnnotation.dictKey();
attribute = constraintAnnotation.attribute();
}
@SneakyThrows
@Override
public boolean isValid(Object object, ConstraintValidatorContext context) {
//直接放行用在controller层上的内容
if(StringUtil.isNotBlank(attribute)){
return true;
}
Integer value = null;
try{
value = Integer.parseInt((String) object);
}
catch (Exception e){
e.printStackTrace();
return false;
}
String name = DictCache.getValue(dictKey,value);
return StringUtil.isNotBlank(name);
}
public Object getFieldValue(Object object,String fieldName) throws IllegalAccessException {
Class clazz = object.getClass();
if(object instanceof Map){
return ((Map) object).get(fieldName);
}
while (ObjectUtil.isNotEmpty(clazz.getSuperclass())) {
for (Field field : clazz.getDeclaredFields()) {
if(fieldName.equals(field.getName())){
field.setAccessible(true);
return field.get(object);
}
}
clazz = clazz.getSuperclass();
}
return null;
}
}

27
hzims-biz-common/src/main/java/com/hnac/hzims/common/invalid/ObjectRequiredInvalid.java

@ -0,0 +1,27 @@
package com.hnac.hzims.common.invalid;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
/**
* @author hx
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE,ElementType.PARAMETER})
@Constraint(validatedBy = ObjectRequiredInvalidator.class)
public @interface ObjectRequiredInvalid {
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
/**
* 对象属性校验必填
* @return
*/
String[] attributes() default {};
String message() default "传入参数不符合要求";
}

66
hzims-biz-common/src/main/java/com/hnac/hzims/common/invalid/ObjectRequiredInvalidator.java

@ -0,0 +1,66 @@
package com.hnac.hzims.common.invalid;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.utils.ObjectUtil;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.lang.reflect.Field;
import java.util.Map;
/**
* @author hx
*/
@Slf4j
public class ObjectRequiredInvalidator implements ConstraintValidator<ObjectRequiredInvalid,Object> {
private String[] attributes;
@Override
public void initialize(ObjectRequiredInvalid constraintAnnotation) {
attributes = constraintAnnotation.attributes();
}
@SneakyThrows
@Override
public boolean isValid(Object object, ConstraintValidatorContext context) {
//判断是否有子属性;子属性按.区分
for(String attribute : attributes){
Object value = object;
String[] singleAttributes = attribute.split("\\.");
for(String singleAttribute : singleAttributes) {
if(value instanceof Map){
value = ((Map)value).get(singleAttribute);
}
else {
value = getFieldValue(value,singleAttribute);
if(ObjectUtil.isEmpty(value)){
return false;
}
}
}
if(ObjectUtil.isEmpty(value)){
return false;
}
}
return true;
}
public Object getFieldValue(Object object,String fieldName) throws IllegalAccessException {
Class clazz = object.getClass();
if(object instanceof Map){
return ((Map) object).get(fieldName);
}
while (ObjectUtil.isNotEmpty(clazz.getSuperclass())) {
for (Field field : clazz.getDeclaredFields()) {
if(fieldName.equals(field.getName())){
field.setAccessible(true);
return field.get(object);
}
}
clazz = clazz.getSuperclass();
}
return null;
}
}

66
hzims-biz-common/src/main/java/com/hnac/hzims/common/launch/LauncherServiceImpl.java

@ -0,0 +1,66 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package com.hnac.hzims.common.launch;
import com.hnac.hzims.common.constant.LauncherConstant;
import org.springblade.core.auto.service.AutoService;
import org.springblade.core.launch.constant.AppConstant;
import org.springblade.core.launch.service.LauncherService;
import org.springblade.core.launch.utils.PropsUtil;
import org.springframework.boot.builder.SpringApplicationBuilder;
import java.util.Properties;
/**
* 启动参数拓展
*
* @author smallchil
*/
@AutoService(LauncherService.class)
public class LauncherServiceImpl implements LauncherService {
@Override
public void launcher(SpringApplicationBuilder builder, String appName, String profile, boolean isLocalDev) {
Properties props = System.getProperties();
// 通用注册
PropsUtil.setProperty(props, "spring.cloud.nacos.discovery.server-addr", LauncherConstant.nacosAddr(profile));
PropsUtil.setProperty(props, "spring.cloud.nacos.config.server-addr", LauncherConstant.nacosAddr(profile));
PropsUtil.setProperty(props, "spring.cloud.sentinel.transport.dashboard", LauncherConstant.sentinelAddr(profile));
// dubbo注册
PropsUtil.setProperty(props, "dubbo.application.name", appName);
PropsUtil.setProperty(props, "dubbo.application.qos.enable", "false");
PropsUtil.setProperty(props, "dubbo.protocol.name", "dubbo");
PropsUtil.setProperty(props, "dubbo.registry.address", "nacos://" + LauncherConstant.nacosAddr(profile));
PropsUtil.setProperty(props, "dubbo.version", AppConstant.APPLICATION_VERSION);
PropsUtil.setProperty(props, "dubbo.scan.base-packages", AppConstant.BASE_PACKAGES);
// seata注册地址
PropsUtil.setProperty(props, "seata.service.grouplist.default", LauncherConstant.seataAddr(profile));
// seata注册group格式
PropsUtil.setProperty(props, "seata.tx-service-group", LauncherConstant.seataServiceGroup(appName));
// seata配置服务group
PropsUtil.setProperty(props, "seata.service.vgroup-mapping.".concat(LauncherConstant.seataServiceGroup(appName)), LauncherConstant.DEFAULT_MODE);
// seata注册模式配置
// PropsUtil.setProperty(props, "seata.registry.type", LauncherConstant.NACOS_MODE);
// PropsUtil.setProperty(props, "seata.registry.nacos.server-addr", LauncherConstant.nacosAddr(profile));
// PropsUtil.setProperty(props, "seata.config.type", LauncherConstant.NACOS_MODE);
// PropsUtil.setProperty(props, "seata.config.nacos.server-addr", LauncherConstant.nacosAddr(profile));
}
}

22
hzims-biz-common/src/main/java/com/hnac/hzims/common/pojo/Tree.java

@ -0,0 +1,22 @@
package com.hnac.hzims.common.pojo;
import java.util.List;
/**
* 基础VO,用于tree结构
*
* @author xiashandong
* @created 2020/9/9 17:30
**/
public interface Tree<T extends Tree> {
List<T> getChildren();
void setChildren(List<T> children);
Long getId();
Long getParentId();
String getName();
}

84
hzims-biz-common/src/main/java/com/hnac/hzims/common/service/UserAuthDataService.java

@ -0,0 +1,84 @@
package com.hnac.hzims.common.service;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springblade.core.tool.api.R;
import org.springblade.system.user.entity.User;
import org.springblade.system.user.feign.IUserClient;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
@AllArgsConstructor
@Slf4j
@Service
public class UserAuthDataService {
private final IUserClient userClient;
/**
* 根据用户ID拼接用户数据权限SQL
* @param userId
* @return
*/
public String getUserAuthDataSQL(Long userId) {
R<User> r = userClient.userInfoById(userId);
String sqlScript = null;
if(r.getCode() != HttpStatus.OK.value() || r.getData() == null) {
return null;
}
User user = r.getData();
if(StringUtils.isBlank(user.getDataScopeType())) {
return null;
}
switch (user.getDataScopeType()) {
case "0" :
//本人
sqlScript = " create_user = " + userId;
break;
case "1":
//所属机构
if(StringUtils.isNotBlank(user.getDeptId())) {
sqlScript = " create_dept = " + user.getDeptId();
}
break;
case "2":
//本部门及下属
if(StringUtils.isNotBlank(user.getDeptId())) {
sqlScript = " create_dept like '" + user.getDeptId() + "%' ";
}
break;
case "3":
//从属机构
if(StringUtils.isNotBlank(user.getDeptIds())) {
sqlScript = " create_dept in (" + user.getDeptIds() + ") ";
}
break;
case "4":
//从属机构及下属
if(StringUtils.isNotBlank(user.getDeptIds())) {
String[] deptIds = user.getDeptIds().split(",");
sqlScript = " ( ";
for(int i = 0;i<deptIds.length;i++) {
sqlScript += " create_dept like '" + deptIds[i] + "%'";
if(i < deptIds.length-1) {
sqlScript += " or ";
}
}
sqlScript += " ) ";
}
break;
case "5":
//个人及下属机构
if(StringUtils.isNotBlank(user.getDeptId())){
sqlScript = " (( create_user = " + userId + " or create_dept like '" + user.getDeptId() + "%' ) " + " and create_dept != " + user.getDeptId() + " ) ";
} else {
sqlScript = " create_user = " + userId;
}
break;
default:
break;
}
return sqlScript;
}
}

171
hzims-biz-common/src/main/java/com/hnac/hzims/common/utils/CacheUtil.java

@ -0,0 +1,171 @@
package com.hnac.hzims.common.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.ObjectUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author hx
*/
@Component
@Slf4j
public class CacheUtil {
/**redis内存储对象容错次数属性名**/
private static final String TOLERANCE_COUNT = "toleranceCount";
@Autowired
public RedisTemplate redisTemplate;
@Autowired
public StringRedisTemplate stringRedisTemplate;
/**String 锁**/
private Lock stringLock = new ReentrantLock();
/**hash 锁**/
private Lock hashLock = new ReentrantLock();
/**zSet 锁**/
private Lock zSetLock = new ReentrantLock();
/**
* redis String类型容错机制处理 超出容错机制自动删除
* @param key 缓存键值
* @param toleranceCountMax 最高容错次数
*/
public void toleranceFaultString(String key,int toleranceCountMax) {
stringLock.lock();
try{
ValueOperations valueOperations= redisTemplate.opsForValue();
Object object = valueOperations.get(key);
redisTemplate.execute(new SessionCallback() {
@Override
public Object execute(RedisOperations operations) throws DataAccessException {
redisTemplate.multi();
if(ObjectUtil.isEmpty(object)) {
return null;
}
//记录错误次数 超出错误阈值删除key值
JSONObject jsonObject = addToleranceCount(object);
if(Integer.parseInt(jsonObject.getString(TOLERANCE_COUNT)) > toleranceCountMax){
stringRedisTemplate.delete(key);
}
else {
valueOperations.setIfPresent(key,JSON.toJSONString(jsonObject));
}
operations.exec();
return null;
}
});
}
finally {
stringLock.unlock();
}
}
/**
* redis hash类型容错机制处理 超出容错机制自动删除
* @param key 缓存键值
* @param hashCode hash值
* @param toleranceCountMax 最高容错次数
*/
public void toleranceFaultHash(String key,String hashCode,int toleranceCountMax) {
hashLock.lock();
try{
HashOperations hashOperations = redisTemplate.opsForHash();
Object object = hashOperations.get(key,hashCode);
redisTemplate.execute(new SessionCallback() {
@Override
public Object execute(RedisOperations operations) throws DataAccessException {
redisTemplate.multi();
if(ObjectUtil.isEmpty(object)) {
return null;
}
//记录错误次数 超出错误阈值删除key值
JSONObject jsonObject = addToleranceCount(object);
if(Integer.parseInt(jsonObject.getString(TOLERANCE_COUNT)) > toleranceCountMax){
hashOperations.delete(key,hashCode);
}
else {
hashOperations.put(key,hashCode,JSON.toJSONString(jsonObject));
}
operations.exec();
return null;
}
});
}
finally {
hashLock.unlock();
}
}
/**
* redis ZSet类型容错机制处理 超出容错机制自动删除
* @param key 键值
* @param object 分数
* @param toleranceCountMax 容错阈值
*/
public void toleranceFaultZSet(String key,Object object,int toleranceCountMax) {
zSetLock.lock();
try{
ZSetOperations zSetOperations = redisTemplate.opsForZSet();
Double score = redisTemplate.opsForZSet().score(key, object);
if(Func.isEmpty(score)) {
return;
}
log.info("score:{}",score);
redisTemplate.execute(new SessionCallback() {
@Override
public Object execute(RedisOperations operations) throws DataAccessException {
redisTemplate.multi();
if(ObjectUtil.isEmpty(object)) {
return null;
}
//删除object 若未达到容错阈值则重新插入回去 达到修改的效果
zSetOperations.remove(key,object);
JSONObject jsonObject = addToleranceCount(object);
if(Integer.parseInt(jsonObject.getString(TOLERANCE_COUNT)) < toleranceCountMax){
zSetOperations.add(key,JSON.toJSONString(jsonObject),score);
}
operations.exec();
return null;
}
});
}
finally {
zSetLock.unlock();
}
}
/***
* 记录错误次数
* @param object redis - value
* @return
*/
public JSONObject addToleranceCount(Object object) {
String json = "";
if(object instanceof String){
json = (String) object;
}
else{
json = JSON.toJSONString(object);
}
JSONObject jsonObject = JSONObject.parseObject(json);
if(Func.isEmpty(jsonObject.getString(TOLERANCE_COUNT))) {
jsonObject.put(TOLERANCE_COUNT,1);
}
else {
int toleranceCount = Integer.parseInt(jsonObject.getString(TOLERANCE_COUNT));
jsonObject.put(TOLERANCE_COUNT,toleranceCount+1);
}
return jsonObject;
}
}

26
hzims-biz-common/src/main/java/com/hnac/hzims/common/utils/CommonUtil.java

@ -0,0 +1,26 @@
/*
* Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* Neither the name of the dreamlu.net developer nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
* Author: Chill 庄骞 (smallchill@163.com)
*/
package com.hnac.hzims.common.utils;
/**
* 通用工具类
*
* @author Chill
*/
public class CommonUtil {
}

142
hzims-biz-common/src/main/java/com/hnac/hzims/common/utils/Condition.java

@ -0,0 +1,142 @@
package com.hnac.hzims.common.utils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.support.QueryField;
import org.springblade.core.mp.support.SqlCondition;
import org.springblade.core.tenant.mp.TenantEntity;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.ObjectUtil;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
/**
* @author ninglong
* @create 2020-08-25 18:59
*/
public class Condition extends org.springblade.core.mp.support.Condition {
/**
* 驼峰转下划线
* @param c
* @return
*/
private static String camel2under(String c) {
String separator = "_";
c = c.replaceAll("([a-z])([A-Z])", "$1" + separator + "$2").toUpperCase();
return c;
}
/**
* 支持配置化的模糊查询
* @param entity 数据库返回的对象实体
* @param query 查询条件实体
* @param <T> 数据库返回的对象实体
* @return
*/
public static <T> LambdaQueryWrapper<T> getQueryWrapper(T entity, Object query) {
QueryWrapper qw = new QueryWrapper();
qw.setEntityClass(entity.getClass());
Class queryClass = query.getClass();
List<Field> fieldList = new ArrayList<>();
while (null != queryClass){
fieldList.addAll(Arrays.asList(queryClass.getDeclaredFields()));
queryClass = queryClass.getSuperclass();
}
for(Field field:fieldList){
field.setAccessible(true);
QueryField queryField = field.getAnnotation(QueryField.class);
if(queryField==null)continue;
Object value;
try {
value = field.get(query);
} catch (Exception e) {
throw new ServiceException("获取属性性出错");
}
if(value==null)continue;
List list = null;
if(value instanceof List){
list = (List)value;
if(list.size()==0)continue;
}
String condition = queryField.condition();
if(Func.isBlank(condition))continue;
String fileName = camel2under(field.getName());
if(SqlCondition.EQUAL.equals(condition)) {
qw.eq(fileName, value);
}else if(SqlCondition.LIKE.equals(condition)){
qw.like(fileName,value);
}else if(SqlCondition.LIKE_LEFT.equals(condition)){
qw.likeLeft(fileName,value);
}else if(SqlCondition.LIKE_RIGHT.equals(condition)){
qw.likeRight(fileName,value);
}else if(SqlCondition.NOT_IN.equals(condition)){
String columnName = queryField.columnName();
if(Func.isBlank(columnName))throw new ServiceException("查询不包含条件时需要指定列名");
qw.notIn(camel2under(columnName),list);
}else if(SqlCondition.IN.equals(condition)){
String columnName = queryField.columnName();
if(Func.isBlank(columnName))throw new ServiceException("查询包含条件时需要指定列名");
qw.in(camel2under(columnName),list);
}
}
return qw.lambda();
}
public static <T> QueryWrapper<T> getQueryWrapper(T entity, Object query, boolean isSearchNull, String alias) {
QueryWrapper qw = new QueryWrapper();
qw.setEntityClass(entity.getClass());
Class queryClass = query.getClass();
List<Field> fieldList = new ArrayList<>();
while (null != queryClass){
fieldList.addAll(Arrays.asList(queryClass.getDeclaredFields()));
queryClass = queryClass.getSuperclass();
}
for(Field field:fieldList){
field.setAccessible(true);
QueryField queryField = field.getAnnotation(QueryField.class);
if(queryField==null) continue;
Object value;
try {
value = field.get(query);
} catch (Exception e) {
throw new ServiceException("获取属性性出错");
}
//处理为空状况
if(!isSearchNull && ObjectUtil.isEmpty(value)) {
continue;
}
List list = null;
if(value instanceof List){
list = (List)value;
if(list.size()==0)continue;
}
String condition = queryField.condition();
if(Func.isBlank(condition))continue;
String fileName = Optional.ofNullable(alias).map(aliasStr -> aliasStr + ".").orElse("") + camel2under(field.getName());
if(SqlCondition.EQUAL.equals(condition)) {
qw.eq(fileName, value);
}else if(SqlCondition.LIKE.equals(condition)){
qw.like(fileName,value);
}else if(SqlCondition.LIKE_LEFT.equals(condition)){
qw.likeLeft(fileName,value);
}else if(SqlCondition.LIKE_RIGHT.equals(condition)){
qw.likeRight(fileName,value);
}else if(SqlCondition.NOT_IN.equals(condition)){
String columnName = queryField.columnName();
if(Func.isBlank(columnName))throw new ServiceException("查询不包含条件时需要指定列名");
qw.notIn(fileName,list);
}else if(SqlCondition.IN.equals(condition)){
String columnName = queryField.columnName();
if(Func.isBlank(columnName))throw new ServiceException("查询包含条件时需要指定列名");
qw.in(fileName,list);
}
}
return qw;
}
}

123
hzims-biz-common/src/main/java/com/hnac/hzims/common/utils/DateUtil.java

@ -0,0 +1,123 @@
package com.hnac.hzims.common.utils;
import org.springblade.core.tool.utils.ObjectUtil;
import java.time.*;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
/**
* @author hx
*/
public class DateUtil {
/***
* Date 转换为 LocalDateTime
* @param convertDate 需转换的时间
* @return
*/
public static LocalDateTime DateToLocalDateTime(Date convertDate){
if(ObjectUtil.isNotEmpty(convertDate)) {
return convertDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
}
return null;
}
/**
* 判斷时间是否在某一天之内
* @param judgeTime
* @param samplingDate
* @return
*/
public static boolean judgeSameDay(LocalDateTime judgeTime, LocalDate samplingDate) {
//取样日期的第一秒
LocalDateTime minSamplingTime = LocalDateTime.of(samplingDate, LocalTime.MIN);
//取样日期的最后一秒
LocalDateTime maxSamplingTime = LocalDateTime.of(samplingDate, LocalTime.MAX);
return judgeTime.isAfter(minSamplingTime) && judgeTime.isBefore(maxSamplingTime);
}
/**
* Java 获取两个日期之间的所有日期
*
* @param startDate
* @param endDate
* @return
*/
public static List<LocalDate> getDatesBetween(LocalDate startDate, LocalDate endDate) {
long numOfDaysBetween = ChronoUnit.DAYS.between(startDate, endDate) + 1;
return IntStream.iterate(0, i -> i + 1).limit(numOfDaysBetween).mapToObj(i -> startDate.plusDays(i)).collect(Collectors.toList());
}
/**
* 获取年份第一天
* @param year
* @return
*/
public static LocalDate getFirstDayByYear(String year) {
return LocalDate.of(Integer.parseInt(year),1,1);
}
/**
* 获取年份最后一天
* @param year
* @return
*/
public static LocalDate getLastDayByYear(String year) {
LocalDate lastMonthFirstDay = LocalDate.of(Integer.parseInt(year),12,1);
return lastMonthFirstDay.with(TemporalAdjusters.lastDayOfYear());
}
/**
* 获取月份第一天
* @param yearAndMonth
* @return
*/
public static LocalDate getFirstDayByYearMonth(String yearAndMonth) {
YearMonth yearMonth = YearMonth.parse(yearAndMonth);
return LocalDate.of(yearMonth.getYear(),yearMonth.getMonth(),1);
}
/**
* 获取月份最后一天
* @param yearAndMonth
* @return
*/
public static LocalDate getLastDayByYearMonth(String yearAndMonth) {
return getFirstDayByYearMonth(yearAndMonth).with(TemporalAdjusters.lastDayOfMonth());
}
/**
* 获取某时刻加上某时段后调的时间
* @param date 指定时刻
* @param duration 时间段
* @param timeUnit 时间单位
* @return
*/
/*public static LocalDateTime plus(LocalDateTime date, Integer duration, String timeUnit) {
DateConstant.UnitEnum enumByUnit = DateConstant.UnitEnum.getEnumByUnit(timeUnit);
Assert.isTrue(ObjectUtil.isNotEmpty(enumByUnit),() -> {
throw new ServiceException("DateUtil.plus内传入的时间单位参数在枚举类中未查询到,传入的参数为:" + timeUnit);
});
switch(enumByUnit) {
case YEAR:
return date.plusYears(duration);
case MONTH:
return date.plusMonths(duration);
case DAY:
return date.plusDays(duration);
case HOUR:
return date.plusHours(duration);
case MINUTER:
return date.plusMinutes(duration);
case SECOND:
return date.plusSeconds(duration);
default:
return null;
}
}*/
}

80
hzims-biz-common/src/main/java/com/hnac/hzims/common/utils/TreeUtil.java

@ -0,0 +1,80 @@
package com.hnac.hzims.common.utils;
import com.hnac.hzims.common.pojo.Tree;
import lombok.Builder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 树结构数据工具类
*
* @author xiashandong
* @created 2020/9/11 10:49
**/
@Builder
public final class TreeUtil {
/**
* 获取某个节点ID以及节点下所有的子节点ID
*/
public <T extends Tree> List<Long> getChildIds(Long id, List<T> list) {
Map<Long, List<Tree>> all = list.stream().collect(Collectors.groupingBy(Tree::getParentId));
boolean flag = list.stream().filter(o -> o.getId().equals(id)).findFirst().isPresent();
if(!flag){
return null;
}
T node = list.stream().filter(o -> o.getId().equals(id)).findFirst().get();
List<Long> ids = new ArrayList<>();
this.putChildId(all, node, ids);
return ids;
}
/**
* 构建文件类型树结构数据
*/
public <T extends Tree> T buildTree(T root, List<T> list, String name) {
//判空
if (list == null || list.size() == 0) {
return root;
}
//分类
Map<Long, List<Tree>> all = list.stream().collect(Collectors.groupingBy(Tree::getParentId));
Map<Long, List<Tree>> display = list.stream().filter(o -> (name == null || name.trim().length() == 0) || o.getName().contains(name)).collect(Collectors.groupingBy(Tree::getId));
//生成树控件
for (Tree item : all.get(-1L)) {
Tree child = this.buildTree(item, all, display);
if (null != child) {
root.setChildren(null == root.getChildren() ? new ArrayList<>() : root.getChildren());
root.getChildren().add(child);
}
}
return root;
}
private void putChildId(Map<Long, List<Tree>> all, Tree node, List<Long> ids) {
ids.add(node.getId());
if (all.containsKey(node.getId())) {
all.get(node.getId()).forEach(child -> this.putChildId(all, child, ids));
}
}
private Tree buildTree(Tree node, Map<Long, List<Tree>> all, Map<Long, List<Tree>> display) {
if (all.containsKey(node.getId())) {
for (Tree item : all.get(node.getId())) {
Tree child = this.buildTree(item, all, display);
if (null != child) {
node.setChildren(null == node.getChildren() ? new ArrayList<>() : node.getChildren());
node.getChildren().add(child);
}
}
}
return display.containsKey(node.getId()) || (node.getChildren() != null && node.getChildren().size() > 0) ? node : null;
}
}

8
hzims-biz-common/src/main/resources/banner.txt

@ -0,0 +1,8 @@
${AnsiColor.BLUE} ______ _ _ ___ ___
${AnsiColor.BLUE} | ___ \| | | | \ \ / /
${AnsiColor.BLUE} | |_/ /| | __ _ __| | ___ \ V /
${AnsiColor.BLUE} | ___ \| | / _` | / _` | / _ \ > <
${AnsiColor.BLUE} | |_/ /| || (_| || (_| || __/ / . \
${AnsiColor.BLUE} \____/ |_| \__,_| \__,_| \___|/__/ \__\
${AnsiColor.BLUE}:: BladeX :: ${spring.application.name}:${AnsiColor.RED}${blade.env}${AnsiColor.BLUE} :: Running SpringBoot ${spring-boot.version} :: ${AnsiColor.BRIGHT_BLACK}

35
hzims-service-api/assets-api/pom.xml

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>hzims-service-api</artifactId>
<groupId>com.hnac.hzims</groupId>
<version>2.5.1.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>assets-api</artifactId>
<version>${hzims.project.version}</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.hnac.hzims</groupId>
<artifactId>ticket-api</artifactId>
<version>2.5.1.RELEASE</version>
</dependency>
<dependency>
<groupId>com.hnac.hzinfo.data</groupId>
<artifactId>hzinfo-data-api</artifactId>
<version>${hzinfo.data.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
</dependency>
</dependencies>
<properties>
<hzims.project.version>2.5.1.RELEASE</hzims.project.version>
</properties>
</project>

175
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/AssetsConstants.java

@ -0,0 +1,175 @@
package com.hnac.hzims;
import lombok.Getter;
public class AssetsConstants {
public final static String APP_NAME = "hzims-assets";
public enum TaskTypeEnum{
MANUAL("1","手动"),
AUTO("2","自动")
;
@Getter
private String type;
@Getter
private String describe;
TaskTypeEnum(String type, String describe) {
this.type = type;
this.describe = describe;
}
}
/**
* 周期类型
*/
public enum CycleTypeEnum {
/**
*
*/
S_CYCLE(0,"秒"),
/**
*
*/
M_CYCLE(1,"分"),
/**
*
*/
H_CYCLE(2,"时"),
/**
*
*/
DAY_CYCLE(3,"天"),
/**
*
*/
WEEK_CYCLE(4,"周"),
/**
*
*/
MONTH_CYCLE(5,"月"),
/**
*
*/
YEAR_CYCLE(6,"年");
@Getter
private int type;
@Getter
private String name;
private CycleTypeEnum(int type,String name){
this.type = type;
this.name = name;
}
}
/**
* 取数规则
*/
public enum AccessRulesEnum {
/**
* 最早值
*/
EARLY_CYCLE(0,"最早值"),
/**
* 最大值
*/
MAX_CYCLE(1,"最大值"),
/**
* 最小值
*/
MIN_CYCLE(2,"最小值"),
/**
* 平均值
*/
AVG_CYCLE(3,"平均值"),
/**
* 和值
*/
SUM_CYCLE(4,"和值"),
/**
* 差值
*/
DIFF_CYCLE(5,"差值"),
/**
* 最后值
*/
FINAL_CYCLE(6,"最后值");
@Getter
private int type;
@Getter
private String name;
private AccessRulesEnum(int type,String name){
this.type = type;
this.name = name;
}
}
/**
* 装机容量
*/
public enum MainEnum {
/**
* 装机容量
*/
INSTALLED_CAPACITY("installedCapacity","装机容量");
@Getter
private String val;
@Getter
private String name;
private MainEnum(String val,String name){
this.val = val;
this.name = name;
}
}
/**
* 运行状态
*/
public enum RunStatus {
run("1","运行中"),
spare("2","热备用"),
access("0","检修"),
;
@Getter
private String status;
@Getter
private String des;
private RunStatus(String status, String des) {
this.status = status;
this.des = des;
}
}
/**
* 装机容量
*/
public enum SignageEnum {
/**
* 发电标识
*/
GENERATION_CAPACITY_SIGNAGE("generation_capacity","发电标识"),
/**
* 有功功率标识
*/
POWER_SIGNAGE_SIGNAGE("active_power","有功功率标识"),
/**
* 合位继电器
*/
JOINT_RELAY_SIGNAGE_SIGNAGE("joint_relay","合位继电器");
@Getter
private String val;
@Getter
private String name;
private SignageEnum(String val,String name){
this.val = val;
this.name = name;
}
}
}

38
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/chche/AssetsNumCache.java

@ -0,0 +1,38 @@
package com.hnac.hzims.spare.chche;
import com.hnac.hzims.spare.constants.AssetsConstant;
import org.springblade.core.cache.utils.CacheUtil;
import java.time.LocalDate;
/**
* @Author: wk
* @Date 2020/8/18
* @Version 1.0
*/
public class AssetsNumCache {
private static final String ASSETS_NUM = "ticket:day";
//序列号位数
private static final Integer SERIAL_NUM = 3;
public static String getCodeNum(){
Integer num = (Integer) CacheUtil.get(AssetsConstant.TICKET_DAY_NUM, ASSETS_NUM, LocalDate.now());
if(num == null || num == 0){
num = 1;
CacheUtil.put(AssetsConstant.TICKET_DAY_NUM, ASSETS_NUM,LocalDate.now(), num);
}
return getCodeNum(num);
}
public static String getCodeNum(int num){
String code = String.valueOf(num);
if(code.length() < SERIAL_NUM){
for (int i = code.length(); i < SERIAL_NUM; i++){
code = "0".concat(code);
}
}
CacheUtil.put(AssetsConstant.TICKET_DAY_NUM, ASSETS_NUM,LocalDate.now(), num + 1);
return code;
}
}

43
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/constants/AssetsConstant.java

@ -0,0 +1,43 @@
package com.hnac.hzims.spare.constants;
import java.math.BigDecimal;
/**
* @Author: wk
* @Date 2020/8/6
* @Version 1.0
*/
public interface AssetsConstant {
/**
* 工单记录生成使用系统名称
*/
final String TICKET_SYSTEM_USE_NAME = "系统";
/**
* 工单记录生成使用系统名称
*/
final BigDecimal TICKET_INITIAL_COEFFICIENT = new BigDecimal("1.0");
/**
* 常量1
*/
final String TICKET_ONE = "1";
/**
* 常量2
*/
final String TICKET_ZRE = "0";
/**
* 常量4
*/
final String TICKET_FOR = "4";
/**
* 常量
*/
final String YES = "YES";
/**
* 工单数量缓存
*/
final String TICKET_DAY_NUM = "hzims:assets";
}

10
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/constants/ScheduledConstant.java

@ -0,0 +1,10 @@
package com.hnac.hzims.spare.constants;
/**
* 定时任务处理常量
*/
public interface ScheduledConstant {
//首页分类
String PUSH_HSTOCK_ALERT_MESSAGE_HANDLE = "pushStockAlertMessagehHandle";
}

58
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/SpAllocationEntity.java

@ -0,0 +1,58 @@
package com.hnac.hzims.spare.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.tenant.mp.TenantEntity;
import java.util.List;
/**
* 实体类
*
* @author Chill
*/
@Data
@TableName("wt_sp_allocation")
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "SpAllocation对象", description = "")
public class SpAllocationEntity extends TenantEntity {
private static final long serialVersionUID = 1L;
/**
* 单据号
*/
@ApiModelProperty(value = "单据号")
private String code;
/**
* 工作流实例ID
*/
@ApiModelProperty(value = "工作流实例ID")
private String rpocInsId;
/**
* 入库仓库
*/
@ApiModelProperty(value = "入库仓库")
private Long inWarehouseId;
/**
* 出库仓库
*/
@ApiModelProperty(value = "出库仓库")
private Long outWarehouseId;
/**
* 备注
*/
@ApiModelProperty(value = "备注")
private String remarks;
/**
*备品备件列表
*/
@ApiModelProperty(value = "备品备件列表")
private transient List<SpRecordEntity> basicList;
}

56
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/SpReceiveEntity.java

@ -0,0 +1,56 @@
package com.hnac.hzims.spare.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.tenant.mp.TenantEntity;
import java.util.List;
/**
* 实体类
*
* @author Chill
*/
@Data
@TableName("wt_sp_receive")
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "SpReceive对象", description = "")
public class SpReceiveEntity extends TenantEntity {
private static final long serialVersionUID = 1L;
/**
* 单据号
*/
@ApiModelProperty(value = "单据号")
private String code;
/**
* 关联工单
*/
@ApiModelProperty(value = "关联工单")
private String ticketCode;
/**
* 工作流实例ID
*/
@ApiModelProperty(value = "工作流实例ID")
private String rpocInsId;
/**
* 仓库库房
*/
@ApiModelProperty(value = "仓库库房")
private Long storageRoom;
/**
* 备注
*/
@ApiModelProperty(value = "备注")
private String remarks;
/**
*备品备件列表
*/
@ApiModelProperty(value = "备品备件列表")
private transient List<SpRecordEntity> basicList;
}

59
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/SpReceivesEntity.java

@ -0,0 +1,59 @@
package com.hnac.hzims.spare.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import org.springblade.core.mp.base.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import org.springblade.core.tenant.mp.TenantEntity;
import java.util.Date;
import java.time.LocalDateTime;
/**
* 实体类
*
* @author Chill
*/
@Data
@TableName("wt_sp_receives")
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "SpReceives对象", description = "")
public class SpReceivesEntity extends TenantEntity {
private static final long serialVersionUID = 1L;
/**
* 单据号
*/
@ApiModelProperty(value = "单据号")
private String code;
/**
* 工单ID
*/
@ApiModelProperty(value = "工单ID")
private String ticketCode;
/**
* 工作流实例ID
*/
@ApiModelProperty(value = "工作流实例ID")
private String rpocInsId;
/**
* 仓库库房
*/
@ApiModelProperty(value = "仓库库房")
private Long storageRoom;
/**
* 备注
*/
@ApiModelProperty(value = "备注")
private String remarks;
/**
* 工具领用单ID
*/
@ApiModelProperty(value = "工具领用单ID")
private Long veceiveId;
}

55
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/SpRecordEntity.java

@ -0,0 +1,55 @@
package com.hnac.hzims.spare.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.tenant.mp.TenantEntity;
import java.math.BigDecimal;
@Data
@TableName("wt_sp_record")
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "SpRecord对象", description = "")
public class SpRecordEntity extends TenantEntity {
/**
* 业务表ID
*/
@ApiModelProperty(value = "业务表ID")
private Long businessId;
/**
* 备品备件ID
*/
@ApiModelProperty(value = "备品备件ID")
private Long spBasicId;
/**
* 数量
*/
@ApiModelProperty(value = "数量")
private Integer amount;
/**
* 数量
*/
@ApiModelProperty(value = "价格")
private BigDecimal price;
/**
* 仓库ID
*/
@ApiModelProperty(value = "仓库ID")
private Long warehouseId;
/**
* 类型
*/
@ApiModelProperty(value = "类型")
private Integer type;
/**
*备品备件列表
*/
@ApiModelProperty(value = "领用人")
private transient Long handler;
}

67
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/SpRevertEntity.java

@ -0,0 +1,67 @@
package com.hnac.hzims.spare.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import org.springblade.core.mp.base.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.util.Date;
import java.time.LocalDateTime;
/**
* 实体类
*
* @author Chill
*/
@Data
@TableName("wt_sp_revert")
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "SpRevert对象", description = "")
public class SpRevertEntity extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 单据号
*/
@ApiModelProperty(value = "单据号")
private String code;
/**
* 工作流实例ID
*/
@ApiModelProperty(value = "工作流实例ID")
private String rpocInsId;
/**
* 仓库库房
*/
@ApiModelProperty(value = "仓库库房")
private Long storageRoom;
/**
* 数量
*/
@ApiModelProperty(value = "数量")
private Integer amount;
/**
* 对应备件ID
*/
@ApiModelProperty(value = "对应备件ID")
private Long spBasicId;
/**
* 备品备件名称
*/
@ApiModelProperty(value = "备品备件名称")
private String name;
/**
* 备注
*/
@ApiModelProperty(value = "备注")
private String remarks;
/**
* 当前处理人
*/
@ApiModelProperty(value = "当前处理人")
private Long currentOperator;
}

29
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/SpTemporaryStockDetailEntity.java

@ -0,0 +1,29 @@
package com.hnac.hzims.spare.entity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
@Data
public class SpTemporaryStockDetailEntity implements Serializable {
@ApiModelProperty(value = "名称")
private String name;
@ApiModelProperty(value = "类型")
private String type;
@ApiModelProperty(value = "单位")
private String unit;
@ApiModelProperty(value = "数量")
private Integer amount;
@ApiModelProperty(value = "关联单号")
private String code;
@ApiModelProperty(value = "时间")
private String createDate;
}

70
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/SpTemporaryStockEntity.java

@ -0,0 +1,70 @@
package com.hnac.hzims.spare.entity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
/**
* 临时库存台账
*/
@Data
public class SpTemporaryStockEntity implements Serializable {
@ApiModelProperty("id")
private Long id;
@ApiModelProperty(value = "类型ID")
private Long managementId;
@ApiModelProperty(value = "类型名称")
private String SparePartsName;
/**
* 名称
*/
@ApiModelProperty(value = "名称")
private String name;
/**
* 编码
*/
@ApiModelProperty(value = "编码")
private String code;
/**
* 规格
*/
@ApiModelProperty(value = "规格")
private String specifications;
/**
* 单位
*/
@ApiModelProperty(value = "单位")
private String unit;
@ApiModelProperty(value = "库存数量")
private Integer quantity;
@ApiModelProperty(value = "出库数量")
private Integer DeliveryQuantity;
@ApiModelProperty(value = "归还数量")
private Integer returnedQuantity;
@ApiModelProperty(value = "消耗数量")
private Integer consumedQuantity;
@ApiModelProperty(value = "临时库存数量")
private Integer stockQuantity;
@ApiModelProperty("所在水厂ID")
private Long waterPlantId;
@ApiModelProperty(value = "水厂名")
private String waterPlantName;
@ApiModelProperty("仓库ID")
private Long warehouseId;
@ApiModelProperty("仓库名称")
private String warehouseName;
}

40
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/SpTicketRelationEntity.java

@ -0,0 +1,40 @@
package com.hnac.hzims.spare.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.tenant.mp.TenantEntity;
@Data
@TableName("wt_sp_ticket_relation")
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "SpTicketRelation对象", description = "")
public class SpTicketRelationEntity extends TenantEntity {
/**
* 出库单ID
*/
@ApiModelProperty(value = "出库单ID")
private Long orderId;
/**
* 备件ID
*/
@ApiModelProperty(value = "备件ID")
private Long spBasicId;
/**
* 工单号
*/
@ApiModelProperty(value = "工单号")
private String ticket;
/**
* 数量
*/
@ApiModelProperty(value = "数量")
private Integer amount;
/**
* 备注
*/
@ApiModelProperty(value = "备注")
private String remarks;
}

63
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/SpWarehouseInEntity.java

@ -0,0 +1,63 @@
package com.hnac.hzims.spare.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.tenant.mp.TenantEntity;
import java.util.List;
/**
* 实体类
*
* @author Chill
*/
@Data
@TableName("wt_sp_warehouse_in")
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "SpWarehouseIn对象", description = "SpWarehouseIn对象")
public class SpWarehouseInEntity extends TenantEntity {
private static final long serialVersionUID = 1L;
/**
* 单据号
*/
@ApiModelProperty(value = "单据号")
private String code;
/**
* 入库类型
*/
@ApiModelProperty(value = "入库类型")
private Long type;
/**
* 工作流实例ID
*/
@ApiModelProperty(value = "工作流实例ID")
private String rpocInsId;
/**
* 仓库库房
*/
@ApiModelProperty(value = "仓库库房")
private Long storageRoom;
/**
* 当前处理人
*/
@ApiModelProperty(value = "当前处理人")
private Long currentOperator;
/**
* 备注
*/
@ApiModelProperty(value = "备注")
private String remarks;
/**
*备品备件列表
*/
@ApiModelProperty(value = "备品备件列表")
private transient List<SpRecordEntity> basicList;
}

63
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/SpWarehouseOutEntity.java

@ -0,0 +1,63 @@
package com.hnac.hzims.spare.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.tenant.mp.TenantEntity;
import java.util.List;
/**
* 实体类
*
* @author Chill
*/
@Data
@TableName("wt_sp_warehouse_out")
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "SpWarehouseOut对象", description = "")
public class SpWarehouseOutEntity extends TenantEntity {
private static final long serialVersionUID = 1L;
/**
* 单据号
*/
@ApiModelProperty(value = "单据号")
private String code;
/**
* 工作流实例ID
*/
@ApiModelProperty(value = "工作流实例ID")
private String rpocInsId;
/**
* 仓库库房
*/
@ApiModelProperty(value = "仓库库房")
private Long storageRoom;
/**
* 仓库库房
*/
@ApiModelProperty(value = "仓库库房")
private Long handler;
/**
* 备注
*/
@ApiModelProperty(value = "备注")
private String remarks;
/**
* 出库类型
*/
@ApiModelProperty(value = "出库类型")
private Long type;
/**
*备品备件列表
*/
@ApiModelProperty(value = "备品备件列表")
private transient List<SpRecordEntity> basicList;
}

97
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/WtSpBasicEntity.java

@ -0,0 +1,97 @@
package com.hnac.hzims.spare.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.NullSerializer;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.tenant.mp.TenantEntity;
import java.math.BigDecimal;
/**
* 实体类
*
* @author Chill
*/
@Data
@TableName("WT_SP_BASIC")
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "WtSpBasic对象", description = "")
public class WtSpBasicEntity extends TenantEntity {
private static final long serialVersionUID = 1L;
/**
* 对应分类编号
*/
@ApiModelProperty(value = "对应分类ID")
private Long managementId;
/**
* 名称
*/
@ApiModelProperty(value = "名称")
private String name;
/**
* 编码
*/
@ApiModelProperty(value = "编码")
private String code;
/**
* 规格
*/
@ApiModelProperty(value = "规格")
private String specifications;
/**
* 品牌
*/
@ApiModelProperty(value = "品牌")
private String brand;
/**
* 单位
*/
@ApiModelProperty(value = "单位")
private String unit;
/**
* 单价
*/
@ApiModelProperty(value = "单价")
@JsonSerialize(nullsUsing = NullSerializer.class)
private BigDecimal price;
@ApiModelProperty(value = "重量")
@JsonSerialize(nullsUsing = NullSerializer.class)
private BigDecimal weight;
@ApiModelProperty(value = "库存上限")
@JsonSerialize(nullsUsing = NullSerializer.class)
private Integer upperLimit;
@ApiModelProperty(value = "库存下限")
@JsonSerialize(nullsUsing = NullSerializer.class)
private Integer lowerLimit;
@ApiModelProperty(value = "是否回收废品")
private String isWaste;
/**
* 主要参数
*/
@ApiModelProperty(value = "主要参数")
private String parameter;
/**
* 备注
*/
@ApiModelProperty(value = "备注")
private String remarks;
/**
* 序列号
*/
@ApiModelProperty(value = "序列号")
private Long codeNumber;
private transient String nameQuery;
}

64
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/WtSpManagementEntity.java

@ -0,0 +1,64 @@
package com.hnac.hzims.spare.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.tenant.mp.TenantEntity;
/**
* 实体类
*
* @author Chill
*/
@Data
@TableName("WT_SP_MANAGEMENT")
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "WtSpManagement对象", description = "")
public class WtSpManagementEntity extends TenantEntity {
private static final long serialVersionUID = 1L;
/**
* 分类名称
*/
@ApiModelProperty(value = "分类名称")
private String name;
/**
* 所属父级
*/
@ApiModelProperty(value = "所属父级")
private Long parentId;
/**
* 祖级机构主键
*/
@ApiModelProperty(value = "祖级机构主键")
private String ancestors;
/**
* 节点等级
*/
@ApiModelProperty(value = "节点等级")
private Integer grade;
/**
* 分类编码
*/
@ApiModelProperty(value = "分类编码")
private String code;
/**
* 备品备件1工具2
*/
@ApiModelProperty(value = "备品备件:1,工具:2")
private String type;
/**
* 备注
*/
@ApiModelProperty(value = "备注")
private String remarks;
/**
* 序列号
*/
@ApiModelProperty(value = "序列号")
private Long codeNumber;
}

27
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/WtSpManagementeExcelEntity.java

@ -0,0 +1,27 @@
package com.hnac.hzims.spare.entity;
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;
@Data
@ColumnWidth(25)
@HeadRowHeight(20)
@ContentRowHeight(18)
public class WtSpManagementeExcelEntity {
@ColumnWidth(25)
@ExcelProperty("一级分类名称")
private String oneName;
@ExcelProperty("一级分类代码")
private String oneCode;
@ColumnWidth(25)
@ExcelProperty("二级分类名称")
private String twoName;
@ColumnWidth(25)
@ExcelProperty("二级分类代码")
private String twoCode;
}

101
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/WtSpProviderEntity.java

@ -0,0 +1,101 @@
package com.hnac.hzims.spare.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.tenant.mp.TenantEntity;
/**
* 实体类
*
* @author Chill
*/
@Data
@TableName("WT_SP_PROVIDER")
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "WtSpProvider对象", description = "")
public class WtSpProviderEntity extends TenantEntity {
private static final long serialVersionUID = 1L;
/**
* 机构ID
*/
@ApiModelProperty(value = "机构ID")
private String organizationId;
/**
* 供应商编码
*/
@ApiModelProperty(value = "供应商编码")
private String organizationCode;
/**
* 供应商名称
*/
@ApiModelProperty(value = "供应商名称")
private String name;
/**
* 供货范围
*/
@ApiModelProperty(value = "供货范围")
private String scopeOfSupply;
/**
* 供货周期
*/
@ApiModelProperty(value = "供货周期")
private String supplyCycle;
/**
* 名称缩写
*/
@ApiModelProperty(value = "名称缩写")
private String logogram;
/**
* 业务联系人
*/
@ApiModelProperty(value = "业务联系人")
private String salesman;
/**
* 法人代表
*/
@ApiModelProperty(value = "法人代表")
private String legalPerson;
/**
* 电话
*/
@ApiModelProperty(value = "电话")
private String phone;
/**
* 手机
*/
@ApiModelProperty(value = "手机")
private String mobilePhone;
/**
* 网址
*/
@ApiModelProperty(value = "网址")
private String website;
/**
* 地址
*/
@ApiModelProperty(value = "地址")
private String address;
/**
* 是否合格01
*/
@ApiModelProperty(value = "是否合格(0:否,1:是)")
private Integer qualifiedFlag;
/**
* 备注
*/
@ApiModelProperty(value = "备注")
private String remark;
/**
* 供应商名称
*/
@ApiModelProperty(value = "供应商名称")
private transient String providerName;
}

55
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/WtSpToolBasicEntity.java

@ -0,0 +1,55 @@
package com.hnac.hzims.spare.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.tenant.mp.TenantEntity;
import java.util.Date;
/**
* 实体类
*
* @author Chill
*/
@Data
@TableName("WT_SP_TOOL_BASIC")
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "WtSpToolBasic对象", description = "")
public class WtSpToolBasicEntity extends TenantEntity {
private static final long serialVersionUID = 1L;
/**
* 工具分类
*/
@ApiModelProperty(value = "工具分类")
private Long spBasicId;
/**
* 保质期
*/
@ApiModelProperty(value = "保质期")
private String qualityGuaranteePeriod;
/**
* 生产日期
*/
@ApiModelProperty(value = "生产日期")
@JsonFormat(pattern="yyyy-MM-dd",timezone = "GMT+8")
private Date productionPeriod;
/**
* 领用数量
*/
@ApiModelProperty(value = "领用数量")
private Long quantityReceived;
/**
* 所属仓库
*/
@ApiModelProperty(value = "所属仓库")
private Long warehouseId;
private transient String nameQuery;
}

96
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/WtSpTotalEntity.java

@ -0,0 +1,96 @@
package com.hnac.hzims.spare.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.NullSerializer;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.tenant.mp.TenantEntity;
import java.math.BigDecimal;
/**
* 实体类
*
* @author Chill
*/
@Data
@TableName("WT_SP_TOTAL")
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "WtSpTotal对象", description = "")
public class WtSpTotalEntity extends TenantEntity {
private static final long serialVersionUID = 1L;
/**
* 对应备件ID
*/
@ApiModelProperty(value = "对应备件ID")
@JsonSerialize(nullsUsing = NullSerializer.class)
private Long spBasicId;
/**
* 最低储备量
*/
@ApiModelProperty(value = "最低储备量")
@JsonSerialize(nullsUsing = NullSerializer.class)
private Long minStock;
/**
* 最高储备量
*/
@ApiModelProperty(value = "最高储备量")
@JsonSerialize(nullsUsing = NullSerializer.class)
private Long maxStock;
/**
* 库存
*/
@ApiModelProperty(value = "库存")
@JsonSerialize(nullsUsing = NullSerializer.class)
private Long stock;
/**
* 最新入库单价
*/
@ApiModelProperty(value = "最新入库单价")
@JsonSerialize(nullsUsing = NullSerializer.class)
private BigDecimal inPrice;
/**
* 最新出库单价
*/
@ApiModelProperty(value = "最新出库单价")
@JsonSerialize(nullsUsing = NullSerializer.class)
private BigDecimal outPrice;
/**
* 出库暂存
*/
@ApiModelProperty(value = "出库暂存")
@JsonSerialize(nullsUsing = NullSerializer.class)
private Long outStock;
/**
* 警戒百分
*/
@ApiModelProperty(value = "警戒百分")
@JsonSerialize(nullsUsing = NullSerializer.class)
private Long warningStock;
/**
* 所属仓库
*/
@ApiModelProperty(value = "所属仓库")
@JsonSerialize(nullsUsing = NullSerializer.class)
private Long warehouseId;
/**
* 备件名称
*/
@ApiModelProperty(value = "备件名称")
private transient String name;
/**
* 编码
*/
@ApiModelProperty(value = "备件编码")
private transient String code;
}

87
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/entity/WtSpWarehouseEntity.java

@ -0,0 +1,87 @@
package com.hnac.hzims.spare.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springblade.core.tenant.mp.TenantEntity;
/**
* 实体类
*
* @author Chill
*/
@Data
@TableName("WT_SP_WAREHOUSE")
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "WtSpWarehouse对象", description = "")
public class WtSpWarehouseEntity extends TenantEntity {
private static final long serialVersionUID = 1L;
/**
* 地址
*/
@ApiModelProperty(value = "地址")
private String address;
/**
* 编码
*/
@ApiModelProperty(value = "编码")
private String code;
/**
* 名称
*/
@ApiModelProperty(value = "名称")
private String name;
/**
* 负责人
*/
@ApiModelProperty(value = "负责人")
private Long manager;
/**
* 当前存量
*/
@ApiModelProperty(value = "当前存量")
private Long stock;
/**
* 库存上限
*/
@ApiModelProperty(value = "库存上限")
private Long maxStock;
/**
* 库存下限
*/
@ApiModelProperty(value = "库存下限")
private Long minStock;
/**
* 警戒百分比
*/
@ApiModelProperty(value = "警戒百分比")
private Long warningStock;
/**
* 备注
*/
@ApiModelProperty(value = "备注")
private String remark;
/**
* 所属单位
*/
@ApiModelProperty(value = "所属单位")
private Long affiliatedUnit;
/**
* 所属单位名称
*/
@ApiModelProperty(value = "所属单位名称")
private String affiliatedName;
/**
* 机构ID
*/
@ApiModelProperty(value = "机构ID")
private transient Long deptId;
}

32
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/enume/BusinessType.java

@ -0,0 +1,32 @@
package com.hnac.hzims.spare.enume;
/**
* 单据类型
*/
public enum BusinessType {
IN(1, "入库"), OUT(2, "出库"), ALLOT(3, "调拨"), RECEIVE(4, "领用"), RETURNED(5, "归还"),RETURN(6,"退回");
private int type;
private String name;
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
BusinessType(int type, String name) {
this.type = type;
this.name = name;
}
}

46
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/enume/WarehouseInType.java

@ -0,0 +1,46 @@
package com.hnac.hzims.spare.enume;
/**
* 入库类型
*/
public enum WarehouseInType {
BUY(1,"购买入库"),BACK(2,"退回入库"),ALLOT(3,"调拨入库"),OLD(4,"旧品入库");
private int type;
private String name;
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
WarehouseInType(int type, String name) {
this.type = type;
this.name = name;
}
/**
* 根据值获取枚举
* @param value
* @return
*/
public static WarehouseInType getTypeName(Integer value){
for (WarehouseInType type:WarehouseInType.values()) {
if(type.getType() == value){
return type;
}
}
return BUY;
}
}

46
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/enume/WarehouseOutType.java

@ -0,0 +1,46 @@
package com.hnac.hzims.spare.enume;
/**
* 出库类型
*/
public enum WarehouseOutType {
MAINTENANCE(1,"维保出库"),REPAIR(2,"维修出库"),ALLOT(3,"调拨出库"),OTHER(4,"其他");
private int type;
private String name;
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
WarehouseOutType(int type, String name) {
this.type = type;
this.name = name;
}
/**
* 根据值获取枚举
* @param value
* @return
*/
public static WarehouseOutType getTypeName(Integer value){
for (WarehouseOutType type:WarehouseOutType.values()) {
if(type.getType() == value){
return type;
}
}
return MAINTENANCE;
}
}

29
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/feign/ISpareClient.java

@ -0,0 +1,29 @@
package com.hnac.hzims.spare.feign;
import com.hnac.hzims.spare.entity.*;
import com.hnac.hzims.spare.vo.WtSpBasicVO;
import org.springblade.core.tool.api.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
import java.util.Map;
@FeignClient(
value = "hzims-assets",fallback = ISpareClientFallback.class
)
public interface ISpareClient {
String API_PREFIX = "/client";
String WAREHOUSEOUT = API_PREFIX+"/warehouseOut";
/**
* 保存工单与出库单关联信息
* @param recordEntity
* @return
*/
@PostMapping(WAREHOUSEOUT)
Boolean warehouseOut(@RequestBody SpRecordEntity recordEntity);
}

20
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/feign/ISpareClientFallback.java

@ -0,0 +1,20 @@
package com.hnac.hzims.spare.feign;
import com.hnac.hzims.spare.entity.*;
import com.hnac.hzims.spare.vo.WtSpBasicVO;
import org.springblade.core.tool.api.R;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import java.util.List;
import java.util.Map;
@Component
public class ISpareClientFallback implements ISpareClient {
@Override
public Boolean warehouseOut(SpRecordEntity recordEntity) {
return false;
}
}

35
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/feign/ISpareOutServiceClient.java

@ -0,0 +1,35 @@
package com.hnac.hzims.spare.feign;
import com.hnac.hzims.spare.vo.WtSpToolVO;
import org.springblade.core.mp.support.BladePage;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient(
value = "hzims-assets",fallback = ISpareOutServiceFallback.class
)
public interface ISpareOutServiceClient {
String API_PREFIX = "/spare";
String SPTOOLLIST = API_PREFIX +"/spTooLList";
@GetMapping(SPTOOLLIST)
BladePage<WtSpToolVO> spTooLList(@RequestParam("waterPlanId") Long waterPlanId,
@RequestParam("tenantId") Long tenantId,
@RequestParam("current") Integer current,
@RequestParam("size") Integer size);
// @GetMapping(SPTOOLLIST)
// BladePage<WtSpToolVO> spTooLList(@RequestParam Long waterPlanId,
// @RequestParam Long tenantId,
// @RequestParam Integer current,
// @RequestParam Integer size,
// @RequestParam String code,
// @RequestParam Long deptId,
// @RequestParam Long warehouseId,
// @RequestParam Long typeId,
// @RequestParam String nameQuery);
}

33
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/feign/ISpareOutServiceFallback.java

@ -0,0 +1,33 @@
package com.hnac.hzims.spare.feign;
import com.hnac.hzims.spare.vo.WtSpToolVO;
import org.springblade.core.mp.support.BladePage;
import org.springframework.stereotype.Component;
@Component
public class ISpareOutServiceFallback implements ISpareOutServiceClient {
@Override
public BladePage<WtSpToolVO> spTooLList(Long waterPlanId,
Long tenantId,
Integer current,
Integer size){
System.out.println("熔断了");
return null;
}
// @Override
// public BladePage<WtSpToolVO> spTooLList(Long waterPlanId,
// Long tenantId,
// Integer current,
// Integer size,
// String code,
// Long deptId,
// Long warehouseId,
// Long typeId,
// String nameQuery){
// System.out.println("熔断了");
// return null;
// }
}

54
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/vo/SpAllocationVO.java

@ -0,0 +1,54 @@
package com.hnac.hzims.spare.vo;
import com.hnac.hzims.spare.entity.SpAllocationEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* 模型VO
*
* @author Chill
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class SpAllocationVO extends SpAllocationEntity {
private static final long serialVersionUID = 1L;
/**
* 拨入库房
*/
@ApiModelProperty(value = "拨入库房")
private String inWarehouseName;
/**
* 拨出库房
*/
@ApiModelProperty(value = "拨出库房")
private String outWarehouseName;
/**
* 用户名称
*/
@ApiModelProperty(value = "用户名称")
private String userName;
/**
* 单位名称
*/
@ApiModelProperty(value = "单位名称")
private String affiliatedName;
@ApiModelProperty(value = "机构ID")
private Long deptId;
@ApiModelProperty(value = "开始时间")
private String startDate;
@ApiModelProperty(value = "结束时间")
private String endDate;
/**
* 备品备件列表
*/
private List<WtSpBasicVO> basicVOList;
}

50
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/vo/SpReceiveVO.java

@ -0,0 +1,50 @@
package com.hnac.hzims.spare.vo;
import com.hnac.hzims.spare.entity.SpReceiveEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* 模型VO
*
* @author Chill
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class SpReceiveVO extends SpReceiveEntity {
private static final long serialVersionUID = 1L;
/**
* 仓库名称
*/
@ApiModelProperty(value = "仓库名称")
private String warehouseName;
/**
* 用户名称
*/
@ApiModelProperty(value = "用户名称")
private String userName;
/**
* 单位名称
*/
@ApiModelProperty(value = "单位名称")
private String affiliatedName;
@ApiModelProperty(value = "机构ID")
private Long deptId;
@ApiModelProperty(value = "开始时间")
private String startDate;
@ApiModelProperty(value = "结束时间")
private String endDate;
private Long sign;
/**
* 备品备件列表
*/
private List<WtSpBasicVO> basicVOList;
}

50
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/vo/SpReceivesVO.java

@ -0,0 +1,50 @@
package com.hnac.hzims.spare.vo;
import com.hnac.hzims.spare.entity.SpReceivesEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* 模型VO
*
* @author Chill
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class SpReceivesVO extends SpReceivesEntity {
private static final long serialVersionUID = 1L;
/**
* 仓库名称
*/
@ApiModelProperty(value = "仓库名称")
private String warehouseName;
/**
* 用户名称
*/
@ApiModelProperty(value = "用户名称")
private String userName;
/**
* 单位名称
*/
@ApiModelProperty(value = "单位名称")
private String affiliatedName;
@ApiModelProperty(value = "机构ID")
private Long deptId;
@ApiModelProperty(value = "开始时间")
private String startDate;
@ApiModelProperty(value = "结束时间")
private String endDate;
/**
* 备品备件列表
*/
private List<WtSpBasicVO> basicVOList;
}

18
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/vo/SpRevertVO.java

@ -0,0 +1,18 @@
package com.hnac.hzims.spare.vo;
import com.hnac.hzims.spare.entity.SpRevertEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 模型VO
*
* @author Chill
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class SpRevertVO extends SpRevertEntity {
private static final long serialVersionUID = 1L;
}

53
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/vo/SpWarehouseInVO.java

@ -0,0 +1,53 @@
package com.hnac.hzims.spare.vo;
import com.hnac.hzims.spare.entity.SpWarehouseInEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* 模型VO
*
* @author Chill
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class SpWarehouseInVO extends SpWarehouseInEntity {
private static final long serialVersionUID = 1L;
/**
* 仓库名称
*/
@ApiModelProperty(value = "仓库名称")
private String warehouseName;
/**
* 入库类型名称
*/
@ApiModelProperty(value = "入库类型名称")
private String typeName;
/**
* 入库人
*/
@ApiModelProperty(value = "入库人")
private String userName;
/**
* 单位名称
*/
@ApiModelProperty(value = "单位名称")
private String affiliatedName;
@ApiModelProperty(value = "机构ID")
private Long deptId;
@ApiModelProperty(value = "开始时间")
private String startDate;
@ApiModelProperty(value = "结束时间")
private String endDate;
/**
* 备品备件列表
*/
private List<WtSpBasicVO> basicVOList;
}

57
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/vo/SpWarehouseOutVO.java

@ -0,0 +1,57 @@
package com.hnac.hzims.spare.vo;
import com.hnac.hzims.spare.entity.SpWarehouseOutEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* 模型VO
*
* @author Chill
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class SpWarehouseOutVO extends SpWarehouseOutEntity {
private static final long serialVersionUID = 1L;
/**
* 仓库名称
*/
@ApiModelProperty(value = "仓库名称")
private String warehouseName;
/**
* 出库类型名称
*/
@ApiModelProperty(value = "出库类型名称")
private String typeName;
/**
* 用户名称
*/
@ApiModelProperty(value = "用户名称")
private String userName;
/**
* 单位名称
*/
@ApiModelProperty(value = "单位名称")
private String affiliatedName;
@ApiModelProperty(value = "机构ID")
private Long deptId;
@ApiModelProperty(value = "开始时间")
private String startDate;
@ApiModelProperty(value = "结束时间")
private String endDate;
@ApiModelProperty(value = "关联工单")
private String ticket;
/**
* 备品备件列表
*/
private List<WtSpBasicVO> basicVOList;
}

34
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/vo/StockVo.java

@ -0,0 +1,34 @@
package com.hnac.hzims.spare.vo;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.NullSerializer;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class StockVo{
@ApiModelProperty(value = "名称")
private String name;
@ApiModelProperty(value = "单位")
private String unit;
@ApiModelProperty(value = "品牌")
private String brand;
@ApiModelProperty(value = "库存数量")
@JsonSerialize(nullsUsing = NullSerializer.class)
private Integer stock;
@ApiModelProperty(value = "库存上限")
@JsonSerialize(nullsUsing = NullSerializer.class)
private Integer upperLimit;
@ApiModelProperty(value = "库存下限")
@JsonSerialize(nullsUsing = NullSerializer.class)
private Integer lowerLimit;
@ApiModelProperty(value = "仓库Id")
private Long warehouseId;
}

60
hzims-service-api/assets-api/src/main/java/com/hnac/hzims/spare/vo/WtSpBasicVO.java

@ -0,0 +1,60 @@
package com.hnac.hzims.spare.vo;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.hnac.hzims.spare.entity.WtSpBasicEntity;
import com.hnac.hzims.ticket.allTicket.vo.TicketInfoStatisticVO;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* 模型VO
*
* @author Chill
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class WtSpBasicVO extends WtSpBasicEntity {
private static final long serialVersionUID = 1L;
/**
* 分类名称
*/
@ApiModelProperty(value = "分类名称")
private String sparePartsName;
/**
* 仓库名称
*/
@ApiModelProperty(value = "仓库名称")
private String warehouseName;
/**
* 库存
*/
@ApiModelProperty(value = "库存")
@JsonSerialize(using = ToStringSerializer.class)
private Long stock;
/**
* 库存下限
*/
@ApiModelProperty(value = "库存下限")
@JsonSerialize(using = ToStringSerializer.class)
private Long minStock;
/**
* 库存上限
*/
@ApiModelProperty(value = "库存上限")
@JsonSerialize(using = ToStringSerializer.class)
private Long maxStock;
/**
* 警戒百分
*/
@ApiModelProperty(value = "警戒百分")
private Long warningStock;
@ApiModelProperty("缺陷")
private List<TicketInfoStatisticVO> ticketInfoStatisticVOList;
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save