xuekang
2024-05-11 bac0878349a1db23e7b420ea164e22fb9db73a99
ecosphere-common 初始化
142个文件已添加
21199 ■■■■■ 已修改文件
ecosphere/ecosphere-common/pom.xml 226 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/dataFile/DataFile.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/dto/AppDTO.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/emnu/CommonResultEmnu.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/emnu/SMSResultEmnu.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/qdl/QdlLedgerAccount.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/query/PageQuery.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/result/CommonResult.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/result/ExpressResult.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/result/PageBean.java 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/result/SMSResult.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/token/UserToken.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/user/SysUser.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/wx/PushMsg.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/constants/PropertiesConstants.java 163 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/constants/PushTemplateConstants.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/constants/QdlConstant.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/constants/ServiceConstants.java 136 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/constants/SystemConstants.java 206 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/conf/NxPayConfig.java 199 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/hnnxPay/HnnxConstant.java 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/hnnxPay/KeyMetadata.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/hnnxPay/KeyProvider.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/hnnxPay/KeyProviderImpl.java 173 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/hnnxPay/KeyRegistry.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/hnnxPay/KeyRegistryImpl.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/hnnxPay/NXHttpClientUtils.java 778 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/hnnxPay/NXPayService.java 524 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/hnnxPay/SignatureSigner.java 130 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/orderQueryTask/OrderQueryEvent.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/orderQueryTask/OrderQueryMessageEntity.java 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/orderQueryTask/OrderQueryTask.java 152 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/orderQueryTask/OrderQueryTrigger.java 70 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/orderQueryTask/OrderQueryUtil.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/laba/LabaPushUtil.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/poscom/api/PoscomService.java 197 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/poscom/config/PoscomConfig.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/poscom/config/PoscomPrintData.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/poscom/config/TempletParams.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/poscom/util/PoscomRequest.java 176 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/poscom/util/PoscomUtil.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/poscom/util/PoscomVoice.java 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/poscom/util/StringToAscii.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/poscom/util/StringToGB18030.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/rateLimit/ApiRateLimit.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/rateLimit/ApiRateLimitAop.java 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/AESUtil.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/AesCbcUtil.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/ApplicationContextUtil.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/BaiduUtil.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/BeanUtil.java 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/CncpUtil.java 832 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/CodeUtil.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/CommonUtil.java 294 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/ComputeUtil.java 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/CryptoUtil.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/DesensitizationUtil.java 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/DiscountUtil.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/DistanceUtil.java 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/ExportExcel.java 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/ExpressUtil.java 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/FileTypeJudge.java 117 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/FtpUtil.java 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/GeTuiPush.java 273 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/GeTuiPushCall.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/HttpUtilExtra.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/IPUtil.java 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/IdGenerator.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/ImageUtil.java 96 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/JGPushCallUtil.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/JGPushUtil.java 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/JWTUtil.java 187 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/LaBaPushUtil.java 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/OSSUtil.java 252 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/PageUtils.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/PayUtil.java 149 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/Pinyin.java 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/PropertyUtil.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/ResourceUtil.java 164 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/ResultHandler.java 151 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/SftpUtil.java 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/TableExportCallUtil.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/TencentMapUtil.java 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/TreeUtil.java 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/TypeConvertUtil.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/VerifyImgUtil.java 153 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/WriterUtil.java 130 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/WxCallUtil.java 185 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/WxUtil.java 284 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/XssUtil.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/enums/FileType.java 187 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/enums/LaPushEnum.java 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/enums/QdlPayScene.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/enums/QdlTradeStatus.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/enums/QdlTradeType.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/oss/YiDongOss.java 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/CallBackUrl.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/syb/SybPayCode.java 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/syb/SybPayUrl.java 164 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/syb/SybPayUtil.java 1628 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/syb/param/MerchantAddParam.java 375 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunst/ConsumeApply.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunst/MerchantApply.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunst/SignContractApply.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunst/YunStParam.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunst/YunStResult.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunst/YunStUtil.java 1092 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunst/系统对接云商通接口流程.txt 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/ApiPost.java 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/YunStUtilNew.java 168 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/po/CreateMember.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/po/OrderPay.java 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/po/PayBack.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/po/PayBackChild.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/po/ResultVo.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/po/SplitRule.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/po/SubOrder.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/po/YstPayUrl.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/po/payment/PaymentOrder.java 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/po/payment/PaymentSplitRule.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/po/payment/PaymentSubOrder.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/sc/client/domain/ScClient.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/sc/client/domain/ScGroup.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/sc/client/四川客管系统接口文档.docx 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/sc/sms/ScSMSUtil.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/sms/SMSCallUtil.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/sms/SMSHistory.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/sms/SMSTemplate.java 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/sms/YpSMSUtil.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/resources/antisamy.xml 2789 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/resources/poscom.properties 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/main/resources/yunsdk.properties 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/test/java/com/nuvole/util/FileUtilTest.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/test/java/com/nuvole/util/IdTest.java 106 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/test/java/com/nuvole/util/JWTUtilTest.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/test/java/com/nuvole/util/JsonTest.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/test/java/com/nuvole/util/MapTest.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/test/java/com/nuvole/util/MixPdTest.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/test/java/com/nuvole/util/TreeUtilTest.java 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/test/java/com/nuvole/util/XssUtilTest.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/src/test/resources/antisamy.xml 2789 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/pom.xml 293 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ecosphere/ecosphere-common/pom.xml
New file
@@ -0,0 +1,226 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.dromara</groupId>
        <artifactId>ecosphere</artifactId>
        <version>${revision}</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>ecosphere-common</artifactId>
    <description>
        ecosphere-common ä¾èµ–项
    </description>
    <dependencies>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
        </dependency>
        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
        </dependency>
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
        </dependency>
        <dependency>
            <groupId>com.belerweb</groupId>
            <artifactId>pinyin4j</artifactId>
        </dependency>
        <!--MD5撒盐-->
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <scope>test</scope>
        </dependency>
        <!--极光推送-->
        <dependency>
            <groupId>cn.jpush.api</groupId>
            <artifactId>jpush-client</artifactId>
            <version>3.3.10</version>
        </dependency>
        <dependency>
            <groupId>org.owasp.antisamy</groupId>
            <artifactId>antisamy</artifactId>
            <version>1.5.8</version>
        </dependency>
        <dependency>
            <groupId>org.owasp.encoder</groupId>
            <artifactId>encoder</artifactId>
            <version>1.2.2</version>
        </dependency>
        <!--小程序 session_key加解密用到的jar-->
        <!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15 -->
        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15</artifactId>
            <version>1.45</version>
        </dependency>
        <!--微信小程序模版推送-->
        <dependency>
            <groupId>com.github.binarywang</groupId>
            <artifactId>weixin-java-miniapp</artifactId>
            <version>3.4.0</version>
        </dependency>
        <dependency>
            <groupId>commons-httpclient</groupId>
            <artifactId>commons-httpclient</artifactId>
            <version>3.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-text</artifactId>
            <version>1.1</version>
        </dependency>
        <!--四川短信-->
        <dependency>
            <groupId>com.wisentsoft</groupId>
            <artifactId>gsmpclient</artifactId>
            <version>1.3.5</version>
            <scope>system</scope>
            <systemPath>${basedir}/../libs/gsmpclient-1.0.4.jar</systemPath>
        </dependency>
        <!--通联(云商通)-->
        <dependency>
            <groupId>com.allinpay</groupId>
            <artifactId>yunst-sdk</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <scope>system</scope>
            <systemPath>${basedir}/../libs/yunst-sdk-0.0.1-SNAPSHOT.jar</systemPath>
        </dependency>
        <!--过滤dto-->
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-jdk8</artifactId>
            <version>1.2.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct-processor</artifactId>
            <version>1.2.0.Final</version>
        </dependency>
        <!--个推推送-->
        <dependency>
            <groupId>com.gexin.platform</groupId>
            <artifactId>gexin-rp-sdk-http</artifactId>
            <version>4.1.0.5</version>
            <scope>system</scope>
            <systemPath>${basedir}/../libs/gexin-rp-sdk-http-4.1.0.5.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.gexin.platform</groupId>
            <artifactId>gexin-rp-sdk-template</artifactId>
            <version>4.0.0.24</version>
            <scope>system</scope>
            <systemPath>${basedir}/../libs/gexin-rp-sdk-template-4.0.0.24.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.gexin.platform</groupId>
            <artifactId>gexin-rp-sdk-base</artifactId>
            <version>4.0.0.30</version>
            <scope>system</scope>
            <systemPath>${basedir}/../libs/gexin-rp-sdk-base-4.0.0.30.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.gexin.platform</groupId>
            <artifactId>gexin-rp-fastjson</artifactId>
            <version>1.0.0.3</version>
            <scope>system</scope>
            <systemPath>${basedir}/../libs/gexin-rp-fastjson-1.0.0.3.jar</systemPath>
        </dependency>
        <!--百度ocr-->
        <dependency>
            <groupId>com.baidu.aip</groupId>
            <artifactId>java-sdk</artifactId>
            <version>4.11.0</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-api</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-simple</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>cpcn.institution</groupId>
            <artifactId>API</artifactId>
            <version>2.5.0.0-SNAPSHOT</version>
            <scope>system</scope>
            <systemPath>${basedir}/../libs/cpcn-payment-api-2.6.0.9.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>cpcn.institution</groupId>
            <artifactId>InstitutionTools</artifactId>
            <version>v1.0.1.4-RELEASE</version>
            <scope>system</scope>
            <systemPath>${basedir}/../libs/InstitutionTools-v1.0.1.4-RELEASE.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>com.csii</groupId>
            <artifactId>sg</artifactId>
            <scope>system</scope>
            <version>1.0.3</version>
            <systemPath>${basedir}/../libs/jinYanEPay-1.0.3.jar</systemPath>
        </dependency>
        <!--提供 EOS S3 ç›¸å…³åŠŸèƒ½ï¼Œå¿…é¡»-->
        <dependency>
            <groupId>com.chinamobile.cmss.eos</groupId>
            <artifactId>eos-java-s3-sdk</artifactId>
            <version>1.11.820</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/../libs/eos-java-s3-sdk-1.11.820.jar</systemPath>
        </dependency>
        <!--提供 EOS ä¸´æ—¶è®¤è¯åŠŸèƒ½ï¼Œå¯é€‰-->
        <dependency>
            <groupId>com.chinamobile.cmss.eos</groupId>
            <artifactId>eos-java-s3-sdk-sts</artifactId>
            <version>1.11.820</version>
            <scope>system</scope>
            <systemPath>${project.basedir}/../libs/eos-java-s3-sdk-sts-1.11.820.jar</systemPath>
        </dependency>
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>2.8.1</version>
        </dependency>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>30.1-jre</version>
        </dependency>
    </dependencies>
</project>
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/dataFile/DataFile.java
New file
@@ -0,0 +1,53 @@
package com.nuvole.common.domain.dataFile;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
 * [{"uid":1562829586751,"path":"","name":"","url":""}]
 */
@Data
@AllArgsConstructor
public class DataFile {
    private Long uid;
    private String path;
    private String name;
    private String url;
    public Long getUid() {
        return uid;
    }
    public void setUid(Long uid) {
        this.uid = uid;
    }
    public String getPath() {
        return path;
    }
    public void setPath(String path) {
        this.path = path;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/dto/AppDTO.java
New file
@@ -0,0 +1,56 @@
package com.nuvole.common.domain.dto;
import lombok.Data;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
 * @Description:
 * @Company: TOO (ps:公司名称)
 * @author: å”
 * @date: 2019/10/31 ä¸‹åˆ6:59
 * @version: V1.0.0
 */
@Data
public class AppDTO<T> {
    private Long attr;
    private Long attr2;
    private Long attr3;
    private Long attr4;
    private String pro;
    private String pro2;
    private String pro3;
    private String pro4;
    private Short small;
    private Short small2;
    private Integer integer;
    private Integer integer2;
    private Object object;
    private Map map;
    private Map map2;
    private Date date;
    private List<T> list;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/emnu/CommonResultEmnu.java
New file
@@ -0,0 +1,52 @@
package com.nuvole.common.domain.emnu;
public enum CommonResultEmnu {
    OK(10000,"OK"),//请求成功
    ERROR(50000,"ERROR"),//操作失败
    INVALID_PARAMS(20000,"INVALID_PARAMS"),//非法参数
    AUTHENTICATION_ERR(20001,"AUTHENTICATION_ERR"),//身份校验错误
    TOKEN_ERR(20002,"TOKEN_ERR"),//token error
    NO_PERMISSION_ERR(20006,"NO_PERMISSION_ERR"),//无访问权限
    CRYPTO_ERR(20003,"CRYPTO_ERR"),//加密/解密错误
    DATA_EMPTY(20004,"EMPTY_ERR"),//空数据
    SIGN_ERR(20005,"SIGN_ERR"),//签名错误
    RENCAI_ERR(20006,"RENCAI_ERR"),//人才信息错误 æ— æ•ˆ
    SERVER_ERR(10001,"SERVER_ERR"),//服务异常
    REQUEST_LIMIT_ERR(20007,"REQUEST_LIMIT_ERR");//请求太频繁
    private Integer code;
    private String info;
    private CommonResultEmnu(Integer code, String info) {
        this.code = code;
        this.info = info;
    }
    public static String getInfo(Integer code) {
        for (CommonResultEmnu item : CommonResultEmnu.values()) {
            if (item.getCode().equals(code)) {
                return item.getInfo();
            }
        }
        return "";
    }
    public Integer getCode() {
        return code;
    }
    public void setCode(Integer code) {
        this.code = code;
    }
    public String getInfo() {
        return info;
    }
    public void setInfo(String info) {
        this.info = info;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/emnu/SMSResultEmnu.java
New file
@@ -0,0 +1,33 @@
package com.nuvole.common.domain.emnu;
public enum SMSResultEmnu {
    OK("0", "OK"),     //请求成功
    ERROR("-10000", "ERROR");//操作失败
    private String code;
    private String msg;
    private SMSResultEmnu(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    public String getMsg() {
        return msg;
    }
    public void setMsg(String msg) {
        this.msg = msg;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/qdl/QdlLedgerAccount.java
New file
@@ -0,0 +1,31 @@
package com.nuvole.common.domain.qdl;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
 * @ClassName QdlLedgerAccount
 * @Author cy
 * @Date 2023/9/1
 * @Description ç¿¼æ”¯ä»˜åˆ†è´¦åˆ—表
 * @Version 1.0
 **/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class QdlLedgerAccount {
    /**
     * å•†æˆ·å·
     */
    private String merchantNo;
    /**
     * å•位:分
     */
    private Long amount;
    /**
     * å¤‡æ³¨
     */
    private String memo;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/query/PageQuery.java
New file
@@ -0,0 +1,28 @@
package com.nuvole.common.domain.query;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * åˆ†é¡µæŸ¥è¯¢å®žä½“封装
 *
 * @author liujun
 * @Date 2019/6/17 10:35
 */
@Data
@ApiModel(value = "分页查询封装")
public class PageQuery {
    @ApiModelProperty("页码")
    private Integer pageNumber = 1;
    @ApiModelProperty("条数")
    private Integer pageSize = 10;
    @ApiModelProperty("排序名称")
    private String sortName;
    @ApiModelProperty("排序方式")
    private String sortOrder;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/result/CommonResult.java
New file
@@ -0,0 +1,56 @@
package com.nuvole.common.domain.result;
import cn.hutool.core.util.ObjectUtil;
import com.nuvole.common.domain.emnu.CommonResultEmnu;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class CommonResult<T> {
    public static final String STATUS_OK = "1";//成功
    public static final String STATUS_ERR = "0";//失败
    public static final Integer CODE_OK = 10000;//请求成功返回码
    @ApiModelProperty("状态值 0:失败 1:成功 ")
    private String status = STATUS_OK;
    @ApiModelProperty("接口返回信息")
    private String info = CommonResultEmnu.OK.getInfo();
    @ApiModelProperty("接口返回信息 code ")
    private Integer code = CommonResultEmnu.OK.getCode();
    @ApiModelProperty("接口返回信息描述 ")
    private String description = "";
    @ApiModelProperty("接口返回值 ")
    private T data;
    public CommonResult() {
    }
    public CommonResult(T data) {
        this.data = ObjectUtil.cloneIfPossible(data);
    }
    public CommonResult(CommonResultEmnu resultEmnu) {
        if (!resultEmnu.getCode().equals(CODE_OK)) {
            this.status = STATUS_ERR;
        }
        this.code = resultEmnu.getCode();
        this.info = resultEmnu.getInfo();
    }
    public CommonResult(CommonResultEmnu resultEmnu, String description) {
        if (!resultEmnu.getCode().equals(CODE_OK)) {
            this.status = STATUS_ERR;
        }
        this.code = resultEmnu.getCode();
        this.info = resultEmnu.getInfo();
        this.description = description;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/result/ExpressResult.java
New file
@@ -0,0 +1,36 @@
package com.nuvole.common.domain.result;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
import java.util.Map;
/**
 * å¿«é€’鸟查询物流返回参数
 *
 * @Author: lc
 * @Date: 2019/6/17 18:46
 */
@Data
public class ExpressResult {
    @ApiModelProperty("用户ID ")
    private String EBusinessID;
    @ApiModelProperty("订单编号 ")
    private String OrderCode;
    @ApiModelProperty("快递公司编码 ")
    private String ShipperCode;
    @ApiModelProperty("物流运单号 ")
    private String LogisticCode;
    @ApiModelProperty("成功与否【true:成功 false:失败】 ")
    private String Success;
    @ApiModelProperty("失败原因 ")
    private String Reason;
    @ApiModelProperty("物流状态:1-已揽收 2-在途中,3-签收,4-问题件 ")
    private String State;
    @ApiModelProperty("物流信息【AcceptStation:描述,AcceptTime:时间】 ")
    private List<Map> Traces;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/result/PageBean.java
New file
@@ -0,0 +1,81 @@
package com.nuvole.common.domain.result;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.NumberUtil;
import com.nuvole.util.BeanUtil;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
// @formatter:off
/**
 *                .-~~~~~~~~~-._       _.-~~~~~~~~~-.
 *            __.'  @Author     ~.   .~    ä»£ç æ— Bug   `.__
 *          .'//     liu.q        \./       (秘籍)      \\`.
 *        .'// [916000612@qq.com]  |   æ¬²ç»ƒç¥žåŠŸ   å¼•刀自宫  \\`.
 *      .'// .-~"""""""~~~~-._     |    _,-~~~~"""""""~-.  \\`.
 *    .'//.-"  2019-04-09     `-.  |  .-'     11:35       "-.\\`.
 *  .'//______.============-..   \ | /   ..-============.______\\`.
 *.'______________________________\|/______________________________`.
 *
 * @Description :
 */
// @formatter:on
@Data
@NoArgsConstructor
@ApiModel("列表 è¿”回结果列表封装")
public class PageBean<T> implements Serializable {
    private static final long serialVersionUID = 1000L;
    @ApiModelProperty("总记录数")
    private Integer total; //总记录数
    @ApiModelProperty("结果集")
    private List<T> rows; //结果集
    @ApiModelProperty("第几页")
    private int pageNumber; //第几页
    @ApiModelProperty("每页记录数")
    private int pageSize; //每页记录数
    @ApiModelProperty("总页数")
    private int pages; // æ€»é¡µæ•°
    @ApiModelProperty("当前页的数量<=pageSize")
    private int size; //当前页的数量<=pageSize
    public PageBean(Object obj) {
        Map map = BeanUtil.obj2Map(obj);
        if(map!=null){
            this.pageNumber = Convert.toInt(map.get("pageNum"));
            this.pageSize = Convert.toInt(map.get("pageSize"));
            this.total = Convert.toInt(map.get("total"));
            this.pages = Convert.toInt(map.get("pages"));
            this.rows = obj == null ? new ArrayList<>() : (List<T>)obj;
            this.size = this.rows.size();
        }
    }
    public void setData(List list){
        if(list != null && list.size() >0){
            this.total = list.size();
            //分页
            if (this.total > 0) {
                int start = Convert.toInt(NumberUtil.mul(pageNumber-1, pageSize));
                int end = Convert.toInt(NumberUtil.mul(pageNumber,pageSize));
                if (start <= total) {
                    if (end > total) {
                        end = total;
                    }
                    this.rows = list.subList(start, end);
                } else {
                    this.rows = new ArrayList<>();
                }
            }
        }
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/result/SMSResult.java
New file
@@ -0,0 +1,32 @@
package com.nuvole.common.domain.result;
import com.nuvole.common.domain.emnu.SMSResultEmnu;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * çŸ­ä¿¡è¿”回结果
 *
 * @Author: lc
 * @Date: 2019/8/5 11:48
 */
@Data
public class SMSResult {
    @ApiModelProperty("状态码")
    private String code;
    @ApiModelProperty("描述")
    private String msg;
    public SMSResult(SMSResultEmnu resultEmnu, String msg) {
        this.code = resultEmnu.getCode();
        this.msg = msg;
    }
    public SMSResult(SMSResultEmnu resultEmnu) {
        this.code = resultEmnu.getCode();
        this.msg = resultEmnu.getMsg();
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/token/UserToken.java
New file
@@ -0,0 +1,26 @@
package com.nuvole.common.domain.token;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.ToString;
/**
 * @author ChenLong
 * @version 1.0
 * @ClassName UserToken
 * @date 2019/5/6 18:45
 * @Description ç™»å½•用户token
 */
@Data
@ToString
@ApiModel(value = "登录用户token")
public class UserToken {
    @ApiModelProperty("登录标识,调用业务接口时需放置到header中")
    String accessToken;
    @ApiModelProperty("过期时间 ç§’")
    Long expiresIn;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/user/SysUser.java
New file
@@ -0,0 +1,19 @@
package com.nuvole.common.domain.user;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.ToString;
@Data
@ToString
@ApiModel(value = "后台用户信息")
public class SysUser {
    @ApiModelProperty("id")
    private Long id;
    @ApiModelProperty("用户名")
    private String userName;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/common/domain/wx/PushMsg.java
New file
@@ -0,0 +1,25 @@
package com.nuvole.common.domain.wx;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "微信小程序-订阅消息")
public class PushMsg {
    @ApiModelProperty("接受的用户openId")
    private String touser;
    @ApiModelProperty("订阅的模板id")
    private String template_id;
    @ApiModelProperty("模板跳转的详情页面,可带参数,不传不跳转")
    private String page;
    private String url;
    @ApiModelProperty("模板内容")
    private JSONObject data;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/constants/PropertiesConstants.java
New file
@@ -0,0 +1,163 @@
package com.nuvole.constants;
/**
 * ç³»ç»Ÿé…ç½®å¸¸é‡
 *
 * @Author: lc
 * @Date: 2019/7/30 19:22
 */
public class PropertiesConstants {
    //服务地址配置
    /**
     * åŽå°æŽ¥å£æœåŠ¡åœ°å€
     */
    public static final String STQ_SERVER = "https://yqzx.jinmingyuan.com";
//    public static final String STQ_SERVER = "https://daguogongjiang.top";
    /**
     * h5服务地址
     */
    public static final String STQ_SERVER_WECHAT = "https://yqzx.jinmingyuan.com";
//    public static final String STQ_SERVER_WECHAT = "https://daguogongjiang.top";
    /**
     * å•†æˆ·æ¨¡å—服务地址
     */
    public static final String STQ_SERVER_MERCHANT = STQ_SERVER + "/service-merchant";
    /**
     * å•†åŸŽæ¨¡å—服务地址
     */
    public static final String STQ_SERVER_SHOP = STQ_SERVER + "/service-shop";
    /**
     * 1 ä½¿ç”¨sftp
     * 2 ä½¿ç”¨ç§»åŠ¨äº‘oss
     */
    public static final int UPLOAD_MODEL = 1;
    public static final int KJ_PAY_WAY = 1;                         //快捷支付渠道【1:通联云商通 2:农行快捷支付】
    /**
     * é™æ€èµ„源服务地址(ftp)
     */
    public static String FILE_SERVER = null;
//    public static final String FILE_SERVER = "https://daguogongjiang.top/sftp"; //公司地址
//    public static final String FILE_SERVER = "http://172.16.2.77/f-static";   //正式环境
    //公众平台配置
    /**
     * å°ç¨‹åºappId
     */
//    public static final String WX_APP_APPID = "wx044ba657d536fa6a";
    // æŒ¯å…´æ¶ˆè´¹-小程序
//    public static final String WX_APP_APPID = "wx22159c42a5805166";
    //数字化生态圈
    public static final String WX_APP_APPID = "wxfc579973fbdde096";
    //京源云 AppSecret
//    public static final String WX_APP_APPID = "wxf6818b61cdbb80e4";
    /**
     * å°ç¨‹åºsecret æŒ¯å…´æ¶ˆè´¹
     */
//    public static final String WX_APP_SECRET = "2635f74b77b0cd1057cb8266e5c2606d";
    // å°ç¨‹åºsecret æ•°å­—化生态圈
    public static final String WX_APP_SECRET = "d5d7d0438028b8c29890784344df8216";
    //小程序secret äº¬æºäº‘
//    public static final String WX_APP_SECRET = "d54f086bce09d291605dc57441fa4908";
    /**
     * å¾®ä¿¡æœåŠ¡å·appId
     */
//    public static final String WX_WECHAT_APPID = "wx4e2cf88d5ffa708e";
    // å…¬å¸H5公众号
    public static final String WX_WECHAT_APPID = "wxad8cc511da676bd4";
    //H5公众号 äº¬æºäº‘
//    public static final String WX_WECHAT_APPID = "wxd163440fc91fd9af";
    //时工 å°ç¨‹åº
//    public static final String WX_WECHAT_APPID = "wx22159c42a5805166";
    /**
     * å¾®ä¿¡æœåŠ¡å·secret
     */
//    public static final String WX_WECHAT_SECRET = "dc3594f91ab86def1277133c45bd2584";
    // å…¬å¸H5公众号
    public static final String WX_WECHAT_SECRET = "d4f742cf77b1534055932a1d970cb8ce";
    //H5公众号 äº¬æºäº‘
//    public static final String WX_WECHAT_SECRET = "d54f086bce09d291605dc57441fa4908";
    /**
     * å¾®ä¿¡æœåŠ¡å•†å•†æˆ·å·
     */
    public static final String WX_SERVER_MCHID = "1633049026";
    // äº¬æºäº‘ å•†æˆ·å·
//    public static final String WX_SERVER_MCHID = "1648271607";
    /**
     * å¾®ä¿¡å°ç¨‹åºæ”¯ä»˜å¹³å°çš„子商户id
     */
    public static final String WX_MINIPAY_PLATFORM_SUB_APPID = "1633682244";
    // äº¬æºäº‘
//    public static final String WX_MINIPAY_PLATFORM_SUB_APPID = null;
    /**
     * å¾®ä¿¡æœåС商 secret
     */
    public static final String WX_SERVER_SECRET = "SKC2E1QGBRVFL7T35MYUN49IA06PZXOH";
    // // äº¬æºäº‘ secret
//    public static final String WX_SERVER_SECRET = "6Lk7s4QWqXr9Dv1OzIJlEM2aA5YbupKS";
    //支付配置
    public static final int PAY_WAY = 3;                            //商城支付渠道【1:通联收银宝 2:通联云商通 æ–°å¢ž3 çº¯å¾®ä¿¡æ”¯ä»˜ 4 ä¸­é‡‘支付】
    static {
        if (UPLOAD_MODEL == 1) {
            FILE_SERVER = "https://yqzx.jinmingyuan.com/file"; //公司地址
        } else if (PropertiesConstants.UPLOAD_MODEL == 2) {
            FILE_SERVER = "https://ecosphere.eos.zhengzhou-4.cmecloud.cn";
        }
    }
    public static final int PAY_TYPE = 2;                           //支付读取参数【1.配置文件读取(固定一个) 2.表里加载(按机构查询)】
    public static final String TL_PAY_APPID = "00143623";           //appid
    public static final String TL_PAY_K = "123456";                 //秘钥
    public static final String TL_PAY_ORGCODE = "55165106012TWGR";  //机构号(平台唯一标识)
    //客管系统
    /**
     * ä¼šå‘˜ä¿¡æ¯è¯»å–类型【1.客管系统 2.本系统(导入方式)】
     */
    public static final int MEMBER_READ_TYPE = 2;
    /**
     * h5服务地址
     */
    public static final String WX_SERVER_WECHAT = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    /**
     * å¾®ä¿¡ ä»˜æ¬¾ç æ”¯ä»˜
     */
    public static final String WX_SERVER_MICROPAY = "https://api.mch.weixin.qq.com/pay/micropay";
    /**
     * å¾®ä¿¡ è®¢å•查询
     */
    public static final String WX_SERVER_ORDERQUERY = "https://api.mch.weixin.qq.com/pay/orderquery";
    /**
     * ä»˜æ¬¾ç æŸ¥è¯¢openid
     */
    public static final String WX_SERVER_AUTHCODE2OPENID = "https://api.mch.weixin.qq.com/tools/authcodetoopenid";
    /**
     * é€šè”收银宝通道code
     */
    public static final String CHANNEL_CODE_SYB = "allinPay";
    /**
     * æ”¯ä»˜å®å¾®ä¿¡ç›´è¿žé€šé“code
     */
    public static final String CHANNEL_CODE_DIRECTPAY = "directPay";
    /**
     * è¿›å…¥åº—铺线下扫码付汇总计算Key
     */
    public static String JOB_SHOP_STATIS_SCANORDER_KEY = "JOB_SHOP_STATIS_SCANORDER_KEY";
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/constants/PushTemplateConstants.java
New file
@@ -0,0 +1,42 @@
package com.nuvole.constants;
/**
 * @Description: æŽ¨é€æ¨¡æ¿ID常量
 * @Author: liujun
 * @Date: 2019-07-23 14:57
 **/
public class PushTemplateConstants {
    /**
     * å¼€å›¢æŽ¨é€æ¨¡æ¿
     */
//    public static final String GROUP_START = "CI5XGGJdQb6IKok0tSrd8HpJHlqyChPc3U58yzAz4Y8";
    /**
     * å‚团推送模板
     */
//    public static final String GROUP_JOIN = "mnGXLJBcwk3vRlaBMowRe51zDpGLtGRDaBh4PIysCOs";
    /**
     * å›¢è´­æˆåŠŸæŽ¨é€è®¢é˜…æ¨¡æ¿æ¶ˆæ¯id
     */
    public static final String GROUP_SUCCESS = "a_ojaiKU0OFR3ihu5taT-F5PuZ3vCI4fxXsybLLdy1Q";
    /**
     * å›¢è´­å¤±è´¥æŽ¨é€è®¢é˜…模板消息id
     */
    public static final String GROUP_FAIL = "Fe9IW6n-j7d1F7L-S3CTNfIS8mrxFDLVbYHivnPnvC8";
    /**
     * å›¢è´­é€¾æœŸæœªæ”¯ä»˜æŽ¨é€è®¢é˜…模板消息id
     */
    public static final String GROUP_NO_PAY = "MAryTGFLOO9X6Pr15Z3iJ0j71boGBKcCMwFEHNHeAes";
    /**
     * è®¢å•支付成功
     */
    public static final String PAY_SUCCESS= "fWkckzC4AtkJfJVQhX6r2PTz0YKNdXUV9yDXQ6r-svI";
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/constants/QdlConstant.java
New file
@@ -0,0 +1,64 @@
package com.nuvole.constants;
/**
 * @ClassName QdlConstant
 * @Author cy
 * @Date 2023/8/28
 * @Description
 * @Version 1.0
 **/
public class QdlConstant {
    /**
     * ç”Ÿäº§çŽ¯å¢ƒåœ°å€
     */
    private static final String PROD_URL = "https://openapi.qdlpay.com";
    /**
     * çº¿ä¸Šèšåˆä¸‹å•接口
     * å¾®ä¿¡å°ç¨‹åºã€å¾®ä¿¡å…¬ä¼—号支付、APP æ‹‰èµ·æ”¯ä»˜å®ã€APP æ‹‰èµ·ç¿¼æ”¯ä»˜
     */
    public static String ONLINEPAYURL = PROD_URL + "/gapi/aggregate/aggregatepay/online/payOrder";
    /**
     * èšåˆæ”¶æ¬¾ç ï¼ˆC æ‰« B)下单
     * å¤–部商户通过该接口进行聚合支付下单,并拉起相应第三方 APP è¿›è¡Œæ”¯ä»˜
     */
    public static String OFFLINEC2BPAYURL = PROD_URL + "/gapi/aggregate/aggregatepay/offline/c2b/payOrder";
    /**
     * åè®®å·
     * æµ‹è¯•环境 20200814030100033652190094557249
     * ç”Ÿäº§çŽ¯å¢ƒ 20200825030100037665282868641830
     */
    public static final String AGREE_ID = "20200825030100037665282868641830";
    /**
     * æ¡ç æŸ¥è¯¢ç”¨æˆ·æ ‡è¯†
     * ç”¨äºŽä»˜æ¬¾ç æ”¯ä»˜å‰æ ¹æ®æ¡ç æŸ¥è¯¢ç”¨æˆ·æ ‡è¯†
     */
    public static String CODE2IDENURL = PROD_URL + "/gapi/o2o/aggregatePay/services/barCodeIdentification";
    /**
     * è®¢å•è¶…æ—¶æ—¶é—´
     */
    public static final String TIME_OUT = "86400";
    /**
     * ç­¾åç±»åž‹
     */
    public static final String SIGN_TYPE = "S002";
    /**
     * èšåˆä»˜æ¬¾ç ï¼ˆB æ‰« C)下单
     * å•†æˆ·ç«¯æ‰«ç”¨æˆ·æ”¯ä»˜æ¡ç å¹¶å‘起扣款
     */
    public static String OFFLINEB2CPAYURL = PROD_URL + "/gapi/aggregate/aggregatepay/offline/b2c/pay";
    /**
     * ä¸‹å•结果查询
     * ç”¨äºŽä¸‹å•结果的状态确认与订单信息查询
     */
    public static String TRADE_QUERY_URL = PROD_URL + "/gapi/aggregate/aggregatepay/tradeQuery";
    /**
     *  é€€æ¬¾
     *  å¤–部商户平台发起的订单退款
     */
    public static String OFFLINE_REFUND_URL = PROD_URL + "/gapi/o2o/aggregatePay/services/offlineRefund";
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/constants/ServiceConstants.java
New file
@@ -0,0 +1,136 @@
package com.nuvole.constants;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
 * å¤–网服务调用
 *
 * @Author: lc
 * @Date: 2019/7/25 14:44
 */
@Component
public class ServiceConstants {
    /**
     * å¯¹å¤–是否走外网服务调用【true æ˜¯ false å¦ã€‘
     */
    public static Boolean SERVICE_TYPE;
    @Value("${service-type}")
    public void setType(Boolean type) {
        SERVICE_TYPE = type;
    }
    /**
     * è°ƒç”¨ç»Ÿä¸€url
     */
    public static final String SERVICE_URL = "http://localhost:9080";
    /**
     * å•†æˆ·è®¢å•查询接口
     */
    public static final String MERCHANT_PAY_RESULT = SERVICE_URL + "/v1/web/pay/queryorder";
    /**
     * æŸ¥è¯¢ç‰©æµåœ°å€
     */
    public static final String SERVICE_EXPRESS_URL = SERVICE_URL + "/v1/shop/web/express/queryExpress";
    /**
     * é€†åœ°å€è§£æžï¼ˆè…¾è®¯åœ°å›¾ï¼‰
     */
    public static final String SERVICE_TENCENT_LOCATION_URL = SERVICE_URL + "/v1/shop/web/map/tencent/location";
    /**
     * å°ç¨‹åºæ”¯ä»˜åœ°å€
     */
    public static final String SERVICE_UNIFIED_URL = SERVICE_URL + "/v1/web/pay/miniProgramPay";
    /**
     * B扫C支付地址
     */
    public static final String SERVICE_B_SWEEP_C_URL = SERVICE_URL + "/v1/web/pay/bSweepCPay";
    /**
     * æ ¹æ®æŽˆæƒç (付款码)获取用户ID åœ°å€
     */
    public static final String SERVICE_AUTHCODE2USERID_URL = SERVICE_URL + "/apiweb/unitorder/authcodetouserid";
    /**
     * b扫c支付结果查询地址
     */
    public static final String SERVICE_PAY_RESULT_URL = SERVICE_URL + "/v1/web/pay/bSweepCPayResult";
    /**
     * çŸ­ä¿¡åœ°å€
     */
    public static final String SERVICE_SMS_URL = SERVICE_URL + "/v1/sms/sendSMS";
    /**
     * å¾®ä¿¡jscode转SessionKey地址
     */
    public static final String SERVICE_JSCODE2SESSION_URL = SERVICE_URL + "/v1/sns/jscode2session";
    /**
     * å¾®ä¿¡èŽ·å–AccessToken
     */
    public static final String SERVICE_TOKEN_URL = SERVICE_URL + "/v1/cgi-bin/token";
    /**
     * å¾®ä¿¡èŽ·å– jsapiTicket
     */
    public static final String SERVICE_JSAPITICKET_URL = SERVICE_URL + "/v1/cgi-bin/jsapiTicket";
    /**
     * å¾®ä¿¡å…¬ä¼—号获取access_token
     */
    public static final String SERVICE_ACCESS_TOKEN_URL = SERVICE_URL + "/v1/sns/oauth2/access_token";
    /**
     * å¾®ä¿¡å…¬ä¼—号获取用户信息
     */
    public static final String SERVICE_USERINFO_URL = SERVICE_URL + "/v1/sns/userinfo";
    /**
     * å¾®ä¿¡èŽ·å–å°ç¨‹åºç ï¼ˆå‰ææ˜¯å·²å‘å¸ƒï¼‰
     */
    public static final String SERVICE_WXACODEUNLIMIT_URL = SERVICE_URL + "/v1/wxa/getwxacodeunlimit";
    /**
     * å¾®ä¿¡æŽ¨é€æ¶ˆæ¯
     */
    public static final String SERVICE_TEMPLATE_SEND_URL = SERVICE_URL + "/v1/cgi-bin/message/wxopen/template/send";
    /**
     * å¾®ä¿¡è®¢é˜…消息-推送
     */
    public static final String SERVICE_SUBSCRIBER_SEND_URL = SERVICE_URL + "/v1/cgi-bin/message/wxopen/subscribe/send";
    /**
     * åˆ—表导出
     */
    public static final String SERVICE_EXPORT_TABLE_URL = SERVICE_URL + "/v1/export/table";
    /**
     * æžå…‰æŽ¨é€
     */
    public static final String SERVICE_JG_PUSH_URL = SERVICE_URL + "/v1/jg/push";
    /**
     * ç™¾åº¦è¯­éŸ³
     */
    public static final String SERVICE_BAI_DU_API = SERVICE_URL + "/v1/merchant/app/baidu/api/speech";
    /**
     * ä¸ªæŽ¨ï¼ˆå•推)
     */
    public static final String SERVICE_GE_TUI_URL = SERVICE_URL + "/v1/gt/push";
    /**
     * ä¸ªæŽ¨ï¼ˆæŽ¨é€ä¸€ä¸ªåˆ—表)
     */
    public static final String SERVICE_GE_TUI_LIST_URL = SERVICE_URL + "/v1/gt/pushList";
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/constants/SystemConstants.java
New file
@@ -0,0 +1,206 @@
package com.nuvole.constants;
/**
 * @author ChenLong
 * @version 1.0
 * @ClassName SystemConstants
 * @date 2019/4/24 17:07
 * @Description ç³»ç»Ÿå…¬ç”¨å¸¸é‡
 */
public class SystemConstants {
    /**
     * ç»¼åˆåŽå°ç”¨æˆ·é»˜è®¤å¯†ç 
     */
    public static final String USER_KEY = "Adu_8097";
    /**
     * å•†æˆ·åŽå°ç”¨æˆ·é»˜è®¤å¯†ç 
     */
    public static final String MERCHANT_USER_K = "Sel_8099";
    /**
     * ç§¯åˆ†æŠµæ‰£é»˜è®¤å€¼ï¼ˆåˆ†ï¼‰
     */
    public static final Long INTEGRAL_DEDUCTION_VAL = 100L;
    /**
     * ç§¯åˆ†æŠµæ‰£ä»·å€¼key
     */
    public static final String INTEGRAL_DEDUCATION = "deducation";
    /********************************************** ç™»å½•标识 ************************************/
    /**
     * ç»Ÿä¸€åŽå°pc角色api
     */
    public static final String BASE_PC_ROLE_API_PREFIX = "basePcRoleApi:";
    /**
     * ç»Ÿä¸€åŽå°pc角色 rest api
     */
    public static final String BASE_PC_ROLE_RESTAPI_PREFIX = "basePcRoleRestApi:";
    /**
     * å•†æˆ·pc角色api
     */
    public static final String MERCHANT_PC_ROLE_API_PREFIX = "merchantPcRoleApi:";
    /**
     * å•†æˆ·pc角色 rest api
     */
    public static final String MERCHANT_PC_ROLE_RESTAPI_PREFIX = "merchantPcRoleRestApi:";
    /**
     * ç»Ÿä¸€åŽå°pc登录标识
     */
    public static final String BASE_PC_USER_PREFIX = "basePcUser:";
    /**
     * å•†æˆ·pc登录标识
     */
    public static final String MERCHANT_PC_USER_PREFIX = "merchantPcUser:";
    public static final String SUPPLIER_PC_USER_PREFIX = "supplierPcUser:";
    /**
     * å•†æˆ·app登录标识
     */
    public static final String MERCHANT_APP_USER_PREFIX = "merchantAppUser:";
    /**
     * å•†åŸŽå¾®ä¿¡ç™»å½•标识(包含商户H5)
     */
    public static final String SHOP_WECHAT_USER_PREFIX = "shopWechatUser:";
    /**
     * å®¢æˆ·ç»ç†app登录标识
     */
    public static final String MANAGER_APP_USER_PREFIX = "managerAppUser:";
    /**
     * æ‰«ç ä»˜æŽˆæƒç™»å½•标识
     */
    public static final String SCAN_WECHAT_USER_PREFIX = "scanWechatUser:";
    /********************************************** token header标识 ************************************/
    /**
     * ç»¼åˆpc token header æ ‡è¯†
     */
    public static final String BASE_PC_TOKEN_HEADER = "BASE-PC-TOKEN-HEADER";
    /**
     * å•†æˆ·pc token header æ ‡è¯†
     */
    public static final String MERCHANT_PC_TOKEN_HEADER = "MERCHANT-PC-TOKEN-HEADER";
    /**
     * ä¾›è´§å•†
     */
    public static final String SUPPLIER_PC_TOKEN_HEADER = "SUPPLIER-PC-TOKEN-HEADER";
    /**
     * å•†æˆ·app token header æ ‡è¯†
     */
    public static final String MERCHANT_APP_TOKEN_HEADER = "MERCHANT-APP-TOKEN-HEADER";
    /**
     * å•†åŸŽå¾®ä¿¡ token header æ ‡è¯†ï¼ˆåŒ…含商户H5)
     */
    public static final String SHOP_WECHAT_TOKEN_HEADER = "SHOP-WECHAT-TOKEN-HEADER";
    /**
     * å®¢æˆ·ç»ç†app token header æ ‡è¯†
     */
    public static final String MANAGER_APP_TOKEN_HEADER = "MANAGER-APP-TOKEN-HEADER";
    /**
     * å•†æˆ·æ‰«ç ä»˜å¾®ä¿¡ token header æ ‡è¯†ï¼ˆåŒ…含商户H5)
     */
    public static final String SCAN_WECHAT_TOKEN_HEADER = "SCAN-WECHAT-TOKEN-HEADER";
    /********************************************** å¯¼å‡ºæ ‡è¯† ************************************/
    /*
     * @Author : liu.q [916000612@qq.com]
     * @Date : 2019-07-18 15:11
     * @Description : å¯¼å‡ºåŠ å¯†ç­¾å-标识
     */
    public static final String EXPORT_SIGN_K = "bc29ru982ur8923jr923hr9y2389";
    /*
     * @Author : liu.q [916000612@qq.com]
     * @Date : 2019-07-18 15:11
     * @Description : å¯¼å‡ºæ•°æ®ç¼“å­˜key å¼€å¤´
     */
    public static final String EXPORT_DATA_K = "exportDataK:";
    /********************************************** é‚®æ‹¼å›¢æ ‡è¯† ************************************/
    /**
     * å›¢è´­æ”¯ä»˜è¶…æ—¶æ—¶é—´key
     */
    public static final String GROUP_PAY_TIMEOUT = "groupPayTimeout";
    /**
     * å›¢è´­æˆå›¢è¶…æ—¶æ—¶é—´key
     */
    public static final String GROUP_COMPLETE_TIMEOUT = "groupCompleteTimeout";
    /**
     * å›¢è´­è§„æ ¼key
     */
    public static final String GROUP_RULE = "groupRule";
    /**********************************************  å•†åŸŽè®¾ç½®æ ‡è¯† ************************************/
    /**
     * å•†å“æ”¯ä»˜æ—¶é—´è®¾ç½®key
     */
    public static final String PAY_TIMEOUT = "pay_timeout";
    /**
     * æ”¶è´§æ—¶é—´è®¾ç½®key
     */
    public static final String RECEIVING_TIMEOUT = "receiving_timeout";
    /**
     * æ—¥å¿—定时清理设置
     */
    public static final String LOG_CLEAN_TIME = "logCleanTime";
    /**
     * å®¢æˆ·èŠ‚è§„åˆ™è®¾ç½®key
     */
    public static final String MEMBER_DAY_RULE = "member_day_rule";
    /**
     * å•次提现金额不低于
     */
    public static final String DRAW_CASH_EACH_MIN_RULE = "draw_cash_each_min";
    /**
     * æ¯å¤©æçŽ°é‡‘é¢ä¸è¶…è¿‡
     */
    public static final String DRAW_CASH_DAY_MAX_RULE = "draw_cash_day_max";
    /**
     * ä¼šå‘˜æ—¥æ´»åŠ¨è§„åˆ™
     */
    public static final String MEMBER_FLASH_ACT_RULE = "member_flash_act_rule";
    /**
     * ä¼šå‘˜æ—¥æ´»åŠ¨å‚ä¸Žå¯¹è±¡
     */
    public static final String MEMBER_FLASH_ACT_JOIN_OBJ = "MEMBER_FLASH_ACT_JOIN_OBJ";
    /**
     * æ˜Ÿçº§æƒç›Šæ´»åŠ¨è§„åˆ™
     */
    public static final String STAR_POWER_ACT_RULE = "star_power_act_rule";
    public static final String STAR_POWER_ACT_JOIN_OBJ = "star_power_act_join_obj";
    /*
    åº”用平台类型(三方平台绑定用户使用)
    appType 1.支付宝-小程序, 2.支付宝-生活号, 3.微信-小程序, 4.微信-公众号
     */
    /** åº”用平台类型-支付宝-小程序 */
    public static final String APP_TYPE_ALI_MINI = "1";
    /** åº”用平台类型-支付宝-生活号 */
    public static final String APP_TYPE_ALI_SHH = "2";
    /** åº”用平台类型-微信-小程序 */
    public static final String APP_TYPE_WECHAT_MINI = "3";
    /** åº”用平台类型-微信-公众号 */
    public static final String APP_TYPE_WECHAT_GZH = "4";
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/conf/NxPayConfig.java
New file
@@ -0,0 +1,199 @@
package com.nuvole.hnnx.conf;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.format.FastDateFormat;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.Method;
import com.nuvole.hnnx.hnnxPay.HnnxConstant;
import com.nuvole.hnnx.hnnxPay.KeyMetadata;
import com.nuvole.hnnx.hnnxPay.KeyRegistry;
import com.nuvole.hnnx.hnnxPay.KeyRegistryImpl;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.security.Key;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
 * @ClassName NxPayConfig
 * @Author cy
 * @Date 2023/10/5
 * @Description
 * @Version 1.0
 **/
//@ConditionalOnProperty(name = "offLinePay.hnnx", havingValue = "true")
@Data
@PropertySource("classpath:hnnx.properties")
@ConfigurationProperties(prefix = "hnnx")
@Component
public class NxPayConfig {
    private String merNbr;
    private String url;
    private String appCode;
    private String certPath;
    private String certPwd;
    private String pubKey;
    private String platSubMerchantId;
    private String branchId;
    public static final String KEYSTORE_TYPE = "PKCS12"; // ç§é’¥ç±»åž‹
//    private static String keyPath = "C:\\Users\\cy\\Desktop\\merchant-rsa.pfx"; // ç§é’¥å®¹å™¨è·¯å¾„
//    private static String cardPwdAlias = "HNNX"; // ç§é’¥è¯ä¹¦åˆ«å
    /**
     * å¿«æ·æ”¯ä»˜å…¬é’¥
     */
    private String kjUrl;
    private String kjMerNbr;
    @Bean(name = "nxPayPrivateKey")
    public PrivateKey payPrivateKey() {
        KeyRegistry keyRegistry = new KeyRegistryImpl();
        KeyMetadata keyMetadata = new KeyMetadata("nxPay", certPath, certPwd, null, certPwd);
        System.out.println(keyMetadata);
        Key privatekey = keyRegistry.getKey(keyMetadata);
        System.out.println(privatekey);
        return (PrivateKey) privatekey;
    }
    @Bean(name = "nxPayPublicKey")
    public PublicKey payPublicKey() {
        BufferedInputStream bis = new BufferedInputStream(new ByteArrayInputStream(("-----BEGIN CERTIFICATE-----\n" + pubKey + "\n-----END CERTIFICATE-----\n").getBytes()));
        Certificate certificate = null;
        CertificateFactory cf = null;
        try {
            cf = CertificateFactory.getInstance("X.509");
            certificate = cf.generateCertificate(bis);
            return certificate.getPublicKey();
        } catch (CertificateException e) {
            e.printStackTrace();
        }
        return null;
    }
    private String kjPubKey;
    private String kjCertPath;
    private String kjCertPwd;
    private String kjPlatSubMerchantId;
//    public static void main(String[] args) throws Exception {
//        InputStream key = new FileInputStream(keyPath);
//        KeyStore ks = KeyStore.getInstance(KEYSTORE_TYPE);
//        ks.load(key, cardPwdAlias.toCharArray());
//        Enumeration<String> keyAlias = ks.aliases();
//        PrivateKey privateKey = null;
//        while (keyAlias.hasMoreElements()) {
//            String nextElement = keyAlias.nextElement();
//            boolean keyEntryFlag = ks.isKeyEntry(nextElement);
//            if (keyEntryFlag) {
//                privateKey = (PrivateKey) ks.getKey(nextElement, cardPwdAlias.toCharArray());
//                break;
//            }
//        }
//
//
//    }
    @Bean(name = "nxKjPayPrivateKey")
    public PrivateKey nxKjPayPrivateKey() throws Exception {
        KeyRegistry keyRegistry = new KeyRegistryImpl();
        KeyMetadata keyMetadata = new KeyMetadata("nxKjPay", kjCertPath,  kjCertPwd, null,  kjCertPwd);
        Key privatekey = keyRegistry.getKey(keyMetadata);
        return (PrivateKey) privatekey;
//        InputStream key = new FileInputStream(keyPath);
//        KeyStore ks = KeyStore.getInstance(KEYSTORE_TYPE);
//        ks.load(key, cardPwdAlias.toCharArray());
//        Enumeration<String> keyAlias = ks.aliases();
//        PrivateKey privateKey = null;
//        while (keyAlias.hasMoreElements()) {
//            String nextElement = keyAlias.nextElement();
//            boolean keyEntryFlag = ks.isKeyEntry(nextElement);
//            if (keyEntryFlag) {
//                privateKey = (PrivateKey) ks.getKey(nextElement, cardPwdAlias.toCharArray());
//                break;
//            }
//        }
//        return privateKey;
    }
    @Bean(name = "nxKjPayPublicKey")
    public PublicKey nxKjPayPublicKey() {
        BufferedInputStream bis = new BufferedInputStream(new ByteArrayInputStream(("-----BEGIN CERTIFICATE-----\n" + kjPubKey + "\n-----END CERTIFICATE-----\n").getBytes()));
        Certificate certificate = null;
        CertificateFactory cf = null;
        try {
            cf = CertificateFactory.getInstance("X.509");
            certificate = cf.generateCertificate(bis);
            return certificate.getPublicKey();
        } catch (CertificateException e) {
            e.printStackTrace();
        }
        return null;
    }
    //    @Bean(name = "nxPayHttpClient")
    public HttpRequest getPayCloseableHttpClient() {
        HttpRequest postRequest = new HttpRequest(url).method(Method.POST);
        String charset = CharsetUtil.CHARSET_UTF_8.toString();
        postRequest.header("appCode", appCode);
        postRequest.header("version", "1.0");
        postRequest.header("charset", charset);
        postRequest.header("algorithm", HnnxConstant.ALGORITHM);
        postRequest.header("deviceId", HnnxConstant.DEVICEID);
        postRequest.header("channelId", HnnxConstant.CHANNELID);
        postRequest.header("sequenceId", getSequenceId());
        return postRequest;
    }
    /**
     * è¯·æ±‚序列号【渠道端产生,一笔业务的唯一标识,贯穿整个交易始终】渠道代码(2位)+日期(yyMMdd 6位)+流水号(24位,appCode+剩余位数流水号)
     *
     * @return
     */
    private String getSequenceId() {
        StringBuilder sequenceIdSb = new StringBuilder();
        sequenceIdSb.append(HnnxConstant.CHANNELID)
                .append(DateUtil.format(new Date(), FastDateFormat.getInstance("yyMMdd")))
                .append(appCode);
        int length = 32 - sequenceIdSb.length();
        String timeTemp = System.currentTimeMillis() + "";
        while (length > 0) {
            if (length > timeTemp.length()) {
                sequenceIdSb.append(timeTemp);
            } else {
                sequenceIdSb.append(timeTemp.substring(0, length));
            }
            length = 32 - sequenceIdSb.length();
        }
        return sequenceIdSb.toString();
    }
    public Map getHeadMap(String sequenceId, String timestamp, String branchId) {
        Map headMap = new HashMap<>();
        String charset = CharsetUtil.CHARSET_UTF_8.toString();
        headMap.put("appCode", appCode);
        headMap.put("version", "1.0");
        headMap.put("charset", charset);
        headMap.put("algorithm", HnnxConstant.ALGORITHM);
        headMap.put("deviceId", HnnxConstant.DEVICEID);
        headMap.put("channelId", HnnxConstant.CHANNELID);
        headMap.put("sequenceId", sequenceId);
        headMap.put("timestamp", timestamp);
//        headMap.put("transCode", transCode);
        headMap.put("branchId", branchId);
        return headMap;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/hnnxPay/HnnxConstant.java
New file
@@ -0,0 +1,85 @@
package com.nuvole.hnnx.hnnxPay;
/**
 * @ClassName HnnxConstant
 * @Author cy
 * @Date 2023/10/5
 * @Description
 * @Version 1.0
 **/
public class HnnxConstant {
    /**
     * å†œä¿¡åªèƒ½è®¾ç½®ä¸€ä¸ªå›žè°ƒ
     */
    public static String ALL_CALL_BACK = "/v1/web/payBack/nx/allBack";
    /**
     * ç”¨æˆ·è¢«æ‰«æ”¯ä»˜
     */
    public static String TRANS_CODE_CORETOALL_PAY = "hnnx.trade.sandbox.upp.coretoall";
    /**
     * é€šç”¨é€€è´§
     */
    public static String TRANS_CODE_RETURNTRANS_PAY = "hnnx.trade.sandbox.upp.returntrans";
    /**
     * é¢„支付
     */
    public static String TRANS_CODE_QRCODEPREPAY_PAY = "hnnx.trade.sandbox.upp.qrCodePrePay";
    /**
     * ç”¨æˆ·ä¸»åŠ¨æ‰«ç ç”Ÿæˆ
     */
    public static String TRANS_CODE_DYACTIVEQRCODE_PAY = "hnnx.trade.sandbox.upp.dyActiveQrCode";
    /**
     * è®¢å•交易状态查询
     */
    public static String TRANS_CODE_QRYQRORDERSTATUS_PAY = "hnnx.trade.sandbox.upp.qryQrOrderStatus";
    /**
     * å¯¹è´¦æŸ¥è¯¢
     */
    public static String TRANS_CODE_ACCOUNTQRY_PAY = "hnnx.trade.sandbox.upp.accountqry";
    /**
     * å¸ç§
     */
    public static String CURRENCYCD = "CNY";
    /**
     * åŠ å¯†ç®—æ³•
     */
    public static String ALGORITHM = "SHA256withRSA";
    /**
     * å†œä¿¡å¿«æ·åªèƒ½è®¾ç½®ä¸€ä¸ªå›žè°ƒ
     */
    public static String NX_KJ_ALL_CALL_BACK = "/v1/web/payBack/nxKj/allBack";
    /**
     * å†œä¿¡å¿«æ·æ”¯ä»˜å‰ç«¯å›žè°ƒURL
     */
    public static String NX_KJ_FRONT_URL ="https://jmy.jinmingyuan.com/payTest/pages/pay/paySuccess?orderId=${ORDERID}&youHuiInfo=${YOUHUIINFO}";
    /**
     * å†œä¿¡å¿«æ·æ”¯ä»˜åŠ å¯†ç®—æ³•
     */
    public static String KJ_ALGORITHM = "SHA1WithRSA";
    //交易渠道号:45
    public static String CHANNELID = "45";
    //送个定值即可
    public static String DEVICEID = "JMY";
    //地区信息
    public static String AREAINFO = "1564960";
    /**
     * å†œä¿¡å¿«æ·æ”¯ä»˜url
     */
    public static String QUICK_PAY_URL = "/pmPay/quickPayRequest.do";
    /**
     * è®¢å•查询
     */
    public static String QUICK_PAY_QUERY_URL = "/common/orderQuery.do";
    /**
     * é€€æ¬¾
     */
    public static String QUICK_PAY_RETURN_URL = "/common/returnTrans.do";
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/hnnxPay/KeyMetadata.java
New file
@@ -0,0 +1,52 @@
package com.nuvole.hnnx.hnnxPay;
/**
 * @author awlwen
 * @since 2017/11/30
 */
public class KeyMetadata {
    private String id;
    private String file;
    private String keyStorePassword;
    private String keyAlias;
    private String keyPassword;
    public KeyMetadata() {
    }
    public KeyMetadata(String id, String file, String keyStorePassword, String keyAlias, String keyPassword) {
        this.id = id;
        this.file = file;
        this.keyStorePassword = keyStorePassword;
        this.keyAlias = keyAlias;
        this.keyPassword = keyPassword;
    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getFile() {
        return file;
    }
    public void setFile(String file) {
        this.file = file;
    }
    public String getKeyStorePassword() {
        return keyStorePassword;
    }
    public void setKeyStorePassword(String keyStorePassword) {
        this.keyStorePassword = keyStorePassword;
    }
    public String getKeyAlias() {
        return keyAlias;
    }
    public void setKeyAlias(String keyAlias) {
        this.keyAlias = keyAlias;
    }
    public String getKeyPassword() {
        return keyPassword;
    }
    public void setKeyPassword(String keyPassword) {
        this.keyPassword = keyPassword;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/hnnxPay/KeyProvider.java
New file
@@ -0,0 +1,14 @@
package com.nuvole.hnnx.hnnxPay;
import java.security.Key;
import java.security.cert.Certificate;
/**
 * @author awlwen
 * @since 2017/11/30
 */
public interface KeyProvider {
    Key getKey(String id, String password);
    Certificate getCertificate(String id);
    Certificate[] getCertificateChain(String id);
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/hnnxPay/KeyProviderImpl.java
New file
@@ -0,0 +1,173 @@
package com.nuvole.hnnx.hnnxPay;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.Assert;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.Key;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
/**
 * @author awlwen
 * @since 2017/11/30
 */
public class KeyProviderImpl implements KeyProvider {
    private static final Map<String, String> SUPPORTED_KEY_TYPE = new HashMap<String, String>();
    static {
        SUPPORTED_KEY_TYPE.put("ks", "jks");
        SUPPORTED_KEY_TYPE.put("jks", "jks");
        SUPPORTED_KEY_TYPE.put("pfx", "pkcs12");
        SUPPORTED_KEY_TYPE.put("p12", "pkcs12");
    }
    /**
     * å¯†é’¥å®¹å™¨æ–‡ä»¶è·¯å¾„
     */
    private String file;
    /**
     * å¯†é’¥å®¹å™¨å¯†ç 
     */
    private String password;
    /**
     * å¯†é’¥å®¹å™¨
     */
    private KeyStore keystore;
    /**
     * åˆå§‹åŒ–标志
     */
    private boolean initialized = false;
    /**
     * æž„造器
     *
     * @param file     å¯†é’¥å®¹å™¨æ–‡ä»¶è·¯å¾„
     * @param password å¯†é’¥å®¹å™¨å¯†ç 
     */
    public KeyProviderImpl(String file, String password) {
        super();
        Assert.notNull(file, "file is required; it must not be null");
        init(file, password);
    }
    /**
     * æ ¹æ®æ–‡ä»¶æ‰©å±•名获取密钥容器类型
     *
     * @param file
     * @return
     */
    private String resolveType(String file) {
        Assert.notNull(file, "file is required; it must not be null");
        String suffix = file.substring(file.lastIndexOf(".") + 1);
        Assert.notNull(suffix, "suffix could not be resolved");
        String supportedType = SUPPORTED_KEY_TYPE.get(suffix.toLowerCase());
        Assert.notNull(supportedType, "unsupported key type");
        return supportedType;
    }
    /**
     * åˆå§‹åŒ–,加载密钥容器
     *
     * @param file     å¯†é’¥å®¹å™¨æ–‡ä»¶è·¯å¾„
     * @param password å¯†é’¥å®¹å™¨å¯†ç 
     */
    private void init(String file, String password) {
        InputStream is = null;
        try {
            //建立文件输入流读取密钥容器
            if (file.startsWith("classpath:")) {
                is = new ClassPathResource(file.replace("classpath:", "")).getInputStream();
            } else {
                is = new BufferedInputStream(new FileInputStream(file));
            }
            //根据文件扩展名建立相应的密钥容器类型
            keystore = KeyStore.getInstance(resolveType(file));
            //将密钥容器密码转换为char数组
            char[] pwd = password == null ? null : password.toCharArray();
            //从指定的输入流中加载密钥容器
            keystore.load(is, pwd);
            initialized = true;
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException ex) {
                    throw new RuntimeException(ex);
                }
            }
        }
    }
    /* (non-Javadoc)
     * @see com.csii.sg.security.KeyProvider#getKey(java.lang.String, java.lang.String)
     */
    public Key getKey(String id, String password) {
        Assert.isTrue(initialized, "keyProvider not been initialized");
        try {
            if (id == null) {
                Enumeration<String> aliases = keystore.aliases();
                for (int count = 0; aliases.hasMoreElements(); count++) {
                    if (count > 1) {
                        throw new IllegalArgumentException("key id not specified");
                    }
                    String alias = aliases.nextElement();
                    if (keystore.isKeyEntry(alias)) {
                        id = alias;
                    }
                }
            }
            char[] pwd = password == null ? null : password.toCharArray();
            return keystore.getKey(id, pwd);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
    /* (non-Javadoc)
     * @see com.csii.sg.security.KeyProvider#getCertificate(java.lang.String)
     */
    public Certificate getCertificate(String id) {
        Assert.isTrue(initialized, "keyProvider not been initialized");
        try {
            return keystore.getCertificate(id);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
    /* (non-Javadoc)
     * @see com.csii.sg.security.KeyProvider#getCertificateChain(java.lang.String)
     */
    public Certificate[] getCertificateChain(String id) {
        Assert.isTrue(initialized, "keyProvider not been initialized");
        try {
            return keystore.getCertificateChain(id);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
    /**
     * @param file the file to set
     */
    public void setFile(String file) {
        this.file = file;
    }
    /**
     * @param password the password to set
     */
    public void setPassword(String password) {
        this.password = password;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/hnnxPay/KeyRegistry.java
New file
@@ -0,0 +1,13 @@
package com.nuvole.hnnx.hnnxPay;
import java.security.Key;
import java.security.cert.Certificate;
/**
 * @author awlwen
 * @since 2017/11/30
 */
public interface KeyRegistry {
    Key getKey(KeyMetadata metadata);
    Certificate getCertificate(String base64);
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/hnnxPay/KeyRegistryImpl.java
New file
@@ -0,0 +1,62 @@
package com.nuvole.hnnx.hnnxPay;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.Key;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
 * @author awlwen
 * @since 2017/11/30
 */
public class KeyRegistryImpl implements KeyRegistry {
    private Map<String, Key> cache = new ConcurrentHashMap<>();
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    private volatile boolean sync = false;
    @Override
    public Key getKey(KeyMetadata metadata) {
        Assert.notNull(metadata, "[Assertion failed] - metadata is required; it must not be null");
        Key key = cache.get(metadata.getId());
        if (key == null || sync) {
            key = getKeyInternal(metadata);
            cache.put(metadata.getId(), key);
        }
        return key;
    }
    @Override
    public Certificate getCertificate(String base64) {
        Assert.hasText(base64, "[Assertion failed] - base64 must have text; it must not be null, empty, or blank");
        BufferedInputStream is = null;
        try {
            is = new BufferedInputStream(new ByteArrayInputStream(base64.trim().getBytes()));
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            Certificate cert = cf.generateCertificate(is);
            return cert;
        } catch (CertificateException ex) {
            throw new RuntimeException(ex);
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException ex) {
                    logger.error("close stream error.", ex);
                }
            }
        }
    }
    private Key getKeyInternal(KeyMetadata metadata) {
        KeyProvider provider = new KeyProviderImpl(metadata.getFile(), metadata.getKeyStorePassword());
        Key key = provider.getKey(metadata.getKeyAlias(), metadata.getKeyPassword());
        Assert.notNull(key, "[Assertion failed] - key must not be null");
        return key;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/hnnxPay/NXHttpClientUtils.java
New file
@@ -0,0 +1,778 @@
package com.nuvole.hnnx.hnnxPay;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.csii.sg.codec.Hex;
import com.csii.sg.security.ValidationException;
import com.csii.sg.security.impl.Permutation;
import com.csii.sg.security.impl.SignatureVerifier;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.nuvole.hnnx.conf.NxPayConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
 * @ClassName HttpClientUtils
 * @Author cy
 * @Date 2023/9/27
 * @Description
 * @Version 1.0
 **/
@Component
@Slf4j
//@ConditionalOnClass(name = "com.nuvole.hnnx.conf.NxPayConfig")
public class NXHttpClientUtils {
    @Autowired
    private PrivateKey nxPayPrivateKey;
    @Autowired
    private PrivateKey nxKjPayPrivateKey;
    @Autowired
    private PublicKey nxPayPublicKey;
    @Autowired
    private PublicKey nxKjPayPublicKey;
    @Autowired
    private NxPayConfig nxPayConfig;
    private static SignatureSigner signable = new SignatureSigner();
    private static SignatureVerifier verifier = new SignatureVerifier();
    public String getPlatSubMerchantId() {
        return nxPayConfig.getPlatSubMerchantId();
    }
    public String getKjPlatSubMerchantId() {
        return nxPayConfig.getKjPlatSubMerchantId();
    }
    public String getBranchId() {
        return nxPayConfig.getBranchId();
    }
    /**
     * åˆ†è½¬ä¸ºå…ƒ
     *
     * @param payMoney
     * @return
     */
    public static BigDecimal convertToYuan(long payMoney) {
        BigDecimal totalAmount = new BigDecimal("" + payMoney).divide(new BigDecimal("100"));
        return totalAmount;
    }
    public static void writeToFile(String sign, String plainStr) {
        File file = new File("D:\\dev_nginx-1.18.0\\html\\testNetPay4.html");
        String content = "<!DOCTYPE html>\n" +
                "<html lang=\"en\">\n" +
                "<head>\n" +
                "    <meta charset=\"UTF-8\">\n" +
                "    <title>Title</title>\n" +
                "\n" +
                "</head>\n" +
                "<body>\n" +
                "\n" +
                "</body>\n" +
                "<script>\n" +
//                "    var url = \"http://221.176.112.3:8006/pmPay/pmPay/quickPayRequest.do\";\n" +
                "    var url = \"http://https://pay.hnnx.com/pmPay/pmPay/quickPayRequest.do\";\n" +
                "    var data ={\n" +
                "        \"deviceType\":\"5\",\n" +
                "        \"signature\": \"" + sign + "\",\n" +
                "        \"plain\": JSON.stringify(" + plainStr + ")\n" +
                "    }\n" +
                "    post(url, data);\n" +
                "    var myForm;\n" +
                "\n" +
                "    function post(URL, pram) {\n" +
                "        var temp = document.createElement(\"form\");\n" +
                "        temp.action = URL;\n" +
                "        temp.method = \"post\";\n" +
                "        temp.style.display = \"none\";\n" +
                "        for (var x in pram) {\n" +
                "            var opt = document.createElement(\"textarea\");\n" +
                "            opt.name = x;\n" +
                "            opt.value = pram[x];\n" +
                "            // alert(opt.name)\n" +
                "            temp.appendChild(opt);\n" +
                "        }\n" +
                "        document.body.appendChild(temp);\n" +
                "        temp.submit();\n" +
                "//        myForm=temp;\n" +
                "    }\n" +
                "</script>\n" +
                "</html>\n";
        try (FileWriter writer = new FileWriter(file)) {
            writer.write(content);
            System.out.println("内容成功写入文件。");
        } catch (IOException e) {
            System.err.println("写入文件时发生错误:" + e.getMessage());
        }
    }
    public static void writeToFile(String url) {
        File file = new File("D:\\dev_nginx-1.18.0\\html\\redirect1.html");
        String content = "<!DOCTYPE html>\n" +
                "<html>\n" +
                "<head>\n" +
                "    <meta http-equiv=\"refresh\" content=\"0; URL='" + url +
                "'\" />\n" +
                "</head>\n" +
                "<body>\n" +
                "    <h1>正在跳转,请稍等...</h1>\n" +
                "</body>\n" +
                "</html>\n";
        try (FileWriter writer = new FileWriter(file)) {
            writer.write(content);
            System.out.println("内容成功写入文件。");
        } catch (IOException e) {
            System.err.println("写入文件时发生错误:" + e.getMessage());
        }
    }
    /**
     * åŠ ç­¾æ–¹æ³•
     *
     * @param headerMap   åŠ å¯†æŠ¥æ–‡å¤´
     * @param payloadJson åŠ å¯†æŠ¥æ–‡ä½“
     * @return
     */
    public String sign(Map headerMap, String payloadJson) {
        log.info("----------- ç­¾åå¼€å§‹ ----------- ");
        log.info("请求参数payloadJson:{}", payloadJson);
        ObjectMapper objectMapper = new ObjectMapper();
        String palin = null;
        try {
            if (payloadJson != null) {
                Map payloadMap = objectMapper.readValue(payloadJson, Map.class);
                headerMap.putAll(payloadMap);
            }
            palin = Permutation.sort(headerMap, "UTF-8");
            log.info("待签名字符串:{}", palin);
        } catch (Exception e) {
            e.printStackTrace();
        }
        String sign = signable.sign(palin, nxPayPrivateKey);
        log.info("签名结果:{}", sign);
        log.info("----------- ç­¾åç»“束 ----------- ");
        return sign;
    }
    public String kjSign(String palin) {
        log.info("----------- ç­¾åå¼€å§‹ ----------- ");
        log.info("请求参数 palin:{}", palin);
        String sign = signable.kjSign(palin, nxKjPayPrivateKey).replaceAll("\\s", "");
        log.info("签名结果:{}", sign);
        log.info("----------- ç­¾åç»“束 ----------- ");
        return sign;
    }
    // å›žè°ƒé€šçŸ¥æ ¡éªŒ
    public boolean notifyRespVerify(String notifyParam) {
        log.info("回调通知验签 body ä¸º: {}", notifyParam);
        int signIndex = notifyParam.lastIndexOf("&signature=");
        if (signIndex == -1) {
            return false;
        }
        String palin = notifyParam.substring(0, signIndex);
        String sign = notifyParam.substring(signIndex).replace("&signature=", "");
        boolean verfiy = false;
        try {
            verfiy = verifier.verify(HnnxConstant.ALGORITHM, palin.getBytes(), Hex.toByte(sign), nxPayPublicKey);
        } catch (ValidationException e) {
            e.printStackTrace();
        }
        if (verfiy) {
            log.info("返回值验签 ç»“果:{}", verfiy);
        } else {
            log.error("返回值验签 ç»“果:{}", verfiy);
        }
        log.info("----------- è¿”回值验签 ç»“束 ----------- ");
        return verfiy;
    }
    public String sendForm(HttpRequest nxPayHttpClient, HashMap<String, Object> payLoadMap) {
        log.info("transCode : {}", nxPayHttpClient.header("transCode"));
        Map headerMap = nxPayConfig.getHeadMap(nxPayHttpClient.header("sequenceId"), nxPayHttpClient.header("timestamp"), nxPayHttpClient.header("branchId"));
        HashMap<String, Object> formData = new HashMap<>();
        formData.put("payload", JSONObject.toJSONString(payLoadMap));
        // åŠå…·ä½“接口的请求报文构成。
        log.info("请求头: {}", JSONObject.toJSONString(headerMap));
        formData.put("signature", sign(headerMap, (String) formData.get("payload")));
        log.info("请求参数: {}", JSONObject.toJSONString(formData));
        HttpResponse httpResponse = nxPayHttpClient.form(formData).execute();
        String body = httpResponse.body();
        verify(body);
        return body;
    }
    /**
     * é¢„支付
     * å¯ä»¥å®žçŽ°ç”¨æˆ·åˆ°æ”¯ä»˜å®æˆ–å¾®ä¿¡çš„é¢„æ”¯ä»˜åŠŸèƒ½ã€‚
     *
     * @param subMerchantId äºŒçº§å•†æˆ·å·
     * @param branchId      äº¤æ˜“机构号
     * @param merSeqNbr     å•†æˆ·æ€»äº¤æ˜“流水号
     * @param transAmt      äº¤æ˜“总金额
     * @param timeStamp     å•†æˆ·äº¤æ˜“æ—¶é—´
     * @param channelNbr    æ¸ é“编号 01-O2O 02-B2C 03-扫码
     * @param payTypCd      B-支付宝扫码支付C-微信扫码支付D-银联扫码支付
     * @param orderTitle    è®¢å•标题
     */
    public String qrCodePrePay(String subMerchantId, String branchId, String operatorId, String merSeqNbr, String authCode, long transAmt, String timeStamp, String channelNbr, char payTypCd,
                               String merUrl, String orderTitle) {
        log.info("----------------- é¢„支付 å¼€å§‹ è®¢å•号为: {},订单金额为:{}----------------- ", merSeqNbr, transAmt);
        HttpRequest nxPayHttpClient = nxPayConfig.getPayCloseableHttpClient();
        //请求序列号【渠道端产生,一笔业务的唯一标识,贯穿整个交易始终】渠道代码(2位)+日期(yyMMdd 6位)+流水号(24位,appCode+剩余位数流水号)
//        String sequenceId = getSequenceId(timeStamp, nxPayConfig.getAppCode());
//        nxPayHttpClient.header("sequenceId", sequenceId);
        nxPayHttpClient.header("timestamp", timeStamp);
        nxPayHttpClient.header("transCode", HnnxConstant.TRANS_CODE_QRCODEPREPAY_PAY);
        nxPayHttpClient.header("branchId", branchId);
        // æ‹¼æŽ¥ä¸šåŠ¡æ•°æ®
        HashMap<String, Object> formData = new HashMap<>();
        // ä¸€çº§å•†æˆ·å·
        formData.put("MerNbr", nxPayConfig.getMerNbr());
        // äºŒçº§å•†æˆ·ç¼–号
        formData.put("SubMerchantId", subMerchantId);
        //商户交易时间
        formData.put("MerTransDateTime", timeStamp);
        //交易总金额
        formData.put("TransAmt", convertToYuan(transAmt));
        formData.put("AuthCode", authCode);
        //渠道编号 01-O2O 02-B2C 03-扫码
        formData.put("ChannelNbr", channelNbr);
        //支付方式 8-线上支付宝扫码支付9-线上微信扫码支付A-线上银联扫码支付B-线下支付宝扫码支付C-线下微信扫码支付D-线下银联扫码支付
        formData.put("PayTypCd", payTypCd);
        formData.put("OrderTitle", orderTitle);
        formData.put("CurrencyCd", "CNY");
        //异步通知Url
        formData.put("MerUrl", merUrl);
        //操作员
        formData.put("OperatorId", operatorId);
        //支付订单号
        formData.put("MerSeqNbr", merSeqNbr);
        String body = sendForm(nxPayHttpClient, formData);
        log.info("----------------- é¢„支付 ç»“束 ----------------- ");
        return body;
    }
    /**
     * ç”¨æˆ·ä¸»åŠ¨æ‰«ç ç”Ÿæˆ
     * ç”¨æˆ·éœ€è¦æ‰«æå•†æˆ·æ”¶æ¬¾ç åŠ¨ç è¿›è¡Œæ”¯ä»˜æ—¶ï¼Œé€šè¿‡æ­¤æŽ¥å£ç”Ÿæˆå•†æˆ·æ”¶æ¬¾ç åŠ¨ç ï¼Œç”Ÿäº§ä¸ŠçŽ°åœ¨å¾®ä¿¡ä¸»æ‰«åŠ¨ç å·²ç»åœæ­¢ä½¿ç”¨ã€‚
     *
     * @param subMerchantId äºŒçº§å•†æˆ·å·
     * @param branchId      äº¤æ˜“机构号
     * @param merSeqNbr     å•†æˆ·æ€»äº¤æ˜“流水号
     * @param transAmt      äº¤æ˜“总金额
     * @param timeStamp     å•†æˆ·äº¤æ˜“æ—¶é—´
     * @param channelNbr    æ¸ é“编号 01-O2O 02-B2C 03-扫码
     * @param payTypCd      B æ”¯ä»˜å®æ‰«ç æ”¯ä»˜ C    å¾®ä¿¡æ‰«ç æ”¯ä»˜ D    é“¶è”扫码支付
     * @param orderTitle    è®¢å•标题
     */
    public String dyActiveQrCode(String subMerchantId, String branchId, String merSeqNbr, long transAmt, String timeStamp, String channelNbr, char payTypCd,
                                 String merUrl, String orderTitle) {
        log.info("----------------- ç”¨æˆ·ä¸»åŠ¨æ‰«ç ç”Ÿæˆ å¼€å§‹ è®¢å•号为: {},订单金额为:{}----------------- ", merSeqNbr, transAmt);
        HttpRequest nxPayHttpClient = nxPayConfig.getPayCloseableHttpClient();
        //请求序列号【渠道端产生,一笔业务的唯一标识,贯穿整个交易始终】渠道代码(2位)+日期(yyMMdd 6位)+流水号(24位,appCode+剩余位数流水号)
//        String sequenceId = getSequenceId(timeStamp, nxPayConfig.getAppCode());
//        nxPayHttpClient.header("sequenceId", sequenceId);
        nxPayHttpClient.header("timestamp", timeStamp);
        nxPayHttpClient.header("transCode", HnnxConstant.TRANS_CODE_DYACTIVEQRCODE_PAY);
        nxPayHttpClient.header("branchId", branchId);
        // æ‹¼æŽ¥ä¸šåŠ¡æ•°æ®
        HashMap<String, Object> formData = new HashMap<>();
        // ä¸€çº§å•†æˆ·å·
        formData.put("MerNbr", nxPayConfig.getMerNbr());
        //商户总交易流水号
        formData.put("MerSeqNbr", merSeqNbr);
        //交易总金额
        formData.put("TransAmt", convertToYuan(transAmt));
        //商户交易时间
        formData.put("MerTransDateTime", timeStamp);
        //渠道编号 01-O2O 02-B2C 03-扫码
        formData.put("ChannelNbr", channelNbr);
        formData.put("CurrencyCd", "CNY");
        //支付方式 B æ”¯ä»˜å®æ‰«ç æ”¯ä»˜ C    å¾®ä¿¡æ‰«ç æ”¯ä»˜ D    é“¶è”扫码支付
        formData.put("PayTypCd", payTypCd);
        // äºŒçº§å•†æˆ·ç¼–号
        formData.put("SubMerchantId", subMerchantId);
        //异步通知Url
        formData.put("MerUrl", merUrl);
        formData.put("OrderTitle", orderTitle);
        String body = sendForm(nxPayHttpClient, formData);
        log.info("----------------- ç”¨æˆ·ä¸»åŠ¨æ‰«ç ç”Ÿæˆ  ç»“束 ----------------- ");
        return body;
    }
    /**
     * ç”¨æˆ·è¢«æ‰«æ”¯ä»˜
     * ç¬¬ä¸‰æ–¹å¹³å°æ‰«æç”¨æˆ·ä»˜æ¬¾ç ï¼Œé€šè¿‡æ­¤æŽ¥å£æäº¤æ”¯ä»˜
     */
    public String coretoall(String subMerchantId, String branchId, String merSeqNbr, long transAmt, String payAuthCode, String timeStamp, String channelNbr,
                            String merUrl, String orderTitle, String terminalCode) {
        log.info("----------------- ç”¨æˆ·è¢«æ‰«æ”¯ä»˜ å¼€å§‹, è®¢å•编号= {} ï¼Œè®¢å•金额为:{}----------------- ", merSeqNbr, transAmt);
        HttpRequest nxPayHttpClient = nxPayConfig.getPayCloseableHttpClient();
        nxPayHttpClient.header("timestamp", timeStamp);
        nxPayHttpClient.header("transCode", HnnxConstant.TRANS_CODE_CORETOALL_PAY);
        nxPayHttpClient.header("branchId", branchId);
        // æ‹¼æŽ¥ä¸šåŠ¡æ•°æ®
        HashMap<String, Object> formData = new HashMap<>();
        // ä¸€çº§å•†æˆ·å·
        formData.put("MerNbr", nxPayConfig.getMerNbr());
        //商户总交易流水号
        formData.put("MerSeqNbr", merSeqNbr);
        //交易总金额
        formData.put("TransAmt", convertToYuan(transAmt));
        //商户交易时间
        formData.put("MerTransDateTime", timeStamp);
        //二维码
        formData.put("QrCodeInfo", payAuthCode);
        //渠道编号 01-O2O 02-B2C 03-扫码
        formData.put("ChannelNbr", channelNbr);
        formData.put("CurrencyCd", HnnxConstant.CURRENCYCD);
        formData.put("AreaInfo", HnnxConstant.AREAINFO);
        // äºŒçº§å•†æˆ·ç¼–号
        formData.put("SubMerchantId", subMerchantId);
        //订单详情
        formData.put("OrderTitle", orderTitle);
        //异步通知Url
        formData.put("MerUrl", merUrl);
        //商户终端设备类型
        formData.put("TerminalType", "04");
        //终端编号 ç”±æŸœå‘˜åœ¨åŽç®¡æ·»åŠ ç»ˆç«¯æ—¶ç”Ÿæˆ
        formData.put("Equipid", "002000156");
        //终端序列号
        formData.put("Equipseqnbr", "000002041170132246");
        formData.put("Lgtude", "113.988007");
        formData.put("Lttude", "34.819642");
        formData.put("AppVersion", "01234567");
        String body = sendForm(nxPayHttpClient, formData);
        log.info("----------------- ç”¨æˆ·è¢«æ‰«æ”¯ä»˜  ç»“束 ----------------- ");
        return body;
    }
    /**
     * è®¢å•交易状态查询
     * ï¬æŽ¥å£è¯´æ˜Ž
     * è¯¥æŽ¥å£æä¾›æ”¯ä»˜ã€é€€æ¬¾äº¤æ˜“的交易状态查询。
     * æ ¹æ®äº¤æ˜“状态TransStatus确定交易结果;
     * å¾®ä¿¡é€€æ¬¾äº¤æ˜“状态查询,非银行卡交易一般在15秒内可查询交易成功,银行卡交易退款需在两分钟后可查询到交易成功。
     *
     * @param merSeqNbr è®¢å•流水号
     * @return
     * @throws Exception
     */
    public String qryQrOrderStatus(String merSeqNbr, String branchId) {
        log.info("----------------- è®¢å•交易状态查询 å¼€å§‹----------------- ");
        HttpRequest nxPayHttpClient = nxPayConfig.getPayCloseableHttpClient();
        String timeStamp = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN);
        //请求序列号【渠道端产生,一笔业务的唯一标识,贯穿整个交易始终】渠道代码(2位)+日期(yyMMdd 6位)+流水号(24位,appCode+剩余位数流水号)
//        String sequenceId = getSequenceId(timeStamp, nxPayConfig.getAppCode());
//        nxPayHttpClient.header("sequenceId", sequenceId);
        nxPayHttpClient.header("timestamp", timeStamp);
        nxPayHttpClient.header("transCode", HnnxConstant.TRANS_CODE_QRYQRORDERSTATUS_PAY);
        nxPayHttpClient.header("branchId", branchId);
        // æ‹¼æŽ¥ä¸šåŠ¡æ•°æ®
        HashMap<String, Object> formData = new HashMap<>();
        // ä¸€çº§å•†æˆ·å·
        formData.put("MerNbr", nxPayConfig.getMerNbr());
        //商户总交易流水号
        formData.put("MerSeqNbr", merSeqNbr);
        String body = sendForm(nxPayHttpClient, formData);
        log.info("----------------- è®¢å•交易状态查询  ç»“束 ----------------- ");
        return body;
    }
    /**
     * é€€æ¬¾
     *
     * @param subMerchantId åŽŸæ”¯ä»˜äº¤æ˜“äºŒçº§å•†æˆ·å·
     * @param branchId
     * @param merSeqNbr     è¦é€€æ¬¾çš„订单号
     * @param merSeqDate    è¦é€€æ¬¾çš„订单交易日期 ä¾‹ï¼š20190810
     * @param origTransAmt  è¦é€€æ¬¾çš„订单的交易金额
     * @param transAmt      é€€æ¬¾é‡‘额
     * @param timeStamp     å½“前日期 ä¾‹ï¼šyyyyMMddHHmmss
     * @return
     */
    public String returntrans(String subMerchantId, String branchId, String merSeqNbr, String merSeqDate, long origTransAmt,
                              long transAmt, String timeStamp) {
        log.info("----------------- é€€æ¬¾ å¼€å§‹----------------- ");
        HttpRequest nxPayHttpClient = nxPayConfig.getPayCloseableHttpClient();
        nxPayHttpClient.header("timestamp", timeStamp);
        nxPayHttpClient.header("transCode", HnnxConstant.TRANS_CODE_RETURNTRANS_PAY);
        nxPayHttpClient.header("branchId", branchId);
        // æ‹¼æŽ¥ä¸šåŠ¡æ•°æ®
        HashMap<String, Object> formData = new HashMap<>();
        // ä¸€çº§å•†æˆ·å·
        formData.put("MerNbr", nxPayConfig.getMerNbr());
        //商户总交易流水号
        formData.put("MerSeqNbr", "TK_" + merSeqNbr);
        //退货交易时间
        formData.put("MerTransDateTime", timeStamp);
        //原商户流水
        formData.put("OrigMerSeqNbr", merSeqNbr);
        //原商户日期
        formData.put("OrigMerDate", merSeqDate);
        //原支付交易金额
        formData.put("OrigTransAmt", convertToYuan(origTransAmt));
        //二级商户号
        formData.put("SubMerchantId", subMerchantId);
        //退货二级商户流水号(随机生成,不允许出现重复,可以和一级商户交易流水号保持一致)
        formData.put("SubMerSeqNo", "TK_" + merSeqNbr);
        //二级商户时间
        formData.put("SubMerDateTime", timeStamp);
        //二级商户退货交易退货金额
        formData.put("SubTransAmt", convertToYuan(transAmt));
        //原二级商户支付流水号(与原支付交易一级商户号流水号一致)
        formData.put("OrigSubMerSeqNo", merSeqNbr);
        //原二级商户支付交易日期(例:20190810)
        formData.put("OrigSubMerDate", merSeqDate);
        //订单号 ä¸ŽäºŒçº§å•†æˆ·æµæ°´å·ä¿æŒä¸€è‡´
        formData.put("OrderNbr", merSeqNbr);
        String body = sendForm(nxPayHttpClient, formData);
        log.info("----------------- é€€æ¬¾ ç»“束----------------- ");
        return body;
    }
    /**
     * å¯¹è´¦æŸ¥è¯¢
     * String subMerchantId, String branchId,
     *
     * @param clearDate å¯¹è´¦æ—¥æœŸ    YYYY-MM-DD
     * @param branchId  äº¤æ˜“机构号
     * @return
     */
    public String accountqry(String clearDate, String branchId) {
        log.info("----------------- å¯¹å¸ å¼€å§‹----------------- ");
        HttpRequest nxPayHttpClient = nxPayConfig.getPayCloseableHttpClient();
        nxPayHttpClient.header("timestamp", DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN));
        nxPayHttpClient.header("transCode", HnnxConstant.TRANS_CODE_ACCOUNTQRY_PAY);
        nxPayHttpClient.header("branchId", branchId);
        // æ‹¼æŽ¥ä¸šåŠ¡æ•°æ®
        HashMap<String, Object> formData = new HashMap<>();
        formData.put("ClearDate", clearDate);
        String body = sendForm(nxPayHttpClient, formData);
        log.info("----------------- å¯¹å¸ ç»“束----------------- ");
        return body;
    }
    // è®¢å•号生成规则 â€œæ¸ é“简称-订单号-主/优惠-发起支付次数”构成
    // ä¾‹å¦‚商圈的主订单第一次发起支付,订单号就是“SQ-商圈订单id-Z-1”
    // å¦‚果这个订单关联有优惠金,优惠金订单号就是"SQ-商圈订单id-Y-1"
    public static String getNxPayOrderId(String prefix, long orderId, char orderType, short tryNum) {
        return new StringBuilder(prefix).append("-").append(orderId).append("-").append(orderType).append("-").append(tryNum).toString();
    }
    /**
     * éªŒç­¾
     *
     * @return
     */
    public boolean verify(String body) {
        log.info("返回值验签 body ä¸º: {}", body);
        log.info("----------- è¿”回值验签 å¼€å§‹ ----------- ");
        boolean verfiy = false;
        try {
            Map<String, Object> bodyMap = JSON.parseObject(body, Feature.OrderedField);
            String sign = (String) bodyMap.remove("signature");
            String payload = (String) bodyMap.remove("payload");
            ObjectMapper objectMapper = new ObjectMapper();
            if (payload != null) {
                Map payloadMap = objectMapper.readValue(payload, Map.class);
                bodyMap.putAll(payloadMap);
            }
            String palin = null;
            palin = Permutation.sort(bodyMap, "UTF-8");
            log.info("排序后的字符串:{}", palin);
            if (StringUtils.isNotEmpty(sign)) {
                verfiy = verifier.verify(HnnxConstant.ALGORITHM, palin.getBytes(), Hex.toByte(sign), nxPayPublicKey);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.error("返回值验签 ç»“果:{}", verfiy);
        log.info("----------- è¿”回值验签 ç»“束 ----------- ");
        return verfiy;
    }
    public boolean kjVerify(String sign, String palin) {
        log.info("返回值验签 palin ä¸º: {}", palin);
        log.info("返回值验签 sign ä¸º: {}", sign);
        log.info("----------- è¿”回值验签 å¼€å§‹ ----------- ");
        boolean verfiy = false;
        try {
            if (StringUtils.isNotEmpty(sign)) {
                verfiy = verifier.verify(HnnxConstant.KJ_ALGORITHM, palin.getBytes(), Base64.getDecoder().decode(sign), nxKjPayPublicKey);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.error("返回值验签 ç»“果:{}", verfiy);
        log.info("----------- è¿”回值验签 ç»“束 ----------- ");
        return verfiy;
    }
    /**
     * é€šç”¨å¿«æ·æ”¯ä»˜
     *
     * @param merSeqNbr     å•†æˆ·æµæ°´å·
     * @param subMerchantId äºŒçº§å•†æˆ·å·
     * @param backURL       åŽå°é€šçŸ¥URL
     * @param frontURL      è¿”回前端URL
     */
    public String quickPayRequest(String subMerchantId, String merSeqNbr, long transAmt, String nowTime,
                                  String frontURL, String backURL, String orderTitle) {
        log.info("----------------- é€šç”¨å¿«æ·æ”¯ä»˜ å¼€å§‹, è®¢å•编号= {} ï¼Œè®¢å•金额为:{}----------------- ", merSeqNbr, transAmt);
        // æ‹¼æŽ¥ä¸šåŠ¡æ•°æ®
        JSONObject formData = new JSONObject();
        formData.put("deviceType", "5");
        HashMap<String, Object> plainData = new HashMap<>();
        // plain å¼€å§‹
        //一级商户id
//        plainData.put("merchId", "010020170801000001");
        plainData.put("merchId", nxPayConfig.getKjMerNbr());
        //优惠前金额    disCountAmt
        //订单名称    orderName
        plainData.put("orderName", orderTitle);
        //币种    ccy
        plainData.put("ccy", "01");
        //返回前端URL    frontURL
        plainData.put("frontURL", frontURL);
        //后台通知URL    backURL
        plainData.put("backURL", backURL);
        //订单备注    orderRemark
        plainData.put("orderRemark", "");
        //渠道号    channelNbr
        plainData.put("channelNbr", "02");
        //交易总金额    txnAmt
        plainData.put("txnAmt", convertToYuan(transAmt));
        //商户流水号    merSeqNbr
        plainData.put("merSeqNbr", merSeqNbr);
        //交易时间    orderTime
        plainData.put("orderTime", nowTime);
        //收款方名称    payee
        //优惠活动名称    specialOffers
        //商户订单号    merchOrderId
        plainData.put("merchOrderId", merSeqNbr);
        JSONArray plainMerTrans = new JSONArray();
        JSONObject plainMerTransData1 = new JSONObject();
        //子交易金额
        plainMerTransData1.put("subTransAmt", convertToYuan(transAmt));
        //二级商户号
        plainMerTransData1.put("subMerchantId", subMerchantId);
        //二级商户交易时间    subMerDateTime
        plainMerTransData1.put("subMerDateTime", nowTime);
        //子流水号    subMerSeqNo
        plainMerTransData1.put("subMerSeqNo", merSeqNbr);
        //二级商户名称    subMerchantName
        plainMerTransData1.put("subMerchantName", "");
        //二级商户商品信息    productInfo
        plainMerTransData1.put("productInfo", "");
        //二级商户信息    subMerImport
//        plainMerTransData1.put("subMerImport", "学费");
//        plainMerTransData1.put("subMerImport", orderTitle);
        //卡券号    platCouponId
        plainMerTransData1.put("platCouponId", "");
        //子卡券交易金额    platCouponAmount
        plainMerTransData1.put("platCouponAmount", "");
        //子积分数    bonusPoint
        plainMerTransData1.put("bonusPoint", "");
        //子积分交易金额    bonusPointAmount
        plainMerTransData1.put("bonusPointAmount", "");
//        plainMerTransData1.put("subInteralAmt", "0.01");
//        plainMerTransData1.put("subCouponAmt", "");
        plainMerTrans.add(plainMerTransData1);
        plainData.put("MerTransList", plainMerTrans);
        String plainStr = JSONObject.toJSONString(plainData);
        log.info("请求参数:{}", plainStr);
//        formData.put("plain", plainData);
        formData.put("plain", plainStr);
        // plain ç»“束
        // å¼€å§‹ç­¾å
        String signature = kjSign(plainStr);
        formData.put("signature", signature);
//        writeToFile(signature, plainStr);
        HttpResponse httpResponse = HttpRequest.post(nxPayConfig.getKjUrl() + HnnxConstant.QUICK_PAY_URL)
                .contentType("application/x-www-form-urlencoded;")
                .form(formData.getInnerMap())
                .timeout(20000)//超时,毫秒
                .execute();
        String location = null;
        log.info("----------------- é€šç”¨å¿«æ·æ”¯ä»˜  ç»“束 ----------------- ");
        if (httpResponse.getStatus() == 302) {
            location = httpResponse.header("Location");
//            writeToFile(location);
            return location;
        }else {
            throw new RuntimeException(httpResponse.body());
        }
    }
    /**
     * å¿«æ·æ”¯ä»˜ è®¢å•状态查询
     *
     * @param orderNbr  è®¢å•编号
     * @param startDate èµ·å§‹æ—¥æœŸ     yyyyMMdd
     * @param endDate   ç»“束日期 yyyyMMdd
     * @param pageSize  æ¯é¡µè®°å½•æ•°
     * @param pageNum   å½“前第几页
     * @return
     */
    public String quickPayOrderQueryRequest(String orderNbr, String startDate, String endDate, int pageSize, int pageNum) {
        log.info("----------------- å¿«æ·æ”¯ä»˜è®¢å•交易状态查询 å¼€å§‹----------------- ");
        String body = null;
        JSONObject formData = new JSONObject();
        formData.put("MerNbr", nxPayConfig.getKjMerNbr());
        //订单编号
        if (StringUtils.isNotEmpty(orderNbr)) {
            formData.put("OrderNbr", orderNbr);
        }
        //起始日期
        if (StringUtils.isNotEmpty(orderNbr)) {
            formData.put("StartDate", startDate);
        }
        //结束日期
        if (StringUtils.isNotEmpty(orderNbr)) {
            formData.put("EndDate", endDate);
        }
        //每页记录数
        formData.put("PageSize", pageSize);
        //当前第几页
        formData.put("PageNum", pageNum);
        log.info("快捷支付订单查询参数:{}", formData);
        body = HttpRequest.post(nxPayConfig.getKjUrl() +  HnnxConstant.QUICK_PAY_QUERY_URL)
                .contentType("application/x-www-form-urlencoded;")
                .form(formData.getInnerMap())
                .timeout(20000)//超时,毫秒
                .execute().body();
        log.info("快捷支付订单查询请求结果:{}", body);
        log.info("----------------- å¿«æ·æ”¯ä»˜è®¢å•交易状态查询  ç»“束 ----------------- ");
        return body;
    }
    /**
     * é€€æ¬¾
     *
     * @param subMerchantId åŽŸæ”¯ä»˜äº¤æ˜“äºŒçº§å•†æˆ·å·
     * @param merSeqNbr     è¦é€€æ¬¾çš„订单号
     * @param merSeqDate    è¦é€€æ¬¾çš„订单交易日期 yyyyMMdd ä¾‹ï¼š20190810
     * @param origTransAmt  è¦é€€æ¬¾çš„订单的交易金额
     * @param transAmt      é€€æ¬¾é‡‘额
     * @param timeStamp     å½“前日期 ä¾‹ï¼šyyyyMMddHHmmss
     * @return
     */
    public String quickPayReturntrans(String subMerchantId, String merSeqNbr, String merSeqDate, long origTransAmt,
                                      long transAmt, String timeStamp) {
        log.info("----------------- é€€æ¬¾ å¼€å§‹----------------- ");
        String timeStampWithSpace = timeStamp.substring(0, 8) + " " + timeStamp.substring(8);
        // æ‹¼æŽ¥ä¸šåŠ¡æ•°æ®
        HashMap<String, Object> formData = new HashMap<>();
        // ä¸€çº§å•†æˆ·å·
        formData.put("MerNbr", nxPayConfig.getKjMerNbr());
        //商户总交易流水号
        formData.put("MerSeqNbr", "TK_" + merSeqNbr);
        //退货交易时间 yyyyMMdd HHmmss  å·®å¼‚!!!!
        formData.put("MerTransDateTime", timeStampWithSpace);
//        formData.put("MerTransDateTime", timeStamp);
        //原商户流水
        formData.put("OrigMerSeqNbr", merSeqNbr);
        //原商户日期
        formData.put("OrigMerDate", merSeqDate);
        //原支付交易金额
        formData.put("OrigTransAmt", convertToYuan(origTransAmt));
        //二级商户号
        formData.put("SubMerchantId", subMerchantId);
        //退货二级商户流水号(随机生成,不允许出现重复,可以和一级商户交易流水号保持一致)
        formData.put("SubMerSeqNo", "TK_" + merSeqNbr);
        //二级商户时间
        formData.put("SubMerDateTime", timeStampWithSpace);
//        formData.put("SubMerDateTime", timeStamp);
        //二级商户退货交易退货金额
        formData.put("SubTransAmt", convertToYuan(transAmt));
        //原二级商户支付流水号(与原支付交易一级商户号流水号一致)
        formData.put("OrigSubMerSeqNo", merSeqNbr);
        //原二级商户支付交易日期(例:20190810)
        formData.put("OrigSubMerDate", merSeqDate);
        //订单号 ä¸ŽäºŒçº§å•†æˆ·æµæ°´å·ä¿æŒä¸€è‡´
        formData.put("OrderNbr", merSeqNbr);
        log.info("快捷支付订单退款参数:{}", formData);
        String body = null;
        HttpResponse httpResponse = HttpRequest.post(nxPayConfig.getKjUrl() + HnnxConstant.QUICK_PAY_RETURN_URL)
                .contentType("application/x-www-form-urlencoded;")
                .form(formData)
                .timeout(20000)//超时,毫秒
                .execute();
        body = httpResponse.body();
        log.info(" å¿«æ·æ”¯ä»˜é€€æ¬¾ç»“果:{}", body);
        log.info("----------------- é€€æ¬¾ ç»“束----------------- ");
        return body;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/hnnxPay/NXPayService.java
New file
@@ -0,0 +1,524 @@
package com.nuvole.hnnx.hnnxPay;
import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.node.ContainerNode;
import com.nuvole.common.domain.emnu.CommonResultEmnu;
import com.nuvole.common.domain.result.CommonResult;
import com.nuvole.constants.PropertiesConstants;
import com.nuvole.hnnx.conf.NxPayConfig;
import com.nuvole.hnnx.orderQueryTask.OrderQueryTask;
import com.nuvole.hnnx.orderQueryTask.OrderQueryUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.Map;
/**
 * @ClassName NXPayService
 * @Author cy
 * @Date 2023/10/6
 * @Description
 * @Version 1.0
 **/
@Service
@Slf4j
//@ConditionalOnClass(name = "com.nuvole.hnnx.conf.NxPayConfig")
public class NXPayService {
    @Autowired(required = false)
    private NXHttpClientUtils nxHttpClientUtils;
    @Autowired
    private NxPayConfig nxPayConfig;
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    public String getPlatSubMerchantId() {
        return nxHttpClientUtils.getPlatSubMerchantId();
    }
    public String getKjPlatSubMerchantId() {
        return nxHttpClientUtils.getKjPlatSubMerchantId();
    }
    public String getBranchId() {
        return nxHttpClientUtils.getBranchId();
    }
    /**
     * C æ‰« B ç»Ÿä¸€ä¸‹å•
     *
     * @param payConfig æ”¯ä»˜å‚数聚合对象
     * @param orderId   å•†æˆ·è®¢å•号
     * @param payMoney  è®¢å•总金额,只能为整数
     * @param title     è®¢å•标题
     * @param authCode  å¾®ä¿¡/支付宝,返回的授权码,支付中心通过授权码获取用户openId,以便进行后续下单交易。
     * @param timeStamp æ—¶é—´æˆ³
     * @return
     * @throws Exception
     */
    public CommonResult<JSONObject> wxScanUnifiedorder(JSONObject payConfig, String orderId, Long payMoney, String title, String goodsInfo, String authCode, String notifyUrl,
                                                       String timeStamp) {
        log.info("【河南农信-C扫B微信支付】 ç»Ÿä¸€ä¸‹å•开始, è®¢å•编号=" + orderId);
        //验证金额
        if (payMoney <= 0 && payMoney <= 0) {
            return new CommonResult<>(CommonResultEmnu.ERROR, "支付失败,不能0元支付!");
        }
        // äºŒçº§å•†æˆ·å·
        String subMerchantId = payConfig.getString("subMerchantId");
        //交易机构号
        String branchId = payConfig.getString("branchId");
        String operatorId = payConfig.getString("operatorId");
        // å†œä¿¡ å¾®ä¿¡æ”¯ä»˜
        String onlinePayResp = null;
        onlinePayResp = nxHttpClientUtils.qrCodePrePay(subMerchantId, branchId, operatorId, orderId, authCode, payMoney, timeStamp, "03", 'C', notifyUrl, title);
        JSONObject onlinePayRespObj = JSONObject.parseObject(onlinePayResp);
        String respCode = onlinePayRespObj.getString("code");
        if (!"000000".equals(respCode)) {
            log.error("河南农信-C扫B支付下单失败!错误结果码:{},错误结果描述:{}", respCode, onlinePayRespObj.getString("message"));
            return new CommonResult<>(CommonResultEmnu.ERROR, onlinePayRespObj.getString("message"));
        }
        JSONObject onlinePayResult = onlinePayRespObj.getJSONObject("payload");
        onlinePayRespObj.put("toPayMethod", "2");
        JSONObject resultMap = nxPreConvertWxParam(onlinePayResult);
        onlinePayRespObj.put("paymentData", resultMap);
        onlinePayRespObj.remove("payload");
//        OrderQueryTask orderQueryTask = ApplicationContextUtil.getBean(OrderQueryTask.class);
//        orderQueryTask.setOrderId(orderId);
//        orderQueryTask.setPayService((short) 7);
//        orderQueryTask.setPayType((short) 1);
//        orderQueryTask.setOrderPayTime(new Date());
        OrderQueryTask orderQueryTask = new OrderQueryTask(eventPublisher, this,nxPayConfig,orderId,(short)7,(short)1,new Date());
        OrderQueryUtil.addTask(orderQueryTask);
        return new CommonResult(onlinePayRespObj);
    }
    public static String getFrontUrl(String orderId, Map youHuiInfo){
        return HnnxConstant.NX_KJ_FRONT_URL.substring(0,56);
//        String frontUrl = HnnxConstant.NX_KJ_FRONT_URL.replace("${ORDERID}", orderId + "");
//        if (youHuiInfo == null){
//            return URLEncoder.encode(frontUrl.replace("${YOUHUIINFO}", ""));
//        }
//        return URLEncoder.encode(frontUrl.replace("${YOUHUIINFO}", JSONObject.toJSONString(youHuiInfo)));
    }
    private JSONObject nxPreConvertWxParam(JSONObject payload) {
        if (payload == null) {
            return payload;
        }
        payload.put("appId", payload.remove("AppId"));
        payload.put("timeStamp", payload.remove("TimeStamp"));
        payload.put("nonceStr", payload.remove("Charset"));
        payload.put("package", payload.remove("Subject"));
        payload.put("signType", payload.remove("SignType"));
        payload.put("paySign", payload.remove("Sign"));
        payload.put("orderNo", payload.remove("MerSeqNbr"));
        return payload;
    }
    /**
     * C æ‰« B ç»Ÿä¸€ä¸‹å•
     *
     * @param payConfig æ”¯ä»˜å‚数聚合对象
     * @param orderId   å•†æˆ·è®¢å•号
     * @param payMoney  è®¢å•总金额,只能为整数
     * @param title     è®¢å•标题
     * @param authCode  å¾®ä¿¡/支付宝,返回的授权码,支付中心通过授权码获取用户openId,以便进行后续下单交易。
     * @param timeStamp æ—¶é—´æˆ³
     * @return
     * @throws Exception
     */
    public CommonResult<JSONObject> zfbScanUnifiedorder(JSONObject payConfig, String orderId, Long payMoney, String title, String goodsInfo, String authCode, String notifyUrl,
                                                        String timeStamp) {
        log.info("【河南农信-C扫B支付-支付宝】 ç»Ÿä¸€ä¸‹å•开始, è®¢å•编号=" + orderId);
        //验证金额
        if (payMoney <= 0 && payMoney <= 0) {
            return new CommonResult<>(CommonResultEmnu.ERROR, "支付失败,不能0元支付!");
        }
        // äºŒçº§å•†æˆ·å·
        String subMerchantId = payConfig.getString("subMerchantId");
        //交易机构号
        String branchId = payConfig.getString("branchId");
        String operatorId = payConfig.getString("operatorId");
        // å†œä¿¡ å¾®ä¿¡æ”¯ä»˜
        String onlinePayResp = null;
        onlinePayResp = nxHttpClientUtils.qrCodePrePay(subMerchantId, branchId, operatorId, orderId, authCode, payMoney, timeStamp, "03", 'B', notifyUrl, title);
        JSONObject onlinePayRespObj = JSONObject.parseObject(onlinePayResp);
        String respCode = onlinePayRespObj.getString("code");
        if (!"000000".equals(respCode)) {
            log.error("河南农信-C扫B支付支付宝下单失败!错误结果码:{},错误结果描述:{}", respCode, onlinePayRespObj.getString("message"));
            return new CommonResult<>(CommonResultEmnu.ERROR, onlinePayRespObj.getString("message"));
        }
        JSONObject onlinePayResult = onlinePayRespObj.getJSONObject("payload");
        onlinePayResult.put("toPayMethod", "2");
        JSONObject paymentData = new JSONObject();
        paymentData.put("tradeNO", onlinePayResult.remove("TradeNo"));
        onlinePayResult.put("paymentData", paymentData);
//        OrderQueryTask orderQueryTask = ApplicationContextUtil.getBean(OrderQueryTask.class);
//        orderQueryTask.setOrderId(orderId);
//        orderQueryTask.setPayService((short) 7);
//        orderQueryTask.setPayType((short) 1);
//        orderQueryTask.setOrderPayTime(new Date());
        OrderQueryTask orderQueryTask = new OrderQueryTask(eventPublisher, this,nxPayConfig,orderId,(short)7,(short)1,new Date());
        OrderQueryUtil.addTask(orderQueryTask);
        return new CommonResult(onlinePayResult);
    }
    /**
     * åŠ¨æ€C æ‰« B ç»Ÿä¸€ä¸‹å•
     *
     * @param payConfig æ”¯ä»˜å‚数聚合对象
     * @param orderId   å•†æˆ·è®¢å•号
     * @param payMoney  è®¢å•总金额,只能为整数
     * @param title     è®¢å•标题
     * @param authCode  å¾®ä¿¡/支付宝,返回的授权码,支付中心通过授权码获取用户openId,以便进行后续下单交易。
     * @param timeStamp æ—¶é—´æˆ³
     * @return
     * @throws Exception
     */
    public CommonResult<JSONObject> zfbActiveScanUnifiedorder(JSONObject payConfig, String orderId, Long payMoney, String title, String goodsInfo, String authCode, String notifyUrl,
                                                              String timeStamp) {
        log.info("【河南农信-动态C扫B支付-支付宝】 ç»Ÿä¸€ä¸‹å•开始, è®¢å•编号=" + orderId);
        return wxAliActiveScanUnifiedorder(payConfig, orderId, payMoney, title, goodsInfo, authCode, notifyUrl, timeStamp, "03", 'B');
    }
    /**
     * åŠ¨æ€C æ‰« B ç»Ÿä¸€ä¸‹å•
     *
     * @param payConfig æ”¯ä»˜å‚数聚合对象
     * @param orderId   å•†æˆ·è®¢å•号
     * @param payMoney  è®¢å•总金额,只能为整数
     * @param title     è®¢å•标题
     * @param authCode  å¾®ä¿¡/支付宝,返回的授权码,支付中心通过授权码获取用户openId,以便进行后续下单交易。
     * @param timeStamp æ—¶é—´æˆ³
     * @return
     * @throws Exception
     */
    public CommonResult<JSONObject> wxActiveScanUnifiedorder(JSONObject payConfig, String orderId, Long payMoney, String title, String goodsInfo, String authCode, String notifyUrl,
                                                             String timeStamp) {
        log.info("【河南农信-动态C扫B支付-微信】 ç»Ÿä¸€ä¸‹å•开始, è®¢å•编号=" + orderId);
        return wxAliActiveScanUnifiedorder(payConfig, orderId, payMoney, title, goodsInfo, authCode, notifyUrl, timeStamp, "03", 'C');
    }
    /**
     * æ”¯ä»˜å®ã€å¾®ä¿¡ åŠ¨æ€c扫B
     *
     * @param payConfig
     * @param orderId
     * @param payMoney
     * @param title
     * @param goodsInfo
     * @param authCode
     * @param notifyUrl
     * @param timeStamp
     * @param channelNbr
     * @param payTypCd
     * @return
     */
    private CommonResult<JSONObject> wxAliActiveScanUnifiedorder(JSONObject payConfig, String orderId, Long payMoney, String title, String goodsInfo, String authCode, String notifyUrl,
                                                                 String timeStamp, String channelNbr, char payTypCd) {
        //验证金额
        if (payMoney <= 0 && payMoney <= 0) {
            return new CommonResult<>(CommonResultEmnu.ERROR, "支付失败,不能0元支付!");
        }
        // äºŒçº§å•†æˆ·å·
        String subMerchantId = payConfig.getString("subMerchantId");
        //交易机构号
        String branchId = payConfig.getString("branchId");
        // å†œä¿¡ å¾®ä¿¡æ”¯ä»˜
        String onlinePayResp = null;
        onlinePayResp = nxHttpClientUtils.dyActiveQrCode(subMerchantId, branchId, orderId, payMoney, timeStamp, channelNbr, payTypCd, notifyUrl, title);
        JSONObject onlinePayRespObj = JSONObject.parseObject(onlinePayResp);
        String respCode = onlinePayRespObj.getString("code");
        if (!"000000".equals(respCode)) {
            log.error("河南农信-动态C扫B支付 ä¸‹å•失败!错误结果码:{},错误结果描述:{}", respCode, onlinePayRespObj.getString("message"));
            return new CommonResult<>(CommonResultEmnu.ERROR, onlinePayRespObj.getString("message"));
        }
        JSONObject onlinePayResult = onlinePayRespObj.getJSONObject("payload");
        onlinePayResult.put("paymentUrl", onlinePayResult.remove("QrCodeInfo"));
        onlinePayResult.put("codeUrl", onlinePayResult.get("paymentUrl"));
//        OrderQueryTask orderQueryTask = ApplicationContextUtil.getBean(OrderQueryTask.class);
//        orderQueryTask.setOrderId(orderId);
//        orderQueryTask.setPayService((short) 7);
//        orderQueryTask.setPayType((short) 1);
//        orderQueryTask.setOrderPayTime(new Date());
        OrderQueryTask orderQueryTask = new OrderQueryTask(eventPublisher, this,nxPayConfig,orderId,(short)7,(short)1,new Date());
        OrderQueryUtil.addTask(orderQueryTask);
        return new CommonResult(onlinePayResult);
    }
    public CommonResult<JSONObject> offlinePayB2COrder(JSONObject payConfig, String orderNum, String timeStamp, String title, String goodsInfo,
                                                       ContainerNode detail, String notifyUrl, Long money, String authPayCode, String terminalCode) {
        // äºŒçº§å•†æˆ·å·
        String subMerchantId = payConfig.getString("subMerchantId");
        //交易机构号
        String branchId = payConfig.getString("branchId");
        String offlineB2CPayResp = null;
        try {
            offlineB2CPayResp = nxHttpClientUtils.coretoall(subMerchantId, branchId, orderNum, money, authPayCode, timeStamp, "03", notifyUrl, title, terminalCode);
        } catch (Exception e) {
            e.printStackTrace();
            return new CommonResult<>(CommonResultEmnu.ERROR, e.getMessage());
        }
        JSONObject offlineB2CPayRespObj = JSONObject.parseObject(offlineB2CPayResp);
        String respCode = offlineB2CPayRespObj.getString("code");
        if (!"000000".equals(respCode)) {
            log.error("河南农信-付款码(B æ‰« C)下单失败!错误结果码:{},错误结果描述:{}", respCode, offlineB2CPayRespObj.getString("message"));
            return new CommonResult<>(CommonResultEmnu.ERROR, offlineB2CPayRespObj.getString("message"));
        }
        //0    äº¤æ˜“成功 1    äº¤æ˜“失败 2    æ’¤é”€ 3    éƒ¨åˆ†é€€è´§ 4    å…¨éƒ¨é€€è´§ 5    å¤„理中 9    äº¤æ˜“è¶…æ—¶
        JSONObject payloadJson = offlineB2CPayRespObj.getJSONObject("payload");
        String tradeStatus = payloadJson.getString("TransStatus");
        if ("0".equals(tradeStatus)) {
            payloadJson.put("waterNo", payloadJson.getString("TransSeqNbr"));
            // æ”¯ä»˜æˆåŠŸ
            return new CommonResult<>(payloadJson);
        } else {
            int count = 4;
            for (int index = 0; index < count; index++) {
                try {
                    Thread.sleep(10 * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                CommonResult<JSONObject> tradeQueryResult = tradeQuery(payConfig, orderNum);
                if (!tradeQueryResult.getCode().equals(CommonResultEmnu.OK.getCode())) {
                    return new CommonResult<>(CommonResultEmnu.ERROR, tradeQueryResult.getDescription());
                }
                payloadJson = tradeQueryResult.getData().getJSONObject("payload");
                tradeStatus = payloadJson.getString("TransStatus");
                if ("0".equals(tradeStatus)) {
                    payloadJson.put("waterNo", payloadJson.getString("TransSeqNbr"));
                    // æ”¯ä»˜æˆåŠŸ
                    return new CommonResult<>(payloadJson);
                } else if ("1".equals(tradeStatus)) {
                    return new CommonResult<>(CommonResultEmnu.ERROR, "交易失败,订单已关闭");
                } else if ("2".equals(tradeStatus)) {
                    return new CommonResult<>(CommonResultEmnu.ERROR, "交易失败,订单已被撤销");
                } else if ("3,4".contains(tradeStatus)) {
                    return new CommonResult<>(CommonResultEmnu.ERROR, "交易失败,订单已被退货");
                } else if ("9".equals(tradeStatus)) {
                    return new CommonResult<>(CommonResultEmnu.ERROR, "交易超时");
                } else if ("5".equals(tradeStatus)) {
                    log.info("交易中,继续查询");
                    count++;
                } else {
                    return new CommonResult<>(CommonResultEmnu.ERROR, tradeQueryResult.getDescription());
                }
            }
        }
        return new CommonResult(payloadJson);
    }
    /**
     * è®¢å•交易状态查询
     *
     * @return
     */
    public CommonResult<JSONObject> tradeQuery(JSONObject payConfig, String orderNum) {
        //交易机构号
        String branchId = payConfig.getString("branchId");
        String tradeQueryResp = nxHttpClientUtils.qryQrOrderStatus(orderNum, branchId);
        JSONObject tradeQueryRespObj = JSONObject.parseObject(tradeQueryResp);
        String respCode = tradeQueryRespObj.getString("code");
        if (!"000000".equals(respCode)) {
            log.error("河南农信-订单交易状态查询失败!错误结果码:{},错误结果描述:{}", respCode, tradeQueryRespObj.getString("message"));
            return new CommonResult<>(CommonResultEmnu.ERROR, tradeQueryRespObj.getString("message"));
        }
        return new CommonResult(tradeQueryRespObj);
    }
    /**
     * é€€æ¬¾
     *
     * @param orderNum     è¦é€€æ¬¾çš„订单号
     * @param merSeqDate   è¦é€€æ¬¾çš„订单交易日期 ä¾‹ï¼š20190810
     * @param origTransAmt è¦é€€æ¬¾çš„订单的交易金额
     * @param transAmt     é€€æ¬¾é‡‘额
     * @param timeStamp    å½“前日期 ä¾‹ï¼šyyyyMMddHHmmss
     * @return
     */
    public CommonResult<JSONObject> returntrans(JSONObject payConfig, String orderNum, String merSeqDate, long origTransAmt,
                                                long transAmt, String timeStamp) {
        // äºŒçº§å•†æˆ·å·
        String subMerchantId = payConfig.getString("subMerchantId");
        //交易机构号
        String branchId = payConfig.getString("branchId");
        String tradeQueryResp = nxHttpClientUtils.returntrans(subMerchantId, branchId, orderNum, merSeqDate, origTransAmt, transAmt, timeStamp);
        JSONObject tradeQueryRespObj = JSONObject.parseObject(tradeQueryResp);
        String respCode = tradeQueryRespObj.getString("code");
        if (!"000000".equals(respCode)) {
            log.error("河南农信-退款失败!错误结果码:{},错误结果描述:{}", respCode, tradeQueryRespObj.getString("message"));
            return new CommonResult<>(CommonResultEmnu.ERROR, tradeQueryRespObj.getString("message"));
        }
        return new CommonResult(tradeQueryRespObj);
    }
    /*** å¯¹è´¦æŸ¥è¯¢
     * String subMerchantId, String branchId,
     *
     * @param clearDate å¯¹è´¦æ—¥æœŸ    YYYY-MM-DD
     * @param branchId äº¤æ˜“机构号
     * @return
     */
    public CommonResult<JSONObject> accountqry(String clearDate, String branchId) {
        String tradeQueryResp = nxHttpClientUtils.accountqry(clearDate, branchId);
        JSONObject tradeQueryRespObj = JSONObject.parseObject(tradeQueryResp);
        String respCode = tradeQueryRespObj.getString("code");
        if (!"000000".equals(respCode)) {
            log.error("河南农信-订单交易状态查询失败!错误结果码:{},错误结果描述:{}", respCode, tradeQueryRespObj.getString("message"));
            return new CommonResult<>(CommonResultEmnu.ERROR, tradeQueryRespObj.getString("message"));
        }
        return new CommonResult(tradeQueryRespObj);
    }
    /**
     * å¾®ä¿¡å°ç¨‹åºæ”¯ä»˜
     *
     * @param payConfig
     * @param orderId
     * @param payMoney
     * @param title
     * @param goodsInfo
     * @param authCode
     * @param notifyUrl
     * @param timeStamp
     * @return
     */
    public CommonResult<JSONObject> wechatMiniPay(JSONObject payConfig, String orderId, Long payMoney, String title, String goodsInfo, String authCode, String notifyUrl,
                                                  String timeStamp) {
        log.info("【河南农信-C扫B微信支付】 ç»Ÿä¸€ä¸‹å•开始, è®¢å•编号=" + orderId);
        //验证金额
        if (payMoney <= 0 && payMoney <= 0) {
            return new CommonResult<>(CommonResultEmnu.ERROR, "支付失败,不能0元支付!");
        }
        // äºŒçº§å•†æˆ·å·
        String subMerchantId = payConfig.getString("subMerchantId");
        //交易机构号
        String branchId = payConfig.getString("branchId");
        String operatorId = payConfig.getString("operatorId");
        // å†œä¿¡ å¾®ä¿¡æ”¯ä»˜
        String onlinePayResp = null;
        onlinePayResp = nxHttpClientUtils.qrCodePrePay(subMerchantId, branchId, operatorId, orderId, authCode, payMoney, timeStamp, "03", 'C', notifyUrl, title);
        JSONObject onlinePayRespObj = JSONObject.parseObject(onlinePayResp);
        String respCode = onlinePayRespObj.getString("code");
        if (!"000000".equals(respCode)) {
            log.error("河南农信-C扫B支付下单失败!错误结果码:{},错误结果描述:{}", respCode, onlinePayRespObj.getString("message"));
            return new CommonResult<>(CommonResultEmnu.ERROR, onlinePayRespObj.getString("message"));
        }
        JSONObject onlinePayResult = onlinePayRespObj.getJSONObject("payload");
        onlinePayRespObj.put("toPayMethod", "2");
        JSONObject resultMap = nxPreConvertWxParam(onlinePayResult);
        onlinePayRespObj.put("paymentData", resultMap);
        onlinePayRespObj.remove("payload");
//        OrderQueryTask orderQueryTask = ApplicationContextUtil.getBean(OrderQueryTask.class);
//        orderQueryTask.setOrderId(orderId);
//        orderQueryTask.setPayService((short) 7);
//        orderQueryTask.setPayType((short) 1);
//        orderQueryTask.setOrderPayTime(new Date());
        OrderQueryTask orderQueryTask = new OrderQueryTask(eventPublisher, this,nxPayConfig,orderId,(short)7,(short)1,new Date());
        OrderQueryUtil.addTask(orderQueryTask);
        return new CommonResult(resultMap);
    }
    /**
     *
     * @param payConfig
     * @param orderId
     * @param payMoney
     * @param title
     * @param goodsInfo
     * @param timeStamp  yyyyMMddHHmmssSSS格式
     * @return
     */
    public CommonResult<JSONObject> kjTrade(JSONObject payConfig, String orderId, Long payMoney, String title, String goodsInfo,
                                            String timeStamp, String frontUrl) {
        String kjSubMerchantId = payConfig.getString("kjSubMerchantId");
        String location = null;
        try {
            location = nxHttpClientUtils.quickPayRequest(kjSubMerchantId, orderId, payMoney,
                    timeStamp, frontUrl,
                    PropertiesConstants.STQ_SERVER + HnnxConstant.NX_KJ_ALL_CALL_BACK,
//                  "http://1.14.252.104:7101/service-merchant" + HnnxConstant.NX_KJ_ALL_CALL_BACK,
                    title);
        } catch (Exception e) {
            log.error("河南农信-快捷支付 ä¸‹å•失败!错误结果描述:{}", e.getMessage());
            return new CommonResult<>(CommonResultEmnu.ERROR, e.getMessage());
        }
        JSONObject onlinePayResult = new JSONObject();
        onlinePayResult.put("paymentUrl", location);
        onlinePayResult.put("codeUrl", location);
        onlinePayResult.put("toPayMethod", "3");
//        OrderQueryTask orderQueryTask = ApplicationContextUtil.getBean(OrderQueryTask.class);
//        orderQueryTask.setOrderId(orderId);
//        orderQueryTask.setPayService((short) 7);
//        orderQueryTask.setPayType((short) 1);
//        orderQueryTask.setOrderPayTime(new Date());
        OrderQueryTask orderQueryTask = new OrderQueryTask(eventPublisher, this,nxPayConfig,orderId,(short)7,(short)1,new Date());
        OrderQueryUtil.addTask(orderQueryTask);
        return new CommonResult(onlinePayResult);
    }
    /**
     * è®¢å•交易状态查询
     *
     * @return
     */
    public CommonResult<JSONArray> kjTradeQuery(String orderNum, String startDate, String endDate, Integer pageSize, Integer pageNum) {
        String tradeQueryResp = nxHttpClientUtils.quickPayOrderQueryRequest(orderNum, startDate, endDate, Convert.toInt(pageSize, 1), Convert.toInt(pageNum, 1));
        if (StringUtils.isEmpty(tradeQueryResp)) {
            return new CommonResult<>(CommonResultEmnu.ERROR, "未查询到数据");
        }
        JSONObject tradeQueryRespObj = JSONObject.parseObject(tradeQueryResp);
        Integer totalNum = tradeQueryRespObj.getInteger("TotalNum");
        if (totalNum == null || totalNum == 0) {
            return new CommonResult<>(CommonResultEmnu.ERROR, "未查询到数据");
        }
        JSONArray orderList = tradeQueryRespObj.getJSONArray("OrderList");
        return new CommonResult(orderList);
    }
    /**
     * é€€æ¬¾
     *
     * @param orderNum     è¦é€€æ¬¾çš„订单号
     * @param merSeqDate   è¦é€€æ¬¾çš„订单交易日期 ä¾‹ï¼š20190810
     * @param origTransAmt è¦é€€æ¬¾çš„订单的交易金额
     * @param transAmt     é€€æ¬¾é‡‘额
     * @param timeStamp    å½“前日期 ä¾‹ï¼šyyyyMMddHHmmss
     * @return
     */
    public CommonResult<JSONObject> kjReturntrans(JSONObject payConfig, String orderNum, String merSeqDate, long origTransAmt,
                                                  long transAmt, String timeStamp) {
        // äºŒçº§å•†æˆ·å·
        String subMerchantId = payConfig.getString("kjSubMerchantId");
        //交易机构号
        String tradeQueryResp = nxHttpClientUtils.quickPayReturntrans(subMerchantId, orderNum, merSeqDate, origTransAmt, transAmt, timeStamp);
        JSONObject tradeQueryRespObj = JSONObject.parseObject(tradeQueryResp);
        String respCode = tradeQueryRespObj.getString("ReturnCode");
        if (!"000000".equals(respCode)) {
            log.error("河南农信-退款失败!错误结果码:{},错误结果描述:{}", respCode, tradeQueryRespObj.getString("ReturnMsg"));
            return new CommonResult<>(CommonResultEmnu.ERROR, tradeQueryRespObj.getString("ReturnMsg"));
        }
        return new CommonResult(tradeQueryRespObj);
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/hnnxPay/SignatureSigner.java
New file
@@ -0,0 +1,130 @@
package com.nuvole.hnnx.hnnxPay;
import com.csii.sg.codec.Hex;
import org.springframework.util.Assert;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.PrivateKey;
import java.security.Signature;
import java.util.*;
/**
 * @author awlwen
 * @since 2017/11/30
 */
public class SignatureSigner {
    /**
     * å°†å­—节数组转换为16进制字符串
     * ç®—法:
     * å°†å­—节数组中每个字节取出后转换为16进制,截取低八位
     * å°†ä¸è¶³2位的字符前补0,解析时可按2位分隔
     *
     * @param byteArray å­—节数组
     * @return 16进制字符
     */
    private String byteToHex(byte[] byteArray) {
        if (byteArray == null) {
            return "";
        }
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < byteArray.length; i++) {
            String hexString = Integer.toHexString(byteArray[i] & 0x00ff);
            if (hexString.length() != 2) {
                //如果字符长度不为2位,前补0占位
                sb.append("0");
            }
            sb.append(hexString);
        }
        return sb.toString();
    }
private static byte[] signLow(String plain, String algorithm, PrivateKey privateKey) {
        Assert.notNull(plain, "plain is null.");
        Assert.notNull(algorithm, "algorithm is null.");
        Assert.notNull(privateKey, "private key is null.");
        try {
            Signature sign = Signature.getInstance(algorithm);
            sign.initSign(privateKey);
            sign.update(plain.getBytes());
            return sign.sign();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
private static byte[] signLowByte(byte[] plain, String algorithm, PrivateKey privateKey) {
        Assert.notNull(plain, "plain is null.");
        Assert.notNull(algorithm, "algorithm is null.");
        Assert.notNull(privateKey, "private key is null.");
        try {
            Signature sign = Signature.getInstance(algorithm);
            sign.initSign(privateKey);
            sign.update(plain);
            return sign.sign();
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
    public static String laBaSign(Map<String, String> parameters, String accessKeySecret) {
        // Step 1: Sort the parameters by key in ascending order
        List<Map.Entry<String, String>> sortedParams = new ArrayList<>(parameters.entrySet());
        Collections.sort(sortedParams, Comparator.comparing(Map.Entry::getKey));
        // Step 2: Generate the string to sign
        StringBuilder stringToSign = new StringBuilder();
        for (Map.Entry<String, String> param : sortedParams) {
            if (param.getValue() != null && !param.getValue().isEmpty()) {
                stringToSign.append(param.getKey()).append("=").append(param.getValue()).append("&");
            }
        }
        stringToSign.deleteCharAt(stringToSign.length() - 1); // Remove the last '&'
        // Step 3: Generate the signature
        try {
            Mac hmacSha256 = Mac.getInstance("HmacSHA256");
            SecretKeySpec keySpec = new SecretKeySpec(accessKeySecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            hmacSha256.init(keySpec);
            byte[] signData = hmacSha256.doFinal(stringToSign.toString().getBytes(StandardCharsets.UTF_8));
            // Step 4: Base64 encode the signature
            return Base64.getEncoder().encodeToString(signData);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * ä½¿ç”¨æä¾›çš„算法与私钥对交易数据签名
     *
     * @param plain      äº¤æ˜“数据明文
     * @param privateKey java.security.PrivateKey ç§é’¥
     * @return ç­¾å
     */
    public String sign(String plain, PrivateKey privateKey) {
        byte[] bytes = signLow(plain, HnnxConstant.ALGORITHM, privateKey);
        return Hex.toHex(bytes);
    }
    /**
     * å¿«æ·æ”¯ä»˜sign
     *
     * @param plain
     * @param privateKey
     * @return
     */
    public String kjSign(String plain, PrivateKey privateKey) {
        byte[] bytes = new byte[0];
        try {
            bytes = signLowByte(plain.getBytes("utf-8"), HnnxConstant.KJ_ALGORITHM, privateKey);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return Base64.getEncoder().encodeToString(bytes);
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/orderQueryTask/OrderQueryEvent.java
New file
@@ -0,0 +1,23 @@
package com.nuvole.hnnx.orderQueryTask;
import org.springframework.context.ApplicationEvent;
/**
 * @ClassName OrderQueryEvent
 * @Author cy
 * @Date 2024/1/2
 * @Description
 * @Version 1.0
 **/
public class OrderQueryEvent extends ApplicationEvent {
    private OrderQueryMessageEntity messageEntity;
    public OrderQueryEvent(Object source, OrderQueryMessageEntity messageEntity) {
        super(source);
        this.messageEntity = messageEntity;
    }
    public OrderQueryMessageEntity getMessageEntity() {
        return this.messageEntity;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/orderQueryTask/OrderQueryMessageEntity.java
New file
@@ -0,0 +1,58 @@
package com.nuvole.hnnx.orderQueryTask;
/**
 * @ClassName OrderQueryMessageEntity
 * @Author cy
 * @Date 2024/1/2
 * @Description
 * @Version 1.0
 **/
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
 * @Description æ¶ˆæ¯å®žä½“ç±»
 **/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class OrderQueryMessageEntity {
    /**
     * 10000 è®¢å•查询,后续可添加其他
     */
    String code;
    /**
     * SQ å•†åœˆè®¢å•
     * SC å•†åŸŽè®¢å•
     * SM H5扫码付订单
     * DTCSB å•†å®¶APP动态主扫(C扫B)
     * BSC ç”¨æˆ·å‡ºç¤ºä»˜æ¬¾ç  B扫C
     */
    String orderChannel;
    /**
     * ç³»ç»Ÿè®¢å•号
     */
    String orderId;
    /**
     * å†œä¿¡ç­‰ä¸‰æ–¹æ”¯ä»˜ç³»ç»Ÿçš„订单号
     */
    String outTradeNo;
    /**
     * 1.微信支付  2.快捷支付
     */
    Short orderType;
    /**
     * æ”¯ä»˜æœåŠ¡æä¾›å•†
     */
    Short payService;
    /**
     * å°è¯•支付的次数,用于生成通联单号
     */
    Short tryPayNum;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/orderQueryTask/OrderQueryTask.java
New file
@@ -0,0 +1,152 @@
package com.nuvole.hnnx.orderQueryTask;
import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.nuvole.common.domain.emnu.CommonResultEmnu;
import com.nuvole.common.domain.result.CommonResult;
import com.nuvole.hnnx.conf.NxPayConfig;
import com.nuvole.hnnx.hnnxPay.NXPayService;
import io.swagger.annotations.ApiModelProperty;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import java.util.Date;
/**
 * @ClassName OrderQueryTask
 * @Author cy
 * @Date 2024/1/2
 * @Description
 * @Version 1.0
 **/
@Slf4j
//@Component
//@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class OrderQueryTask implements Runnable {
//    @Autowired
    private ApplicationEventPublisher eventPublisher;
//    @Autowired
    private NXPayService nxPayService;
//    @Autowired
    private NxPayConfig nxPayConfig;
    @ApiModelProperty("订单ID")
    private String orderId;
    @ApiModelProperty("支付服务商")
    private Short payService;
    @ApiModelProperty("农信需要区分是否为快捷支付 1 æ™®é€šæ”¯ä»˜ 2快捷支付")
    private Short payType;
    @ApiModelProperty("订单尝试支付时间")
    private Date orderPayTime;
    @Override
    public void run() {
        Date nowTime = new Date();
        long lastDuration = nowTime.getTime() - orderPayTime.getTime();
        if (lastDuration > 10 * 60 * 1000) {
            log.error("10钟前的订单,取消任务:{}", orderId);
            OrderQueryUtil.cancelTask(orderId);
            return;
        }
        log.info("查询订单为{}, è®¢å•初始支付时间为{}", orderId, orderPayTime);
        boolean isPaySuccess = false;
        String[] orderInfoArr = orderId.split("-");
        String orderChannel = orderInfoArr[0];
        String myOrderId = orderInfoArr[1];
        Short tryPayNum = Convert.toShort(orderInfoArr[3],null);
        String outTradeNo = null;
        if (payService == 7) {
            if (payType == 1) {
                JSONObject payConfig = new JSONObject();
                payConfig.put("branchId", nxPayConfig.getBranchId());
                CommonResult<JSONObject> tradeQueryResult = nxPayService.tradeQuery(payConfig, orderId);
                // TransStatus 0    äº¤æ˜“成功 1    äº¤æ˜“失败 2    æ’¤é”€ 3    éƒ¨åˆ†é€€è´§ 4    å…¨éƒ¨é€€è´§ 5    å¤„理中 9    äº¤æ˜“è¶…æ—¶
                if (!tradeQueryResult.getCode().equals(CommonResultEmnu.OK.getCode())) {
                    OrderQueryUtil.cancelTask(orderId);
                    return;
                }
                JSONObject tradeQueryResultJson = tradeQueryResult.getData();
                JSONObject payload = tradeQueryResultJson.getJSONObject("payload");
                Integer transStatus = payload.getInteger("TransStatus");
                if (transStatus != null) {
                    if (transStatus == 0) {
                        isPaySuccess = true;
                        outTradeNo = payload.getString("TransSeqNbr");
                    } else if (transStatus == 1 || transStatus == 9) {
                        log.error("交易失败 æˆ– äº¤æ˜“超时,取消任务.{}", orderId);
                        OrderQueryUtil.cancelTask(orderId);
                    }
                }
            } else if (payType == 2) {
                //orderStatus   0-待支付 1-成功 2-失败 3-处理中 4-订单取消
                CommonResult<JSONArray> tradeQueryResult = nxPayService.kjTradeQuery(orderId, null, null, 1, 1);
                if (!tradeQueryResult.getCode().equals(CommonResultEmnu.OK.getCode())) {
                    OrderQueryUtil.cancelTask(orderId);
                    return;
                }
                JSONArray tradeQueryResultJsonArr = tradeQueryResult.getData();
                if (tradeQueryResultJsonArr != null && tradeQueryResultJsonArr.size() > 0){
                    JSONObject tradeQueryResultJson = (JSONObject) tradeQueryResultJsonArr.get(0);
                    Integer transStatus = tradeQueryResultJson.getInteger("orderStatus");
                    if (transStatus != null) {
                        if (transStatus == 1) {
                            isPaySuccess = true;
                            outTradeNo = tradeQueryResultJson.getString("TransSeqNbr");
                        } else if (transStatus == 2 || transStatus == 4) {
                            log.error("交易失败 æˆ– è®¢å•取消,取消任务.{}", orderId);
                            OrderQueryUtil.cancelTask(orderId);
                        }
                    }
                }
            } else {
                log.error("支付方式错误,取消任务.{}", orderId);
                OrderQueryUtil.cancelTask(orderId);
            }
        } else {
            log.error("目前除农信外,其他暂不查询");
            OrderQueryUtil.cancelTask(orderId);
        }
        // åˆ¤æ–­æ”¯ä»˜çŠ¶æ€ï¼Œç¡®å®šæ˜¯å¦å‘é€é€šçŸ¥
        if (isPaySuccess) {
            eventPublisher.publishEvent(new OrderQueryEvent(this,
                    OrderQueryMessageEntity.builder().code("10000").orderChannel(orderChannel).orderId(myOrderId).outTradeNo(outTradeNo).payService(payService).tryPayNum(tryPayNum).build()));
            OrderQueryUtil.cancelTask(orderId);
        }
    }
    public OrderQueryTask(ApplicationEventPublisher eventPublisher, NXPayService nxPayService, NxPayConfig nxPayConfig, String orderId, Short payService, Short payType, Date orderPayTime) {
        this.eventPublisher = eventPublisher;
        this.nxPayService = nxPayService;
        this.nxPayConfig = nxPayConfig;
        this.orderId = orderId;
        this.payService = payService;
        this.payType = payType;
        this.orderPayTime = orderPayTime;
    }
    public String getOrderId() {
        return orderId;
    }
    public Short getPayService() {
        return payService;
    }
    public Short getPayType() {
        return payType;
    }
    public Date getOrderPayTime() {
        return orderPayTime;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/orderQueryTask/OrderQueryTrigger.java
New file
@@ -0,0 +1,70 @@
package com.nuvole.hnnx.orderQueryTask;
import io.swagger.annotations.ApiModelProperty;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import java.time.Instant;
import java.util.Date;
/**
 * @ClassName OrderQueryTrigger
 * @Author cy
 * @Date 2024/1/2
 * @Description
 * @Version 1.0
 **/
public class OrderQueryTrigger implements Trigger {
    @ApiModelProperty("订单尝试支付时间")
    private Date orderPayTime;
//    @Override
//    public Date nextExecutionTime(TriggerContext triggerContext) {
//        // æ ¹æ®ä¸åŒçš„æ—¶é—´æ®µè¿”回下一次执行任务的时间
//        Date nowTime = new Date();
//
//        long lastDuration = nowTime.getTime() - orderPayTime.getTime();
//
//        // æ ¹æ®æ—¶é—´æ®µè®¾ç½®ä¸åŒçš„æ‰§è¡Œé—´éš”
//        //间隔时间  æŸ¥è¯¢é¢‘率
//        //(0~10]    2s
//        //(10~30]   5s
//        //(30~60]   15s
//        //(60~180]  60s
//        if (lastDuration <= 10000) {
//            return new Date(System.currentTimeMillis() + 2000);
//        } else if (lastDuration <= 30000) {
//            return new Date(System.currentTimeMillis() + 5000);
//        } else if (lastDuration <= 60000) {
//            return new Date(System.currentTimeMillis() + 15000);
//        } else {
//            return new Date(System.currentTimeMillis() + 60000);
//        }
//    }
    @Override
    public Instant nextExecution(TriggerContext triggerContext) {
        // æ ¹æ®ä¸åŒçš„æ—¶é—´æ®µè¿”回下一次执行任务的时间
        long lastDuration = System.currentTimeMillis() - orderPayTime.getTime();
        // æ ¹æ®æ—¶é—´æ®µè®¾ç½®ä¸åŒçš„æ‰§è¡Œé—´éš”
        //间隔时间  æŸ¥è¯¢é¢‘率
        //(0~10]    2s
        //(10~30]   5s
        //(30~60]   15s
        //(60~180]  60s
        if (lastDuration <= 10000) {
            return Instant.ofEpochMilli(System.currentTimeMillis() + 2000);
        } else if (lastDuration <= 30000) {
            return Instant.ofEpochMilli(System.currentTimeMillis() + 5000);
        } else if (lastDuration <= 60000) {
            return Instant.ofEpochMilli(System.currentTimeMillis() + 15000);
        } else {
            return Instant.ofEpochMilli(System.currentTimeMillis() + 60000);
        }
    }
    public OrderQueryTrigger(Date orderPayTime) {
        this.orderPayTime = orderPayTime;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/hnnx/orderQueryTask/OrderQueryUtil.java
New file
@@ -0,0 +1,61 @@
package com.nuvole.hnnx.orderQueryTask;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.DefaultManagedTaskScheduler;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
/**
 * @ClassName OrderQueryUtil
 * @Author cy
 * @Date 2024/1/2
 * @Description
 * @Version 1.0
 **/
@Slf4j
//@Component
public class OrderQueryUtil {
    private static TaskScheduler taskScheduler = new DefaultManagedTaskScheduler();
//    @Autowired
//    public void setTaskScheduler(TaskScheduler taskScheduler) {
//        OrderQueryUtil.taskScheduler = taskScheduler;
//    }
    // ç”¨äºŽå–消任务
    private static Map<String, ScheduledFuture> taskMap = new ConcurrentHashMap<>();
    public static Map<String, ScheduledFuture> getTaskMap() {
        return taskMap;
    }
    private static TaskScheduler getExecutor() {
        return taskScheduler;
    }
    public static ScheduledFuture addTask(OrderQueryTask task) {
        ScheduledFuture scheduledFuture = getExecutor().schedule(task, new OrderQueryTrigger(task.getOrderPayTime()));
        taskMap.put(task.getOrderId(), scheduledFuture);
        log.info("新增订单号为{}, è®¢å•初始支付时间为{}", task.getOrderId(), task.getOrderPayTime());
        return scheduledFuture;
    }
    public static void cancelTask(ScheduledFuture future) {
        future.cancel(true);
    }
    public static void cancelTask(String taskId) {
        log.info("取消订单号为{}", taskId);
        ScheduledFuture future = taskMap.remove(taskId);
        if (future != null) {
            future.cancel(true);
        }
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/laba/LabaPushUtil.java
New file
@@ -0,0 +1,31 @@
//package com.nuvole.laba;
//
//import com.nuvole.laba.conf.LaBaPushConfig;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.stereotype.Component;
//
///**
// * @ClassName laba
// * @Author cy
// * @Date 2023/12/4
// * @Description
// * @Version 1.0
// **/
//@Component
//public class LabaPushUtil {
//    private static LaBaPushConfig laBaPushConfig;
//
//    @Autowired
//    public void setLaBaPushConfig(LaBaPushConfig laBaPushConfig) {
//        LabaPushUtil.laBaPushConfig = laBaPushConfig;
//    }
//
//    public static void sendMsg(String message) {
//        // ä½¿ç”¨apiProperties中的key和secret来发送消息
//        String serverUrl = laBaPushConfig.getServerUrl();
//        String key = laBaPushConfig.getAccessKeyId();
//        String secret = laBaPushConfig.getAccessKeySecret();
//
//        // å®žçŽ°æ¶ˆæ¯å‘é€é€»è¾‘...
//    }
//}
ecosphere/ecosphere-common/src/main/java/com/nuvole/poscom/api/PoscomService.java
New file
@@ -0,0 +1,197 @@
package com.nuvole.poscom.api;
import com.alibaba.fastjson.JSONObject;
import com.nuvole.common.domain.result.CommonResult;
import com.nuvole.poscom.config.PoscomConfig;
import com.nuvole.poscom.config.PoscomPrintData;
import com.nuvole.poscom.config.TempletParams;
import com.nuvole.poscom.util.PoscomRequest;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
/**
 * @Description ä½³åšäº‘打印机接口
 * @Author ZHAOXL
 * @Date 2024/3/6 16:24
 * @Version 1.0
 */
@Slf4j
public class PoscomService {
    /**
     * æ·»åŠ æ‰“å°æœº
     * @param deviceID* ç»ˆç«¯ç¼–号。
     * @param deviceName* è®¾å¤‡åç§°ï¼Œæœ€å¤§64位数据长度。
     * @param grpID åˆ†ç»„ ID ã€‚
     * @return CommonResult
     * @Author ZHAOXL
     * @Date 2024/3/6 16:53
     * @Version 1.0
     */
    public static CommonResult<JSONObject> addDev(String deviceID, String deviceName, Integer grpID) {
        Map<String, String> params = new HashMap<String, String>();
        String reqTime = String.valueOf(Calendar.getInstance().getTimeInMillis());
        params.put("reqTime", reqTime);
        String securityCode = DigestUtils.md5Hex(PoscomConfig.memberCode + reqTime + PoscomConfig.apiKey + deviceID);
        params.put("securityCode", securityCode);
        params.put("memberCode", PoscomConfig.memberCode);
        params.put("deviceID", deviceID);
        params.put("devName", deviceName);
        if (grpID != null) {
            params.put("grpID", grpID + "");
        }
        log.debug("=====请求参数 START=====\r\n" + "---> adddev <---\r\n" + params + "\r\n=====请求参数 END=====");
        String result = PoscomRequest.sendPost("http://api.poscom.cn/apisc/adddev", params);
        log.debug("=====请求返回 START=====\r\n" + result + "\r\n=====请求返回 END=====");
        JSONObject resultObject = JSONObject.parseObject(result);
        return new CommonResult(resultObject);
    }
    /**
     * æ‰“印机切换播报类型
     * @param deviceID* ç»ˆç«¯ç¼–号。
     * @param voiceType* è¯­éŸ³ç±»åž‹ã€‚0 çœŸäººè¯­éŸ³ï¼Œ1 æ»´æ»´è¯­éŸ³ï¼Œ2 ä¸è‡ªåŠ¨æ’­æ”¾æ–°è®¢å•ï¼ŒçœŸäººè¯­éŸ³ï¼Œ3 ä¸è‡ªåŠ¨æ’­æ”¾æ–°è®¢å•ï¼Œæ»´æ»´è¯­éŸ³ã€‚
     * @return
     * @Author ZHAOXL
     * @Date 2024/3/7 15:48
     * @Version 1.0
     */
    public static CommonResult<JSONObject> setVoiceType(String deviceID, String voiceType) {
        Map<String, String> params = new HashMap<String, String>();
        String reqTime = String.valueOf(Calendar.getInstance().getTimeInMillis());
        params.put("reqTime", reqTime);
        String securityCode = DigestUtils.md5Hex(PoscomConfig.memberCode + reqTime + PoscomConfig.apiKey + deviceID);
        params.put("securityCode", securityCode);
        params.put("memberCode", PoscomConfig.memberCode);
        params.put("deviceID", deviceID);
        params.put("voiceType", voiceType);
        log.debug("=====请求参数 START=====\r\n" + "---> setVoiceType <---\r\n" + params + "\r\n=====请求参数 END=====");
        String result = PoscomRequest.sendPost("http://api.poscom.cn/apisc/setVoiceType", params);
        log.debug("=====请求返回 START=====\r\n" + result + "\r\n=====请求返回 END=====");
        JSONObject resultObject = JSONObject.parseObject(result);
        return new CommonResult(resultObject);
    }
    /**
     * åˆ é™¤æ‰“印机
     * @param deviceID* ç»ˆç«¯ç¼–号。
     * @return CommonResult
     * @Author ZHAOXL
     * @Date 2024/3/7 9:47
     * @Version 1.0
     */
    public static CommonResult<JSONObject> delDev(String deviceID) {
        Map<String, String> params = new HashMap<String, String>();
        String reqTime = String.valueOf(Calendar.getInstance().getTimeInMillis());
        params.put("reqTime", reqTime);
        String securityCode = DigestUtils.md5Hex(PoscomConfig.memberCode + reqTime + PoscomConfig.apiKey + deviceID);
        params.put("securityCode", securityCode);
        params.put("memberCode", PoscomConfig.memberCode);
        params.put("deviceID", deviceID);
        log.debug("=====请求参数 START=====\r\n" + "---> deldev <---\r\n" + params + "\r\n=====请求参数 END=====");
        String result = PoscomRequest.sendPost("http://api.poscom.cn/apisc/deldev", params);
        log.debug("=====请求返回 START=====\r\n" + result + "\r\n=====请求返回 END=====");
        JSONObject resultObject = JSONObject.parseObject(result);
        return new CommonResult(resultObject);
    }
    /**
     * æŒ‡å®šæ¨¡æ¿æ‰“印
     * @param deviceID* ç»ˆç«¯ç¼–号。
     * @param templetParams* æ¨¡æ¿å‚æ•°
     * @return CommonResult
     * @Author ZHAOXL
     * @Date 2024/3/7 10:19
     * @Version 1.0
     */
    public static CommonResult<JSONObject> templetPrint(String deviceID, TempletParams templetParams) {
        Map<String, String> params = new HashMap<String, String>();
        String reqTime = String.valueOf(Calendar.getInstance().getTimeInMillis());
        params.put("reqTime", reqTime);
        String securityCode = DigestUtils.md5Hex(PoscomConfig.memberCode + deviceID + reqTime + PoscomConfig.apiKey);
        params.put("securityCode", securityCode);
        params.put("memberCode", PoscomConfig.memberCode);
        params.put("deviceID", deviceID);
        params.put("templetID", PoscomConfig.templetId);
        String tData = JSONObject.toJSONString(templetParams);
        params.put("tData", tData);
        params.put("charset","1"); //Default:1, 1:GB18030, 2:GB2312, 3:GBK, 4:UTF-8, 5:Unicode, 6:ISO8859-1, 7:BIG5
        params.put("msgNo","");
        params.put("reprint","0");
        params.put("multi","0");
        params.put("times","");
        params.put("token", "");
        log.debug("=====请求参数 START=====\r\n" + "---> templetPrint <---\r\n" + params + "\r\n=====请求参数 END=====");
        String result = PoscomRequest.sendPost("http://api.poscom.cn/apisc/templetPrint", params);
        log.debug("=====请求返回 START=====\r\n" + result + "\r\n=====请求返回 END=====");
        JSONObject resultObject = JSONObject.parseObject(result);
        return new CommonResult(resultObject);
    }
    /**
     * å‘送语音到打印机
     * @param* ç»ˆç«¯ç¼–号。
     * @param* è¯­éŸ³å†…容。
     * @return
     * @Author ZHAOXL
     * @Date 2024/3/7 10:29
     * @Version 1.0
     */
    public static CommonResult<JSONObject> sendVoice(String deviceID, String voice) {
        Map<String, String> params = new HashMap<String, String>();
        String reqTime = String.valueOf(Calendar.getInstance().getTimeInMillis());
        params.put("reqTime", reqTime);
        String securityCode = DigestUtils.md5Hex(PoscomConfig.memberCode + deviceID + reqTime + PoscomConfig.apiKey);
        params.put("securityCode", securityCode);
        params.put("memberCode", PoscomConfig.memberCode);
        params.put("deviceID", deviceID);
        params.put("voice", voice);
        params.put("token", "");
        log.debug("=====请求参数 START=====\r\n" + "---> sendVoice <---\r\n" + params + "\r\n=====请求参数 END=====");
        String result = PoscomRequest.sendPost("http://api.poscom.cn/apisc/sendVoice", params);
        log.debug("=====请求返回 START=====\r\n" + result + "\r\n=====请求返回 END=====");
        JSONObject resultObject = JSONObject.parseObject(result);
        return new CommonResult(resultObject);
    }
    public static CommonResult<JSONObject> sendMsg(String deviceID) {
        Map<String, String> params = new HashMap<String, String>();
        String reqTime = String.valueOf(Calendar.getInstance().getTimeInMillis());
        params.put("reqTime", reqTime);
        String securityCode = DigestUtils.md5Hex(PoscomConfig.memberCode + deviceID + reqTime + reqTime + PoscomConfig.apiKey);
        params.put("securityCode", securityCode);
        params.put("memberCode", PoscomConfig.memberCode);
        params.put("deviceID", deviceID);
        //-----票据打印机 æ ¼å¼ç±»åž‹:2
        params.put("mode", "2");
        params.put("msgDetail", PoscomPrintData.ReceiptData2);
        //-----票据打印机 æ ¼å¼ç±»åž‹:2
        params.put("charset","1"); //Default:1, 1:GB18030, 2:GB2312, 3:GBK, 4:UTF-8, 5:Unicode, 6:ISO8859-1, 7:BIG5
        params.put("msgNo", reqTime);
        log.debug("=====请求参数 START=====\r\n" + "---> sendMsg <---\r\n" + params + "\r\n=====请求参数 END=====");
        String result = PoscomRequest.sendPost("http://api.poscom.cn/apisc/sendMsg", params);
        log.debug("=====请求返回 START=====\r\n" + result + "\r\n=====请求返回 END=====");
        JSONObject resultObject = JSONObject.parseObject(result);
        return new CommonResult(resultObject);
    }
    public static CommonResult<JSONObject> queryState(String deviceID) {
        Map<String, String> params = new HashMap<String, String>();
        String reqTime = String.valueOf(Calendar.getInstance().getTimeInMillis());
        params.put("reqTime", reqTime);
        String securityCode = DigestUtils.md5Hex(PoscomConfig.memberCode + reqTime + PoscomConfig.apiKey + reqTime);
        params.put("securityCode", securityCode);
        params.put("memberCode", PoscomConfig.memberCode);
        params.put("msgNo", reqTime);
        log.debug("=====请求参数 START=====\r\n" + "---> sendMsg <---\r\n" + params + "\r\n=====请求参数 END=====");
        String result = PoscomRequest.sendPost("http://api.poscom.cn/apisc/queryState", params);
        log.debug("=====请求返回 START=====\r\n" + result + "\r\n=====请求返回 END=====");
        JSONObject resultObject = JSONObject.parseObject(result);
        return new CommonResult(resultObject);
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/poscom/config/PoscomConfig.java
New file
@@ -0,0 +1,27 @@
package com.nuvole.poscom.config;
import com.nuvole.util.PropertyUtil;
/**
 * @Description ä½³åšäº‘打印机配置
 * @Author ZHAOXL
 * @Date 2024/3/6 16:23
 * @Version 1.0
 */
public class PoscomConfig {
    private static String fileName = "poscom.properties";
    // å•†æˆ·ç¼–码
    public static String memberCode;
    // è¯·æ±‚APIKEY
    public static String apiKey;
    // æ¨¡æ¿ç¼–号
    public static String templetId;
    static {
        memberCode = PropertyUtil.getProp(fileName, "memberCode");
        apiKey = PropertyUtil.getProp(fileName, "apiKey");
        templetId = PropertyUtil.getProp(fileName, "templetId");
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/poscom/config/PoscomPrintData.java
New file
@@ -0,0 +1,62 @@
package com.nuvole.poscom.config;
/**
 * @Description ä½³åšäº‘打印机打印信息的内容
 * @Author ZHAOXL
 * @Date 2024/3/6 17:28
 * @Version 1.0
 */
public interface PoscomPrintData {
    //票据 mode:1
    String ReceiptData1 = "佳博云打印,无线聚商机互联网+时代,佳博云打印终端能帮您轻松实现远程打印,让您随时随地接单盈利。终端编号:864031028000000!@#$%^&*()_+~{};'\\,../<>?联系邮箱:service@poscom.cn ç½‘址:http://cloud.poscom.cn";
    //票据 mode:2
    String ReceiptData2 = "佳博云打印,无线聚商机\r\n"
            + "互联网+时代,佳博云打印终端能帮您轻松实现远程打印,让您随时随地接单盈利。\r\n"
            + "<gpBarCode Type=2 Height=20 Position=2>123456789012</gpBarCode>终端编号:864031028000000\r\n"
            + "1: UPC-A:\r\n"
            + "<gpBarCode Type=1 Height=40 Position=0>11111111111</gpBarCode>"
            + "2: JAN13(EAN13):\r\n"
            + "<gpBarCode Type=2 Height=45 Position=1>222222222222</gpBarCode>"
            + "3: JAN8(EAN8):\r\n"
            + "<gpBarCode Type=3 Height=50 Position=2>3333333</gpBarCode>"
            + "4: CODE39:\r\n"
            + "<gpBarCode Type=4 Height=55 Position=3>33333</gpBarCode>"
            + "5: ITF:\r\n"
            + "<gpBarCode Type=5 Height=40 Position=2>444444</gpBarCode>"
            + "6: CODABAR:\r\n"
            + "<gpBarCode Type=6 Height=45 Position=1>A52$1+2-23C</gpBarCode>"
            + "abcdefghijklmnopqrstuvwxyz\r\n"
            + "ABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n"
            + "1234567890\r\n"
            + "!@#$%^&*()_+~{};'\\,../<>?\r\n"
            + "<gpQRCode>http://cloud.poscom.cn</gpQRCode>";
    //票据 mode:3
    String ReceiptData3 = "1D21221B61010D0A4120434146450D0A1B401B6101382F462C204E6F2E382C204A696E677975616E20526F61640D0A4A6964612C205A68756861692C204775616E67646F6E670D0A353139303135204368696E610D0A303735362D3838383838380D0A1B402D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D0D0A494E56204E6F20B5A5BAC5C2EB3A2030312D3130303030310D0A44617465202020C8D5C6DA20203A2030362F31392F3230313720383A33353A323920414D0D0A53616C65736D616E20BEADCAD6C8CB3A20416E64790D0A437573746F6D657220B9CBBFCD20203A20434153480D0A20200D0A1B61011B2108494E564F49434520CAD5BEDD0D0A1B40200D0A4974656D0920202020205174792020202020205072696365202020202020202020202020546F74616C0D0AC6B7C3FB092020202020CAFDC1BF2020202020BCDBC7AE20202020202020202020202020D7DCCAFD0D0A2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D0D0A43617070756363696E6F20202020203120202020202032382E303020202020202020202020202032382E30300D0A4C61747465202020202020202020203120202020202032382E303020202020202020202020202032382E30300D0A0D0A0D0A2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D0D0A20202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020202020201B6102546F74616C3A35362E30300D0A0909090920202020202020202020202020202020202020202020202D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D2D0D0A4772616E6420546F74616C20D7DCCAFD3A35362E30300D0A0D0A0D0A1B401B61015468616E6B20596F752E20506C6561736520436F6D6520416761696E2E0D0A0D0A200D0A1D564200";
    //标签 mode:2
    String LabelData2 = "^XA^MNN^PW480^LL0400^LH0,0^CW1,E:MSUNG.FNT^FS"
            + "^CI28"
            + "^FO30,20 ^A0,30,30 ^FD[190]^FS"
            + "^FO20,50 ^A1,30,30 ^FD目的地^FS"
            + "^FO120,50 ^A1,30,30 ^FD目的地代码^FS"
            + "^FO20,85 ^A1,30,30 ^FD始发地^FS"
            + "^FO120,85 ^A1,30,30 ^FD始发地代码^FS"
            + "^FO300,60 ^A1,36,36 ^FD样张测试^FS"
            + "^FO20,120 ^A1,35,35 ^FD件数^FS"
            + "^FO100,122 ^A0,30,30 ^FD0^FS"
            + "^FO120,122 ^A0,30,30 ^FD0325^FS"
            + "^FO190,122 ^A0,30,30 ^FD16:08^FS"
            + "^FO 330,110 ^A0,50,50 ^FD0-0^FS"
            + "^FO28,200^BY4^BCN,110,Y,N,N,N ^FD>;160637000020^FS"
            + "^FO0,170^GB480,0,4^FS"
            + "^FO280,0^GB,170,4^FS"
            + "^FO0,0^GB480,400,4^FS"
            + "^XZ";
    //标签 mode:3
    String LabelData3 = "EFBBBF5E58415E4D4E4E5E50573438305E4C4C303430305E4C48302C305E4357312C453A4D53554E472E464E545E46530D0A5E434932380D0A5E464F33302C3230205E41302C33302C3330205E46445B3139305D5E46530D0A5E464F32302C3530205E41312C33302C3330205E4644E79BAEE79A84E59CB05E46530D0A5E464F3132302C3530205E41312C33302C3330205E4644E79BAEE79A84E59CB0E4BBA3E7A0815E46530D0A5E464F32302C3835205E41312C33302C3330205E4644E5A78BE58F91E59CB05E4653220D0A5E464F3132302C3835205E41312C33302C3330205E4644E5A78BE58F91E59CB0E4BBA3E7A0815E46530D0A5E464F3330302C3630205E41312C33362C3336205E4644E6A0B7E5BCA0E6B58BE8AF955E46530D0A5E464F32302C313230205E41312C33352C3335205E4644E4BBB6E695B05E46530D0A5E464F3130302C313232205E41302C33302C3330205E4644305E46530D0A5E464F3132302C313232205E41302C33302C3330205E4644303332355E46530D0A5E464F3139302C313232205E41302C33302C3330205E464431363A30385E46530D0A5E464F203333302C313130205E41302C35302C3530205E4644302D305E46530D0A5E464F32382C3230305E4259345E42434E2C3131302C592C4E2C4E2C4E205E46443E3B3136303633373030303032305E46530D0A5E464F302C3137305E47423438302C302C345E46530D0A5E464F3238302C305E47422C3137302C345E46530D0A5E464F302C305E47423438302C3430302C345E46530D0A5E585A";
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/poscom/config/TempletParams.java
New file
@@ -0,0 +1,33 @@
package com.nuvole.poscom.config;
import io.swagger.annotations.ApiModel;
import lombok.Data;
/**
 * @Description æ¨¡æ¿å‚æ•°
 * @Author ZHAOXL
 * @Date 2024/3/7 10:11
 * @Version 1.0
 */
@Data
@ApiModel(value ="模板参数")
public class TempletParams {
    // å•†åº—名称
    private String shopName;
    // äº¤æ˜“流水
    private String payWater;
    // è®¢å•ä»·æ ¼
    private String orderPrice;
    // ä¼˜æƒ åˆ¸æŠµæ‰£
    private String couponFace;
    // ç§¯åˆ†æŠµæ‰£
    private String payIntegral;
    // æ”¶æ¬¾äºº
    private String cashier;
    // æ”¶æ¬¾æ—¶é—´
    private String createTime;
    // å®žæ”¶é‡‘额
    private String payMoney;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/poscom/util/PoscomRequest.java
New file
@@ -0,0 +1,176 @@
package com.nuvole.poscom.util;
import com.alibaba.fastjson.JSONObject;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
/**
 * @Description ä½³åšäº‘打印机请求类
 * @Author ZHAOXL
 * @Date 2024/3/6 16:26
 * @Version 1.0
 */
public class PoscomRequest {
    /**
     * Http Request POST Method
     *
     * @param urlStr è¯·æ±‚URL
     * @param params è¯·æ±‚参数
     * @return
     */
    public static String sendPost(String urlStr, Map<String, String> params){
        String result = "";
        HttpURLConnection conn = null;
        String BOUNDARY = "----------------------------------------------";
        int retry = 0;
        while (retry < 3) {
            result = "";
            try {
                URL url = new URL(urlStr);
                conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(5000);
                conn.setReadTimeout(30000);
                conn.setDoOutput(true);
                conn.setDoInput(true);
                conn.setUseCaches(false);
                conn.setRequestMethod("POST");
                conn.setRequestProperty("Connection", "Keep-Alive");
                conn.setRequestProperty("User-Agent",
                        "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");
                conn.setRequestProperty("Content-Type",
                        "multipart/form-data; boundary=" + BOUNDARY);
                DataOutputStream out = new DataOutputStream(conn.getOutputStream());
                if (params != null) {
                    StringBuffer strBuf = new StringBuffer();
                    Iterator iter = params.entrySet().iterator();
                    while (iter.hasNext()) {
                        Map.Entry entry = (Map.Entry) iter.next();
                        String inputName = (String) entry.getKey();
                        String inputValue = (String) entry.getValue();
                        if (inputValue == null) {
                            continue;
                        }
                        strBuf.append("\r\n").append("--").append(BOUNDARY)
                                .append("\r\n");
                        strBuf.append("Content-Disposition: form-data; name=\""
                                + inputName + "\"\r\n\r\n");
                        strBuf.append(inputValue);
                    }
                    out.write(strBuf.toString().getBytes("UTF-8"));
                }
                String endData = "\r\n--" + BOUNDARY + "--\r\n";
                out.write(endData.getBytes());
                out.flush();
                out.close();
                // å®šä¹‰ BufferedReader输入流来读取URL的响应
                BufferedReader reader = new BufferedReader(new InputStreamReader(
                        conn.getInputStream(),"UTF-8"));
                String line;
                while ((line = reader.readLine()) != null) {
                    result += line;
                }
                reader.close();
                reader = null;
                JSONObject resultObject = JSONObject.parseObject(result);
                int code = (int) resultObject.get("code");
                if (code > 1) {
                    throw new RuntimeException((String) resultObject.get("msg"));
                }
                break;
            } catch (Exception e) {
                retry++;
                System.out.println("=====请求异常 START=====\r\n" + urlStr + "\r\n=====请求异常 END=====");
                e.printStackTrace();
            } finally {
                if (conn != null) {
                    conn.disconnect();
                    conn = null;
                }
            }
        }
        return result;
    }
    /**
     * Http Request GET Method
     *
     * @param urlStr è¯·æ±‚URL
     * @param params è¯·æ±‚参数
     * @return
     */
    public static String sendGet(String urlStr, Map<String, String> params) {
        String result = "", paramsString = "";
        HttpURLConnection conn = null;
        try {
            if (params != null) {
                Iterator iter = params.entrySet().iterator();
                while (iter.hasNext()) {
                    Map.Entry entry = (Map.Entry) iter.next();
                    String inputName = (String) entry.getKey();
                    String inputValue = (String) entry.getValue();
                    if (inputValue == null) {
                        continue;
                    }
                    paramsString += inputName + "=" + inputValue + "&";
                }
            }
            URL url = new URL(urlStr + "?" + paramsString);
            conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(30000);
            conn.setRequestProperty("Connection", "Keep-Alive");
            conn.setRequestProperty("User-Agent",
                    "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");
            // å»ºç«‹å®žé™…的连接
            conn.connect();
            // å®šä¹‰ BufferedReader输入流来读取URL的响应
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    conn.getInputStream()));
            String line;
            while ((line = reader.readLine()) != null) {
                result += line;
            }
            reader.close();
            reader = null;
        } catch (Exception e) {
            System.out.println("=====请求异常 START=====\r\n" + urlStr + "\r\n=====请求异常 END=====");
            e.printStackTrace();
        } finally {
            if (conn != null) {
                conn.disconnect();
                conn = null;
            }
        }
        return result;
    }
    /**
    * èŽ·å–è¿‡åŽ»ç¬¬å‡ å¤©çš„æ—¥æœŸ
    *
    * @param past ä¸Žå½“天差异天数
    * @return
    */
    public static String getPastDate(int past) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) - past);
        Date today = calendar.getTime();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        String result = format.format(today);
        return result;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/poscom/util/PoscomUtil.java
New file
@@ -0,0 +1,36 @@
package com.nuvole.poscom.util;
import java.math.BigDecimal;
/**
 * @Description äº‘打印机工具类
 * @Author ZHAOXL
 * @Date 2024/3/8 16:36
 * @Version 1.0
 */
public class PoscomUtil {
    /**
     * åˆ†è½¬ä¸ºå…ƒ
     * @Author ZHAOXL
     * @Date 2024/3/8 16:48
     * @Version 1.0
     */
    public static String convertToYuan(Long payMoney) {
        if (payMoney == null) {
            return "0";
        }
        BigDecimal totalAmount = new BigDecimal("" + payMoney).divide(new BigDecimal("100"));
        return totalAmount + "";
    }
    /**
     * long转String
     * @Author ZHAOXL
     * @Date 2024/3/8 16:39
     * @Version 1.0
     */
    public static String longToString(Long param) {
        return param == null ? "0" : Long.toString(param);
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/poscom/util/PoscomVoice.java
New file
@@ -0,0 +1,101 @@
package com.nuvole.poscom.util;
import java.math.BigDecimal;
/**
 * @Description è¯­éŸ³å†…容格式化
 * @Author ZHAOXL
 * @Date 2024/3/7 13:15
 * @Version 1.0
 */
public class PoscomVoice {
    /**
     * æ”¯ä»˜å®
     */
    public final static String ZFB = "2007";
    /**
     * å¾®ä¿¡
     */
    public final static String WX = "2008";
    /**
     * äº‘闪付
     */
    public final static String YSF = "2011";
    /**
     * çް金
     */
    public final static String XJ = "2014";
    /**
     * è¯­éŸ³ç±»åž‹ã€‚
     * 2 ä¸è‡ªåŠ¨æ’­æ”¾æ–°è®¢å•ï¼ŒçœŸäººè¯­éŸ³
     */
    public final static String VOICE_TYPE_2 = "2";
    /**
     * è¯­éŸ³ä¸­éƒ¨å†…容
     */
    public final static String VOICE_MIDDLE = "已收款";
    /**
     * åˆ†éš”符
     */
    public final static String SPLIT = "|";
    private final static String unit[][] = {{"", "万", "亿"}, {"", "十", "百", "千"}};
    /**
     * æ ¼å¼åŒ–语音字符串
     * @param strs å‚æ•°
     * @return String
     * @Author ZHAOXL
     * @Date 2024/3/7 13:57
     * @Version 1.0
     */
    public static String format(String strs) {
        StringBuilder sb=new StringBuilder();
        for (char c : strs.toCharArray()) {
            sb.append(c);
            sb.append(SPLIT);
        }
        return sb.toString();
    }
    /**
     * æ ¼å¼åŒ–金额
     * @param price é‡‘额
     * @return String
     * @Author ZHAOXL
     * @Date 2024/3/7 16:07
     * @Version 1.0
     */
    public static String priceFormat(Long price) {
        BigDecimal decimal = new BigDecimal("" + price).divide(new BigDecimal("100"));
        Double n = decimal.doubleValue();
        StringBuilder sb = new StringBuilder();
        String numStr = String.valueOf(n);
        int dotIndex = numStr.indexOf(".");
        String decimalPart = numStr.substring(dotIndex);
        if (".0".equals(decimalPart)) {
            decimalPart = "";
        }
        int integerPart = (int) Math.floor(n);
        if (integerPart == 0) {
            sb.append("0");
        };
        for (int i = 0; i < unit[0].length && integerPart > 0; i++) {
            sb.insert(0, unit[0][i]);
            for (int j = 0; j < unit[1].length && n > 0; j++) {
                if (integerPart % 10 > 0) {
                    sb.insert(0, integerPart % 10 + unit[1][j]);
                }
                integerPart = integerPart / 10;
            }
        }
        sb.append(decimalPart + "元");
        return sb.toString();
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/poscom/util/StringToAscii.java
New file
@@ -0,0 +1,49 @@
package com.nuvole.poscom.util;
import java.io.UnsupportedEncodingException;
public class StringToAscii {
    private static String toHexUtil(int n){
        String rt="";
        switch(n){
            case 10:rt+="A";break;
            case 11:rt+="B";break;
            case 12:rt+="C";break;
            case 13:rt+="D";break;
            case 14:rt+="E";break;
            case 15:rt+="F";break;
            default:
                rt+=n;
        }
        return rt;
    }
    public static String toHex(int n){
        StringBuilder sb=new StringBuilder();
        if(n/16==0){
            return toHexUtil(n);
        }else{
            String t=toHex(n/16);
            int nn=n%16;
            sb.append(t).append(toHexUtil(nn));
        }
        return sb.toString();
    }
    public static String parseAscii(String str){
        StringBuilder sb=new StringBuilder();
        byte[] bs=str.getBytes();
        for(int i=0;i<bs.length;i++) {
            sb.append("0x");
            sb.append(toHex(bs[i]));
        }
        return sb.toString();
    }
    public static void main(String[] args) throws UnsupportedEncodingException {
        String s="10.5";
        System.out.println("转换后的字符串是:"+ StringToAscii.parseAscii(s));
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/poscom/util/StringToGB18030.java
New file
@@ -0,0 +1,29 @@
package com.nuvole.poscom.util;
import java.nio.charset.Charset;
public class StringToGB18030 {
    public static String toGB18030(String str) {
        StringBuilder sb=new StringBuilder("0x");
        Charset gb18030 = Charset.forName("GB18030");
        byte[] bytes = str.getBytes(gb18030);
        for (byte b : bytes) {
            sb.append(Integer.toHexString(b & 0xFF).toUpperCase());
        }
        return sb.toString();
    }
    public static String parseGB18030(String strs) {
        StringBuilder sb=new StringBuilder();
        for (char c : strs.toCharArray()) {
            sb.append(toGB18030(Character.toString(c)));
        }
        return sb.toString();
    }
    public static void main(String[] args) {
        String s = "已收到";
        System.out.println("转换后的字符串是:"+ StringToGB18030.parseGB18030(s));
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/rateLimit/ApiRateLimit.java
New file
@@ -0,0 +1,35 @@
package com.nuvole.rateLimit;
import java.lang.annotation.*;
import java.util.concurrent.TimeUnit;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Documented
public @interface ApiRateLimit {
    /**
     * èµ„源的key,唯一
     * ä½œç”¨ï¼šä¸åŒçš„æŽ¥å£ï¼Œä¸åŒçš„æµé‡æŽ§åˆ¶
     */
    String key() default "";
    /**
     * æœ€å¤šçš„访问限制次数
     */
    double permitsPerSecond();
    /**
     * èŽ·å–ä»¤ç‰Œæœ€å¤§ç­‰å¾…æ—¶é—´
     */
    long timeout();
    /**
     * èŽ·å–ä»¤ç‰Œæœ€å¤§ç­‰å¾…æ—¶é—´,单位(例:分钟/秒/毫秒) é»˜è®¤:毫秒
     */
    TimeUnit timeunit() default TimeUnit.MILLISECONDS;
    /**
     * å¾—不到令牌的提示语
     */
    String msg() default "系统繁忙,请稍后再试.";
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/rateLimit/ApiRateLimitAop.java
New file
@@ -0,0 +1,81 @@
package com.nuvole.rateLimit;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.google.common.util.concurrent.RateLimiter;
import com.nuvole.common.domain.emnu.CommonResultEmnu;
import com.nuvole.common.domain.result.CommonResult;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.Map;
@Slf4j
@Aspect
@Component
public class ApiRateLimitAop {
    /**
     * ä¸åŒçš„æŽ¥å£ï¼Œä¸åŒçš„æµé‡æŽ§åˆ¶
     * map的key为 Limiter.key
     */
    private final Map<String, RateLimiter> limitMap = Maps.newConcurrentMap();
    @Around("@annotation(com.nuvole.rateLimit.ApiRateLimit)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        //拿limit的注解
        ApiRateLimit limit = method.getAnnotation(ApiRateLimit.class);
        if (limit != null) {
            //key作用:不同的接口,不同的流量控制
            String key = limit.key();
            RateLimiter rateLimiter = null;
            //验证缓存是否有命中key
            if (!limitMap.containsKey(key)) {
                // åˆ›å»ºä»¤ç‰Œæ¡¶
                rateLimiter = RateLimiter.create(limit.permitsPerSecond());
                limitMap.put(key, rateLimiter);
                log.info("新建了令牌桶={},容量={}", key, limit.permitsPerSecond());
            }
            rateLimiter = limitMap.get(key);
            // æ‹¿ä»¤ç‰Œ
            boolean acquire = rateLimiter.tryAcquire(limit.timeout(), limit.timeunit());
            // æ‹¿ä¸åˆ°å‘½ä»¤ï¼Œç›´æŽ¥è¿”回异常提示
            if (!acquire) {
                log.debug("令牌桶={},获取令牌失败", key);
                this.responseFail(limit.msg());
                return null;
            }
        }
        return joinPoint.proceed();
    }
    /**
     * @param msg æç¤ºä¿¡æ¯
     */
    private void responseFail(String msg) {
        HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
        CommonResult resultData = new CommonResult(CommonResultEmnu.REQUEST_LIMIT_ERR, msg);
        response.setContentType("application/json;charset=UTF-8");
        PrintWriter out = null;
        try {
            out = response.getWriter();
        } catch (IOException e) {
            e.printStackTrace();
        }
        out.print(JSONObject.toJSONString(resultData));
        out.flush();
        out.close();
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/AESUtil.java
New file
@@ -0,0 +1,57 @@
package com.nuvole.util;
// @formatter:off
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
/**
 *                .-~~~~~~~~~-._       _.-~~~~~~~~~-.
 *            __.'  @Author     ~.   .~    ä»£ç æ— Bug   `.__
 *          .'//     liu.q        \./       (秘籍)      \\`.
 *        .'// [916000612@qq.com]  |   æ¬²ç»ƒç¥žåŠŸ   å¼•刀自宫  \\`.
 *      .'// .-~"""""""~~~~-._     |    _,-~~~~"""""""~-.  \\`.
 *    .'//.-"  2019-04-24     `-.  |  .-'     14:58       "-.\\`.
 *  .'//______.============-..   \ | /   ..-============.______\\`.
 *.'______________________________\|/______________________________`.
 *
 * @Description :
 */
// @formatter:on
public class AESUtil {
    public static String k = "lNQqkL1BfSwt2MKw";
    /*
     * @Author : liu.q [916000612@qq.com]
     * @Date : 2019-04-24 15:01
     * @param mixpd : å¯†ç 
     * @return : java.lang.String åŠ å¯†åŽçš„å¯†ç 
     * @Description : AES加密
     */
    public static String encode(String s){
        if (StrUtil.isBlank(s)) {
            return  "";
        }
        AES aes = SecureUtil.aes(k.getBytes());
        return aes.encryptHex(s);
    }
    /*
     * @Author : liu.q [916000612@qq.com]
     * @Date : 2019-04-24 15:01
     * @param mixpd : åŠ å¯†çš„å¯†ç 
     * @return : java.lang.String è§£å¯†åŽçš„密码
     * @Description :AES解密
     */
    public static String decode(String s){
        if (StrUtil.isBlank(s)) {
            return  "";
        }
        AES aes = SecureUtil.aes(k.getBytes());
        return aes.decryptStr(s, CharsetUtil.CHARSET_UTF_8);
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/AesCbcUtil.java
New file
@@ -0,0 +1,61 @@
package com.nuvole.util;
import java.security.AlgorithmParameters;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
 * å¾®ä¿¡åŠ è§£å¯†å·¥å…·ç±»
 *
 * @author liujun
 * @Date 2019/5/27 17:36
 */
public class AesCbcUtil {
    static {
        // BouncyCastle是一个开源的加解密解决方案,主页在http://www.bouncycastle.org/
        Security.addProvider(new BouncyCastleProvider());
    }
    /**
     * AES解密
     *
     * @param data
     *            //密文,被加密的数据
     * @param key
     *            //秘钥
     * @param iv
     *            //偏移量
     * @param encodingFormat
     *            //解密后的结果需要进行的编码
     * @return
     * @throws Exception
     */
    public static String decrypt(String data, String key, String iv, String encodingFormat) throws Exception {
        // initialize();
        // è¢«åŠ å¯†çš„æ•°æ®
        byte[] dataByte = Base64.decodeBase64(data.getBytes());
        // åŠ å¯†ç§˜é’¥
        byte[] keyByte = Base64.decodeBase64(key.getBytes());
        // åç§»é‡
        byte[] ivByte = Base64.decodeBase64(iv.getBytes());
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
        SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
        AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
        parameters.init(new IvParameterSpec(ivByte));
        // åˆå§‹åŒ–
        cipher.init(Cipher.DECRYPT_MODE, spec, parameters);
        byte[] resultByte = cipher.doFinal(dataByte);
        if (null != resultByte && resultByte.length > 0) {
            String result = new String(resultByte, encodingFormat);
            return result;
        }
        return null;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/ApplicationContextUtil.java
New file
@@ -0,0 +1,35 @@
package com.nuvole.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
 * @ClassName ApplicationContextUtil
 * @Author cy
 * @Date 2023/6/20
 * @Description
 * @Version 1.0
 **/
@Component
public class ApplicationContextUtil implements ApplicationContextAware {
    private static ApplicationContext applicationContext;
    public static Object getBean(String beanName){
        return applicationContext.getBean(beanName);
    }
    public static <T> T getBean(Class<T> clazz){
        return (T)applicationContext.getBean(clazz);
    }
    public ApplicationContext getApplicationContext(){
        return applicationContext;
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        ApplicationContextUtil.applicationContext = applicationContext;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/BaiduUtil.java
New file
@@ -0,0 +1,65 @@
package com.nuvole.util;
import com.baidu.aip.speech.AipSpeech;
import com.baidu.aip.speech.TtsResponse;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONObject;
import java.util.HashMap;
/**
 * ç™¾åº¦æ™ºèƒ½äº‘工具类
 *
 * @Author: lc
 * @Date: 2020/4/27 17:02
 */
@Slf4j
public class BaiduUtil {
    //详细请搜索百度智能云查看
    //设置APPID/AK/SK
    private static final String APP_ID = "19624255";
    private static final String API_KEY = "NqUfTfQUi31Gu5L0fD8YXRWZ";
    private static final String SECRET_KEY = "DrFxoeyOEz23x3NUVb6GMo2PsZTiXk1a";
    /**
     * åˆå§‹åŒ–一个AipSpeech
     */
    private static AipSpeech aipSpeech = new AipSpeech(APP_ID, API_KEY, SECRET_KEY);
    /**
     * è¯­éŸ³åˆæˆ - é€šè¿‡æ–‡å­—转化为mp3
     *
     * @Author: lc
     * @Date: 2020/4/27 17:03
     */
    public static byte[] speech(String text) {
        // å¯é€‰ï¼šè®¾ç½®ç½‘络连接参数
        aipSpeech.setConnectionTimeoutInMillis(2000);
        aipSpeech.setSocketTimeoutInMillis(60000);
        // è°ƒç”¨æŽ¥å£
        HashMap<String, Object> options = new HashMap<>(16);
        /*语速,取值0-15,默认为5中语速*/
        options.put("spd", 5);
        /*音调,取值0-15,默认为5中语调*/
        options.put("pit", 5);
        /*音量,取值0-15,默认为5中音量*/
        options.put("vol", 10);
        // å‘音人选择, åŸºç¡€éŸ³åº“:0为度小美,1为度小宇,3为度逍遥,4为度丫丫,
        // ç²¾å“éŸ³åº“:5为度小娇,103为度米朵,106为度博文,110为度小童,111为度小萌,默认为度小美
        options.put("per", 0);
        TtsResponse res = aipSpeech.synthesis(text, "zh", 1, options);
        byte[] data = res.getData();
        JSONObject res1 = res.getResult();
        if (data != null) {
            return data;
        }
        if (res1 != null) {
            log.info(res1.toString(2));
        }
        return null;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/BeanUtil.java
New file
@@ -0,0 +1,80 @@
package com.nuvole.util;
import org.apache.commons.beanutils.BeanMap;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
// @formatter:off
 /**
 *                .-~~~~~~~~~-._       _.-~~~~~~~~~-.
 *            __.'  @Author     ~.   .~    ä»£ç æ— Bug   `.__
 *          .'//     liu.q        \./       (秘籍)      \\`.
 *        .'// [916000612@qq.com]  |   æ¬²ç»ƒç¥žåŠŸ   å¼•刀自宫  \\`.
 *      .'// .-~"""""""~~~~-._     |    _,-~~~~"""""""~-.  \\`.
 *    .'//.-"  2019-04-07     `-.  |  .-'     19:44       "-.\\`.
 *  .'//______.============-..   \ | /   ..-============.______\\`.
 *.'______________________________\|/______________________________`.
 *
 * @Description : bean map äº’相转换工具类
 */
// @formatter:on
 public class BeanUtil {
     public static <T> Map<String, Object> bean2Map(T bean, Map<String, Object> mp) {
         if (bean == null) {
             return mp;
         }
         try {
             BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
             PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
             for (PropertyDescriptor property : propertyDescriptors) {
                 String k = property.getName();
                 if (!k.equals("class")) {
                     Method getter = property.getReadMethod();// Java中提供了用来访问某个属性的
                     // getter/setter方法
                     Object value;
                     value = getter.invoke(bean);
                     mp.put(k, value);
                 }
             }
         } catch (IntrospectionException e) {
             e.printStackTrace();
         } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
             e.printStackTrace();
         }
         return mp;
     }
     public static <T> T map2Bean(Map<String, Object> mp, Class<T> beanCls) throws IllegalAccessException, InstantiationException, InvocationTargetException, IntrospectionException {
         T t = null;
         BeanInfo beanInfo = Introspector.getBeanInfo(beanCls);
         PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
         t = beanCls.newInstance();
         for (PropertyDescriptor property : propertyDescriptors) {
             String k = property.getName();
             if (mp.containsKey(k)) {
                 Object value = mp.get(k);
                 Method setter = property.getWriteMethod();// Java中提供了用来访问某个属性的
                 // getter/setter方法
                 setter.invoke(t, value);
             }
         }
         return t;
     }
     public static  Map obj2Map(Object obj) {
         if (obj == null) {
             return new BeanMap();
         }
         return new BeanMap(obj);
     }
 }
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/CncpUtil.java
New file
@@ -0,0 +1,832 @@
package com.nuvole.util;
import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSONObject;
import com.nuvole.common.domain.emnu.CommonResultEmnu;
import com.nuvole.common.domain.result.CommonResult;
import cpcn.institution.tools.net.RequestDgtEnvlp;
import cpcn.institution.tools.util.DigitalEnvelopeUtil;
import cpcn.institution.tools.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import payment.api.system.AggregateEnvironment;
import payment.api.system.Gateway4FileEnvironment;
import payment.api.system.PaymentEnvironment;
import payment.api.system.TxMessenger;
import payment.api.tx.TxBaseRequest;
import payment.api.tx.TxBaseResponse;
import payment.api.tx.aggregate.Tx5011Request;
import payment.api.tx.aggregate.Tx5011Response;
import payment.api.tx.foundationaccount.*;
import payment.api.tx.gatheringaccredit.Tx2751Request;
import payment.api.tx.gatheringaccredit.Tx2751Response;
import payment.api.tx.payroll.Tx4600Request;
import payment.api.tx.payroll.Tx4600Response;
import payment.api.tx.statement.Tx1850Request;
import payment.api.tx.statement.Tx1850Response;
import payment.api.util.GUIDGenerator;
import payment.api.vo.ImageInfo;
import payment.api.vo.SplitItem;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;
/**
 * @ClassName CncpUtil
 * @Author cy
 * @Date 2023/7/13
 * @Description
 * @Version 1.0
 **/
@Slf4j
public class CncpUtil {
    public static void initUtil(String configPath) {
        try {
            PaymentEnvironment.initialize(configPath);
        } catch (Exception e) {
            e.printStackTrace();
        }
        CncpUtil.paymentConfigPath = configPath;
    }
    private static String paymentConfigPath;
    public static String getPaymentConfigPath() {
        return paymentConfigPath;
    }
    /**
     * å½±å°ä»¶é‡‡é›†
     *
     * @param businessType ä¸šåŠ¡ç±»åž‹ï¼š 10-壹企付-开户上传身份影印图片(默认)  11-壹企付-实名用户补充影印件 12-壹企付-开户信息修改影印件 20-薪享付-签约上传身份影印图片 30-信用支付-准入授权影像件 40-信用支付-用信申请凭证
     * @return
     */
    public static Tx4600Response tx4600(short businessType, String userId, ArrayList<ImageInfo> imageTypes) {
        Tx4600Request txRequest = new Tx4600Request();
        txRequest.setInstitutionID(PaymentEnvironment.institutionID);
        txRequest.setTxSN(IdGenerator.getUUID());
        txRequest.setBusinessType(businessType + "");
        txRequest.setUserID(userId);
        txRequest.setImageInfoList(imageTypes);
        // 3.执行报文处理
        try {
            txRequest.process();
        } catch (Exception e) {
            e.printStackTrace();
        }
        HashMap<String, String> map = new HashMap<String, String>();
        map.put("Flag", "50");
        putCommonParam(map, txRequest);
        return dealRequestResult(map, Tx4600Response.class);
    }
    /**
     * å¼€æˆ·æŽ¥å£ç”¨äºŽä¸ªäººã€ä¼ä¸šç”¨æˆ·æˆ–个体工商户在机构系统开立银行电子账户环节。
     *
     * @return
     * @throws Exception
     */
    public static Tx4601Response tx4601(String userId) throws Exception {
        // 1.取得参数
        String institutionID = PaymentEnvironment.institutionID;
        String txSN = GUIDGenerator.genGUID();
//        String userID = null;
        String userID = "cy88888888";
        String userType = "11";
        String parentUserID = null;
        String phoneNumber = "17721229769";
        String userName = "常远";
        String credentialType = "0";
        String credentialNumber = "410105199603076114";
        String issDate = "20230130";
        String expiryDate = "20231230";
        String indAddress = "中国河南省郑州市金水区北林路街道";
        String indEmail = "166459@qq.com";
        String province = "41";
        String city = "410100";
        String district = "410105";
//        String credentialAddress = request.getParameter("CredentialAddress");
//        String occupation = request.getParameter("Occupation");
//        String corporationName = "CorporationName";
//        String corporationShort = "CorporationShort";
//        String categoryType = "CategoryType";
//        String corEmail = "CorEmail";
//        String corAddress = "CorAddress";
//        String industryBelongType = "IndustryBelongType";
//        String industry = "Industry";
//        String scale = "Scale";
//        String basicAcctNo = "BasicAcctNo";
//        String approvalNo = "ApprovalNo";
//        String authCapital = "AuthCapital";
//        String businessScope = "BusinessScope";
//        String corType = "CorType";
//        String unifiedSocialCreditCode = "UnifiedSocialCreditCode";
//        String AllLicenceIssDate = "AllLicenceIssDate";
//        String allLicenceExpiryDate = "AllLicenceExpiryDate";
//        String legalPersonName = "LegalPersonName";
//        String legalCredentialType = "LegalCredentialType";
//        String legalCredentialNumber = "LegalCredentialNumber";
//        String legalPersonIssDate = "LegalPersonIssDate";
//        String legalPersonExpiryDate = "LegalPersonExpiryDate";
//        String legalPersonContactNumber = "LegalPersonContactNumber";
//        String legalPersonEmail = "LegalPersonEmail";
//        String shareholder = "Shareholder";
//        String controller = "Controller";
//        String beneficiary = "Beneficiary";
//        String consigneeName = "ConsigneeName";
//        String consigneeCredentialType = "ConsigneeCredentialType";
//        String consigneeCredentialNumber = "ConsigneeCredentialNumber";
//        String consigneeIssDate = "ConsigneeIssDate";
//        String consigneeExpiryDate = "ConsigneeExpiryDate";
//        String consigneeContactNumber = "ConsigneeContactNumber";
////
//        String[] shareholderNames = "ShareholderName";
//        String[] shCredentialTypes = "ShCredentialType";
//        String[] shCredentialNumbers = "ShCredentialNumber";
//        String[] shPersonIssDates = "ShPersonIssDate";
//        String[] shPersonExpiryDates = "ShPersonExpiryDate";
//
//        String managerName = "ManagerName";
//        String managerCredentialType = "ManagerCredentialType";
//        String managerCredentialNumber = "ManagerCredentialNumber";
//        String managerIssDate = "ManagerIssDate";
//        String managerExpiryDate = "ManagerExpiryDate";
//        String managerContactNumber = "ManagerContactNumber";
//        String managerEmail = "ManagerEmail";
//        String managerCredentialAddress = "ManagerCredentialAddress";
//        String managerOccupation = "ManagerOccupation";
//        String retailerRegNumber = "RetailerRegNumber";
//        String retailerName = "RetailerName";
//        String retailerLicenseIssDate = "RetailerLicenseIssDate";
//        String retailerLicenseExpiryDate = "RetailerLicenseExpiryDate";
//        String retailerFormation = "RetailerFormation";
//        String retailerAddress = "RetailerAddress";
//        String retailerProvince = "RetailerProvince";
//        String retailerCity = "RetailerCity";
//        String retailerDistrict = "RetailerDistrict";
//        String retailerBusinessScope = "RetailerBusinessScope";
//
//        String bankAbilityFlag = "BankAbilityFlag";
//        String bindingTxSN = "BindingTxSN";
//        String bankID = "BankID";
//        String bankAccountNumber = "BankAccountNumber";
//        String bankPhoneNumber = "BankPhoneNumber";
//        String cNAPSCode = "CNAPSCode";
//        String branchName = "BranchName";
//        String bankProvince = "BankProvince";
//        String bankCity = "BankCity";
        // 2.创建交易请求对象
        Tx4601Request tx4601Request = new Tx4601Request();
        tx4601Request.setInstitutionID(institutionID);
        tx4601Request.setTxSN(txSN);
        tx4601Request.setUserID(userID);
        tx4601Request.setParentUserID(parentUserID);
        tx4601Request.setUserType(userType);
//        tx4601Request.setAcceptanceConfirmType(acceptanceConfirmType);
//        tx4601Request.setAccountLevel(accountLevel);
//        tx4601Request.setImageCollectionTxSN(imageCollectionTxSN);
//        tx4601Request.setNoticeURL(noticeURL);
        tx4601Request.setBusinessType("10");
        tx4601Request.setPhoneNumber(phoneNumber);
        tx4601Request.setUserName(userName);
        tx4601Request.setCredentialType(credentialType);
        tx4601Request.setCredentialNumber(credentialNumber);
        tx4601Request.setIssDate(issDate);
        tx4601Request.setExpiryDate(expiryDate);
        tx4601Request.setIndAddress(indAddress);
        tx4601Request.setIndEmail(indEmail);
//        tx4601Request.setCredentialAddress(credentialAddress);
//        tx4601Request.setOccupation(occupation);
//        tx4601Request.setCorporationName(corporationName);
//        tx4601Request.setCorporationShort(corporationShort);
//        tx4601Request.setCategoryType(categoryType);
//        tx4601Request.setCorEmail(corEmail);
//        tx4601Request.setCorAddress(corAddress);
        tx4601Request.setProvince(province);
        tx4601Request.setCity(city);
        tx4601Request.setDistrict(district);
//        tx4601Request.setIndustryBelongType(industryBelongType);
//        tx4601Request.setIndustry(industry);
//        tx4601Request.setScale(scale);
//        tx4601Request.setBasicAcctNo(basicAcctNo);
//        tx4601Request.setApprovalNo(approvalNo);
//        tx4601Request.setAuthCapital(authCapital);
//        tx4601Request.setBusinessScope(businessScope);
//        tx4601Request.setCorType(corType);
//        tx4601Request.setUnifiedSocialCreditCode(unifiedSocialCreditCode);
//        tx4601Request.setAllLicenceIssDate(AllLicenceIssDate);
//        tx4601Request.setAllLicenceExpiryDate(allLicenceExpiryDate);
//        tx4601Request.setLegalPersonName(legalPersonName);
//        tx4601Request.setLegalCredentialType(legalCredentialType);
//        tx4601Request.setLegalCredentialNumber(legalCredentialNumber);
//        tx4601Request.setLegalPersonIssDate(legalPersonIssDate);
//        tx4601Request.setLegalPersonExpiryDate(legalPersonExpiryDate);
//        tx4601Request.setLegalPersonContactNumber(legalPersonContactNumber);
//        tx4601Request.setLegalPersonEmail(legalPersonEmail);
//        tx4601Request.setShareholder(shareholder);
//        tx4601Request.setController(controller);
//        tx4601Request.setBeneficiary(beneficiary);
//        tx4601Request.setConsigneeName(consigneeName);
//        tx4601Request.setConsigneeCredentialType(consigneeCredentialType);
//        tx4601Request.setConsigneeCredentialNumber(consigneeCredentialNumber);
//        tx4601Request.setConsigneeIssDate(consigneeIssDate);
//        tx4601Request.setConsigneeExpiryDate(consigneeExpiryDate);
//        tx4601Request.setConsigneeContactNumber(consigneeContactNumber);
//
//        ArrayList<ShareholderPart> shareholderPartsList = null;
//        if(shareholderNames != null && shareholderNames.length > 0){
//            shareholderPartsList = new ArrayList<ShareholderPart>();
//            for(int i = 0; i < shareholderNames.length; i ++){
//                ShareholderPart shareholderPart = new ShareholderPart();
//                shareholderPart.setShareholderName(shareholderNames[i]);
//                shareholderPart.setShCredentialType(shCredentialTypes[i]);
//                shareholderPart.setShCredentialNumber(shCredentialNumbers[i]);
//                shareholderPart.setShPersonIssDate(shPersonIssDates[i]);
//                shareholderPart.setShPersonExpiryDate(shPersonExpiryDates[i]);
//
//                shareholderPartsList.add(shareholderPart);
//            }
//        }
//        tx4601Request.setShareholderPartsList(shareholderPartsList);
//
//        tx4601Request.setManagerName(managerName);
//        tx4601Request.setManagerCredentialType(managerCredentialType);
//        tx4601Request.setManagerCredentialNumber(managerCredentialNumber);
//        tx4601Request.setManagerIssDate(managerIssDate);
//        tx4601Request.setManagerExpiryDate(managerExpiryDate);
//        tx4601Request.setManagerContactNumber(managerContactNumber);
//        tx4601Request.setManagerEmail(managerEmail);
//        tx4601Request.setManagerCredentialAddress(managerCredentialAddress);
//        tx4601Request.setManagerOccupation(managerOccupation);
//        tx4601Request.setRetailerRegNumber(retailerRegNumber);
//        tx4601Request.setRetailerName(retailerName);
//        tx4601Request.setRetailerLicenseIssDate(retailerLicenseIssDate);
//        tx4601Request.setRetailerLicenseExpiryDate(retailerLicenseExpiryDate);
//        tx4601Request.setRetailerFormation(retailerFormation);
//        tx4601Request.setRetailerAddress(retailerAddress);
//        tx4601Request.setRetailerProvince(retailerProvince);
//        tx4601Request.setRetailerCity(retailerCity);
//        tx4601Request.setRetailerDistrict(retailerDistrict);
//        tx4601Request.setRetailerBusinessScope(retailerBusinessScope);
//        tx4601Request.setBankAbilityFlag(bankAbilityFlag);
//        tx4601Request.setBindingTxSN(bindingTxSN);
//        tx4601Request.setBankID(bankID);
//        tx4601Request.setBankAccountNumber(bankAccountNumber);
//        tx4601Request.setBankPhoneNumber(bankPhoneNumber);
//        tx4601Request.setCNAPSCode(cNAPSCode);
//        tx4601Request.setBranchName(branchName);
//        tx4601Request.setBankProvince(bankProvince);
//        tx4601Request.setBankCity(bankCity);
        // 3.执行报文处理
        tx4601Request.process();
        // 4.将参数放置到request对象
 /*       map.put("plainText", tx4601Request.getRequestPlainText());
        map.put("message", tx4601Request.getRequestMessage());
        map.put("signature", tx4601Request.getRequestSignature());
        map.put("txCode", "4601");
        map.put("txName", "开户");*/
        HashMap<String, String> map = new HashMap<String, String>();
        putCommonParam(map, tx4601Request);
        // 5.转向Request.jsp页面
        return dealRequestResult(map, Tx4601Response.class);
    }
    /**
     * ç”¨æˆ·ä¿¡æ¯æŸ¥è¯¢
     *
     * @return
     */
    public static Tx4691Response tx4691(String userId) {
        Tx4691Request txRequest = new Tx4691Request();
        txRequest.setInstitutionID(PaymentEnvironment.institutionID);
        txRequest.setUserID(userId);
        // 3.执行报文处理
        try {
            txRequest.process();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return dealRequestResult(putCommonParam(null, txRequest), Tx4691Response.class);
    }
    public static Tx4691Response tx4691QueryUserInfo(Long businessId, char businessType) {
        return tx4691(getUserId(businessId, businessType));
    }
    /**
     * ç»‘定银行卡,解绑银行卡
     *
     * @param operationFlag    æ“ä½œæ ‡è¯†:  10=绑卡 20=解绑 30=升级
     * @param bankAccountType  è´¦æˆ·ç±»åž‹ï¼š 11=个人账户 12=企业账 æˆ·
     * @param credentialNumber èº«ä»½è¯å·
     * @return
     */
    public static Tx4611Response tx4611(short operationFlag, String userId, short bankAccountType,
                                        String credentialNumber
            , String bankAccountName, String bankAccountNumber, String bankPhoneNumber, String
                                                validDate, String cvn2) {
        // æŸ¥è¯¢ é“¶è¡Œå¡
        //绑定银行 ID  å‚考《银行编码表》
        String bankID = null;
        //卡类型 10借记账户 20贷记账户
        String bankCardType = null;
        Tx2751Response tx2751Response = tx2751(bankAccountNumber);
        if (tx2751Response != null && "2000".equals(tx2751Response.getCode())) {
            bankCardType = tx2751Response.getCardMediaType();
            bankID = tx2751Response.getBankID();
        }
        Tx4611Request txRequest = new Tx4611Request();
        txRequest.setInstitutionID(PaymentEnvironment.institutionID);
        txRequest.setOperationFlag(operationFlag + "");
        txRequest.setBindingTxSN(IdGenerator.getUUID());
        txRequest.setUserID(userId);
        txRequest.setBindingWay("10");
        //账户类型: 11=个人账户 12=企业账 æˆ·
        txRequest.setBankAccountType(bankAccountType + "");
        txRequest.setBankCardType(bankCardType + "");
        txRequest.setCredentialType("0");
        txRequest.setCredentialNumber(credentialNumber);
        txRequest.setBankID(bankID);
        txRequest.setBankAccountName(bankAccountName);
        txRequest.setBankAccountNumber(bankAccountNumber);
        txRequest.setBankPhoneNumber(bankPhoneNumber);
        txRequest.setValidDate(validDate);
        txRequest.setCVN2(cvn2);
        // 3.执行报文处理
        try {
            txRequest.process();
        } catch (Exception e) {
            return null;
        }
        // 4.将参数放置到request对象
        /*map.put("txCode", "4611");
        map.put("txName", "绑卡&解绑(API)");*/
        Tx4611Response tx4611Response = dealRequestResult(putCommonParam(null, txRequest), Tx4611Response.class);
        return tx4611Response;
    }
    public static Tx2751Response tx2751(String accountNumber) {
        // 2.创建交易请求对象
        Tx2751Request txRequest = new Tx2751Request();
        txRequest.setInstitutionID(PaymentEnvironment.institutionID);
        txRequest.setTxSN(IdGenerator.getUUID());
        txRequest.setAccountNumber(accountNumber);
        // 3.执行报文处理
        try {
            txRequest.process();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        Tx2751Response tx4613Response = dealRequestResult(putCommonParam(null, txRequest), Tx2751Response.class);
        return tx4613Response;
    }
    /**
     * ç»‘卡确认
     *
     * @param bindingTxSN  tx4611返回值中 é“¶è¡Œè´¦æˆ·ç»‘定流水号
     * @param businessType ä¸šåŠ¡ç±»åž‹ï¼š 10=绑卡 20=开户
     * @param verifyWay    éªŒè¯æ–¹å¼ï¼š10 çŸ­ä¿¡éªŒè¯ 20 å°é¢æ‰“款验证
     * @return
     */
    public static Tx4613Response tx4613(String bindingTxSN, short businessType, short verifyWay, String smsCode, Long amount) {
        Tx4613Request txRequest = new Tx4613Request();
        txRequest.setInstitutionID(PaymentEnvironment.institutionID);
        txRequest.setBusinessType(businessType + "");
        txRequest.setVerifyWay(verifyWay + "");
        txRequest.setSMSCode(smsCode);
        txRequest.setAmount(Convert.toStr(amount));
        txRequest.setTxSN(bindingTxSN);
        // 3.执行报文处理
        try {
            txRequest.process();
        } catch (Exception e) {
            return null;
        }
        Tx4613Response tx4613Response = dealRequestResult(putCommonParam(null, txRequest), Tx4613Response.class);
        return tx4613Response;
    }
    /**
     * æ”¯ä»˜API
     *
     * @param orderId            è®¢å•id
     * @param payerUserID        ä»˜æ¬¾ç”¨æˆ· ID
     * @param payeeUserID        æ”¶æ¬¾ç”¨æˆ· ID
     * @param paymentWay         æ”¯ä»˜æ–¹å¼: 00=余额支付 02=信用支付 10=快捷支付 12-钱包支付 20=网银支付 30=代收支付 40=聚合支付(停止接入新商户)
     *                           42=条码支付 43-扫码预授权 50=O2O 60=POS(暂不支持) 70=信用支付 80-跳转支付
     * @param amount             å•位:分,
     *                           PaymentWay=42,ScanPaymentType =40 æ—¶,金额可为 0
     *                           PaymentWay=42,InstallmentType=20,ScanPaymentType=20 æ—¶,Amount å¿…须大于等于 100 å…ƒ
     *                           PaymentWay=80,InstallmentType=20,PayType=32 æ—¶,Amount å¿…须大于等于 100 å…ƒ
     * @param pageURL            å›žè°ƒ URL åœ°å€
     * @param goodsName          å•†å“åç§° PaymentWay=02/12/40/42/80 å¿…å¡«
     * @param platformName       å¹³å°åç§° PaymentWay=80 å¿…å¡«
     * @param clientIP           ç”¨æˆ· IP PaymentWay=12,80 å¿…å¡«
     * @param hasSubsequentSplit æ˜¯å¦æœ‰åŽç»­åˆ†è´¦:1-否 2-是 é»˜è®¤ä¸ºå¦
     * @param hasSubsequentSplit æ˜¯å¦æœ‰åŽç»­åˆ†è´¦:1-否 2-是 é»˜è®¤ä¸ºå¦
     * @param remark             å¤‡æ³¨ Payment=30 ä¸”是对公支付业务时,必传
     * @param payWay             æ”¯ä»˜æ–¹å¼ 45=H5支付(PayType=30、31、32、33)
     *                           46=APP æ”¯ä»˜ï¼ˆPayType=30、31、32、33)
     *                           47=手机迷你付(PayType=33)
     *                           48=手机 Pay ï¼ˆPayType=34、35)
     *                           50=JSAPI(PayType=31、32)
     *                           51=小程序支付(PayType=31、32)
     * @param payType            æ”¯ä»˜ç±»åž‹ 30=手机网银 31=微信 32=支付宝 33=银联 34=Apple Pay 35=Android Pay
     * @param subAppID           AppID(商户进件录入)微信必填PayType=31 æ”¯ä»˜å®é€‰å¡«ï¼ˆæ”¯ä»˜å®ç›´è¿žã€æ”¯ä»˜å®å°ç¨‹åºå¿…填)
     * @param subOpenID          ç”¨æˆ· ID å¾®ä¿¡ï¼šopenid æ”¯ä»˜å®ï¼š buyer_user_id ï¼ˆPayWay=50/51 å¿…填)
     * @param redirectSource     è·³è½¬å‰æ¥æº 10=App,20=H5, 30=公众号,40=小程序
     * @param scanPaymentType    æ¡ç æ”¯ä»˜ç±»åž‹: 10=微信 20=支付宝 30=银联 40=聚合码 50=数字人民币支付
     * @param scanPaymentWay     æ¡ç æ”¯ä»˜æ–¹å¼: 41=正扫 42=反扫
     * @param scanPaymentCode    æ¡åæ‰«æ”¯ä»˜æŽˆæƒç  ScanPaymentWay=42 æ—¶å¿…å¡«
     * @param scanPageUrlType    é¡µé¢è·³è½¬æ–¹å¼ 10=公众号 20=小程序 ScanPaymentType=10-微信扫码时此字段为必填项,默认为公众号。
     * @param splitItemsList     åˆ†è´¦ç»“算域
     * @return
     */
    public static Tx5011Response tx5011(String orderId, String payerUserID, String payeeUserID, String paymentWay, Long amount, String pageURL
            , String goodsName, String platformName, String clientIP, Short hasSubsequentSplit, String remark, JSONObject extension
            , String agreeId, String payWay, String payType, String subAppID, String subOpenID, String redirectSource
                                        // æ¡ç å‚æ•°
            , String scanPaymentType, String scanPaymentWay, String scanPaymentCode, String scanPageUrlType
                                        //分账结算参数
            , ArrayList<SplitItem> splitItemsList
    ) {
        Tx5011Request txRequest = new Tx5011Request();
        txRequest.setInstitutionID(PaymentEnvironment.institutionID);
        txRequest.setTxSN(orderId);
        txRequest.setOrderNo(orderId);
        txRequest.setPayerUserID(payerUserID);
        txRequest.setPayeeUserID(payeeUserID);
        txRequest.setPaymentWay(paymentWay);
        txRequest.setAmount(Convert.toStr(amount, "0"));
        txRequest.setPageURL(pageURL);
        txRequest.setGoodsName(goodsName);
        txRequest.setPlatformName(platformName);
        txRequest.setClientIP(clientIP);
        txRequest.setHasSubsequentSplit(Convert.toStr(hasSubsequentSplit, "1"));
        txRequest.setRemark(remark);
        txRequest.setExtension(extension == null ? null : extension.toJSONString());
        //10=快捷支付
        if ("10".equals(paymentWay)) {
            txRequest.setBindingTxSN(agreeId);
        } else if ("80".equals(paymentWay)) {
            // è·³è½¬æ”¯ä»˜
            txRequest.setPayWay(payWay);
            txRequest.setPayType(payType);
            //支付方式限制:10=不限定
            txRequest.setLimitPay("10");
            txRequest.setSubAppID(subAppID);
            txRequest.setSubOpenID(subOpenID);
            //installmentType åˆ†æœŸæŽ§åˆ¶æ ‡è¯† 10-不指定分期 20-指定分期 PayType=32、33,PayWay=45-H5支付时必填
            txRequest.setInstallmentType("10");
            txRequest.setRedirectSource(redirectSource);
        } else if ("42".equals(paymentWay)) {
            //条码支付方式选择域
            txRequest.setScanPaymentType(scanPaymentType);
            txRequest.setScanPaymentWay(scanPaymentWay);
            txRequest.setScanPaymentCode(scanPaymentCode);
            txRequest.setScanPageUrlType(scanPageUrlType);
        }
        txRequest.setSplitItemsList(splitItemsList);
        // 3.执行报文处理
        try {
            txRequest.process();
        } catch (Exception e) {
            e.printStackTrace();
        }
        Tx5011Response tx5011Response = dealRequestResult(putCommonParam(null, txRequest), Tx5011Response.class);
        return tx5011Response;
    }
    /**
     * å¾®ä¿¡h5  jsapi支付
     *
     * @return
     */
    public static Tx5011Response tx5011WxH5Pay(String orderId, String payerUserID, String payeeUserID, Long amount, String pageURL
            , String goodsName, String shopName, String clientIP, Short hasSubsequentSplit, String remark, JSONObject extension
            , String subAppID, String subOpenID, String redirectSource
                                               //分账结算参数
            , ArrayList<SplitItem> splitItemsList
    ) {
        return tx5011(orderId, payerUserID, payeeUserID, "80", amount, pageURL, goodsName, shopName, clientIP, hasSubsequentSplit, remark, extension
                , null, "50", "31", subAppID, subOpenID, redirectSource,
                null, null, null, null
                , splitItemsList);
    }
    /**
     * å¾®ä¿¡å°ç¨‹åºæ”¯ä»˜
     *
     * @return
     */
    public static Tx5011Response tx5011WxMiniPay(String orderId, String payerUserID, String payeeUserID, Long amount, String pageURL
            , String goodsName, String shopName, String clientIP, Short hasSubsequentSplit, String remark, JSONObject extension
            , String subAppID, String subOpenID, String redirectSource
                                                 //分账结算参数
            , ArrayList<SplitItem> splitItemsList
    ) {
        return tx5011(orderId, payerUserID, payeeUserID, "80", amount, pageURL, goodsName, shopName, clientIP, hasSubsequentSplit, remark, extension
                , null, "51", "31", subAppID, subOpenID, redirectSource,
                null, null, null, null
                , splitItemsList);
    }
    /**
     * é“¶è¡Œå¡å¿«æ·æ”¯ä»˜
     *
     * @return
     */
    public static Tx5011Response tx5011BankCardKjPay(String orderId, String payerUserID, String payeeUserID, Long amount, String pageURL
            , String goodsName, String shopName, String clientIP, Short hasSubsequentSplit, String remark, JSONObject extension
            , String agreeId
                                                     //分账结算参数
            , ArrayList<SplitItem> splitItemsList) {
        return tx5011(orderId, payerUserID, payeeUserID, "10", amount, pageURL, goodsName, shopName, null, hasSubsequentSplit, remark, extension
                , agreeId, null, null, null, null, null,
                null, null, null, null
                , splitItemsList);
    }
    public static Tx1850Response tx1850(LocalDate billDate) throws Exception {
        // 1.取得参数
//        String batchNO = request.getParameter("BatchNO");
//        String payeeUserID = request.getParameter("PayeeUserID");
        // 2.创建交易请求对象
        Tx1850Request txRequest = new Tx1850Request();
        txRequest.setInstitutionID(PaymentEnvironment.institutionID);
//        txRequest.setBatchNO(batchNO);
        txRequest.setBillDate(billDate.toString().replace("-", ""));
//        txRequest.setPayeeUserID(payeeUserID);
        // 3.执行报文处理
        txRequest.process();
        // 4.将参数放置到request对象
        HashMap<String, String> map = new HashMap<String, String>();
       /* map.put("plainText", txRequest.getRequestPlainText());
        map.put("message", txRequest.getRequestMessage());
        map.put("signature", txRequest.getRequestSignature());
        map.put("txCode", "1850");
        map.put("txName", "对账文件下载");*/
        map.put("Flag", "50");
        putCommonParam(map, txRequest);
        return dealRequestResult(map, Tx1850Response.class);
    }
    /**
     * ç”¨äºŽæŸ¥è¯¢è´¦æˆ·ä¸­å¯è§£å†»çš„金额信息
     *
     * @param businessId
     * @return
     */
    public static Tx4660Response tx4660QueryDjBalance(Long businessId, char businessType) {
        return tx4660(getUserId(businessId, businessType));
    }
    private static Tx4660Response tx4660(String userId) {
        Tx4660Request txRequest = new Tx4660Request();
        txRequest.setInstitutionID(PaymentEnvironment.institutionID);
        txRequest.setUserID(userId);
        // 3.执行报文处理
        try {
            txRequest.process();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return dealRequestResult(putCommonParam(null, txRequest), Tx4660Response.class);
    }
    /**
     * ä¸šåŠ¡ID ç”Ÿæˆè§„则
     *
     * @param businessId
     * @param businessType
     * @return
     */
    public static String getUserId(Long businessId, char businessType) {
        return businessType + "" + businessId;
    }
    /**
     * æ”¾å…¥å…¬å…±å‚æ•°
     *
     * @param map
     * @param baseRequest
     */
    public static HashMap<String, String> putCommonParam(HashMap<String, String> map, TxBaseRequest baseRequest) {
        if (map == null) {
            map = new HashMap<>();
        }
        map.put("plainText", baseRequest.getRequestPlainText());
        map.put("message", baseRequest.getRequestMessage());
        map.put("signature", baseRequest.getRequestSignature());
        map.put("txCode", baseRequest.getTxCode());
        map.put("isDgEnv", PaymentEnvironment.isDgEnv);
        map.put("dgtlEnvlp", baseRequest.getDgtlEnvlp());
        map.put("signAlgorithm", baseRequest.getSignAlgorithm());
        map.put("signSN", baseRequest.getSignSN());
        map.put("encryptSN", baseRequest.getEncryptSN());
        map.put("institutionID", PaymentEnvironment.institutionID);
        return map;
    }
    /**
     * å‘送请求,解析请求
     *
     * @param map
     * @return
     */
    public static <T extends TxBaseResponse> T
    dealRequestResult(HashMap<String, String> map, Class<T> responseType) {
        try {
            // èŽ·å¾—å‚æ•°message和signature
            String message = map.get("message");
            String signature = map.get("signature");
            String txCode = map.get("txCode");
            String flag = map.get("Flag");
            // ä¸Žæ”¯ä»˜å¹³å°è¿›è¡Œé€šè®¯
            TxMessenger txMessenger = new TxMessenger();
            String[] respMsg = null;
            // Flag=10:cmb, 20:paymentAccount
            RequestDgtEnvlp requestDgtEnvlp = new RequestDgtEnvlp();
            if ("YES".equals(map.get("isDgEnv"))) {
                requestDgtEnvlp.setIsDgEnv(map.get("isDgEnv"));
            } else {
                requestDgtEnvlp.setIsDgEnv("NO");
            }
            requestDgtEnvlp.setDgtlEnvlp(map.get("dgtlEnvlp"));
            requestDgtEnvlp.setSignAlgorithm(map.get("signAlgorithm"));
            requestDgtEnvlp.setSignSN(map.get("signSN"));
            requestDgtEnvlp.setEncryptSN(map.get("encryptSN"));
            requestDgtEnvlp.setInstitutionID(map.get("institutionID"));
            if ("50".equals(flag)) {
                respMsg = txMessenger.send(message, signature, requestDgtEnvlp, Gateway4FileEnvironment.GATEWAY4FILE_URL);
            } else if ("90".equals(flag)) {
                respMsg = txMessenger.send(message, signature, requestDgtEnvlp, AggregateEnvironment.aggregateTxURL);// 0:message;
            } else {
                respMsg = txMessenger.send(message, signature, requestDgtEnvlp);// 0:message;
            }
            String plainText;
            if ("YES".equals(respMsg[2])) {
                //如果响应是数字信封,对消息进行对称解密
                try {
                    log.info("开始对响应消息做对称解密。。。。。。");
                    if ("YES".equals(PaymentEnvironment.isDoubleCert)) {
                        log.info("双证解密。。。。。。");
                        respMsg[0] = DigitalEnvelopeUtil.doubleDecryptResponse(respMsg[0], respMsg[3], respMsg[5], respMsg[6]);
                    } else {
                        respMsg[0] = DigitalEnvelopeUtil.decryptResponse(respMsg[0], respMsg[3], respMsg[5], respMsg[6]);
                    }
                    plainText = respMsg[0];
                    respMsg[0] = cpcn.institution.tools.util.Base64.encode(respMsg[0], "UTF-8");
                    respMsg[0] = respMsg[0] + "," + respMsg[5] + "," + respMsg[4] + "," + respMsg[2];
                    log.info("响应消息做对称解密完成。。。。。。");
                    log.info("响应消息报文:[" + plainText + "]");
                } catch (Exception e) {
                    System.out.println("异常内容:" + e);
                    throw new Exception(e + "对称解密异常!");
                }
            } else {
                // 1:signature
                plainText = new String(cpcn.institution.tools.util.Base64.decode(respMsg[0]), "UTF-8");
                if (StringUtil.isNotEmpty(respMsg[5])) {
                    respMsg[0] = respMsg[0] + "," + respMsg[5] + "," + respMsg[4] + "," + respMsg[2];
                }
            }
            log.debug("[message]=[" + respMsg[0] + "]");
            log.debug("[signature]=[" + respMsg[1] + "]");
            log.debug("[plainText]=[" + plainText + "]");
            // å°†ç»“果保存在request中,以备在Response.jsp页面显示
            return getResponse(respMsg[0], respMsg[1], responseType);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * åå°„创建返回值对象
     *
     * @param responseMessage
     * @param responseSignature
     * @param responseType
     * @param <T>
     * @return
     */
    private static <T extends TxBaseResponse> T
    getResponse(String responseMessage, String responseSignature, Class<T> responseType) {
        // åˆ›å»ºå¹¶è¿”回对应的子类对象
        T response = null;
        try {
            Constructor<T> constructor = responseType.getDeclaredConstructor(String.class, String.class);
            response = constructor.newInstance(responseMessage, responseSignature);
        } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return response;
    }
    //````````````````````````````````````````````````````````````
    public static CommonResult<Tx4611Response> testTx4611() {
        String userId = "cy88888888";
        Tx4611Response tx4611Response = tx4611((short) 10, userId, (short) 11, "410105199603076114",
                "常远", "6255861234567897910", "17721229769", null, null);
        if ("2000".equals(tx4611Response.getCode())) {
            String status = tx4611Response.getStatus();
            if ("40".equals(status)) {
                return new CommonResult(CommonResultEmnu.ERROR, tx4611Response.getResponseMessage());
            } else {
                return new CommonResult(tx4611Response);
            }
//            if ("15".equals(status)) {
//                log.info("待短信验证,此状态时支付平台已经给用户手机号发送短信验证码,机构系统需要调用4613-绑卡确认接口回填短信验证码,支付平台验证后返回绑卡结果");
//            } else if ("17".equals(status)) {
//                log.info("待被动打款验证,表示支付平台没有向企业账户进行打款,机构系统可通过 4616-绑卡查询接口查询企业账户绑卡状态");
//            } else if ("18".equals(status)) {
//                log.info("被动已打款待验证,表示支付平台已向企业账户进行打款,机构系统可以调用 4613-绑卡确认接口回填打款金额,支付平台验证后返回绑卡结果。");
//            } else if ("40".equals(status)) {
//                log.info("失败,表示用户提交的身份信息有误,需要核实后重新发起绑卡请求");
//            }
        } else {
            return new CommonResult(CommonResultEmnu.ERROR, tx4611Response.getMessage());
        }
    }
    /**
     * ç»‘卡测试
     */
    public static CommonResult testTx4613(String bindingTxSN) {
        Tx4613Response tx4613Response = tx4613(bindingTxSN, (short) 10, (short) 10, "134679", null);
        if (!"2000".equals(tx4613Response.getCode())) {
            return new CommonResult(CommonResultEmnu.ERROR, tx4613Response.getMessage());
        }
        return new CommonResult();
    }
    /**
     * ç»‘卡测试
     */
    public static CommonResult testTx2751() {
        Tx2751Response response = tx2751("6255861234567897910");
        if (!"2000".equals(response.getCode())) {
            return new CommonResult(CommonResultEmnu.ERROR, response.getMessage());
        }
        return new CommonResult();
    }
    public static CommonResult test4660() {
        Tx4660Response response = tx4660("cy88888888");
        if (!"2000".equals(response.getCode())) {
            return new CommonResult(CommonResultEmnu.ERROR, response.getMessage());
        }
        return new CommonResult();
    }
    public static void main(String[] args) {
        // åˆå§‹åŒ–支付环境
        try {
            PaymentEnvironment.initialize("D:\\MyProjects\\jmy\\ecosphere\\ecosphere-merchant\\src\\main\\resources\\cncpConfig\\payment");
        } catch (Exception e) {
            e.printStackTrace();
        }
        String userId = "cy88888888";
        tx4691(userId);
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/CodeUtil.java
New file
@@ -0,0 +1,56 @@
package com.nuvole.util;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
/**
 * ç ç”Ÿæˆç±»
 *
 * @Author: lc
 * @Date: 2019/6/13 10:29
 */
public class CodeUtil {
    /**
     * è‡ªå®šä¹‰code++
     *
     * @param maxCode    æœ¬çº§æœ€å¤§code
     * @param parentCode çˆ¶çº§code
     * @Author: lc
     * @Date: 2019/6/13 10:32
     */
    public static String getCode(String maxCode, String parentCode) {
        if (StrUtil.isBlank(parentCode)) {
            parentCode = "";
        }
        if (StrUtil.isBlank(maxCode)) {
            return parentCode + "001";
        } else {
            maxCode = Convert.toStr(Convert.toLong(maxCode) + 1);
            for (int i = 0; i < maxCode.length() % 3; i++) {
                maxCode = "0" + maxCode;
            }
            return maxCode;
        }
    }
    /**
     * ç”Ÿæˆæ—¥æœŸæ ¼å¼çš„编号
     *
     * @Author: lc
     * @Date: 2019/7/2 15:19
     */
    public static String getTimeCode() {
        String time = DateUtil.format(DateUtil.date(), "yyyyMMddHHmmss");
        return time + RandomUtil.randomNumbers(4);
    }
    public static void main(String[] args) {
        System.out.println(getCode("002001", "002"));
        System.out.println(getTimeCode());
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/CommonUtil.java
New file
@@ -0,0 +1,294 @@
package com.nuvole.util;
// @formatter:off
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.crypto.SecureUtil;
import com.alibaba.fastjson.JSON;
import com.nuvole.constants.SystemConstants;
import jakarta.servlet.ServletInputStream;import jakarta.servlet.http.HttpServletRequest;import jakarta.servlet.http.HttpServletResponse;import org.apache.commons.text.StringEscapeUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
 * .-~~~~~~~~~-._       _.-~~~~~~~~~-.
 * __.'  @Author     ~.   .~    ä»£ç æ— Bug   `.__
 * .'//     liu.q        \./       (秘籍)      \\`.
 * .'// [916000612@qq.com]  |   æ¬²ç»ƒç¥žåŠŸ   å¼•刀自宫  \\`.
 * .'// .-~"""""""~~~~-._     |    _,-~~~~"""""""~-.  \\`.
 * .'//.-"  2019-04-09     `-.  |  .-'     10:48       "-.\\`.
 * .'//______.============-..   \ | /   ..-============.______\\`.
 * .'______________________________\|/______________________________`.
 *
 * @Description :
 */
// @formatter:on
public class CommonUtil {
    /**
     * @Author : liuq
     * @Date : Create in 2018/7/1 ä¸Šåˆ1:20
     * @Description : é©¼å³°è½¬ä¸‹åˆ’线
     */
    public static String camel2Underline(String line) {
        return StrUtil.toUnderlineCase(line);
    }
    /*
     * @Author : liu.q [916000612@qq.com]
     *
     * @Date : 2019-04-29 16:45
     *
     * @Description : ä¸‹åˆ’线转驼峰
     */
    public static String Underline2camel(String para) {
        return StrUtil.toCamelCase(para);
    }
    /**
     * @Author : liu.q
     * @Date : 2019-03-01 09:49
     * @Description : èŽ·å–request
     */
    public static HttpServletRequest getRequest() {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        return request;
    }
    /**
     * @Author : liu.q
     * @Date : 2019-03-01 09:49
     * @Description : response
     */
    public static HttpServletResponse getResponse() {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
                .getRequestAttributes();
        HttpServletResponse response = requestAttributes.getResponse();
        return response;
    }
    /**
     * @Author : liu.q
     * @Date : 2019-03-01 09:51
     * @Description : èŽ·å–è®¿é—®åœ°å€
     */
    public static String getHost() {
        HttpServletRequest request = getRequest();
        String scheme = request.getHeader("X-Forwarded-Scheme");
        if (scheme == null) {
            scheme = request.getScheme();
        }
        String port = request.getHeader("X-Forwarded-port");
        if (port == null) {
            port = request.getServerPort() + "";
        }
        if ("443".equals(port) || "80".equals(port)) {
            return scheme + "://" + request.getServerName();
        }
        return scheme + "://" + request.getServerName() + ":" + port;// +request.getRequestURI();
    }
    /**
     * èŽ·å–è¯·æ±‚å‚æ•°
     *
     * @return
     */
    public static Map getParameterMap() {
        // å‚æ•°Map
        Map properties = CommonUtil.getRequest().getParameterMap();
        // è¿”回值Map
        Map returnMap = new HashMap();
        Iterator entries = properties.entrySet().iterator();
        Map.Entry entry;
        String name = "";
        String value = "";
        while (entries.hasNext()) {
            entry = (Map.Entry) entries.next();
            name = (String) entry.getKey();
            Object valueObj = entry.getValue();
            if (null == valueObj) {
                continue;
            } else if (valueObj instanceof String[]) {
                String[] values = (String[]) valueObj;
                for (int i = 0; i < values.length; i++) {
                    value = values[i] + ",";
                }
                value = value.substring(0, value.length() - 1);
            } else {
                value = valueObj.toString();
                // å½“value为string empty为有效值 by zxc on 2020/5/11 15:00
                if ("".equals(value)) {
                    continue;
                }
            }
            returnMap.put(name, value);
        }
        return returnMap;
    }
    public static String getExportSign(String url, String timestamp) {
        System.out.println("is url:" + URLUtil.getPath(url));
        return Convert
                .toStr(SecureUtil.md5(SecureUtil.md5(URLUtil.getPath(url) + timestamp) + SystemConstants.EXPORT_SIGN_K).hashCode());
    }
    public static String listToString(List<String> items) {
        String result = "";
        if (items != null && items.size() > 0) {
            for (int i = 0; i < items.size(); i++) {
                if (i == 0) {
                    result += items.get(i);
                } else {
                    result += "," + items.get(i);
                }
            }
        }
        return result;
    }
    public static <T> T getObjFromReq(Class<T> clazz) {
        String s = JSON.toJSONString(getParameterMap());
        return JSON.parseObject(StringEscapeUtils.unescapeHtml4(s), clazz);
    }
    public static <T> T getObjFromReqBody(Class<T> clazz) {
        String jsonStr = getRequestBody();
        return JSON.parseObject(StringEscapeUtils.unescapeHtml4(jsonStr), clazz);
    }
    /**
     * èŽ·å–request body值
     *
     * @param
     * @return
     */
    private static String getRequestBody() {
        HttpServletRequest request = getRequest();
        try {
            return getStringFromInputStream(request.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static String getStringFromInputStream(ServletInputStream stream) throws IOException {
        StringBuilder sb = new StringBuilder();
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
            char[] ch = new char[1024];
            int bytesRead;
            while ((bytesRead = reader.read(ch)) != -1) {
                sb.append(ch, 0, bytesRead);
            }
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return sb.toString();
    }
    /**
     * èŽ·å–ç”¨æˆ·æ ‡è¯†
     *
     * @return
     */
    public static String getUserAgent() {
        HttpServletRequest request = getRequest();
        return request.getHeader("User-Agent");
    }
    /**
     * èŽ·å–å®¢æˆ·ç«¯æ ‡è¯†
     *
     * @return 1.支付宝-小程序, 2.支付宝-生活号, 3.微信-小程序, 4.微信-公众号
     */
    public static String getClientType() {
        HttpServletRequest request = getRequest();
        return request.getHeader("CLIENT-TYPE");
    }
    /**
     * æ˜¯å¦ä¸ºå¾®ä¿¡å°ç¨‹åº
     *
     * @return
     */
    public static boolean isWxMin() {
        String userAgent = getUserAgent();
        return userAgent.contains("MiniProgram");
    }
    /**
     * æ˜¯å¦ä¸ºå¾®ä¿¡å†…置浏览器
     *
     * @return
     */
    public static boolean isWxBro() {
        String userAgent = getUserAgent();
        return userAgent.contains("MicroMessenger");
    }
    /**
     * æ˜¯å¦ä¸ºæ”¯ä»˜å®å†…置浏览器
     *
     * @return
     */
    public static boolean isAliBro() {
        String userAgent = getUserAgent();
        return userAgent.contains("Alipay");
    }
    /**
     * æ˜¯å¦ä¸ºæ”¯ä»˜å®å°ç¨‹åºå®¢æˆ·ç«¯
     *
     * @return
     */
    public static boolean isAliMin() {
        String userAgent = getUserAgent();
        String clientType = getClientType();
        return userAgent.contains("Alipay") && SystemConstants.APP_TYPE_ALI_MINI.equals(clientType);
    }
    /**
     * æ˜¯å¦ä¸ºç¿¼æ”¯ä»˜
     *
     * @return
     */
    public static boolean isBestPayBro() {
        String userAgent = getUserAgent();
        return userAgent.contains("Bestpay");
    }
    /**
     * æ˜¯å¦ä¸ºäº‘闪付
     *
     * @return
     */
    public static boolean isCloudPayBro() {
        String userAgent = getUserAgent();
        return userAgent.contains("CloudPay");
    }
    public static boolean isUnionPayBro() {
        String userAgent = getUserAgent();
        return userAgent.contains("UnionPay");
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/ComputeUtil.java
New file
@@ -0,0 +1,102 @@
package com.nuvole.util;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
/**
 * è®¡ç®—工具类
 *
 * @Author: lc
 * @Date: 2019/5/23 19:10
 */
public class ComputeUtil {
    /**
     * è®¡ç®—百分比
     *
     * @param num   å æ¯”值
     * @param total æ€»æ•°
     * @param scale å°æ•°
     * @Author: lc
     * @Date: 2019/8/22 10:32
     */
    public static String percentum(double num, double total, int scale) {
        if (num == 0 || total == 0) {
            return "0";
        }
        DecimalFormat df = (DecimalFormat) NumberFormat.getInstance();
        //可以设置精确几位小数
        df.setMaximumFractionDigits(scale);
        //模式 ä¾‹å¦‚四舍五入
        df.setRoundingMode(RoundingMode.HALF_UP);
        double accuracy_num = num / total * 100;
        return df.format(accuracy_num);
    }
    /**
     * èŽ·å–ä¸¤ä¸ªæ—¥æœŸä¹‹é—´æ‰€æœ‰æ—¥æœŸï¼ˆå¹´æœˆæ—¥ï¼‰
     *
     * @Author: lc
     * @Date: 2019/8/23 13:41
     */
    public static List<String> getBetweenDates(String begin, String end, String formatString) {
        SimpleDateFormat format = new SimpleDateFormat(formatString);
        List<String> result = new ArrayList<String>();
        try {
            Calendar tempStart = Calendar.getInstance();
            tempStart.setTime(format.parse(begin));
            tempStart.add(Calendar.DAY_OF_YEAR, 1);
            Calendar tempEnd = Calendar.getInstance();
            tempEnd.setTime(format.parse(end));
            result.add(format.format(format.parse(begin)));
            while (tempStart.before(tempEnd)) {
                result.add(format.format(tempStart.getTime()));
                tempStart.add(Calendar.DAY_OF_YEAR, 1);
            }
            result.add(format.format(format.parse(end)));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /**
     * èŽ·å–ä¿©ä¸ªæ—¥æœŸé—´çš„æ‰€æœ‰æ—¥æœŸï¼ˆå¹´æœˆï¼‰
     *
     * @Author: lc
     * @Date: 2019/8/24 16:31
     */
    public static List<String> getBetweenMonths(String minDate, String maxDate, String formatString) {
        ArrayList<String> result = new ArrayList<String>();
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(formatString);//格式化为年月
            Calendar min = Calendar.getInstance();
            Calendar max = Calendar.getInstance();
            min.setTime(sdf.parse(minDate));
            min.set(min.get(Calendar.YEAR), min.get(Calendar.MONTH), 1);
            max.setTime(sdf.parse(maxDate));
            max.set(max.get(Calendar.YEAR), max.get(Calendar.MONTH), 2);
            Calendar curr = min;
            while (curr.before(max)) {
                result.add(sdf.format(curr.getTime()));
                curr.add(Calendar.MONTH, 1);
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return result;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/CryptoUtil.java
New file
@@ -0,0 +1,55 @@
package com.nuvole.util;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
/**
 * @author ChenLong
 * @version 1.0
 * @ClassName CryptoUtil
 * @date 2019/5/6 11:47
 * @Description åŠ å¯†ï¼Œè§£å¯†å·¥å…·ç±»
 */
public class CryptoUtil {
    // ç³»ç»Ÿå†…部使用
    private static final String PUBK = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCTREknOkrusbeH7kBe3mSw4AwVT438IWmX/jKmcvYxaAWRrBJiMl7gk37L78HBG/ZstLLcdKBYYdj/5cvVWDQfv+uxbv/piZhOmQej98jWIXEA8aFEk724nFRJ7nfcEhHSWfzbTfgZw0KDO1mWdjWHnHIx/MtD0HIFFIyzg3aO7wIDAQAB";
    private static final String PRIK = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAJNESSc6Su6xt4fuQF7eZLDgDBVPjfwhaZf+MqZy9jFoBZGsEmIyXuCTfsvvwcEb9my0stx0oFhh2P/ly9VYNB+/67Fu/+mJmE6ZB6P3yNYhcQDxoUSTvbicVEnud9wSEdJZ/NtN+BnDQoM7WZZ2NYeccjH8y0PQcgUUjLODdo7vAgMBAAECgYBVu5Y+0Q/Yf/uRleFBmYTS98vxCBxnoOgBRUolXp32y1EaqisVoa9cXGGfxhdtHaNLS7Mo5niGm4giCZytuii1RO8kVXDAgMM2KRVIkOj2yTKJPRxgh9u0ja18MrpkCGnWYBYiU6irq+Ugu9+srkQSefPFX47U2QbLtxV5XF4iuQJBAMgh3FvAwV99tqGe+z+JtySRdtqEfK0M3Z4vpyqSH6miT1CbEqT942rPHbIUUqLwf6VMjxTYACwcLpVy/k3xrg0CQQC8YHkLxzE52o/wg817Rwwh0LpXz6dghQK7g6eMQyUi4C2PiOmqxpCFk2DOR0R4Rcw6SKxB4XQgyqM2zrdBsa3rAkEAtQcz/WbpQ8hCOAXHvNyEZjaSbOzkneACY0E1k+Njcp0X45CyF750RLweX2PUsACdZddPoYoU9dF0Lck70SNozQJBAIPBPiicw7NhSTfCGCBXSwcDxLHSTZFWttiMds3F0N2ZyoQQEM8fXsnukND2S8+LkhJZ7hGOLPkaghm9b7OFIM0CQEDvsXNcmF2+SWfFJDR57tblAIsOSLGeODWnlzaaFUFDHlbrCkexLJ+o1+C4xHMzUMHHMjHDJVpKt2EJdkfh4xU=";
    // ç¬¬ä¸‰æ–¹ äººæ‰æŽ¥å£
    private static final String RCMPUBK = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCqmYlQIg1eA6bavzgUx6CjlPcJpoTmqY/lBph8VRYH2G0ez/7Yl/Ooc5J9/1nhJ7Ql4u7TRjYZrgw8z3Ul1/kQtel4GQdGOEadb1mmzHRlp5xeqiwj5/fJV+8CbqMNj+mobIJVbdV/oRpxTQMck3NRH1X52LsVFBixp079eGoSawIDAQAB";
    private static final String RCMPRIK = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAKqZiVAiDV4Dptq/OBTHoKOU9wmmhOapj+UGmHxVFgfYbR7P/tiX86hzkn3/WeEntCXi7tNGNhmuDDzPdSXX+RC16XgZB0Y4Rp1vWabMdGWnnF6qLCPn98lX7wJuow2P6ahsglVt1X+hGnFNAxyTc1EfVfnYuxUUGLGnTv14ahJrAgMBAAECgYEAo/7kWPvjDbVE+JNJPfCJI7dXoxdIOtRVVzx36U2B2BjdDPm1alDoEc7HzAdkR2T7cFAudTrRVu5RJUPowXBUI4H/m19JrJiYKqlmhUUrlf+TxFajkUPC1fUSGKzj+Oh/H76/unZbOmhp+TMkopyeI0tU7xmXHuEZk9i2Zq1z+oECQQDbDPa9PpOFLdc0iONfMlYSh4wXUVfhiH2gQ6G10Mf3K6KN6ESnwULWuhrE/N7Zw6zuZBdEqveanJ6NVcaIR8Y5AkEAx2BeQSO0WSkUgKNB9xaVutDddDuKferRpomcecUEf2LN/z3u4DE7P3O9Gwi4iQTHrxMhfLq/VKa8yJjUv5a9wwJAYTk/yn8buuC9w/N996K/0TmYVEEmYFPUbm2WOLySBIK5g4Kz9kExCV1QxF34C29uMeD68t9vRpB9Tv3jQFmbAQJAKu2t/bqRV21H89azGl+rh5j3RdKYJDqOP5x7q6BnMoJ0tlOAfpc7GZNzEUIUcbQsxp6I5FFVZwWrukll7YaofwJBALRdRoP+FOkJv+MMP8Dytxe8c3Cy1OIEkRglPDydmwDoAp+sObm80vKgmfR/llsK2Z1DppvDRkpVHwWtHwZfqZQ=";
    public static String rsaEncode(String s, Short flag) {
        RSA rsa = null;
        if (flag == null || flag == 1) {
            rsa = SecureUtil.rsa(PRIK, PUBK);
        } else if (flag != null && flag == 2) {
            rsa = SecureUtil.rsa(RCMPRIK, RCMPUBK);
        }
        return Base64.encode(
                rsa.encrypt(StrUtil.bytes(s, CharsetUtil.CHARSET_UTF_8), KeyType.PublicKey));
    }
    public static String rsaDecode(String s, Short flag) {
        RSA rsa = null;
        if (flag == null || flag == 1) {
            rsa = SecureUtil.rsa(PRIK, PUBK);
        } else if (flag != null && flag == 2) {
            rsa = SecureUtil.rsa(RCMPRIK, RCMPUBK);
        }
        return new String(rsa.decrypt(Base64.decode(s), KeyType.PrivateKey));
    }
    public static void main(String[] args) {
        String str = "zhangsan";
        System.out.println(rsaEncode(str, (short) 2));
        str = "JyfPzIktNeH4VWkGIUzMpaJiOcCvlZQkE5q1tKnxH0xK/FNAcPgrLJYBscp6oHDCd7+FTkjkOicQepkE7UiceEY0zqvQrutVE1kjy4TNH0V4NIAoCk7y5qzo19m/247vh+GbZEW/C4qTRbtrFNoolO4hfMxuH7kqNB5VS8OdIRQ=";
        System.out.println(rsaDecode(str, (short) 2));
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/DesensitizationUtil.java
New file
@@ -0,0 +1,58 @@
package com.nuvole.util;
import cn.hutool.core.util.StrUtil;
/**
 * @author ChenLong
 * @version 1.0
 * @ClassName DesensitizationUtil
 * @date 2019/4/28 19:37
 * @Description è„±æ•å·¥å…·ç±»
 */
public class DesensitizationUtil {
    public static String esensitizationdName(String str) {
        if (StrUtil.isBlank(str)) {
            return "";
        }
        String res = str.substring(0, 1);
        for (int i = 1; i < str.length(); i++) {
            res += "*";
        }
        return res;
    }
    /**
     * Createed by PKZ
     * Date 2019/6/4 13:35
     * Description:手机号脱敏
     **/
    public static String esensitizationdMobile(String mobile) {
        if (StrUtil.isBlank(mobile)) {
            return "";
        }
        if (mobile.length() != 11) {
            return "";
        }
        String start = mobile.substring(0, 3);
        String end = mobile.substring(mobile.length() - 4, mobile.length());
        return start + "****" + end;
    }
    /**
     * Createed by PKZ
     * Date 2019/6/4 13:35
     * Description:身份证号脱敏
     **/
    public static String esensitizationdIdcard(String idcard) {
        if (StrUtil.isBlank(idcard)) {
            return "";
        }
        if (idcard.length() != 18) {
            return "";
        }
        String start = idcard.substring(0, 4);
        String end = idcard.substring(idcard.length() - 4, idcard.length());
        return start + "******" + end;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/DiscountUtil.java
New file
@@ -0,0 +1,51 @@
package com.nuvole.util;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.NumberUtil;
import org.apache.commons.lang.StringUtils;
import java.util.HashMap;
import java.util.Map;
/**
 * @ClassName DiscountUtil
 * @Author cy
 * @Date 2023/5/25
 * @Description
 * @Version 1.0
 **/
public class DiscountUtil {
    /**
     * @param totalMoney æ€»é‡‘额
     * @param discount   æŠ˜æ‰£
     * @return
     */
    public static Map<String, Long> getDiscount(long totalMoney, String discount) {
        if (StringUtils.isBlank(discount)) {
            return null;
        }
        HashMap<String, Long> map = new HashMap<>();
        if ("10".equals(discount)) {
            map.put("disCountMoney", 0l);
            map.put("payMoney", totalMoney);
            return map;
        }
        Double disc = NumberUtil.div(Convert.toDouble(discount), Convert.toDouble(10));   //折扣
        //折扣优惠后应付金额
        Long payMoney = Convert.toLong(Math.ceil(NumberUtil.mul(Convert.toDouble(totalMoney), disc)));  // æ‰“折后金额(向上取整)
        // ä¼˜æƒ é‡‘额
        Long disCountMoney = 0l;
        if (Convert.toDouble(totalMoney) >= payMoney) {
            disCountMoney = totalMoney - payMoney;
        } else {
            disCountMoney = totalMoney;
            payMoney = 0L;
        }
//        map.put("totalMoney", totalMoney);
        map.put("disCountMoney", disCountMoney);
        map.put("payMoney", payMoney);
        return map;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/DistanceUtil.java
New file
@@ -0,0 +1,44 @@
package com.nuvole.util;
/**
 * è®¡ç®—坐标距离工具类
 *
 * @Author: lc
 * @Date: 2019/5/23 19:10
 */
public class DistanceUtil {
    private static double EARTH_RADIUS = 6378.137;
    private static double rad(double d) {
        return d * Math.PI / 180.0;
    }
    /**
     * é€šè¿‡ç»çº¬åº¦èŽ·å–è·ç¦»(单位:米)(腾讯坐标)
     *
     * @Author: lc
     * @Date: 2019/5/23 19:14
     */
    public static double getDistance(double lat1, double lng1, double lat2, double lng2) {
        double radLat1 = rad(lat1);
        double radLat2 = rad(lat2);
        double a = radLat1 - radLat2;
        double b = rad(lng1) - rad(lng2);
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2)
                + Math.cos(radLat1) * Math.cos(radLat2)
                * Math.pow(Math.sin(b / 2), 2)));
        s = s * EARTH_RADIUS;
        s = Math.round(s * 10000d) / 10000d;
        s = s * 1000;
        return s;
    }
    public static void main(String[] args) {
        //金明源-杨金路34.844000,113.743560
        double distance = getDistance(34.844222, 113.743300, 34.844000, 113.743560);
        System.out.println("距离" + distance + "ç±³");
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/ExportExcel.java
New file
@@ -0,0 +1,79 @@
package com.nuvole.util;
// @formatter:off
import jakarta.servlet.http.HttpServletResponse;import lombok.val;import org.apache.poi.hssf.usermodel.*;
import java.net.URLEncoder;import java.util.Date;import java.util.List;import java.util.Locale; /**
 *                .-~~~~~~~~~-._       _.-~~~~~~~~~-.
 *            __.'  @Author     ~.   .~    ä»£ç æ— Bug   `.__
 *          .'//     liu.q        \./       (秘籍)      \\`.
 *        .'// [916000612@qq.com]  |   æ¬²ç»ƒç¥žåŠŸ   å¼•刀自宫  \\`.
 *      .'// .-~"""""""~~~~-._     |    _,-~~~~"""""""~-.  \\`.
 *    .'//.-"  2019-07-17     `-.  |  .-'     16:54       "-.\\`.
 *  .'//______.============-..   \ | /   ..-============.______\\`.
 *.'______________________________\|/______________________________`.
 *
 * @Description :
 */
// @formatter:on
public class ExportExcel {
    public static void exportExcel(String fileName, List<String> titles, List<List<Object>> rows, HttpServletResponse response) throws Exception {
        // å£°æ˜Žä¸€ä¸ªå·¥ä½œè–„
        HSSFWorkbook workbook = new HSSFWorkbook();
        // ç”Ÿæˆä¸€ä¸ªè¡¨æ ¼
        HSSFSheet sheet = workbook.createSheet();
        // è®¾ç½®è¡¨æ ¼é»˜è®¤åˆ—宽度为15个字节
        sheet.setDefaultColumnWidth((short) 18);
        //设置标题
        HSSFRow title = sheet.createRow(0);
        for (int i = 0; i < titles.size(); i++) {
            HSSFCell cell = title.createCell(i);
            HSSFRichTextString text = new HSSFRichTextString(titles.get(i));
            cell.setCellValue(text);
        }
        //设置数据
        HSSFCellStyle cellStyle = workbook.createCellStyle();
        for (int i = 0; i < rows.size(); i++) {
            HSSFRow row = sheet.createRow(i + 1);
            List<Object> clo = rows.get(i);
            int index = 0;
            for (Object o : clo) {
                HSSFCell cell = row.createCell(index);
                if (o instanceof Date) {
                    HSSFDataFormat format = workbook.createDataFormat();
                    cellStyle.setDataFormat(format.getFormat("yyyy-mm-dd HH:mm:ss"));
                    cell.setCellStyle(cellStyle);
                    cell.setCellValue((Date) o);
                } else if (o instanceof Double) {
                    HSSFDataFormat format = workbook.createDataFormat();
                    cellStyle.setDataFormat(format.getFormat("#,##0.00"));
                    cell.setCellStyle(cellStyle);
                    cell.setCellValue(Double.valueOf(o.toString()));
                } else {
                    HSSFDataFormat format = workbook.createDataFormat();
                    cellStyle.setDataFormat(format.getFormat("@"));
                    cell.setCellStyle(cellStyle);
                    cell.setCellValue(o.toString());
                }
                index++;
            }
        }
        // å‘Šè¯‰æµè§ˆå™¨ç”¨ä»€ä¹ˆè½¯ä»¶å¯ä»¥æ‰“开此文件
        response.setHeader("content-Type", "application/vnd.ms-excel");
        //解决 è‹¹æžœæµè§ˆå™¨ä¹±ç é—®é¢˜
        val ua = CommonUtil.getRequest().getHeader("User-Agent").toLowerCase(Locale.ENGLISH);
        if (ua.indexOf("macintosh") > -1 && ua.indexOf("chrome") < 0) {
            fileName = new String(fileName.getBytes(), "iso8859-1");
        } else {
            fileName = URLEncoder.encode(fileName, "utf-8");
        }
        // ä¸‹è½½æ–‡ä»¶çš„默认名称
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
        response.flushBuffer();
        workbook.write(response.getOutputStream());
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/ExpressUtil.java
New file
@@ -0,0 +1,84 @@
package com.nuvole.util;
import java.net.URLEncoder;
import java.util.HashMap;
import com.nuvole.common.domain.result.ExpressResult;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
/**
 * å¿«é€’鸟物流接口
 *
 * @Author: lc
 * @Date: 2019/6/13 15:36
 */
@Slf4j
public class ExpressUtil {
    private static String fileName = "express.properties";
    //电商ID
    public static String EBusinessID = "";
    //电商加密私钥,快递鸟提供,注意保管,不要泄漏
    public static String AppKey = "";
    //请求url,
    public static String ReqURL = "";
    //快递类型
    public static String Type = "";
    static {
        EBusinessID = PropertyUtil.getProp(fileName, "EBusinessID");
        AppKey = PropertyUtil.getProp(fileName, "AppKey");
        ReqURL = PropertyUtil.getProp(fileName, "ReqURL");
        Type = PropertyUtil.getProp(fileName, "Type");
    }
    /**
     * æŸ¥è¯¢è®¢å•物流轨迹(Json方式 ï¼‰[3000次/天,每单每天限查 5 æ¬¡,并发不超过 10 æ¬¡/S]
     *
     * @Author: lc
     * @Date: 2019/6/13 15:38
     */
    public static ExpressResult getOrderTracesByJson(String expressType, String expressCode) {
        try {
            //如果不传快递公司标识则取默认值
            if (StrUtil.isEmpty(expressType)) {
                expressType = Type;
            }
            String requestData = "{'OrderCode':'','ShipperCode':'" + expressType + "','LogisticCode':'" + expressCode + "'}";
            HashMap<String, Object> params = new HashMap<>();
            params.put("RequestData", URLEncoder.encode(requestData, "UTF-8"));
            params.put("EBusinessID", EBusinessID);
            params.put("RequestType", "1002");   //请求接口指令
            String dataSign = encrypt(requestData, AppKey, "UTF-8");
            params.put("DataSign", URLEncoder.encode(dataSign, "UTF-8"));
            params.put("DataType", "2");   //json方式
            String result = HttpUtil.post(ReqURL, params);
            System.out.println(result);
            return JSONUtil.toBean(result, ExpressResult.class);
        } catch (Exception e) {
            e.printStackTrace();
            return new ExpressResult();
        }
    }
    //加密 (进行MD5加密,然后Base64编码,最后 è¿›è¡ŒURL(utf-8)编码)
    private static String encrypt(String content, String keyValue, String charset) {
        if (keyValue != null) {
            return Base64.encode(SecureUtil.md5(content + keyValue).toLowerCase(), charset);
        }
        return Base64.encode(SecureUtil.md5(content).toLowerCase(), charset);
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/FileTypeJudge.java
New file
@@ -0,0 +1,117 @@
package com.nuvole.util;
import com.nuvole.util.enums.FileType;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
// @formatter:off
/**
 *                .-~~~~~~~~~-._       _.-~~~~~~~~~-.
 *            __.'  @Author     ~.   .~    ä»£ç æ— Bug   `.__
 *          .'//     liu.q        \./       (秘籍)      \\`.
 *        .'// [916000612@qq.com]  |   æ¬²ç»ƒç¥žåŠŸ   å¼•刀自宫  \\`.
 *      .'// .-~"""""""~~~~-._     |    _,-~~~~"""""""~-.  \\`.
 *    .'//.-"  2019-04-24     `-.  |  .-'     15:56       "-.\\`.
 *  .'//______.============-..   \ | /   ..-============.______\\`.
 *.'______________________________\|/______________________________`.
 *
 * @Description :
 */
// @formatter:on
public class FileTypeJudge {
    private FileTypeJudge() {
    }
    /**
     * å°†æ–‡ä»¶å¤´è½¬æ¢æˆ16进制字符串
     *
     * @return 16进制字符串
     */
    private static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }
    /**
     * å¾—到文件头
     *
     * @param filePath æ–‡ä»¶è·¯å¾„
     * @return æ–‡ä»¶å¤´
     * @throws IOException
     */
    private static String getFileContent(String filePath) throws IOException {
        byte[] b = new byte[28];
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream(filePath);
            inputStream.read(b, 0, 28);
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    throw e;
                }
            }
        }
        return bytesToHexString(b);
    }
    private static String getFileContent(InputStream inputStream){
        InputStream is = inputStream;
        byte[] b = new byte[28];
        try {
            is.read(b, 0, 28);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bytesToHexString(b);
    }
    /**
     * åˆ¤æ–­æ–‡ä»¶ç±»åž‹
     *
     * @return æ–‡ä»¶ç±»åž‹
     */
    public static String getType(InputStream inputStream){
        String fileHead = getFileContent(inputStream);
        if (fileHead == null || fileHead.length() == 0) {
            return null;
        }
        fileHead = fileHead.toUpperCase();
        FileType[] fileTypes = FileType.values();
        for (FileType type : fileTypes) {
            if (fileHead.startsWith(type.getValue())) {
                return type.toString();
            }
        }
        return "";
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/FtpUtil.java
New file
@@ -0,0 +1,88 @@
package com.nuvole.util;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.FileUtil;
import cn.hutool.extra.ftp.Ftp;
import cn.hutool.extra.ftp.FtpMode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTP;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
 * @author ChenLong
 * @version 1.0
 * @ClassName FtpUtil
 * @date 2019/4/15 14:16
 */
@Slf4j
public class FtpUtil {
    public static Properties getFtpProp() {
        Properties props = new Properties();
        InputStream in = null;
        try {
            ResourceLoader resourceLoader = new DefaultResourceLoader();
            in = resourceLoader.getResource("ftp.properties").getInputStream();
            props.load(in);
            return props;
        } catch (IOException e) {
            e.printStackTrace();
            return props;
        } finally {
            ResourceUtil.safeClose(in);
        }
    }
    public static Ftp getFtp() {
        Properties props = getFtpProp();
        String url = props.getProperty("ftp.url");
        int port = Convert.toInt(props.getProperty("ftp.port"));
        String username = props.getProperty("ftp.username");
        String mixpd = props.getProperty("ftp.mixpd");
        Ftp ftp = new Ftp(url, port, username, mixpd);
        ftp.setMode(FtpMode.Passive);
        ftp.getClient().setActivePortRange(50000, 55000);
        ftp.getClient().setRemoteVerificationEnabled(false);
        try {
            ftp.getClient().setFileType(FTP.BINARY_FILE_TYPE);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ftp;
    }
    public static void upload(Ftp ftp, String sourceFilePath,String targetFilePath) {
        String FileName = targetFilePath.substring(targetFilePath.lastIndexOf("/") + 1);
        String targetPath = targetFilePath.substring(0, targetFilePath.lastIndexOf("/"));
        ftp.upload(targetPath, FileName, new File(sourceFilePath));
    }
    public static void upload(Ftp ftp, String FileName,InputStream inputStream,String targetPath) {
        ftp.upload(targetPath,FileName,inputStream);
    }
    public static void download(Ftp ftp, String sourceFilePath,String targetFilePath) {
        String sourceName = sourceFilePath.substring(sourceFilePath.lastIndexOf("/") + 1);
        String sourcePath = sourceFilePath.substring(0, sourceFilePath.lastIndexOf("/"));
        ftp.download(sourcePath, sourceName, FileUtil.file(targetFilePath));
    }
    public static void close(Ftp ftp) {
        if (ftp != null) {
            try {
                ftp.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/GeTuiPush.java
New file
@@ -0,0 +1,273 @@
package com.nuvole.util;
import com.gexin.rp.sdk.base.IAliasResult;
import com.gexin.rp.sdk.base.IPushResult;
import com.gexin.rp.sdk.base.impl.AppMessage;
import com.gexin.rp.sdk.base.impl.ListMessage;
import com.gexin.rp.sdk.base.impl.SingleMessage;
import com.gexin.rp.sdk.base.impl.Target;
import com.gexin.rp.sdk.base.notify.Notify;
import com.gexin.rp.sdk.base.payload.APNPayload;
import com.gexin.rp.sdk.exceptions.RequestException;
import com.gexin.rp.sdk.http.IGtPush;
import com.gexin.rp.sdk.template.AbstractTemplate;
import com.gexin.rp.sdk.template.TransmissionTemplate;
import com.nuvole.common.domain.emnu.CommonResultEmnu;
import com.nuvole.common.domain.result.CommonResult;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
 * æŽ¨é€å·¥å…·ç±»ï¼ˆä¸ªæŽ¨ï¼‰
 *
 * @Author: lc
 * @Date: 2020/4/26 13:41
 */
public class GeTuiPush {
    private static String url = "http://sdk.open.api.igexin.com/apiex.htm";
//    private static String appId = "0TrCn76GcW8T4y3wediOn9";
    private static String appId = "g1FYuSXD2x5HY2KfWswP19";
//    private static String appKey = "FUPAiYeLSo5hbPIZrRDT21";
    private static String appKey = "kkMqLLBGLd7wx0mhIbG9l5";
//    private static String masterSecret = "ne5FG9hfS77RNyGAnQF5p1";
    private static String masterSecret = "AEuOKMlvTY9aLrdjtPhzy7";
    private static IGtPush igtPush = new IGtPush(url, appKey, masterSecret);
    /**
     * ä¸ºç”¨æˆ·ç»‘定别名
     *
     * @param clientId å®¢æˆ·ç«¯èº«ä»½id
     * @param alias    åˆ«å
     * @Author: lc
     * @Date: 2020/4/26 13:36
     */
    public static CommonResult bindAlias(String clientId, String alias) {
        IAliasResult ret = null;
        try {
            ret = igtPush.bindAlias(appId, alias, clientId);
            System.out.println("is bindAlias res:" + ret.getResponse());
        } catch (RequestException e) {
            e.printStackTrace();
        }
        if (ret != null) {
            Map res = ret.getResponse();
            if ("ok".equals(res.get("result").toString())) {
                return new CommonResult(res);
            } else {
                return new CommonResult(CommonResultEmnu.ERROR, res.get("error_msg").toString());
            }
        } else {
            return new CommonResult(CommonResultEmnu.ERROR, "绑定个推别名时出现异常!");
        }
    }
    //测试
    public static void main(String[] args) {
        bindAlias("0482fa489fe285cbb8b96054f81a0b4f", "123456789");
        pushMessageToSingle("测试demo", "测试demo内容", 2, "123456789");
    }
    /**
     * å•推(单个clientId/别名)
     *
     * @param title   æ ‡é¢˜
     * @param content å†…容
     * @param type    ç±»åž‹ã€1.设备id(clientId) 2.别名】
     * @param val     ç±»åž‹å€¼ï¼ˆclientId/别名)
     * @Author: lc
     * @Date: 2020/4/26 13:31
     */
    public static Map pushMessageToSingle(String title, String content, int type, String val) {
        /*透传消息模版*/
        AbstractTemplate template = getTransmissionTemplate(title, content);
        // å•推消息类型
        SingleMessage message = getSingleMessage(template);
        Target target = new Target();
        target.setAppId(appId);
        if (type == 1) {
            target.setClientId(val);
        } else {
            target.setAlias(val);//别名需要提前绑定
        }
        IPushResult ret = null;
        try {
            ret = igtPush.pushMessageToSingle(message, target);
            System.out.println("is pushMessageToSingle res:" + ret.getResponse());
        } catch (RequestException e) {
            e.printStackTrace();
            ret = igtPush.pushMessageToSingle(message, target, e.getRequestId());
        }
        if (ret != null) {
            return ret.getResponse();
        } else {
            System.out.println("个推单条推送服务器响应异常");
            return null;
        }
    }
    /**
     * æŽ¨é€ä¸€ä¸ªåˆ—表
     *
     * @param title   æ ‡é¢˜
     * @param content å†…容
     * @parma type    ç±»åž‹ã€1.设备id(clientId) 2.别名】
     * @parma jsonArray    ç±»åž‹å€¼ï¼ˆclientId/别名)
     * @Author: lc
     * @Date: 2020/4/26 13:37
     */
    public static Map pushMessageToList(String title, String content, int type, List<String> list) {
        /*透传消息模版*/
        AbstractTemplate template = getTransmissionTemplate(title, content);
        ListMessage message = new ListMessage();
        message.setData(template);
        // è®¾ç½®æ¶ˆæ¯ç¦»çº¿ï¼Œå¹¶è®¾ç½®ç¦»çº¿æ—¶é—´
        message.setOffline(true);
        // ç¦»çº¿æœ‰æ•ˆæ—¶é—´ï¼Œå•位为毫秒,可选
        message.setOfflineExpireTime(24 * 1000 * 3600);
        message.setPriority(1);
        String taskId = igtPush.getContentId(message);
        // é…ç½®æŽ¨é€ç›®æ ‡
        List targets = new ArrayList();
        for (int i = 0; i < list.size(); i++) {
            String cid = list.get(i);
            Target target = new Target();
            target.setAppId(appId);
            if (type == 1) {
                target.setClientId(cid);
            } else {
                target.setAlias(cid);
            }
            targets.add(target);
        }
        IPushResult ret = null;
        try {
            ret = igtPush.pushMessageToList(taskId, targets);
            System.out.println("is pushMessageToList:" + ret.getResponse());
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (ret != null) {
            return ret.getResponse();
        } else {
            System.out.println("个推推送一个列表服务器响应异常");
            return null;
        }
    }
    /**
     * æŽ¨é€æ‰€æœ‰æ‰‹æœºç”¨æˆ·
     *
     * @param title   æ ‡é¢˜
     * @param content å†…容
     * @Author: lc
     * @Date: 2020/4/26 13:36
     */
    public static Map pushMessageToApp(String title, String content) {
        /*透传消息模版*/
        AbstractTemplate template = getTransmissionTemplate(title, content);
        // å•推消息类型
        AppMessage message = new AppMessage();
        message.setData(template);
        message.setOffline(true);
        message.setOfflineExpireTime(24 * 1000 * 3600);  //离线有效时间,单位为毫秒,可选
        //全量推送时希望能控制推送速度不要太快,缓减服务器连接压力,可设置定速推送。如果未设置则按默认推送速度发送
        message.setSpeed(100);   // è®¾ç½®ä¸º100,含义为个推控制下发速度在100条/秒左右
        List<String> appIdList = new ArrayList<String>();
        appIdList.add(appId);
        message.setAppIdList(appIdList);
        IPushResult ret = null;
        try {
            ret = igtPush.pushMessageToApp(message);
            System.out.println("is pushMessageToApp res:" + ret.getResponse());
        } catch (RequestException e) {
            e.printStackTrace();
            ret = igtPush.pushMessageToApp(message, e.getRequestId());
        }
        if (ret != null) {
            return ret.getResponse();
        } else {
            System.out.println("个推推送所有手机用户服务器响应异常");
            return null;
        }
    }
    /**
     * é€ä¼ æ¶ˆæ¯æ¨¡ç‰ˆ
     *
     * @param title   æ ‡é¢˜
     * @param content å†…容
     * @Author: lc
     * @Date: 2020/4/26 13:46
     */
    private static TransmissionTemplate getTransmissionTemplate(String title, String content) {
        TransmissionTemplate template = new TransmissionTemplate();
        /*设置APPID与APPKEY*/
        template.setAppId(appId);
        template.setAppkey(appKey);
        /*透传消息设置,1为强制启动应用,客户端接收到消息后就会立即启动应用;2为等待应用启动*/
        template.setTransmissionType(2);
        template.setTransmissionContent(content);
        /*ios消息推送*/
        template.setAPNInfo(getAPNPayload());
        Notify notify = new Notify();
//        notify.setIntent("intent:#intent;action=android.intent.action.oppopush;package=cn.com.pconline.android.browser;component=cn.com.android.browser/cn.com.android.browser.push.MultivendorPushActivity;S.protocol=pconlinebrowser://information-article/8270922;end");
        notify.setIntent("intent:#Intent;action=android.intent.action.oppopush;launchFlags=0x14000000;component=com.liuqit.notebook/io.dcloud.PandoraEntry;S.UP-OL-SU=true;S.title=" + title + ";S.content=" + content + ";S.payload=" + content + ";end");
        notify.setTitle(title);
        notify.setContent(content);
        /*第三方*/
        template.set3rdNotifyInfo(notify);
        return template;
    }
    private static SingleMessage getSingleMessage(AbstractTemplate template) {
        SingleMessage message = new SingleMessage();
        message.setData(template);
        // è®¾ç½®æ¶ˆæ¯ç¦»çº¿ï¼Œå¹¶è®¾ç½®ç¦»çº¿æ—¶é—´
        message.setOffline(true);
        // ç¦»çº¿æœ‰æ•ˆæ—¶é—´ï¼Œå•位为毫秒,可选
        message.setOfflineExpireTime(72 * 3600 * 1000);
        message.setPriority(1);
        // åˆ¤æ–­å®¢æˆ·ç«¯æ˜¯å¦wifi环境下推送。1为仅在wifi环境下推送,0为不限制网络环境,默认不限
        message.setPushNetWorkType(0);
        return message;
    }
    private static APNPayload getAPNPayload() {
        APNPayload payload = new APNPayload();
        //在已有数字基础上加1显示,设置为-1时,在已有数字上减1显示,设置为数字时,显示指定数字
        payload.setAutoBadge("+1");
        payload.setContentAvailable(1);
        //ios 12.0 ä»¥ä¸Šå¯ä»¥ä½¿ç”¨ Dictionary ç±»åž‹çš„ sound
        payload.setSound("default");
        payload.setCategory("$由客户端定义");
        payload.addCustomMsg("由客户自定义消息key", "由客户自定义消息value");
        //简单模式APNPayload.SimpleMsg
        payload.setAlertMsg(new APNPayload.SimpleAlertMsg("hello"));
//        payload.setAlertMsg(getDictionaryAlertMsg());  //字典模式使用APNPayload.DictionaryAlertMsg
        //设置语音播报类型,int类型,0.不可用 1.播放body 2.播放自定义文本
        payload.setVoicePlayType(0);
        return payload;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/GeTuiPushCall.java
New file
@@ -0,0 +1,62 @@
package com.nuvole.util;
import cn.hutool.http.HttpUtil;
import com.nuvole.constants.ServiceConstants;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @Description:
 * @Company: TOO (ps:公司名称)
 * @author: å”
 * @date: 2020/5/16 ä¸‹åˆ8:47
 * @version: V1.0.0
 */
@Slf4j
public class GeTuiPushCall {
    /**
     * å•推(单个clientId/别名)
     *
     * @param title   æ ‡é¢˜
     * @param content å†…容
     * @param type    ç±»åž‹ã€1.设备id(clientId) 2.别名】
     * @param val     ç±»åž‹å€¼ï¼ˆclientId/别名)
     * @Author: lc
     * @Date: 2020/4/26 13:31
     */
    public static String pushMessageToSingle(String title, String content, int type, String val) {
        String url = ServiceConstants.SERVICE_GE_TUI_URL;
        Map<String, Object> map = new HashMap<>();
        map.put("title", title);
        map.put("content", content);
        map.put("type", type);
        map.put("val", val);
        return HttpUtil.post(url, map);
    }
    /**
     * æŽ¨é€ä¸€ä¸ªåˆ—表
     *
     * @param title   æ ‡é¢˜
     * @param content å†…容
     * @parma type    ç±»åž‹ã€1.设备id(clientId) 2.别名】
     * @parma jsonArray    ç±»åž‹å€¼ï¼ˆclientId/别名)
     * @Author: lc
     * @Date: 2020/4/26 13:37
     */
    public static String pushMessageToList(String title, String content, int type, List<String> list) {
        String url = ServiceConstants.SERVICE_GE_TUI_LIST_URL;
        Map<String, Object> map = new HashMap<>();
        map.put("title", title);
        map.put("content", content);
        map.put("type", type);
        map.put("list", list);
        return HttpUtil.post(url, map);
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/HttpUtilExtra.java
New file
@@ -0,0 +1,49 @@
package com.nuvole.util;
import cn.hutool.core.io.IoUtil;
import com.alibaba.fastjson.JSON;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.text.StringEscapeUtils;
import java.io.IOException;
import java.nio.charset.Charset;
/**
 * @ClassName HttpUtilExtra
 * @Description http扩展工具类
 * @Author Chen Long
 * @Date 2019/8/23
 * @Version 1.0
 */
public class HttpUtilExtra {
    /**
     * èŽ·å–request body值
     * @param request
     * @return
     */
    public static String getRequestBody(HttpServletRequest request) {
        try {
            return IoUtil.read(request.getInputStream(), Charset.forName("UTF-8"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }
    /**
     * request body è½¬å¯¹è±¡
     * @param request
     * @param classz
     * @return
     */
    public static <T> T getObjByRequestBody(HttpServletRequest request, Class<T> classz) {
        String body = StringEscapeUtils.unescapeHtml4(getRequestBody(request));
        return JSON.parseObject(body, classz);
    }
    public static <T> T getObjByRequestBody(Class<T> classz) {
        String body = StringEscapeUtils.unescapeHtml4(getRequestBody(CommonUtil.getRequest()));
        return JSON.parseObject(body, classz);
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/IPUtil.java
New file
@@ -0,0 +1,80 @@
package com.nuvole.util;
import jakarta.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;
public class IPUtil {
    /*
     * @Author : liu.q [916000612@qq.com]
     * @Date : 2019-05-11 17:06
     * @Description :获取用户真实IP地址,不使用request.getRemoteAddr()的原因是有可能用户使用了代理软件方式避免真实IP地址,可是,如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP值
     */
    public static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
            // å¤šæ¬¡åå‘代理后会有多个ip值,第一个ip才是真实ip
            if (ip.indexOf(",") != -1) {
                ip = ip.split(",")[0];
            }
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
    /**
     * èŽ·å–æœ¬åœ°IP地址(局域网)
     *
     * @Author: lc
     * @Date: 2019/11/8 11:59
     */
    public static String getLocalHostIp() {
        try {
            InetAddress candidateAddress = null;
            // éåŽ†æ‰€æœ‰çš„ç½‘ç»œæŽ¥å£
            for (Enumeration ifaces = NetworkInterface.getNetworkInterfaces(); ifaces.hasMoreElements(); ) {
                NetworkInterface iface = (NetworkInterface) ifaces.nextElement();
                // åœ¨æ‰€æœ‰çš„æŽ¥å£ä¸‹å†éåކIP
                for (Enumeration inetAddrs = iface.getInetAddresses(); inetAddrs.hasMoreElements(); ) {
                    InetAddress inetAddr = (InetAddress) inetAddrs.nextElement();
                    if (!inetAddr.isLoopbackAddress()) {// æŽ’除loopback类型地址
                        if (inetAddr.isSiteLocalAddress()) {
                            // å¦‚果是site-local地址
                            return inetAddr.toString().replace("/", "");
                        } else if (candidateAddress == null) {
                            //site-local类型的地址未被发现,先记录候选地址
                            candidateAddress = inetAddr;
                        }
                    }
                }
            }
            if (candidateAddress != null) {
                return candidateAddress.toString().replace("/", "");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/IdGenerator.java
New file
@@ -0,0 +1,30 @@
package com.nuvole.util;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
/**
 * @author ChenLong
 * @version 1.0
 * @ClassName IdGenerator
 * @Description id生成器
 * @date 2019/4/18 11:33
 */
public class IdGenerator {
    private static Snowflake snowflake;
    public static Long getId() {
        return snowflake.nextId();
    }
    static {
        snowflake = IdUtil.createSnowflake(RandomUtil.randomInt(0, 31), RandomUtil.randomInt(0, 31));
    }
    public static String getUUID() {
        return IdUtil.simpleUUID();
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/ImageUtil.java
New file
@@ -0,0 +1,96 @@
package com.nuvole.util;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
//// @formatter:off
//import javax.imageio.*;import javax.imageio.metadata.IIOMetadata;import javax.imageio.stream.ImageOutputStream;import java.awt.*;import java.awt.image.BufferedImage;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream; /**
// *                .-~~~~~~~~~-._       _.-~~~~~~~~~-.
// *            __.'  @Author     ~.   .~    ä»£ç æ— Bug   `.__
// *          .'//     liu.q        \./       (秘籍)      \\`.
// *        .'// [916000612@qq.com]  |   æ¬²ç»ƒç¥žåŠŸ   å¼•刀自宫  \\`.
// *      .'// .-~"""""""~~~~-._     |    _,-~~~~"""""""~-.  \\`.
// *    .'//.-"  2019-04-24     `-.  |  .-'     12:53       "-.\\`.
// *  .'//______.============-..   \ | /   ..-============.______\\`.
// *.'______________________________\|/______________________________`.
// *
// * @Description :
// */
//// @formatter:on
//
public class ImageUtil {
    public static void main(String[] args) throws Exception {
        byte[] imageBytes = getImageBytes("C:\\Users\\cy\\Pictures\\营业执照\\111.jpg");
        System.out.println(imageBytes.length);
    }
    public static byte[] getImageBytes(String imagePath) throws Exception {
        // è¯»å–图片文件
        BufferedImage bufferedImage = ImageIO.read(new File(imagePath));
        // å°†å›¾ç‰‡å†™å…¥å­—节流
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ImageIO.write(bufferedImage, "jpg", baos);
        // è¿”回字节数组
        return baos.toByteArray();
    }
//
//    /*
//     * @Author : liu.q [916000612@qq.com]
//     * @Date : 2019-04-24 12:55
//     * @param OldInputStream : åŽŸå›¾
//     * @param w : å®½
//     * @param h : é«˜
//     * @param quality : è´¨é‡
//     * @return : InputStream åŽ‹ç¼©åŽçš„å›¾
//     * @Description :
//     */
//    public static InputStream ImgCompress(InputStream OldInputStream,String suffix,int w, int h, float quality) {
//        try {
//            /** å¤„理宽高 */
//            BufferedImage bufferedImage =  ImageIO.read(OldInputStream);
//            int new_w = bufferedImage.getWidth(null);
//            int new_h = bufferedImage.getHeight(null);
//            if(new_w<=w || new_h<=h){//原图宽高小于要压缩的宽高就不压缩了。
//                return OldInputStream;
//            }
//            double bili;
//            if(w<=0 || h<=0){
//                if(w>0){
//                    bili=(double)w/new_w;
//                    new_h = (int) (new_h*bili);
//                    new_w=w;
//                }else{
//                    if(h>0){
//                        bili=(double)h/new_h;
//                        new_w = (int) (new_w*bili);
//                        new_h=h;
//                    }
//                }
//            }else{
//                new_w=w;
//                new_h=h;
//            }
//
//            BufferedImage image_to_save = new BufferedImage(new_w, new_h,bufferedImage.getType());
//            image_to_save.getGraphics().drawImage(bufferedImage.getScaledInstance(new_w, new_h, Image.SCALE_SMOOTH), 0,0, null);
//            ImageWriter imageWriter =  ImageIO.getImageWritersBySuffix(suffix).next();
//            IIOMetadata imageMetaData = imageWriter.getDefaultImageMetadata(new ImageTypeSpecifier(image_to_save), null);
//            //质量压缩
//            if (quality >= 0 && quality <= 1f) {
//                ImageWriteParam jpegParams = imageWriter.getDefaultWriteParam();
//                jpegParams.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
//                jpegParams.setCompressionQuality(quality);
//            }
//            //写入图片
//            imageWriter.write(imageMetaData,new IIOImage(image_to_save, null, null), null);
//            imageWriter.dispose();
//
//            return imageWriter;
//        } catch (IOException ex) {
//            ex.printStackTrace();
//        }
//    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/JGPushCallUtil.java
New file
@@ -0,0 +1,31 @@
package com.nuvole.util;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.nuvole.constants.ServiceConstants;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
import java.util.Map;
/**
 * @Description:
 * @Company: TOO (ps:公司名称)
 * @author: å”
 * @date: 2019/12/2 ä¸‹åˆ3:47
 * @version: V1.0.0
 */
@Slf4j
public class JGPushCallUtil {
    public static String push(String content,String title,String userid,String businessid,String businesstype) {
        String path = ServiceConstants.SERVICE_JG_PUSH_URL;
        Map<String,Object> param = new HashMap<>(5);
        param.put("content",content);
        param.put("title",title);
        param.put("userid",userid);
        param.put("businessid",businessid);
        param.put("businesstype",businesstype);
        return HttpUtil.post(path,param);
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/JGPushUtil.java
New file
@@ -0,0 +1,84 @@
package com.nuvole.util;
import cn.hutool.core.convert.Convert;
import cn.jiguang.common.ClientConfig;
import cn.jiguang.common.resp.APIConnectionException;
import cn.jiguang.common.resp.APIRequestException;
import cn.jpush.api.JPushClient;
import cn.jpush.api.push.PushResult;
import cn.jpush.api.push.model.Platform;
import cn.jpush.api.push.model.PushPayload;
import cn.jpush.api.push.model.audience.Audience;
import cn.jpush.api.push.model.notification.AndroidNotification;
import cn.jpush.api.push.model.notification.IosNotification;
import cn.jpush.api.push.model.notification.Notification;
import java.util.HashMap;
import java.util.Map;
/**
 * Createed by PKZ
 * Date 2019/5/28 14:46
 * Description:极光推送
 */
public class JGPushUtil {
    private static String MASTER_SECRET="142cc44b9a7031b1b461530a";
    private static String APP_KEY="382144e6869af95cb99ba6f3";
/*
    private static String MASTER_SECRET="7d926843009a59d013100ad9";
    private static String APP_KEY="050c7ed3f0218d5c96a9c73c";
*/
    //极光推送
    private static PushPayload buildPushObject_ios_audienceMore_messageWithExtras(String content,String title,String userid,String businessid,String businesstype) {
        Map m=new HashMap();
        m.put("id",businessid);
        m.put("type",businesstype);
        return PushPayload.newBuilder()
                .setPlatform(Platform.all())//推送所有平台
                .setAudience(Audience.alias(userid))//别名推送
                //.setAudience(Audience.all())//全部推送
              /*  .setMessage(Message.newBuilder()//发送透传消息
                        .setMsgContent(content)
                        .setTitle(title)
                        .addExtra("from", "JPush")
                        .addExtra("businessid",businessid)
                        .addExtra("businesstype",businesstype)
                        .build())*/
                .setNotification(
                        Notification.newBuilder()
                                .addPlatformNotification(AndroidNotification.newBuilder().setAlert(content).setTitle(title).addExtras(m).build())
                                .addPlatformNotification(IosNotification.newBuilder().setAlert(content).addExtras(m).build())
                                .build()
                )//发送通知
                .build();
    }
     /**
       * Createed by PKZ
       * Date 2019/5/28 15:01
       * Description:极光推送
      * @param content æŽ¨é€å†…容
      * @param title æ ‡é¢˜
      * @param userid æŽ¨é€åˆ«å
      * @param businessid ä¸šåŠ¡id
      * @param businesstype ä¸šåŠ¡ç±»åž‹ï¼ˆ1:扫码支付订单)
       **/
    public static String push(String content,String title,String userid,String businessid,String businesstype){
        PushPayload payload=buildPushObject_ios_audienceMore_messageWithExtras(content,title,userid,businessid,businesstype);
        JPushClient jpushClient = new JPushClient(MASTER_SECRET, APP_KEY, null, ClientConfig.getInstance());
        PushResult result=new PushResult();
        try {
            result= jpushClient.sendPush(payload);
        } catch (APIConnectionException e) {
            e.printStackTrace();
        } catch (APIRequestException e) {
            e.printStackTrace();
        }
        return Convert.toStr(result.statusCode);
    }
    public static void main(String[] args) {
        push("支付宝收款成功2元","支付宝收款成功2元","1255396878833553408","1139417207521021952","1"
        );
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/JWTUtil.java
New file
@@ -0,0 +1,187 @@
package com.nuvole.util;
import cn.hutool.core.convert.Convert;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import java.util.Map;
/**
 * @ClassName JWTUtil
 * @Description JWT工具类
 * @Author Chen Long
 * @Date 2019/8/20
 * @Version 1.0
 */
public class JWTUtil {
    /**
     * PC类型JWT
     */
    public static final String JWT_TYPE_PC = "PC";
    /**
     * å®¢æˆ·ç»ç†ç±»åž‹jwt
     */
    public static final String JWT_TYPE_MANAGER_WX_MINI = "MANAGER_WX_MINI";
    /**
     * APP类型JWT
     */
    public static final String JWT_TYPE_APP = "APP";
    /**
     * SCANPAY JWT
     */
    public static final String JWT_TYPE_SCANPAY = "SCANPAY";
    /**
     * PC类型JWT超时时长
     */
    public static final long JWT_TYPE_PC_EXPIRE = 2 * 60 * 60 * 1000;
    /**
     * å®¢æˆ·ç»ç†å°ç¨‹åºç±»åž‹JWT超时时长
     */
    public static final long JWT_TYPE_MANAGER_WX_MINI_EXPIRE = 7 * 24 * 60 * 60 * 1000;
    /**
     * APP类型JWT超时时长
     */
    public static final long JWT_TYPE_APP_EXPIRE = 2 * 60 * 60 * 1000;
    /**
     * SCANPAY JWT超时时长
     */
    public static final long JWT_TYPE_SCANPAY_EXPIRE = 2 * 60 * 60 * 1000;
    /**
     * è‡ªå®šä¹‰å‰ç¼€
     */
    private static final String JWT_SIGN_PREFIX = "o6t48fVSqCUCu";
    /**
     * åР坆坆钥
     */
    private static final String JWT_SECRET = "sHyPanQN8wAt3sKBix9Fla7iGvwWs4hfE4YhluMYvbtBdX6sOiEeGU4lHhVgdrsO";
    /**
     * åˆ›å»º JWT
     *
     * @param jwtType
     * @param claims
     * @return
     * @Description jwt荷载
     * iss: jwt签发者
     * sub: jwt所面向的用户
     * aud: æŽ¥æ”¶jwt的一方
     * exp: jwt的过期时间,这个过期时间必须要大于签发时间
     * nbf: å®šä¹‰åœ¨ä»€ä¹ˆæ—¶é—´ä¹‹å‰ï¼Œè¯¥jwt都是不可用的.
     * iat: jwt的签发时间
     * jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
     */
    public static String generateJwt(String jwtType, Map<String, Object> claims) {
        //签发时间
        long nowMillis = System.currentTimeMillis();
        //超时时间
        long expMillis = 0;
        if (jwtType.equalsIgnoreCase(JWT_TYPE_PC)) {
            expMillis = nowMillis + JWT_TYPE_PC_EXPIRE;
        } else if (jwtType.equalsIgnoreCase(JWT_TYPE_APP)) {
            expMillis = nowMillis + JWT_TYPE_APP_EXPIRE;
        } else if (jwtType.equalsIgnoreCase(JWT_TYPE_SCANPAY)) {
            expMillis = nowMillis + JWT_TYPE_SCANPAY_EXPIRE;
        } else if (jwtType.equalsIgnoreCase(JWT_TYPE_MANAGER_WX_MINI)) {
            expMillis = nowMillis + JWT_TYPE_MANAGER_WX_MINI_EXPIRE;
        }
        for (Map.Entry<String, Object> entry : claims.entrySet()) {
            entry.setValue(AESUtil.encode(
                    Convert.toStr(
                            entry.getValue())));
        }
        String compactJws = Jwts.builder()
                .setClaims(claims)
                .setIssuedAt(new Date(nowMillis))
                .setExpiration(new Date(expMillis))
                .signWith(SignatureAlgorithm.HS512, JWT_SECRET)
                .compact();
        return JWT_SIGN_PREFIX + compactJws;
    }
    /**
     * æ ¡éªŒjwt是否合法
     *
     * @param jwt
     * @return
     */
    public static boolean checkJWT(String jwt) {
        try {
            getClaims(jwt);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
    /**
     * èŽ·å–claims
     *
     * @param jwt
     * @return
     */
    public static Claims getClaims(String jwt) {
        jwt = jwt.substring(JWT_SIGN_PREFIX.length());
        Claims claims;
        claims = Jwts.parser()
                .setSigningKey(JWT_SECRET)
                .parseClaimsJws(jwt)
                .getBody();
        return claims;
    }
    /**
     * èŽ·å–claims sub
     *
     * @param jwt
     * @return
     */
    public static String getSubOfClaims(String jwt) {
        return getValOfClaims(jwt, "sub");
    }
    /**
     * èŽ·å–claims roles
     *
     * @param jwt
     * @return
     */
    public static String getRolesOfClaims(String jwt) {
        return getValOfClaims(jwt, "roles");
    }
    /**
     * @param jwt
     * @param key
     * @Method getValOfClaims
     * @Description æ ¹æ®key获取claims值
     * @Return java.lang.String
     * @Author Chen Long
     * @Date 2019/8/27
     * @Version 1.0
     */
    public static String getValOfClaims(String jwt, String key) {
        return AESUtil.decode(
                Convert.toStr(
                        getClaims(jwt).get(key)));
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/LaBaPushUtil.java
New file
@@ -0,0 +1,104 @@
package com.nuvole.util;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSONObject;
import com.nuvole.hnnx.hnnxPay.NXHttpClientUtils;
import com.nuvole.hnnx.hnnxPay.SignatureSigner;
import com.nuvole.util.enums.LaPushEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @ClassName LaBaPushUtil
 * @Author cy
 * @Date 2023/12/7
 * @Description
 * @Version 1.0
 **/
@Slf4j
public class LaBaPushUtil {
    private static final String DEVICE_ID = "202312080001";
    private static String ACCESSKEYSECRET = "AtR4g5sa24fdy6GII3hts75_CSYH";
    private static String accessKeyId = "IOT_ACCOUNT_TEST_CSYH";
    private static SignatureSigner signable = new SignatureSigner();
    //生产环境
    private static String scUrl = "https://voice.tysmartpos.com/api/bank/pushmsg";
    //测试环境
    private static String csUrl = "https://voicetest.tysmartpos.com/api/bank/pushmsg";
//    public static void main(String[] args) {
//        String deviceId = "202312080001";
////        String 010859416327 = "202312080001";
////        push(deviceId, LaPushEnum.YINHANG, 111);
//        pushMessageToSingle(deviceId, LaPushEnum.ZFB, 222);
//////        push(deviceId, LaPushEnum.WX, 333);
//        pushMessageToSingle(deviceId, LaPushEnum.CANCLE, 444);
//    }
    public static void pushMessageToSingle(String deviceId, LaPushEnum pushType, long money) {
        if (StringUtils.isEmpty(deviceId)){
            return;
        }
        Map<String, String> parameters = new HashMap<>();
        parameters.put("accessKeyId", accessKeyId);
        parameters.put("requestId", String.valueOf(System.currentTimeMillis()));
        //请求时间戳,格式如:1593532800000
        parameters.put("timestamp", String.valueOf(System.currentTimeMillis()));
        //设备编号
        parameters.put("deviceId", deviceId);
        String moneyYuan = NXHttpClientUtils.convertToYuan(money).toString();
        parameters.put("content", pushType.getName() + moneyYuan + "元");
        String signStr = signable.laBaSign(parameters, ACCESSKEYSECRET);
        parameters.put("sign", signStr);
        String jsonBody = JSONObject.toJSONString(parameters);
        String result = null;
        log.info("天喻云音响请求参数:{}", jsonBody);
        HttpResponse response = HttpRequest.post(csUrl)
                .contentType("application/json")
                .body(jsonBody)
                .execute();
        // èŽ·å–å“åº”ç»“æžœ
        result = response.body();
        log.info("天喻云音响推送返回值:{}", result);
        return;
    }
    public static void pushMessageToList(LaPushEnum pushType, long money, List<String> deviceIdList) {
        Map<String, String> parameters = new HashMap<>();
        parameters.put("accessKeyId", accessKeyId);
        parameters.put("requestId", String.valueOf(System.currentTimeMillis()));
        //请求时间戳,格式如:1593532800000
        parameters.put("timestamp", String.valueOf(System.currentTimeMillis()));
        String moneyYuan = NXHttpClientUtils.convertToYuan(money).toString();
        parameters.put("content", pushType.getName() + moneyYuan + "元");
        deviceIdList.forEach(deviceId -> {
            //设备编号
            parameters.put("deviceId", deviceId);
            String signStr = signable.laBaSign(parameters, ACCESSKEYSECRET);
            parameters.put("sign", signStr);
            String jsonBody = JSONObject.toJSONString(parameters);
            String result = null;
            log.info("天域喇叭推送请求参数:{}", jsonBody);
            HttpResponse response = HttpRequest.post(csUrl)
                    .contentType("application/json")
                    .body(jsonBody)
                    .execute();
            // èŽ·å–å“åº”ç»“æžœ
            result = response.body();
            log.info("天域喇叭推送返回值:{}", result);
        });
        return;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/OSSUtil.java
New file
@@ -0,0 +1,252 @@
package com.nuvole.util;
import cn.hutool.core.io.FileUtil;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;
import org.apache.commons.lang.StringUtils;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.time.Instant;
import java.util.Date;
import java.util.Properties;
/**
 * @author ChenLong
 * @version 1.0
 * @ClassName SFtpUtil
 * @date 2019/7/24 20:53
 */
public class OSSUtil {
    private static String bucketName = null;
    private static String endpoint = null;
    private static String endpointNet = null;
    private static String region = null;
    private static String accessKey = null;
    private static String secretKey = null;
    private static AmazonS3 amazonS3NetClient = null;
    public static Properties getYdOssProp() {
        Properties props = new Properties();
        InputStream in = null;
        try {
            ResourceLoader resourceLoader = new DefaultResourceLoader();
            in = resourceLoader.getResource("ydOss.properties").getInputStream();
            props.load(in);
            return props;
        } catch (IOException e) {
            e.printStackTrace();
            return props;
        } finally {
            ResourceUtil.safeClose(in);
        }
    }
//    private static AmazonS3 client = null;
    public static AmazonS3 ossInit() {
        Properties props = getYdOssProp();
        bucketName = props.getProperty("ydOss.bucketName");
        endpoint = props.getProperty("ydOss.endpoint");
        region = props.getProperty("ydOss.region");
        accessKey = props.getProperty("ydOss.accessKey");
        secretKey = props.getProperty("ydOss.secretKey");
        // åˆ›å»º AmazonS3 å®žä¾‹ã€‚
        AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder.EndpointConfiguration(endpoint, region);
        BasicAWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
        AWSCredentialsProvider credentialsProvider = new AWSStaticCredentialsProvider(credentials);
        AmazonS3 client = AmazonS3ClientBuilder.standard()
                .withEndpointConfiguration(endpointConfiguration)
                .withCredentials(credentialsProvider).build();
        return client;
    }
    /**
     * èŽ·å–å¤–ç½‘oss地址
     *
     * @return
     */
    public static AmazonS3 ossNetInit() {
        if (amazonS3NetClient != null) {
            return amazonS3NetClient;
        }
        Properties props = getYdOssProp();
        bucketName = props.getProperty("ydOss.bucketName");
        endpointNet = props.getProperty("ydOss.endpointNet");
        region = props.getProperty("ydOss.region");
        accessKey = props.getProperty("ydOss.accessKey");
        secretKey = props.getProperty("ydOss.secretKey");
        // åˆ›å»º AmazonS3 å®žä¾‹ã€‚
        AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder.EndpointConfiguration(endpointNet, region);
        BasicAWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
        AWSCredentialsProvider credentialsProvider = new AWSStaticCredentialsProvider(credentials);
        amazonS3NetClient = AmazonS3ClientBuilder.standard()
                .withEndpointConfiguration(endpointConfiguration)
                .withCredentials(credentialsProvider).build();
        return amazonS3NetClient;
    }
    // ä¸Šä¼ æ–‡ä»¶ã€‚
    public static void upload(AmazonS3 client, String fileName, InputStream inputStream, String targetPath) {
        if (targetPath.startsWith("/")) {
            targetPath = targetPath.substring(1);
        }
        String objectName = targetPath + "/" + fileName;
        objectName = objectName.replace("//", "/");
        mkdirFolder(client, targetPath);
        ObjectMetadata objectMetadata = new ObjectMetadata();
        try {
            // è®¾ç½®å¯¹è±¡ï¼ˆObject)大小。
            objectMetadata.setContentLength(inputStream.available());
            // è®¾ç½®ä¸Šä¼ å†…容类型。
//            objectMetadata.setContentType("text/plain");
        } catch (IOException e) {
            e.printStackTrace();
        }
        // ä¸Šä¼ åŒæ—¶è®¾ç½®è®¿é—®æƒé™ï¼Œä¾‹å¦‚'Private'私有权限。
        PutObjectRequest request = new PutObjectRequest(bucketName, objectName, inputStream, objectMetadata);
        request.setCannedAcl(CannedAccessControlList.Private);
        PutObjectResult putObjectResult = client.putObject(request);
//        PutObjectResult putObjectResult = client.putObject(bucketName, objectName, inputStream, null);
        if (putObjectResult == null) {
            return;
        }
        try {
//            return getShareUrl(objectName);
            return;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return;
    }
    public static void upload(AmazonS3 client, String sourceFilePath, String targetFilePath, boolean isDelSourceFile) {
        String targetPath = targetFilePath.substring(0, targetFilePath.lastIndexOf("/"));
        System.out.println("上传 æœ¬åœ°è·¯å¾„" + sourceFilePath+" ä¸Šä¼ åˆ° " + targetFilePath);
        File file = new File(sourceFilePath);
        FileInputStream fileInputStream = null;
        try {
            fileInputStream = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return;
        }
        upload(client, file.getName(), fileInputStream, targetPath);
        if (isDelSourceFile) {
            FileUtil.del(sourceFilePath);
        }
        return;
    }
    public static void upload(AmazonS3 client, String FileName, BufferedImage bufferedImage, String targetPath)
            throws IOException {
        if (FileName.lastIndexOf(".") <= -1) {
            return;
        }
        String ext = FileName.substring(FileName.lastIndexOf(".") + 1);
        String sourceFilePath = System.getProperty("user.dir") + ResourceUtil.createFileName(ext);
        File tmpFile = FileUtil.touch(sourceFilePath);
        ImageIO.write(bufferedImage, "png", tmpFile);
        System.out.println("targetPath" + targetPath);
        upload(client, sourceFilePath, targetPath + FileName, true);
    }
    public static void download(AmazonS3 client, String sourceFilePath, String targetFilePath) {
        if (StringUtils.isEmpty(sourceFilePath)){
            return;
        }
        if (sourceFilePath.startsWith("/")){
            sourceFilePath = sourceFilePath.substring(1);
        }
        // å°†æ–‡ä»¶ï¼ˆObject)下载到文件中,并返回文件(Object)的元数据。
        GetObjectRequest request = new GetObjectRequest(bucketName, sourceFilePath);
        ObjectMetadata meta = client.getObject(request, FileUtil.touch(targetFilePath));
    }
    /**
     * åˆ›å»ºæ–‡ä»¶å¤¹
     *
     * @return
     */
    private static boolean mkdirFolder(AmazonS3 client, String directory) {
        String folder = String.copyValueOf(directory.toCharArray());
        if (directory.startsWith("/")) {
            folder = folder.substring(1);
        }
        if (!folder.endsWith("/")) {
            folder = folder + "/";
        }
        PutObjectResult putObjectResult = client.putObject(bucketName, folder, new ByteArrayInputStream(new byte[0]), null);
        return putObjectResult != null;
    }
    /**
     * èŽ·å–å¯¹è±¡çš„åˆ†äº«é“¾æŽ¥
     *
     * @param objectName
     * @return
     */
    public static String getShareUrl(String objectName) {
        ossNetInit();
        // ç”Ÿæˆå¯é¢„览的外链。
        GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, objectName);
        // è®¾ç½®è¿‡æœŸæ—¶é—´ï¼Œå½“到达该时间点时,URL å°±ä¼šè¿‡æœŸï¼Œå…¶ä»–人不再能访问该对象(Object)。
        Date expiration = new Date();
        // è®¾ç½® 30 åˆ†é’ŸåŽè¿‡æœŸã€‚
        long expTimeMillis = Instant.now().toEpochMilli();
        expTimeMillis += 1000 * 60 * 10;
        expiration.setTime(expTimeMillis);
        request.setExpiration(expiration);
        // è®¾ç½®è¿”回头
        // è®¾ç½®ä¸º "inline" æ—¶åœ¨æµè§ˆå™¨ä¸­å±•示,设置为 "attachment" æ—¶ä»¥æ–‡ä»¶å½¢å¼ä¸‹è½½ã€‚
        // æ­¤å¤–设置为 "attachment;filename=\"filename.jpg\"" ï¼Œè¿˜å¯ä»¥è®©ä¸‹è½½çš„æ–‡ä»¶åå­—重命名为 "filename.jpg"。
        ResponseHeaderOverrides headerOverrides = new ResponseHeaderOverrides();
        headerOverrides.setContentDisposition("inline");
        request.setResponseHeaders(headerOverrides);
        URL url = amazonS3NetClient.generatePresignedUrl(request);
        return url.toString();
    }
    public static void close(AmazonS3 client) {
        if (client != null) {
            client.shutdown();
        }
    }
    public static void main(String[] args) {
        // åˆ›å»º AmazonS3 å®žä¾‹ã€‚
        endpoint = "https://eos-beijing-7.cmecloud.cn";
        region = "beijing7";
        accessKey = "EDVFWAO1INQKHGJ78MK0";
        secretKey = "rQSMQ02h6oQPMaZyXR85XxLVhZh92jrwXFRkX6FX";
        bucketName = "ecosphere";
        AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder.EndpointConfiguration(endpoint, region);
        BasicAWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
        AWSCredentialsProvider credentialsProvider = new AWSStaticCredentialsProvider(credentials);
        AmazonS3 amazonS3 = AmazonS3ClientBuilder.standard()
                .withEndpointConfiguration(endpointConfiguration)
                .withCredentials(credentialsProvider).build();
        OSSUtil.download(amazonS3, "/ecosphereBase/2024/1/3/5894af65566a44a791baa4246bd5910a.csv", "C:\\Users\\cy\\Desktop\\新建文件夹\\b.csv");
        OSSUtil.close(amazonS3);
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/PageUtils.java
New file
@@ -0,0 +1,41 @@
package com.nuvole.util;
/**
 * @Description:
 * @Company: TOO (ps:公司名称)
 * @author: å”
 * @date: 2020/2/18 ä¸‹åˆ12:49
 * @version: V1.0.0
 */
public class PageUtils {
    public static String orderParser(String sortName, String sortOrder, String... prefix) {
        // Determine sortOrder equals 'asc' or 'desc'
        if (!(sortOrder.equals("asc") || sortOrder.equals("desc"))) {
            throw new IllegalArgumentException("Illegal sortOrder parameter");
        }
        // åˆ¤æ–­åˆ—名称的合法性,防止SQL注入。只能是【字母,数字,下划线】
        if (!sortName.matches("[A-Za-z0-9_]+")) {
            throw new IllegalArgumentException("Illegal sortName parameter");
        }
        StringBuilder sb = new StringBuilder();
        // å­˜åœ¨å‰ç¼€
        if (prefix.length != 0) {
            sb.append(prefix[0] + ".");
        }
        sb.append(CommonUtil.camel2Underline("`" + sortName + "`") + " " + sortOrder);
        return sb.toString();
    }
    public static void main(String[] args) {
//        System.out.println(orderParser("createTime", "asc"));
//        System.out.println(orderParser("createTime", "asc", "abc"));
//        System.out.println(orderParser("createTime,if((1=1),sleep(1),sleep(0))", "asc", "abc"));
        System.out.println(orderParser("createTime", "asc,if((1=1),sleep(1),sleep(0))", "abc"));
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/PayUtil.java
New file
@@ -0,0 +1,149 @@
package com.nuvole.util;
import cn.hutool.crypto.SecureUtil;
import jakarta.servlet.http.HttpServletRequest;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
/**
 * @author ChenLong
 * @version 1.0
 * @ClassName PayUtil
 * @date 2019/7/30 21:51
 */
public class PayUtil {
    public static Map getSignMap(Object f, String appKey) {
        TreeMap<String, String> map = new TreeMap<String,String>();
        Field[] fields = f.getClass().getDeclaredFields();
        for (int i = 0, len = fields.length; i < len; i++) {
            String varName = fields[i].getName();
            try {
                boolean accessFlag = fields[i].isAccessible();
                //fields[i].setAccessible(true);
                Object o = fields[i].get(f);
                if (!"0".equals(String.valueOf(o)) && !"null".equals(String.valueOf(o)) && !String.valueOf(o).isEmpty()) {
                    map.put(varName, String.valueOf(o));
                }
                System.out.println("传入的对象中包含一个如下的变量:" + varName + " = " + o);
                //fields[i].setAccessible(accessFlag);
            } catch (IllegalArgumentException ex) {
                ex.printStackTrace();
            } catch (IllegalAccessException ex) {
                ex.printStackTrace();
            }
        }
        map.remove("serialVersionUID");
        if (map.containsKey("validtime") && map.get("validtime").equals("null")) {
            map.remove("validtime");
        }
        map.put("sign", sign(map, appKey));
        return map;
    }
    public static String sign(TreeMap<String, String> params, String appkey) {
        if (params.containsKey("sign"))// ç­¾åæ˜Žæ–‡ç»„装不包含sign字段
            params.remove("sign");
        params.put("key", appkey);
        StringBuilder sb = new StringBuilder(512);
        for (Map.Entry<String, String> entry : params.entrySet()) {
            if (entry.getValue() != null && entry.getValue().length() > 0) {
                sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
            }
        }
        if (sb.length() > 0) {
            sb.deleteCharAt(sb.length() - 1);
        }
        String sign =  SecureUtil.md5(sb.toString());
        params.remove("key");
        return sign;
    }
    public static Map<String,String>  notify(HttpServletRequest request){
        InputStream inStream = null;
        ByteArrayOutputStream outSteam=null;
        Map<String, String> params =null;
        try {
            inStream = request.getInputStream();
            outSteam = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = inStream.read(buffer)) != -1) {
                outSteam.write(buffer, 0, len);
            }
            String resultxml = new String(outSteam.toByteArray(), "utf-8");
            params = xmlStrToMap(resultxml);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                outSteam.close();
                inStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return params;
    }
    public static String getNotifyParam(HttpServletRequest request) {
        InputStream inStream = null;
        ByteArrayOutputStream outSteam = null;
        String resultStr = null;
        try {
            inStream = request.getInputStream();
            outSteam = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = inStream.read(buffer)) != -1) {
                outSteam.write(buffer, 0, len);
            }
            resultStr = new String(outSteam.toByteArray(), "utf-8");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                outSteam.close();
                inStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultStr;
    }
    /**
     * Xml字符串转换为Map
     *
     * @param xmlStr
     * @return
     */
    public static Map<String, String> xmlStrToMap(String xmlStr) {
        Map<String, String> map = new HashMap<String, String>();
        Document doc;
        try {
            doc = DocumentHelper.parseText(xmlStr);
            Element root = doc.getRootElement();
            List children = root.elements();
            if (children != null && children.size() > 0) {
                for (int i = 0; i < children.size(); i++) {
                    Element child = (Element) children.get(i);
                    map.put(child.getName(), child.getTextTrim());
                }
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        return map;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/Pinyin.java
New file
@@ -0,0 +1,80 @@
package com.nuvole.util;
// @formatter:off
import net.sourceforge.pinyin4j.PinyinHelper;import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; /**
 *                .-~~~~~~~~~-._       _.-~~~~~~~~~-.
 *            __.'  @Author     ~.   .~    ä»£ç æ— Bug   `.__
 *          .'//     liu.q        \./       (秘籍)      \\`.
 *        .'// [916000612@qq.com]  |   æ¬²ç»ƒç¥žåŠŸ   å¼•刀自宫  \\`.
 *      .'// .-~"""""""~~~~-._     |    _,-~~~~"""""""~-.  \\`.
 *    .'//.-"  2019-04-10     `-.  |  .-'     17:35       "-.\\`.
 *  .'//______.============-..   \ | /   ..-============.______\\`.
 *.'______________________________\|/______________________________`.
 *
 * @Description :
 */
// @formatter:on
public class Pinyin {
    /**
     * æµ‹è¯•main方法
     *
     * @param args
     */
    public static void main(String[] args) {
        System.out.println(ToFirstChar("汉字转换为拼音").toUpperCase()); //转为首字母大写
        System.out.println(ToPinyin("汉字转换为拼音"));
    }
    /**
     * èŽ·å–å­—ç¬¦ä¸²æ‹¼éŸ³çš„ç¬¬ä¸€ä¸ªå­—æ¯
     *
     * @param chinese
     * @return
     */
    public static String ToFirstChar(String chinese) {
        String pinyinStr = "";
        char[] newChar = chinese.toCharArray();  //转为单个字符
        HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
        defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
        defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
        for (int i = 0; i < newChar.length; i++) {
            if (newChar[i] > 128) {
                try {
                    pinyinStr += PinyinHelper.toHanyuPinyinStringArray(newChar[i], defaultFormat)[0].charAt(0);
                } catch (BadHanyuPinyinOutputFormatCombination e) {
                    e.printStackTrace();
                }
            } else {
                pinyinStr += newChar[i];
            }
        }
        return pinyinStr;
    }
    /**
     * æ±‰å­—转为拼音
     *
     * @param chinese
     * @return
     */
    public static String ToPinyin(String chinese) {
        String pinyinStr = "";
        char[] newChar = chinese.toCharArray();
        HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
        defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
        defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
        for (int i = 0; i < newChar.length; i++) {
            if (newChar[i] > 128) {
                try {
                    pinyinStr += PinyinHelper.toHanyuPinyinStringArray(newChar[i], defaultFormat)[0];
                } catch (BadHanyuPinyinOutputFormatCombination e) {
                    e.printStackTrace();
                }
            } else {
                pinyinStr += newChar[i];
            }
        }
        return pinyinStr;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/PropertyUtil.java
New file
@@ -0,0 +1,35 @@
package com.nuvole.util;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
 * è¯»å–配置文件
 *
 * @Author: lc
 * @Date: 2019/6/13 15:31
 */
@Slf4j
public class PropertyUtil {
    public static String getProp(String fileName, String k) {
        Properties props = new Properties();
        InputStream in = null;
        try {
            ResourceLoader resourceLoader = new DefaultResourceLoader();
            in = resourceLoader.getResource(fileName).getInputStream();
            props.load(in);
            return props.getProperty(k);
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        } finally {
            ResourceUtil.safeClose(in);
        }
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/ResourceUtil.java
New file
@@ -0,0 +1,164 @@
package com.nuvole.util;
import cn.hutool.core.convert.Convert;
import java.io.Closeable;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Calendar;
import java.util.HashMap;
/**
 * @author ChenLong
 * @version 1.0
 * @ClassName FileUtil
 * @date 2019/4/15 13:06
 */
public class ResourceUtil {
    public static void safeClose(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    // ç”Ÿæˆftp æ–‡ä»¶ä¸Šä¼ è·¯å¾„
    public static String createFilePath() {
        Calendar ca = Calendar.getInstance();
        String year = Convert.toStr(ca.get(Calendar.YEAR));
        String mon = Convert.toStr(ca.get(Calendar.MONTH) + 1);
        String day = Convert.toStr(ca.get(Calendar.DAY_OF_MONTH));
        return "/" + year + "/" + mon + "/" + day + "/";
    }
    /**
     * ç”Ÿæˆæ–‡ä»¶å
     * @author ChenLong
     * @date 2019/4/26 11:22
     * @version 1.0
     * @param ext æ–‡ä»¶æ‰©å±•名 ï¼ˆdoc,xls等)
     * @return : java.lang.String
     */
    public static String createFileName(String ext) {
        Calendar ca = Calendar.getInstance();
        String year = Convert.toStr(ca.get(Calendar.YEAR));
        String mon = Convert.toStr(ca.get(Calendar.MONTH) + 1);
        String day = Convert.toStr(ca.get(Calendar.DAY_OF_MONTH));
        return "/" + year + "/" + mon + "/" + day + "/" + IdGenerator.getUUID() + "." + ext;
    }
    /**
     * ç”Ÿæˆæ–‡ä»¶å¤¹
     * @author ChenLong
     * @date 2019/4/26 11:22
     * @version 1.0
     * @return : java.lang.String
     */
    public static String createFileFolder() {
        Calendar ca = Calendar.getInstance();
        String year = Convert.toStr(ca.get(Calendar.YEAR));
        String mon = Convert.toStr(ca.get(Calendar.MONTH) + 1);
        String day = Convert.toStr(ca.get(Calendar.DAY_OF_MONTH));
        return "/" + year + "/" + mon + "/" + day + "/";
    }
    // @formatter:off
   /**       çŒªçŒªä¿ä½‘ æ°¸æ— bug
    *  _._ _..._ .-',     _.._(`))
    * '-. `     '  /-._.-'    ',/
    *    )         \            '.
    *   / _    _    |             \
    *  |  a    a    /              |
    *  \   .-.                     ;
    *   '-('' ).-'       ,'       ;
    *      '-;           |      .'
    *         \           \    /
    *         | 7  .__  _.-\   \
    *         | |  |  ``/  /`  /
    *        /,_|  |   /,_/   /
    *           /,_/      '`-'
    *
    * @Author : liu.q [916000612@qq.com]
    * @Date : 2019-04-24 15:32
    * @Description :  èŽ·å–æ–‡ä»¶çœŸå®žç±»åž‹
    */
    // @formatter:on
   // ç¼“存文件头信息-文件头信息
   public static final HashMap<String, String> mFileTypes = new HashMap<String, String>();
    static {
        // images
        mFileTypes.put("FFD8FF", "jpg");
        mFileTypes.put("89504E47", "png");
        mFileTypes.put("47494638", "gif");
        mFileTypes.put("49492A00", "tif");
        mFileTypes.put("424D", "bmp");
        //
        mFileTypes.put("41433130", "dwg"); // CAD
        mFileTypes.put("38425053", "psd");
        mFileTypes.put("7B5C727466", "rtf"); // æ—¥è®°æœ¬
        mFileTypes.put("3C3F786D6C", "xml");
        mFileTypes.put("68746D6C3E", "html");
        mFileTypes.put("44656C69766572792D646174653A", "eml"); // é‚®ä»¶
        mFileTypes.put("D0CF11E0", "doc");
        mFileTypes.put("D0CF11E0", "xls");//excel2003版本文件
        mFileTypes.put("5374616E64617264204A", "mdb");
        mFileTypes.put("252150532D41646F6265", "ps");
        mFileTypes.put("255044462D312E", "pdf");
        mFileTypes.put("504B0304", "docx");
        mFileTypes.put("504B0304", "xlsx");//excel2007以上版本文件
        mFileTypes.put("52617221", "rar");
        mFileTypes.put("57415645", "wav");
        mFileTypes.put("41564920", "avi");
        mFileTypes.put("2E524D46", "rm");
        mFileTypes.put("000001BA", "mpg");
        mFileTypes.put("000001B3", "mpg");
        mFileTypes.put("6D6F6F76", "mov");
        mFileTypes.put("3026B2758E66CF11", "asf");
        mFileTypes.put("4D546864", "mid");
        mFileTypes.put("1F8B08", "gz");
    }
    public static String getFileType(FileInputStream is) {
        String value = null;
        try {
            byte[] b = new byte[4];
            /*
             * int read() ä»Žæ­¤è¾“入流中读取一个数据字节。int read(byte[] b) ä»Žæ­¤è¾“入流中将最多 b.length
             * ä¸ªå­—节的数据读入一个 byte æ•°ç»„中。 int read(byte[] b, int off, int len)
             * ä»Žæ­¤è¾“入流中将最多 len ä¸ªå­—节的数据读入一个 byte æ•°ç»„中。
             */
            is.read(b, 0, b.length);
            StringBuilder builder = new StringBuilder();
            if (b == null || b.length <= 0) {
                return null;
            }
            String hv;
            for (int i = 0; i < b.length; i++) {
                // ä»¥åå…­è¿›åˆ¶ï¼ˆåŸºæ•° 16)无符号整数形式返回一个整数参数的字符串表示形式,并转换为大写
                hv = Integer.toHexString(b[i] & 0xFF).toUpperCase();
                if (hv.length() < 2) {
                    builder.append(0);
                }
                builder.append(hv);
            }
            value = builder.toString();
        } catch (Exception e) {
        } finally {
            if (null != is) {
                try {
                    is.close();
                } catch (IOException e) {
                }
            }
        }
        return value;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/ResultHandler.java
New file
@@ -0,0 +1,151 @@
package com.nuvole.util;
import com.nuvole.common.domain.emnu.CommonResultEmnu;
import com.nuvole.common.domain.result.CommonResult;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Supplier;
/**
 * åŠŸèƒ½æè¿°ï¼šCommonResult工具
 * @author xuekang
 * @date 2024-04-16 10:59
 * @version 1.0
 * @param <E> data类型
 */
public class ResultHandler<E> {
    /** CommonResult */
    private final CommonResult<E> result;
    /** è®¾ç½®ç©ºå¤„理函数 */
    private Supplier<E> nullProcess;
    /** è®¾ç½®data空处理函数 */
    private Supplier<E> dataNullProcess;
    /** é”™è¯¯ç å¤„理函数 */
    private List<ErrorProcess<E>> errorProcessList;
    public ResultHandler(CommonResult<E> result) {
        this.result = result;
    }
    public ResultHandler(CommonResult<E> result, ResultHandler<E> resultHandler) {
        this.result = result;
        this.nullProcess = resultHandler.nullProcess;
        this.dataNullProcess = resultHandler.dataNullProcess;
        this.errorProcessList = resultHandler.errorProcessList;
    }
    /**
     * è®¾ç½®ç©ºå¤„理函数
     * @param nullProcess ç©ºå¤„理函数
     * @return ResultHandler
     */
    public ResultHandler<E> setNullProcess(Supplier<E> nullProcess) {
        this.nullProcess = nullProcess;
        return this;
    }
    /**
     * è®¾ç½®data空处理函数
     * @param dataNullProcess data ç©ºå¤„理函数
     * @return ResultHandler
     */
    public ResultHandler<E> setDataNullProcess(Supplier<E> dataNullProcess) {
        this.dataNullProcess = dataNullProcess;
        return this;
    }
    /**
     * é”™è¯¯ç å¤„理函数
     * @param code é”™è¯¯ç 
     * @param errorProcessList å‡½æ•°
     * @return ResultHandler
     */
    public ResultHandler<E> appendError(Integer code, Supplier<E> errorProcessList) {
        if (this.errorProcessList == null) {
            this.errorProcessList = new LinkedList<>();
        }
        this.errorProcessList.add(new ErrorProcess<>(code, errorProcessList));
        return this;
    }
    /**
     * CommonResult工具
     * @param result CommonResult
     * @return ResultHandler
     * @param <T> data类型
     */
    public static <T>ResultHandler<T> getInstance(CommonResult<T> result) {
        return new ResultHandler<>(result);
    }
    /**
     * èŽ·å–
     * @param result CommonResult
     * @param resultHandler ResultHandler
     * @return ResultHandler
     * @param <T> date类型
     */
    public static <T>ResultHandler<T> getInstance(CommonResult<T> result, ResultHandler<T> resultHandler) {
        return new ResultHandler<>(result, resultHandler);
    }
    /**
     * èŽ·å–data
     * @return data
     */
    public E getDate() {
        if (result == null) {
            if (nullProcess != null) {
                return nullProcess.get();
            }
            return null;
        }
        Integer code = result.getCode();
        if (code.equals(CommonResultEmnu.OK.getCode())) {
            E data = result.getData();
            if (data == null && dataNullProcess != null) {
                return this.dataNullProcess.get();
            }
            return data;
        }
        if (errorProcessList == null) {
            return null;
        }
        for (ErrorProcess<E> process : this.errorProcessList) {
            if (code.equals(process.getCode())) {
                return process.getSupplier().get();
            }
        }
        return null;
    }
    public static void main(String[] args) {
//        Maps.EntryTransformer<BaseServiceClient, String, CommonResult<String>> getAllManagerByOrgCode = BaseServiceClient::getAllManagerByOrgCode;
//        ClientUtil.getDate(BaseServiceClient.class, BaseServiceClient::getAllManagerByOrgCode, null);
        ResultHandler.getInstance(new CommonResult<>())
                .setNullProcess(() -> {
                    throw new RuntimeException("");
                })
                .setDataNullProcess(() -> "")
                .appendError(1, () -> "")
                .getDate();
    }
    /**
     * åŠŸèƒ½æè¿°ï¼šé”™è¯¯å¤„ç†é€»è¾‘
     * @author xuekang
     * @date 2024-04-16 13:26
     * @version 1.0
     */
    @Data
    @AllArgsConstructor
    private static class ErrorProcess<E> {
        /** é”™è¯¯ç  */
        private Integer code;
        /** å¤„理函数 */
        private Supplier<E> supplier;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/SftpUtil.java
New file
@@ -0,0 +1,124 @@
package com.nuvole.util;
import cn.hutool.core.io.FileUtil;
import cn.hutool.extra.ssh.JschUtil;
import cn.hutool.extra.ssh.Sftp;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.ResourceLoader;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
 * @author ChenLong
 * @version 1.0
 * @ClassName SFtpUtil
 * @date 2019/7/24 20:53
 */
public class SftpUtil {
    public static Properties getFtpProp() {
        Properties props = new Properties();
        InputStream in = null;
        try {
            ResourceLoader resourceLoader = new DefaultResourceLoader();
            in = resourceLoader.getResource("sftp.properties").getInputStream();
            props.load(in);
            return props;
        } catch (IOException e) {
            e.printStackTrace();
            return props;
        } finally {
            ResourceUtil.safeClose(in);
        }
    }
    public static Sftp getSftp() {
        Properties props = getFtpProp();
        String url = props.getProperty("ftp.url");
        String username = props.getProperty("ftp.username");
        String mixpd = props.getProperty("ftp.mixpd");
        return JschUtil.createSftp(url, 22, username, mixpd);
    }
    public static void upload(Sftp sftp, String sourceFilePath, String targetFilePath, boolean isDelSourceFile) {
        System.out.println("begin upload");
        String targetPath = targetFilePath.substring(0, targetFilePath.lastIndexOf("/"));
        System.out.println("begin mkDirs");
        sftp.mkDirs(targetPath);
        System.out.println("end mkDirs");
        sftp.put(sourceFilePath, targetFilePath);
        System.out.println("upload finish");
        if (isDelSourceFile) {
            FileUtil.del(sourceFilePath);
        }
    }
    public static void main(String[] args) {
//        String url = "116.198.40.76";
//        String username = "mysftp";
//        String mixpd = "Bjjmy_2020";
//        Sftp sftp = JschUtil.createSftp(url, 22, username, mixpd);
//        String sourceFilePath = "D:/tmp/2023/8/9/84cd0f68c1764e10a2f9307e7bd3333a/Excel测试.zip";
//        String targetFilePath = "/ecosphereShopKf/goodsUploadMsgFile/2023/8/9/84cd0f68c1764e10a2f9307e7bd3333a/Excel测试.zip";
//        upload(sftp, sourceFilePath, targetFilePath);
        String paramsStr = "材质#304不锈钢|产地#郑州";
        String[] paramsArr = paramsStr.split("\\|");
        for (String paramKV : paramsArr) {
            String[] paramKVArr = paramKV.split("#");
            if (paramKVArr.length != 2) {
                System.out.println(paramKVArr.length);
            }
            if (paramKVArr[0].length() > 20 || paramKVArr[1].length() > 300) {
                System.out.println(paramKVArr[0].length());
            }
        }
    }
    public static void upload(Sftp sftp, String FileName, InputStream inputStream, String targetPath) {
        if (FileName.lastIndexOf(".") <= -1) {
            return;
        }
        String ext = FileName.substring(FileName.lastIndexOf(".") + 1);
        String sourceFilePath = System.getProperty("user.dir") + ResourceUtil.createFileName(ext);
        System.out.println("begin ");
        System.out.println("tmpFile.getPath(): ");
        File tmpFile = FileUtil.touch(sourceFilePath);
        FileUtil.writeFromStream(inputStream, tmpFile.getPath());
        System.out.println("tmpFile: " + tmpFile);
        upload(sftp, sourceFilePath, targetPath + FileName, true);
    }
    public static void upload(Sftp sftp, String FileName, BufferedImage bufferedImage, String targetPath)
            throws IOException {
        if (FileName.lastIndexOf(".") <= -1) {
            return;
        }
        String ext = FileName.substring(FileName.lastIndexOf(".") + 1);
        String sourceFilePath = System.getProperty("user.dir") + ResourceUtil.createFileName(ext);
        File tmpFile = FileUtil.touch(sourceFilePath);
        ImageIO.write(bufferedImage, "png", tmpFile);
        System.out.println("targetPath" + targetPath);
        upload(sftp, sourceFilePath, targetPath + FileName, true);
    }
    public static void download(Sftp sftp, String sourceFilePath, String targetFilePath) {
        sftp.download(sourceFilePath, FileUtil.touch(targetFilePath));
    }
    public static void del(Sftp sftp, String targetFilePath) {
        sftp.delFile(targetFilePath);
    }
    public static void close(Sftp sftp) {
        if (sftp != null) {
            sftp.close();
        }
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/TableExportCallUtil.java
New file
@@ -0,0 +1,35 @@
package com.nuvole.util;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.mysql.fabric.xmlrpc.base.Params;
import com.nuvole.constants.ServiceConstants;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
import java.util.Map;
/**
 * @Description: å¤–网接口导出工具
 * @Company: TOO (ps:公司名称)
 * @author: å”
 * @date: 2019/11/22 ä¸Šåˆ10:20
 * @version: V1.0.0
 */
@Slf4j
public class TableExportCallUtil {
    public static String getResult(String url, String sign, Long time, HashMap params) {
        String path = ServiceConstants.SERVICE_EXPORT_TABLE_URL;
        Map<String,Object> param = new HashMap<>(4);
        param.put("url",url);
        param.put("sign",sign);
        param.put("time",time);
        param.put("params", new JSONObject(params));
        return HttpUtil.get(path,param);
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/TencentMapUtil.java
New file
@@ -0,0 +1,99 @@
package com.nuvole.util;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
/**
 * è…¾è®¯åœ°å›¾å·¥å…·ç±»
 *
 * @Author: lc
 * @Date: 2019/6/28 14:57
 */
@Slf4j
public class TencentMapUtil {
    //腾讯地图秘钥
    public static String k = "5DUBZ-M5AKR-MZQWH-WPFLA-N4MNT-KBF44";
    //腾讯地图位置展示地址
    public static String mapUrl = "https://apis.map.qq.com/tools/poimarker";
    //逆地址解析地址
    public static String locationUrl = "https://apis.map.qq.com/ws/geocoder/v1";
    //签名校验sk
    public static String SK = "jCtZhEfr0u6FR8DrBqOI3XnUlZ7NTN0";
    /**
     * ç»çº¬åº¦è§£æžåœ°å€
     *
     * @param lat çº¬åº¦
     * @param lng çº¬åº¦
     * @Author: lc
     * @Date: 2019/6/28 15:13
     */
    public static String getLocation(String lat, String lng) {
        //组装数据
        Map<String, Object> r = new HashMap<>();
        String url = "/ws/geocoder/v1?";
        r.put("location", lat + "," + lng);
        r.put("key", k);
        String sign = SecureUtil.md5(url + coverMap2String(r) + SK);
        r.put("sig", sign);
        String result = HttpUtil.get(locationUrl, r);
        return result;
    }
    /**
     * ç”±æ–‡å­—地址到经纬度的转换能力,并同时提供结构化的省市区地址信息。
     * @param address
     * @return
     */
    public static String geocoder(String address) {
        //组装数据
        Map<String, Object> r = new HashMap<>();
        String url = "/ws/geocoder/v1?";
        r.put("address", address);
        r.put("key", k);
        String sign = SecureUtil.md5(url + coverMap2String(r) + SK);
        r.put("sig", sign);
        String result = HttpUtil.get(locationUrl, r);
        return result;
    }
    /**
     * å°†å‚数按key进行字典升序排列key1=value1
     */
    public static String coverMap2String(Map<String, Object> data) {
        TreeMap<String, Object> tree = new TreeMap<>();
        Iterator<Map.Entry<String, Object>> it = data.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, Object> en = it.next();
            tree.put(en.getKey(), en.getValue());
        }
        it = tree.entrySet().iterator();
        StringBuffer sf = new StringBuffer(512);
        while (it.hasNext()) {
            Map.Entry<String, Object> en = it.next();
            sf.append(en.getKey() + "=" + en.getValue()
                    + "&");
        }
        return sf.substring(0, sf.length() - 1);
    }
    public static void main(String[] args) {
        System.out.println("is result:" + getLocation("34.799145", "113.649445"));
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/TreeUtil.java
New file
@@ -0,0 +1,105 @@
package com.nuvole.util;
import cn.hutool.core.convert.Convert;
import java.util.*;
/**
 * @author ChenLong
 * @version 1.0
 * @ClassName TreeUtil
 * @Description tree工具类
 * @date 2019/4/23 15:50
 */
public class TreeUtil {
    public static <T> List<Map> convert2Tree(List<T> list) {
        return convert2Tree(list, null, "children");
    }
    public static <T> List<Map> convert2Tree(List<T> list, String childrenKey) {
        return convert2Tree(list, null, childrenKey);
    }
    public static <T> List<Map> convert2Tree(List<T> list, Map<String, String> mapping) {
        return convert2Tree(list, mapping, "children");
    }
    /**
     * å¯¹è±¡æ•°ç»„格式化为tree结构,对象中必须具有{id,pid}属性
     *
     * @param list
     * @param mapping     {"label":"name"} å°†æ•°æ®åº“查询list中的label属性替换为name属性
     * @param childrenKey è‡ªèŠ‚ç‚¹key名称 é»˜è®¤ä¸ºchildren
     * @return : java.util.List<java.util.Map>
     * @author ChenLong
     * @date 2019/4/23 18:44
     * @version 1.0
     */
    public static <T> List<Map> convert2Tree(List<T> list, Map<String, String> mapping, String childrenKey) {
        if (list == null || list.size() <= 0) {
            return new ArrayList<Map>();
        }
        Map root = new HashMap();
        root.put(childrenKey, new ArrayList<Map>());
        LinkedHashMap<String, Map> dataSet = new LinkedHashMap<String, Map>();
        for (T obj : list) {
            Map map;
            if (obj instanceof Map) {
                map = new HashMap(){{
                    putAll((Map) obj);
                }};
            } else {
                map = TypeConvertUtil.obj2Map(obj);
            }
            //结果转换
            if (mapping != null) {
                for (String key : mapping.keySet()) {
                    if (map.containsKey(key)) {
                        map.put(mapping.get(key), map.get(key));
                        //移除原有属性
                        map.remove(key);
                    }
                }
            }
            dataSet.put(Convert.toStr(map.get("id")), map);
        }
        //组装树
        for (String key : dataSet.keySet()) {
            Object parentId = ((dataSet.get(key)).get("pid"));
            if(parentId == null){
                /* å¢žåŠ ä¸€ç§å¤§å°å†™ç±»åž‹
                 * @author dqh
                 * @date  2024-04-12
                 **/
                parentId = ((dataSet.get(key)).get("PId"));
            }
            String pid = Convert.toStr(parentId);
            if (pid.equals("0")) {
                ((List<Map>) root.get(childrenKey)).add((Map) dataSet.get(key));
            } else {
                Map pNode = (Map) dataSet.get(pid);
                if (pNode != null) {
                    if (pNode.get(childrenKey) == null) {
                        List children = new ArrayList<Map>();
                        pNode.put(childrenKey, children);
                    }
                    ((List<Map>) pNode.get(childrenKey)).add((Map) dataSet.get(key));
                } else {
                    ((List<Map>) root.get(childrenKey)).add((Map) dataSet.get(key));
                }
            }
        }
        if (root.get(childrenKey) != null) {
            return (List<Map>) root.get(childrenKey);
        } else {
            return new ArrayList<Map>();
        }
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/TypeConvertUtil.java
New file
@@ -0,0 +1,36 @@
package com.nuvole.util;
import org.springframework.cglib.beans.BeanMap;
import java.util.HashMap;
import java.util.Map;
/**
 * @author ChenLong
 * @version 1.0
 * @ClassName TypeConvertUtil
 * @Description ç±»åž‹è½¬æ¢å·¥å…·ç±»
 * @date 2019/4/23 15:54
 */
public class TypeConvertUtil {
    /**
     * object转map
     * @author ChenLong
     * @date 2019/4/23 18:35
     * @version 1.0
     * @param obj éœ€è½¬æ¢å¯¹è±¡
     * @return : java.util.Map
    */
    public static Map obj2Map(Object obj) {
        HashMap map = new HashMap();
        if (obj != null) {
            BeanMap beanMap = BeanMap.create(obj);
            for (Object key : beanMap.keySet()) {
                map.put(key + "", beanMap.get(key));
            }
        }
        return map;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/VerifyImgUtil.java
New file
@@ -0,0 +1,153 @@
package com.nuvole.util;
// @formatter:off
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
/**
 * .-~~~~~~~~~-._       _.-~~~~~~~~~-.
 * __.'  @Author     ~.   .~    ä»£ç æ— Bug   `.__
 * .'//     liu.q        \./       (秘籍)      \\`.
 * .'// [916000612@qq.com]  |   æ¬²ç»ƒç¥žåŠŸ   å¼•刀自宫  \\`.
 * .'// .-~"""""""~~~~-._     |    _,-~~~~"""""""~-.  \\`.
 * .'//.-"  2019-06-24     `-.  |  .-'     15:43       "-.\\`.
 * .'//______.============-..   \ | /   ..-============.______\\`.
 * .'______________________________\|/______________________________`.
 *
 * @Description :
 */
// @formatter:on
public class VerifyImgUtil {
    private static int T_WIDTH = 320;  //源文件宽度
    private static int T_HEIGHT = 180;  //源文件高度
    /*
     * @Author : liu.q [916000612@qq.com]
     * @Date : 2019-06-24 15:46
     * @Description : éšæœºç”ŸæˆæŠ å›¾åæ ‡
     */
    public static Map<String, Integer> generateCutoutCoordinates(int w, int h) {
        Map<String, Integer> result = new HashMap();
        int x = new SecureRandom().nextInt(T_WIDTH - w);
        int y = new SecureRandom().nextInt(T_HEIGHT - h);
        while (x < w + 10) {
            x = new SecureRandom().nextInt(275);
        }
        result.put("x", x);
        result.put("y", y);
        return result;
    }
    /*
     * @Author : liu.q [916000612@qq.com]
     * @Date : 2019-06-24 16:22
     * @Description :生成滑块
     */
    public static Map<String, BufferedImage> initSlidingBlock(BufferedImage sourceImg, int[][] templateImgData, int x, int y, int w, int h) throws Exception {
        // æ”¯æŒalpha通道的rgb图像
        BufferedImage newTemplateImg = new BufferedImage(w, h, BufferedImage.TYPE_4BYTE_ABGR);
        for (int i = 0; i < templateImgData.length; i++) {
            for (int j = 0; j < templateImgData[0].length; j++) {
                int rgb = templateImgData[i][j];
                if (rgb == 1) {
                    int rgb_ori = sourceImg.getRGB(x + i, y + j);
                    int r = (0xff & rgb_ori);
                    int g = (0xff & (rgb_ori >> 8));
                    int b = (0xff & (rgb_ori >> 16));
                    rgb_ori = r + (g << 8) + (b << 16) + (255 << 24);
                    newTemplateImg.setRGB(i, j, rgb_ori);
                    //创建遮罩层
                    BufferedImage cover = new BufferedImage(10, 10, BufferedImage.TYPE_INT_RGB);
                    Graphics2D coverG2 = (Graphics2D) cover.getGraphics();
                    coverG2.setColor(Color.BLACK);
                    coverG2.fillRect(0, 0, 10, 10);
                    coverG2.dispose();
                    Graphics2D bgG2 = (Graphics2D) sourceImg.getGraphics();
                    //开启透明度
                    bgG2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, 0.5f));
                    //描绘
                    bgG2.drawImage(cover, i + x, y + j, 1, 1, null);
                    //结束透明度
                    bgG2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
                    bgG2.dispose();
                }
                if (rgb == 0) {
                    //不用搭理
                }
                if (rgb == 2) {
                    //秒边
                    newTemplateImg.setRGB(i, j, 16777215);
                    sourceImg.setRGB(x + i, y + j, 16777215);
                }
            }
        }
        Map<String, BufferedImage> result = new HashMap<>();
        result.put("newTemplateImg", newTemplateImg);
        result.put("newSourceImg", sourceImg);
        return result;
    }
    /*
     * @Author : liu.q [916000612@qq.com]
     * @Date : 2019-06-21 15:37
     * @Description : èŽ·å–base64
     */
    public static String getBase64(BufferedImage bi) {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        String res = "";
        try {
            ImageIO.write(bi, "png", outputStream);
            res = Base64.getEncoder().encodeToString(outputStream.toByteArray());
            res = "data:image/png;base64," + res;
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return res;
    }
    /*
     * @Author : liu.q [916000612@qq.com]
     * @Date : 2019-06-24 17:22
     * @Description : ç”ŸæˆæŠ å›¾å›¾å½¢çŸ©é˜µ
     */
    public static int[][] getTemplateData(BufferedImage bi) {
        int[][] data = new int[bi.getWidth()][bi.getHeight()];
        for (int i = 0; i < bi.getWidth(); i++) {
            for (int j = 0; j < bi.getHeight(); j++) {
                int rgb = bi.getRGB(i, j);
                int leftRgb = -1, rightRgb = -1, upRgb = -1, downRgb = -1;
                if (j > 0)
                    leftRgb = bi.getRGB(i, j - 1);
                if (j < bi.getHeight() - 1)
                    rightRgb = bi.getRGB(i, j + 1);
                if (i > 0)
                    upRgb = bi.getRGB(i - 1, j);
                if (i < bi.getWidth() - 1)
                    downRgb = bi.getRGB(i + 1, j);
                if (rgb == -1 && (i == 0 || i == bi.getWidth() - 1 || j == 0 || j == bi.getHeight() - 1)) {
                    data[i][j] = 2; //è¾¹
                } else if (rgb == -1 && (leftRgb != -1 || rightRgb != -1 || upRgb != -1 || downRgb != -1)) {
                    data[i][j] = 2;//è¾¹
                } else if (rgb == -1) {
                    data[i][j] = 1;//内容区域
                } else {
                    data[i][j] = 0;//透明区域
                }
            }
        }
        return data;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/WriterUtil.java
New file
@@ -0,0 +1,130 @@
package com.nuvole.util;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.file.FileWriter;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class WriterUtil {
    private static String path = "F:\\data\\";
   /* @Test
    public void test() {
        login("nodata", 1122L, "男", "172.16.60.222", "https://www.baidu.com");
        member(11222L, "nodata", Convert.toShort(1), "12121");
    }*/
    /**
     * å†™å…¥å•†åŸŽç™»å½•数据
     *
     * @param code     æœºå™¨ç 
     * @param memberId ä¼šå‘˜id
     * @param sex      æ€§åˆ«
     * @param ip       ip地址
     * @param address  ç™»å½•地址
     * @Author: lc
     * @Date: 2019/10/23 15:13
     */
    public static void login(String code, Long memberId, String sex, String ip, String address) {
//        String day = DateUtil.today();
//        FileWriter writer = new FileWriter(path + "login\\" + day + ".txt");
//        String time = CodeUtil.getTimeCode();
//        writer.append(time + " " + code + " " + memberId + " " + sex + " " + ip + " " + address + "\n");
    }
    /**
     * å†™å…¥ä¼šå‘˜æ³¨å†Œ/修改数据
     *
     * @param memberId ä¼šå‘˜id
     * @param area     åœ°åŒº
     * @param type     æ“ä½œç±»åž‹ã€1.新增 2.完善】
     * @param birthday ç”Ÿæ—¥
     * @Author: lc
     * @Date: 2019/10/23 15:13
     */
    public static void member(Long memberId, String area, Short type, String birthday) {
//        String day = DateUtil.today();
//        FileWriter writer = new FileWriter(path + "member\\" + day + ".txt");
//        String time = CodeUtil.getTimeCode();
//        writer.append(time + " " + memberId + " " + area + " " + type + " " + birthday + "\n");
    }
    /**
     * å†™å…¥è®¢å•数据
     *
     * @param orderId     è®¢å•id
     * @param orderType   è®¢å•类型【1.商城 2.商户】
     * @param payMoney    æ”¯ä»˜é‡‘额
     * @param memberId    ä¼šå‘˜id
     * @param orderState  è®¢å•状态【1.待支付 2.已完成 3.已退款 4.支付失败】
     * @param payType     æ”¯ä»˜æ¸ é“【1.支付宝 2.微信 3.云闪付】
     * @param payWay      æ”¯ä»˜æ–¹å¼ã€1.扫码 2.线上 ã€‘
     * @param useScore    ä½¿ç”¨ç§¯åˆ†
     * @param couponId    ä½¿ç”¨ä¼˜æƒ åˆ¸id
     * @param couponMoney ä¼˜æƒ åˆ¸é‡‘额
     * @param areaId      å•†æˆ·æ‰€å±žåŒºåŸŸid
     * @Author: lc
     * @Date: 2019/10/23 15:13
     */
    public static void order(Long orderId, String orderType, Long payMoney, Long memberId, Short orderState, Short payType, Short payWay, Long useScore, Long couponId, Long couponMoney, String areaId) {
//        String day = DateUtil.today();
//        FileWriter writer = new FileWriter(path + "order\\" + day + ".txt");
//        String time = CodeUtil.getTimeCode();
//        writer.append(time + " " + orderId + " " + orderType + " " + payMoney + " " + memberId + " " + orderState + " " +
//                payType + " " + payWay + " " + useScore + " " + couponId + " " + couponMoney + " " + areaId + "\n");
    }
    /**
     * å†™å…¥å•†å“æ•°æ®
     *
     * @param goodsSpuId å•†å“SpuId
     * @param goodsSkuId å•†å“SkuId
     * @param money      é‡‘额
     * @param state      çŠ¶æ€ã€1.新增 2.上架 3.下架 4.出售】
     * @Author: lc
     * @Date: 2019/10/23 15:13
     */
    public static void goods(Long goodsSpuId, Long goodsSkuId, Long money, Short state) {
//        String day = DateUtil.today();
//        FileWriter writer = new FileWriter(path + "goods\\" + day + ".txt");
//        String time = CodeUtil.getTimeCode();
//        writer.append(time + " " + goodsSpuId + " " + goodsSkuId + " " + money + " " + state + "\n");
    }
    /**
     * å†™å…¥å•†å“é”€å”®
     *
     * @param goodsSpuId å•†å“SpuId(规格)
     * @param goodsSkuId å•†å“SkuId(属性)
     * @Author: lc
     * @Date: 2019/10/23 15:13
     */
    public static void goodsSell(Long goodsSpuId, Long goodsSkuId) {
//        String day = DateUtil.today();
//        FileWriter writer = new FileWriter(path + "goodsSell\\" + day + ".txt");
//        String time = CodeUtil.getTimeCode();
//        writer.append(time + " " + goodsSpuId + " " + goodsSkuId + "\n");
    }
    /**
     * æ‰§è¡Œæ‰‹åŠ¨å›žè°ƒçš„è®¢å•id
     * @param builder
     * @throws IOException
     */
    public static void callBackGoodsInfo(StringBuilder builder) throws IOException {
        String fileName = new SimpleDateFormat("yyyyMMdd").format(new Date()) + ".csv";
        String day = DateUtil.today();
        FileWriter writer = new FileWriter(path + "回调订单" +fileName );
        writer.append(String.valueOf(builder));
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/WxCallUtil.java
New file
@@ -0,0 +1,185 @@
package com.nuvole.util;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.http.HttpUtil;
import com.nuvole.common.domain.wx.PushMsg;
import com.nuvole.constants.ServiceConstants;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * @Description: å¤–网接口请求工具类(微信)
 * @Author: liujun
 * @Date: 2019-07-25 11:59
 **/
@Slf4j
public class WxCallUtil {
    /**
     * èŽ·å–ä¸´æ—¶ç™»å½•å‡­è¯code
     *
     * @param jsCode
     * @return
     */
    public static String getOpenidSessionKey(String jsCode) {
        String url = ServiceConstants.SERVICE_JSCODE2SESSION_URL;
        Map<String, Object> paramMap = new HashMap<>(1);
        paramMap.put("jsCode", jsCode);
        return HttpUtil.get(url, paramMap);
    }
    /**
     * èŽ·å–AccessToken
     *
     * @return
     */
    public static String getAccessToken() {
        String url = ServiceConstants.SERVICE_TOKEN_URL;
        String result = HttpUtil.get(url);
        log.info("getAccessToken è¿”回值: {}", result);
        return result;
    }
    /**
     * èŽ·å– jsapi_ticket
     *
     * @return
     */
    public static String getJsapTicket(String accessToken) {
        String url = ServiceConstants.SERVICE_JSAPITICKET_URL;
        Map<String, Object> paramMap = new HashMap<>(1);
        paramMap.put("accessToken", accessToken);
        return HttpUtil.get(url, paramMap);
    }
    /**
     * å¾®ä¿¡å…¬ä¼—号获取access_token
     *
     * @param code
     * @return
     */
    public static String getWechatAccessToken(String code) {
        String url = ServiceConstants.SERVICE_ACCESS_TOKEN_URL;
        Map<String, Object> paramMap = new HashMap<>(1);
        paramMap.put("code", code);
        return HttpUtil.get(url, paramMap);
    }
    /**
     * å¾®ä¿¡å…¬ä¼—号获取用户信息
     *
     * @param accessToken
     * @param openId
     * @return
     */
    public static String getWechatUserInfo(String accessToken, String openId) {
        String url = ServiceConstants.SERVICE_USERINFO_URL;
        Map<String, Object> paramMap = new HashMap<>(2);
        paramMap.put("accessToken", accessToken);
        paramMap.put("openId", openId);
        return HttpUtil.get(url, paramMap);
    }
    /**
     * èŽ·å–å°ç¨‹åºç ï¼ˆå‰ææ˜¯å·²å‘å¸ƒï¼‰
     *
     * @param accessToken
     * @param scene
     * @param width
     * @param page
     * @return
     */
    public static byte[] getQRcode(String accessToken, String scene, int width, String page) {
        byte[] result = null;
        String url = ServiceConstants.SERVICE_WXACODEUNLIMIT_URL;
        if (false) {
            HttpClient client = new HttpClient();
            PostMethod method = new PostMethod(url);
            HttpMethodParams paramMap = new HttpMethodParams();
            paramMap.setParameter("accessToken", accessToken);
            paramMap.setParameter("scene", scene);
            paramMap.setParameter("width", width);
            paramMap.setParameter("page", page);
            method.setParams(paramMap);
            try {
                int statusCode = client.executeMethod(method);
                if (statusCode != HttpStatus.SC_OK) {
                    log.info("Method failed: " + method.getStatusLine());
                } else {
                    // è¿”回响应消息
                    result = method.getResponseBodyAsString().getBytes(method.getResponseCharSet());
                }
                method.releaseConnection();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } else {
            RestTemplate rest = new RestTemplate();
            try {
                Map<String, Object> param = new HashMap<>();
                url = url + "?accessToken=" + accessToken + "&scene=" + scene + "&width=" + width + "&page=" + page;
                MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
                HttpEntity requestEntity = new HttpEntity(param, headers);
                ResponseEntity<byte[]> entity = rest.exchange(url, HttpMethod.POST, requestEntity, byte[].class,
                        new Object[0]);
                result = entity.getBody();
                /*BASE64Encoder encoder = new BASE64Encoder();
                String imageStr = encoder.encode(result);
                imageStr = HtmlUtils.htmlEscape(imageStr);
                BASE64Decoder decoder = new BASE64Decoder();
                result = decoder.decodeBuffer(imageStr);*/
            } catch (Exception e) {
                log.error("调用小程序生成微信永久小程序码URL接口异常", e);
            }
        }
        return result;
    }
    /**
     * å¾®ä¿¡æŽ¨é€æ¶ˆæ¯
     *
     * @param openId
     * @param formId
     * @param templateId
     * @param page
     * @param items
     */
    public static void push(String openId, String formId, String templateId, String page, List<String> items) {
        String url = ServiceConstants.SERVICE_TEMPLATE_SEND_URL;
        Map<String, Object> paramMap = new HashMap<>(5);
        paramMap.put("openId", openId);
        paramMap.put("formId", formId);
        paramMap.put("templateId", templateId);
        paramMap.put("page", page);
        paramMap.put("items", CommonUtil.listToString(items));
        HttpUtil.get(url, paramMap);
    }
    /* *
     * å¾®ä¿¡å°ç¨‹åºè®¢é˜…消息推送
     *
     * @author lc
     * @date 2020/1/2 14:28
     */
    public static void pushSend(PushMsg pushMsg, String accessToken) {
        String url = ServiceConstants.SERVICE_SUBSCRIBER_SEND_URL;
        Map<String, Object> paramMap = BeanUtil.beanToMap(pushMsg);
        paramMap.put("accessToken", accessToken);
        HttpUtil.get(url, paramMap);
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/WxUtil.java
New file
@@ -0,0 +1,284 @@
package com.nuvole.util;
import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
import cn.binarywang.wx.miniapp.bean.WxMaTemplateData;
import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage;
import cn.binarywang.wx.miniapp.config.WxMaInMemoryConfig;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.nuvole.common.domain.dto.AppDTO;
import com.nuvole.common.domain.wx.PushMsg;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.beans.BeanUtils;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.HtmlUtils;
import java.util.*;
/**
 * å°ç¨‹åºå·¥å…·ç±»
 *
 * @author liujun
 * @Date 2019/5/27 16:40
 */
@Slf4j
public class WxUtil {
    /**
     * èŽ·å–ä¸´æ—¶ç™»å½•å‡­è¯code
     *
     * @param appid  AppID(小程序ID)
     * @param secret AppSecret(小程序密钥)
     * @param jsCode ç™»å½•时获取的Code
     * @return
     */
    public static String getOpenidSessionKey(String appid, String secret, String jsCode) {
        String url = "https://api.weixin.qq.com/sns/jscode2session";
        Map<String, Object> paramMap = new HashMap<>(3);
        paramMap.put("appid", appid);
        paramMap.put("secret", secret);
        paramMap.put("js_code", jsCode);
        paramMap.put("grant_type", "authorization_code");
        return HttpUtil.get(url, paramMap);
    }
    /**
     * èŽ·å–AccessToken
     *
     * @param appid  AppID(小程序ID)
     * @param secret AppSecret(小程序密钥)
     * @return
     */
    public static String getAccessToken(String appid, String secret) {
        String url = "https://api.weixin.qq.com/cgi-bin/token";
        Map<String, Object> paramMap = new HashMap<>(3);
        paramMap.put("appid", appid);
        paramMap.put("secret", secret);
        paramMap.put("grant_type", "client_credential");
        String s = HttpUtil.get(url, paramMap);
        log.info("获取AccessToken å‚æ•°= ã€‹appid:{},secret:{}", appid, secret);
        log.info("获取AccessToken = ã€‹{}", s);
        return s;
    }
    /**
     * èŽ·å–AccessToken
     *
     * @param accessToken getAccessToken方法获取的access_token
     * @return
     */
    public static String getJsapTicket(String accessToken) {
        String url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket";
        Map<String, Object> paramMap = new HashMap<>(3);
        paramMap.put("type", "jsapi");
        paramMap.put("access_token", accessToken);
        return HttpUtil.get(url, paramMap);
    }
    /**
     * Createed by PKZ Date 2019/6/18 17:11 Description:微信公众号获取access_token
     **/
    public static String getWechatAccessToken(String appid, String secret, String code) {
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token";
        Map<String, Object> paramMap = new HashMap<>(3);
        paramMap.put("appid", appid);
        paramMap.put("secret", secret);
        paramMap.put("code", code);
        paramMap.put("grant_type", "authorization_code");
        return HttpUtil.get(url, paramMap);
    }
    /**
     * Createed by PKZ Date 2019/6/18 17:13 Description:微信公众号获取用户信息
     **/
    public static String getWechatUserInfo(String access_token, String openid) {
        String url = "https://api.weixin.qq.com/sns/userinfo";
        Map<String, Object> paramMap = new HashMap<>(3);
        paramMap.put("access_token", access_token);
        paramMap.put("openid", openid);
        paramMap.put("lang", "zh_CN");
        return HttpUtil.get(url, paramMap);
    }
    /**
     * è¯¥æŽ¥å£ç”¨äºŽå°† code æ¢å–用户手机号
     *
     * @param access_token
     * @param code
     * @return
     */
    public static String getUserPhoneNumber(String access_token, String code) {
        String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + access_token;
        Map<String, Object> paramMap = new HashMap<>(1);
        paramMap.put("code", code);
        String result = HttpUtil.post(url, JSONUtil.toJsonStr(paramMap));
        log.info("getUserPhoneNumber=>{}", result);
        JSONObject resultInfo = JSONObject.parseObject(result);
        if (resultInfo.getIntValue("errcode") == 0) {
            return resultInfo.getJSONObject("phone_info").getString("purePhoneNumber");
        }
        return null;
    }
    /**
     * èŽ·å– URL Link
     *
     * @param access_token
     * @return
     */
    public static String generateUrllink(String access_token) {
        String url = "https://api.weixin.qq.com/wxa/generate_urllink?access_token=" + access_token;
        Map<String, Object> paramMap = new HashMap<>(1);
        String result = HttpUtil.post(url, JSONUtil.toJsonStr(paramMap));
        log.info("generateUrllink=>{}", result);
        JSONObject resultInfo = JSONObject.parseObject(result);
        if (resultInfo.getIntValue("errcode") == 0) {
            return resultInfo.getString("url_link");
        }
        return null;
    }
    /*
     * @Author : liu.q [916000612@qq.com]
     *
     * @Date : 2019-06-27 09:49
     *
     * @Description :获取小程序码(前提是已发布)
     *
     * @secne å‚æ•°
     *
     * @width ç å®½
     *
     * @page ç è·³è½¬è·¯å¾„
     */
    public static byte[] getQRcode(String access_token, String scene, int width, String page) {
        RestTemplate rest = new RestTemplate();
        byte[] result = null;
        try {
            String url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=" + access_token;
            Map<String, Object> param = new HashMap<>();
            param.put("scene", scene);
//            param.put("access_token", access_token); //access_token接在url后
            param.put("page", page);
            param.put("width", width);
            param.put("auto_color", true);
            Map<String, Object> line_color = new HashMap<>();
            line_color.put("r", 54);
            line_color.put("g", 56);
            line_color.put("b", 115);
            param.put("line_color", line_color);
            MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
            AppDTO sto = new AppDTO();
            AppDTO s = new AppDTO();
            sto.setMap(param);
            sto.setPro(url);
            BeanUtils.copyProperties(sto, s);
//            String result22 = HttpUtil.post(url, JSONUtil.toJsonStr(param));
//            log.info("getUserPhoneNumber=>{}",result22);
            HttpEntity requestEntity = new HttpEntity(s.getMap(), headers);
            ResponseEntity<byte[]> entity = rest.exchange(s.getPro(), HttpMethod.POST, requestEntity, byte[].class,
                    new Object[0]);
            result = entity.getBody();
            if (entity.getHeaders().getContentType().isCompatibleWith(MediaType.APPLICATION_JSON)) {
                log.error(new String(result));
                return null;
            }
            System.out.println(entity.toString());
            String imageStr = Base64.getEncoder().encodeToString(result);
            imageStr = HtmlUtils.htmlEscape(imageStr);
            result = Base64.getDecoder().decode(imageStr);
        } catch (Exception e) {
            e.printStackTrace();
            log.error("调用小程序生成微信永久小程序码URL接口异常", e);
        }
        return result;
    }
    /**
     * æŽ¨é€æ¶ˆæ¯
     *
     * @param appId
     * @param secret
     * @param openId
     * @param formId
     * @param templateId
     * @param page
     * @param items
     */
    public static void push(String appId, String secret, String openId, String formId, String templateId, String page,
                            List<String> items) {
        // 1,配置小程序信息
        WxMaInMemoryConfig wxConfig = new WxMaInMemoryConfig();
        // å°ç¨‹åºappid
        wxConfig.setAppid(appId);
        // å°ç¨‹åºAppSecret
        wxConfig.setSecret(secret);
        WxMaService wxMaService = new WxMaServiceImpl();
        wxMaService.setWxMaConfig(wxConfig);
        // 2,设置模版信息(keyword1:类型,keyword2:内容)
        List<WxMaTemplateData> templateDataList = new ArrayList<>(items.size());
        for (int i = 0; i < items.size(); i++) {
            WxMaTemplateData data = new WxMaTemplateData("keyword" + (i + 1), items.get(i));
            templateDataList.add(data);
        }
        // 3,设置推送消息
        WxMaTemplateMessage templateMessage = WxMaTemplateMessage.builder().toUser(openId).formId(formId)
                .templateId(templateId).data(templateDataList).page(page).build();
        // 4,发起推送
        try {
            wxMaService.getMsgService().sendTemplateMsg(templateMessage);
        } catch (WxErrorException e) {
            log.info("任务失败:" + e.getMessage());
        }
    }
    /* *
     * å°ç¨‹åº-订阅消息-推送消息
     *
     * @author lc
     * @date 2019/12/30 9:52
     */
    public static String pushSend(PushMsg pushMsg, String accessToken) {
        String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + accessToken;
        try {
            System.out.println("is :" + JSONUtil.toJsonStr(pushMsg));
            String result = HttpUtil.post(url, JSONUtil.toJsonStr(pushMsg));
            log.info("is push result:" + result);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /* *
     * å…¬ä¼—号-模板消息
     *
     */
    public static String h5PubpushSend(PushMsg pushMsg, String accessToken) {
        String url = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=" + accessToken;
        try {
            System.out.println("is :" + JSONUtil.toJsonStr(pushMsg));
            String result = HttpUtil.post(url, JSONUtil.toJsonStr(pushMsg));
            log.info("is push result:" + result);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/XssUtil.java
New file
@@ -0,0 +1,37 @@
package com.nuvole.util;
import cn.hutool.core.util.StrUtil;
import org.apache.commons.text.StringEscapeUtils;
import org.owasp.validator.html.AntiSamy;
import org.owasp.validator.html.Policy;
import org.owasp.validator.html.PolicyException;
import org.owasp.validator.html.ScanException;
import java.io.InputStream;
/**
 * @author ChenLong
 * @version 1.0
 * @ClassName XSSUtil
 * @date 2019/7/16 18:13
 */
public class XssUtil {
    public static String clearXss(String val) {
        if (StrUtil.isBlank(val)) {
            return val;
        }
        try {
            InputStream is = XssUtil.class.getResourceAsStream("/antisamy.xml");
            AntiSamy antiSamy = new AntiSamy();
            Policy policy = Policy.getInstance(is);
            return StringEscapeUtils.unescapeHtml4(antiSamy.scan(val, policy).getCleanHTML());
        } catch (PolicyException e) {
            e.printStackTrace();
        } catch (ScanException e) {
            e.printStackTrace();
        }
        return val;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/enums/FileType.java
New file
@@ -0,0 +1,187 @@
package com.nuvole.util.enums;
// @formatter:off
/**
 *                .-~~~~~~~~~-._       _.-~~~~~~~~~-.
 *            __.'  @Author     ~.   .~    ä»£ç æ— Bug   `.__
 *          .'//     liu.q        \./       (秘籍)      \\`.
 *        .'// [916000612@qq.com]  |   æ¬²ç»ƒç¥žåŠŸ   å¼•刀自宫  \\`.
 *      .'// .-~"""""""~~~~-._     |    _,-~~~~"""""""~-.  \\`.
 *    .'//.-"  2019-04-24     `-.  |  .-'     15:58       "-.\\`.
 *  .'//______.============-..   \ | /   ..-============.______\\`.
 *.'______________________________\|/______________________________`.
 *
 * @Description :
 */
// @formatter:on
public enum FileType {
    /**
     * JEPG.
     */
    JPEG("FFD8FF"),
    /**
     * PNG.
     */
    PNG("89504E47"),
    /**
     * GIF.
     */
    GIF("47494638"),
    /**
     * TIFF.
     */
    TIFF("49492A00"),
    /**
     * Windows Bitmap.
     */
    BMP("424D"),
    /**
     * CAD.
     */
    DWG("41433130"),
    /**
     * Adobe Photoshop.
     */
    PSD("38425053"),
    /**
     * Rich Text Format.
     */
    RTF("7B5C727466"),
    /**
     * XML.
     */
    XML("3C3F786D6C"),
    /**
     * HTML.
     */
    HTML("68746D6C3E"),
    /**
     * Email [thorough only].
     */
    EML("44656C69766572792D646174653A"),
    /**
     * Outlook Express.
     */
    DBX("CFAD12FEC5FD746F"),
    /**
     * Outlook (pst).
     */
    PST("2142444E"),
    /**
     * MS Word/Excel.
     */
    XLS_DOC("D0CF11E0"),
    /**
     * MS Access.
     */
    MDB("5374616E64617264204A"),
    /**
     * WordPerfect.
     */
    WPD("FF575043"),
    /**
     * Postscript.
     */
    EPS("252150532D41646F6265"),
    /**
     * Adobe Acrobat.
     */
    PDF("255044462D312E"),
    /**
     * Quicken.
     */
    QDF("AC9EBD8F"),
    /**
     * Windows Password.
     */
    PWL("E3828596"),
    /**
     * ZIP Archive.
     */
    ZIP("504B0304"),
    /**
     * RAR Archive.
     */
    RAR("52617221"),
    /**
     * Wave.
     */
    WAV("57415645"),
    /**
     * AVI.
     */
    AVI("41564920"),
    /**
     * Real Audio.
     */
    RAM("2E7261FD"),
    /**
     * Real Media.
     */
    RM("2E524D46"),
    /**
     * MPEG (mpg).
     */
    MPG("000001BA"),
    /**
     * Quicktime.
     */
    MOV("6D6F6F76"),
    /**
     * Windows Media.
     */
    ASF("3026B2758E66CF11"),
    /**
     * MIDI.
     */
    MID("4D546864");
    private String value = "";
    /**
     * Constructor.
     *
     * @param type
     */
    private FileType(String value) {
        this.value = value;
    }
    public String getValue() {
        return value;
    }
    public void setValue(String value) {
        this.value = value;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/enums/LaPushEnum.java
New file
@@ -0,0 +1,41 @@
package com.nuvole.util.enums;
/**
 * æ’­æŠ¥ç±»åž‹:
 * 01-XX银行收款成功
 * 02-支付宝收款成功
 * 03-微信收款成功
 * 10-取消支付
 */
public enum LaPushEnum {
    YINHANG("01", "XX银行收款成功"),
    ZFB("02", "支付宝收款成功"),
    WX("03", "微信收款成功"),
    YSF("04", "云闪付收款成功"),
    KJZF("05", "快捷支付收款成功"),
    CANCLE("10", "取消支付");
    private String code;
    private String name;
    private LaPushEnum(String code, String name) {
        this.code = code;
        this.name = name;
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/enums/QdlPayScene.java
New file
@@ -0,0 +1,37 @@
package com.nuvole.util.enums;
/**
 * æ”¯ä»˜åœºæ™¯
 */
public enum QdlPayScene {
    H5("H5", "微信公众号"),
    APP("APP", "微信小程序"),
    ZFB_APP("ZFB-APP", "支付宝小程序"),
    EXTERNAL_APP("EXTERNAL-APP",
            "端外模式(指定支付工具直接跳转 paymentUrl,未指定工具使用公司提供选择工具页面也跳转 paymentUrl)");
    private String code;
    private String name;
    private QdlPayScene(String code, String name) {
        this.code = code;
        this.name = name;
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/enums/QdlTradeStatus.java
New file
@@ -0,0 +1,49 @@
package com.nuvole.util.enums;
public enum QdlTradeStatus {
    SUCCESS("SUCCESS", "交易成功", "下单、退款"),
    FAIL("FAIL", "交易失败", "下单、退款"),
    WAITFORPAY("WAITFORPAY", "订单中间状态 ä¸‹å•:等待支付 é€€æ¬¾ï¼šå¤„理中", "下单、退款"),
    CLOSE("CLOSE", "订单超时关闭", "下单"),
    REFUNDED("REFUNDED", "已全部退款", "退款"),
    REFUNDING("REFUNDING", "部分退款", "退款"),
    REVOKED("REVOKED", "订单已撤销", "撤销"),
    REVOKING("REVOKING", "订单撤销中", "撤销");
    private String code;
    private String name;
    /**
     * ä½œç”¨åŸŸ
     */
    private String scope;
    private QdlTradeStatus(String code, String name, String scope) {
        this.code = code;
        this.name = name;
        this.scope = scope;
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getScope() {
        return scope;
    }
    public void setScope(String scope) {
        this.scope = scope;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/enums/QdlTradeType.java
New file
@@ -0,0 +1,35 @@
package com.nuvole.util.enums;
public enum QdlTradeType {
    BESTPAY("BESTPAY", "翼支付用户"),
    TENPAY("TENPAY", "微信用户"),
    QUICKPASS("QUICKPASS", "云闪付用户"),
    WEBANKPAY("WEBANKPAY", "微粒贷用户"),
    ALIPAY("ALIPAY", "支付宝用户"),
    REAL_TIME("REAL_TIME", "回调通知类型 å³æ—¶åˆ°è´¦"),
    REAL_TIME_PRO("REAL_TIME_PRO", "回调通知类型 é«˜çº§å³æ—¶åˆ°è´¦"),
    REFUND("REFUND", "回调通知类型 é€€æ¬¾");
    private String code;
    private String name;
    private QdlTradeType(String code, String name) {
        this.code = code;
        this.name = name;
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/oss/YiDongOss.java
New file
@@ -0,0 +1,126 @@
package com.nuvole.util.oss;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.SdkClientException;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;
import com.amazonaws.services.s3.model.PutObjectResult;
import com.amazonaws.services.s3.model.ResponseHeaderOverrides;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.net.URL;
import java.time.Instant;
import java.util.Date;
public class YiDongOss {
    // å¡«å†™è¦ä¸Šä¼ åˆ°çš„存储桶名称,例如'example-bucket'。
    private static final String bucketName = "ecosphere";
    // å¡«å†™å­˜å‚¨æ¡¶ï¼ˆBucket)所在地域对应的 endpoint å’Œ Region。
    private static final String endpoint = "https://eos.zhengzhou-4.cmecloud.cn";
    private static final String region = "zhengzhou4";
    // å¡«å†™ EOS è´¦å·çš„认证信息,或者子账号的认证信息。
    private static final String accessKey = "1PMC6XN2QVDEN6M6IWQB";
    private static final String secretKey = "tfbfDxHZGUIl7s3kb2fJyHCLtpZLydbzEhlTRmIy";
    private static AmazonS3 client = null;
    static {
        // åˆ›å»º AmazonS3 å®žä¾‹ã€‚
        AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder.EndpointConfiguration(endpoint, region);
        BasicAWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
        AWSCredentialsProvider credentialsProvider = new AWSStaticCredentialsProvider(credentials);
        client = AmazonS3ClientBuilder.standard()
                .withEndpointConfiguration(endpointConfiguration)
                .withCredentials(credentialsProvider).build();
    }
    public static void main(String[] args) throws Exception {
        try {
            String filePath = "C:\\Users\\cy\\Pictures\\铁窗泪.jpg";
            File uploadFile = new File(filePath);
            String fileName = uploadFile.getName();
            String foldName = "2023/12/19/";
//            mkdirFolder(client, bucketName,foldName);
//            uploadFile(client, bucketName, foldName + fileName, new FileInputStream(uploadFile));
            String shareUrl = getShareUrl(foldName + fileName);
        } catch (AmazonServiceException e) {
            // ä¸Šä¼ å¤±è´¥ã€‚
//            System.out.println("发生异常 AmazonServiceException,通常原因是请求内容错误。");
            System.out.println("Error Code: " + e.getErrorCode());
        } catch (SdkClientException e) {
            System.out.println("Error Message: " + e.getMessage());
        } finally {
            if (client != null) {
                client.shutdown();
            }
        }
    }
    // ä¸Šä¼ æ–‡ä»¶ã€‚
    public static String upload(String fileName, InputStream inputStream, String targetPath) {
        String objectName = targetPath + "/" + fileName;
        mkdirFolder(targetPath);
        PutObjectResult putObjectResult = client.putObject(bucketName, objectName, inputStream, null);
        if (putObjectResult == null) {
            return null;
        }
        try {
            return getShareUrl(objectName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * åˆ›å»ºæ–‡ä»¶å¤¹
     *
     * @return
     */
    private static boolean mkdirFolder(String directory) {
        PutObjectResult putObjectResult = client.putObject(bucketName, directory, new ByteArrayInputStream(new byte[0]), null);
        return putObjectResult != null;
    }
    /**
     * èŽ·å–å¯¹è±¡çš„åˆ†äº«é“¾æŽ¥
     *
     * @param objectName
     * @return
     */
    public static String getShareUrl(String objectName) throws Exception {
        // ç”Ÿæˆå¯é¢„览的外链。
        GeneratePresignedUrlRequest request =
                new GeneratePresignedUrlRequest(bucketName, objectName);
        // è®¾ç½®è¿‡æœŸæ—¶é—´ï¼Œå½“到达该时间点时,URL å°±ä¼šè¿‡æœŸï¼Œå…¶ä»–人不再能访问该对象(Object)。
        Date expiration = new Date();
//        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
//        expiration = simpleDateFormat.parse("2024/12/20 23:59:59");
        // è®¾ç½® 7 å¤©åŽè¿‡æœŸã€‚
        long expTimeMillis = Instant.now().toEpochMilli();
        expTimeMillis += 1000 * 60 * 60 * 24 * 7;
        expiration.setTime(expTimeMillis);
        request.setExpiration(expiration);
        // è®¾ç½®è¿”回头
        // è®¾ç½®ä¸º "inline" æ—¶åœ¨æµè§ˆå™¨ä¸­å±•示,设置为 "attachment" æ—¶ä»¥æ–‡ä»¶å½¢å¼ä¸‹è½½ã€‚
        // æ­¤å¤–设置为 "attachment;filename=\"filename.jpg\"" ï¼Œè¿˜å¯ä»¥è®©ä¸‹è½½çš„æ–‡ä»¶åå­—重命名为 "filename.jpg"。
        ResponseHeaderOverrides headerOverrides = new ResponseHeaderOverrides();
        headerOverrides.setContentDisposition("inline");
        request.setResponseHeaders(headerOverrides);
        URL url = client.generatePresignedUrl(request);
        System.out.println(url);
        return url.toString();
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/CallBackUrl.java
New file
@@ -0,0 +1,64 @@
package com.nuvole.util.pay.allinPay;
/**
 * æ”¯ä»˜å›žè°ƒåœ°å€
 *
 * @Author: lc
 * @Date: 2019/8/27 14:57
 */
public class CallBackUrl {
    /**
     * å•†åŸŽç»Ÿä¸€æ”¯ä»˜ä¸‹å•回调地址
     */
    public static String unifiedStoreGoodsPayUrl = "/v1/shop/web/payBack/storeGoodsPayBack";
    /**
     * å•†åŸŽç»Ÿä¸€æ”¯ä»˜ä¸‹å•回调地址
     */
    public static String storeShareFundRecordPayUrl = "/v1/shop/web/payBack/storeShareFundRecordCallBack";
    /**
     * å•†åŸŽå¿«æ·æ”¯ä»˜ä¸‹å•回调地址
     */
    public static String shortcutStoreGoodsPayUrl = "/v1/shop/web/payBack/shortcutStoreGoodsPayBack";
    /**
     * çº¯å°ç¨‹åºæ”¯ä»˜å›žè°ƒåœ°å€
     */
    public static String xcxGoodsPayUrl = "/v1/shop/web/payBack/xcxGoodsPayBack";
    /**
     * æ”¶é“¶å®ä¸‹ï¼Œå¾®ä¿¡æ”¯ä»˜C扫B扫码付2.0回调url
     */
    public static String sybWxC2BPayUrl = "v1/web/payBack/sybScanPayGoodsPayBack";
    /**
     * H5扫码支付--银行卡快捷支付 å›žè°ƒ
     */
    public static String sybKJPayUrl = "v1/web/payBack/scanPayGoodsSybPayBack";
    /**
     * psv为支付宝时,支付宝支付 C扫B扫码付回调
     */
    public static String zfbC2BPayUrl = "v1/web/payBack/scanPayGoodsSybPayBack";
    /**
     * psv为微信时,支付宝支付 C扫B扫码付回调
     */
    public static String wxC2BPayUrl = "v1/web/payBack/scanPayGoodsPayBack";
    /**
     * psv为云商通时, å•†æˆ·çº¿ä¸Šå¾®ä¿¡æ”¯ä»˜å›žè°ƒ  sc å•†åŸŽ
     */
    public static String ystScPayUrl = "v1/web/payBack/wechatMerchantBack";
    /**
     * æçŽ°ç­¾çº¦é€šçŸ¥(接收)
     */
    public static String ystTxSignUrl = "v1/web/payBack/signAcctNotify";
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/syb/SybPayCode.java
New file
@@ -0,0 +1,89 @@
package com.nuvole.util.pay.allinPay.syb;
/**
 * é€šè”交易状态码(快捷支付)
 *
 * @author: lc
 * @date: æ—¥æœŸï¼š2018å¹´11月26日 æ—¶é—´ï¼šä¸‹åˆ1:45:46
 */
public class SybPayCode {
    //其余3开头的错误,请读取errmsg
    /**
     * äº¤æ˜“成功
     */
    public static final String PAY_MSG_0000 = "0000";
    /**
     * éœ€èŽ·å–çŸ­ä¿¡éªŒè¯ç ,进行下一步确认操作
     */
    public static final String PAY_MSG_1999 = "1999";
    /**
     * äº¤æ˜“已受理(请查询结果)
     */
    public static final String PAY_MSG_2000 = "2000";
    /**
     * äº¤æ˜“已受理(请查询结果)
     */
    public static final String PAY_MSG_2018 = "2000";
    /**
     * äº¤æ˜“异常,请查询交易
     */
    public static final String PAY_MSG_3054 = "3054";
    /**
     * äº¤æ˜“异常,请查询交易
     */
    public static final String PAY_MSG_3004 = "3004";
    /**
     * åŽŸäº¤æ˜“ä¸å…è®¸æ’¤é”€æˆ–é€€è´§
     */
    public static final String PAY_MSG_3012 = "3012";
    /**
     * åŽŸäº¤æ˜“ä¸å­˜åœ¨
     */
    public static final String PAY_MSG_3035 = "3035";
    /**
     * åŽŸäº¤æ˜“ä¸å­˜åœ¨
     */
    public static final String PAY_MSG_1001 = "1001";
    /**
     * åè®®ä¸å­˜åœ¨
     */
    public static final String PAY_MSG_3045 = "3045";
    /**
     * å¡ä¿¡æ¯æˆ–手机号码错误
     */
    public static final String PAY_MSG_3046 = "3046";
    /**
     * è¯·é‡æ–°èŽ·å–éªŒè¯ç 
     */
    public static final String PAY_MSG_3057 = "3057";
    /**
     * çŸ­ä¿¡éªŒè¯ç é”™è¯¯
     */
    public static final String PAY_MSG_3058 = "3058";
    /**
     * çŸ­ä¿¡éªŒè¯ç å‘送失败
     */
    public static final String PAY_MSG_3059 = "3059";
    /**
     * å…¶ä»–错误
     */
    public static final String PAY_MSG_3999 = "3999";
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/syb/SybPayUrl.java
New file
@@ -0,0 +1,164 @@
package com.nuvole.util.pay.allinPay.syb;
/**
 * é€šè”支付地址(收银宝)
 *
 * @Author: lc
 * @Date: 2019/8/27 14:57
 */
public class SybPayUrl {
    /**
     * å•†æˆ·è®¢å•查询接口
     */
    public static final String MERCHANT_PAY_RESULT = "https://vsp.allinpay.com/apiweb/tranx/queryorder";
    /**
     * ç»Ÿä¸€ä¸‹å•接口
     */
    public static String UNIFIED_ORDER_URL = "https://vsp.allinpay.com/apiweb/unitorder/pay";
    /**
     * é€šè”支付B扫C下单接口地址
     */
    public static String ORDER_B_SWEEP_C_URL = "https://vsp.allinpay.com/apiweb/unitorder/scanqrpay";
    //收银宝进件接口前缀
//    private static String SYB_PREFIX = "https://vsp.allinpay.com/cusapi";
    private static String SYB_PREFIX = "https://syb-test.allinpay.com/vsppcusapi";
    /**
     * æ”¶é“¶åŒ…商户进件URL
     */
    public static String SYB_MERCHANT_ADD_URL = SYB_PREFIX + "/merchantapi/add";
    /**
     * å•†æˆ·å®¡æ ¸çŠ¶æ€æŸ¥è¯¢
     */
    public static String SYB_MERCHANT_ADD_QUERYSTATUS_URL = SYB_PREFIX + "/merchantapi/querystatus";
    /**
     * åˆè§„性状态查询接口
     */
    public static String SYB_MERCHANT_ADD_QUERYCUSRGC_URL = SYB_PREFIX + "/merchantapi/querycusrgc";
    /**
     * åˆè§„性审核补录统一h5接口
     */
    public static String SYB_MERCHANT_ADD_REPAIRCUSRGC_URL = SYB_PREFIX + "/merchantapi/repaircusrgc";
    /**
     * å¾®ä¿¡/支付宝认证状态查询
     */
    public static String SYB_MERCHANT_ADD_QUERYWXVERIFYSTATE_URL = SYB_PREFIX + "/merchantapi/querywxverifystate";
    /**
     * è®¤è¯ç»Ÿä¸€H5
     */
    public static String SYB_MERCHANT_ADD_WXVERIFY_URL = SYB_PREFIX + "/merchantapi/wxverify";
    /**
     * æ— çº¸åŒ–进件协议签约状态查询
     */
    public static String SYB_MERCHANT_ADD_QUERYELECTSIGN_URL = SYB_PREFIX + "/merchantapi/queryelectsign";
    /**
     * æ— çº¸åŒ–进件协议重发接口
     */
    public static String SYB_MERCHANT_ADD_ELECTSIGN_URL = SYB_PREFIX + "/merchantapi/electsign";
    /**
     * æ— çº¸åŒ–进件电子协议URL接口查询
     */
    public static String SYB_MERCHANT_ADD_QUERYELECTURL_URL = SYB_PREFIX + "/merchantapi/queryelecturl";
    /**
     * æ”¶é“¶å®æ–‡ä»¶ä¸Šä¼ URL
     */
    public static String SYB_FILE_UPLOAD_URL = SYB_PREFIX + "/sybupfile";
    /**
     * æ ¹æ®æŽˆæƒç (付款码)获取用户ID åœ°å€
     */
    public static final String SERVICE_AUTHCODE2USERID_URL = "https://vsp.allinpay.com/apiweb/unitorder/authcodetouserid";
    /**
     * é€šè”查询支付结果接口
     */
    public static String PAY__RESULT_B_SWEEP_C_URL = "https://vsp.allinpay.com/apiweb/unitorder/query";
    /**
     * åŠ¨æ€C扫B支付回调地址
     */
    public static String ACTIVE_C_SWEEP_B_URL_SYB = "/v1/web/payBack/activeCsweepBBack";
    public static String ACTIVE_C_SWEEP_B_URL_WX = "/v1/web/payBack/activeCsweepBBackWx";
    /**
     * é€šè”对面付总公司重定向地址
     */
    public static String F2F_HEAD_BACK_URL = "https://syb.allinpay.com/sappweb/usertrans/cuspay";
    /**
     * é“¶è”云闪付授权userid
     */
    public static final String UNION_AUTH_URL = "https://vsp.allinpay.com/apiweb/unitorder/authcodetouserid";
    /**
     * é“¶è”云闪付支付
     */
    public static final String UNION_PAY_URL = "https://vsp.allinpay.com/apiweb/unitorder/pay";
    /**
     * é€šè”接口地址
     */
    public static String ALLINPAY_URL = "https://vsp.allinpay.com";
//    public static String ALLINPAY_URL = "https://syb-test.allinpay.com";
    /**
     * ç”³è¯·ç­¾çº¦ï¼ˆé€šè”快捷支付)
     */
    public static String AGREEAPPLY_URL = ALLINPAY_URL + "/apiweb/qpay/agreeapply";
    /**
     * ç”³è¯·ç¡®è®¤ï¼ˆé€šè”快捷支付)
     */
    public static String AGREECONFIRM_URL = ALLINPAY_URL + "/apiweb/qpay/agreeconfirm";
    /**
     * æ”¯ä»˜ç”³è¯·é‡å‘验证短信(通联快捷支付)
     */
    public static String AGREEMS_URL = ALLINPAY_URL + "/apiweb/qpay/agreesms";
    /**
     * æ”¯ä»˜ç”³è¯·ï¼ˆé€šè”快捷支付)
     */
    public static String PAYAPPLYAGREE_URL = ALLINPAY_URL + "/apiweb/qpay/payapplyagree";
    /**
     * æ”¯ä»˜ç¡®è®¤ï¼ˆé€šè”快捷支付)
     */
    public static String PAYAGREECONFIRM_URL = ALLINPAY_URL + "/apiweb/qpay/payagreeconfirm";
    /**
     * é‡å‘支付短信(通联快捷支付)
     */
    public static String PAYSMSAGREE_URL = ALLINPAY_URL + "/apiweb/qpay/paysmsagree";
    /**
     * æŸ¥è¯¢ç­¾çº¦ä¿¡æ¯ï¼ˆé€šè”快捷支付)
     */
    public static String AGREEQUERY_URL = ALLINPAY_URL + "/apiweb/qpay/agreequery";
    /**
     * é“¶è¡Œå¡è§£ç»‘(通联快捷支付)
     */
    public static String UNBIND_URL = ALLINPAY_URL + "/apiweb/qpay/unbind";
    /**
     * æŸ¥è¯¢äº¤æ˜“结果
     */
    public static String QUERY_URL = ALLINPAY_URL + "/apiweb/qpay/query";
    /**
     * å•†åŸŽå›žè°ƒé€šçŸ¥
     */
    public static String SHOP_CALL_BACK = "http://10.94.2.161:9010/service-shop/v1/shop/web/payBack/storeGoodsPayBack";
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/syb/SybPayUtil.java
New file
@@ -0,0 +1,1628 @@
package com.nuvole.util.pay.allinPay.syb;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.nuvole.common.domain.emnu.CommonResultEmnu;
import com.nuvole.common.domain.result.CommonResult;
import com.nuvole.constants.PropertiesConstants;
import com.nuvole.constants.ServiceConstants;
import com.nuvole.util.IdGenerator;
import com.nuvole.util.pay.allinPay.syb.param.MerchantAddParam;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.jcajce.spec.SM2ParameterSpec;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
/**
 * é€šè”支付工具类(收银宝)
 *
 * @Author: lc
 * @Date: 2019/8/27 14:57
 */
public class SybPayUtil {
    //版本号
    private static final String version = "11";
    //支付信息
    private static final String k = PropertiesConstants.TL_PAY_K;
    private static final String appId = PropertiesConstants.TL_PAY_APPID;
    private static final String orgCode = PropertiesConstants.TL_PAY_ORGCODE;
    //测试用下列参数
    //快捷支付测试环境参数
    private static final String tlk = "allinpay888";
    private static final String tlappId = "00000051";
    private static final String tlCusId = "990581007426001";
    //快捷支付正式环境所用测试参数
   /* private static final String tlk = "a0ea3fa20dbd7bb4d5abf1d59d63bae8";
    private static final String tlappId = "00000003";
    private static final String tlCusId = "990440148166000";*/
    /**算法常量:SM3withSM2*/
    private static final String ALGORITHM_SM3SM2_BCPROV = "SM3withSM2";
    /** ç®—法常量:SM3加密长度 */
    private final static int SM3withSM2_RS_LEN=32;
    /**
     * ç»Ÿä¸€æ”¯ä»˜
     *
     * @param orgid:通联机构号
     * @param cusid:通联商户号
     * @param appid:通联appid
     * @param sub_appid:微信支付APPID,
     * @param acct:用户标识(微信openid)
     * @param trxamt:交易金额(分)
     * @param reqsn:商户交易单号
     * @param paytype:交易方式(W01:微信  A01:支付宝)
     * @param notify_url:交易结果通知地址
     * @param key:商户对应的key
     * @param asinfo:分账信息,可以为空
     * @param body:标题
     * @param remark:备注
     * @Author: lc
     * @Date: 2019/8/27 15:25
     */
    public static String unifiedOrder(String orgid, String cusid, String appid, String sub_appid, String acct, Integer trxamt,
                                      String reqsn, String paytype, String notify_url, String key, String asinfo, String body, String remark) {
        //组装数据
        Map paramMap = new HashMap<String, String>();
        if (StrUtil.isNotEmpty(orgid)) {
            paramMap.put("orgid", orgid);
        }
        paramMap.put("cusid", cusid);
        paramMap.put("appid", appid);
        paramMap.put("version", version);
        paramMap.put("trxamt", Convert.toStr(trxamt));
        paramMap.put("reqsn", reqsn);
        paramMap.put("paytype", paytype);
        paramMap.put("randomstr", IdGenerator.getUUID());
        if (StrUtil.isNotEmpty(body)) {
            paramMap.put("body", body);
        }
        if (StrUtil.isNotEmpty(remark)) {
            paramMap.put("remark", remark);
        }
        if (StrUtil.isNotEmpty(acct)) {
            paramMap.put("acct", acct);
        }
        paramMap.put("notify_url", notify_url);
        paramMap.put("signtype", "RSA");
        if (StrUtil.isNotEmpty(asinfo)) {
            paramMap.put("asinfo", asinfo);
        }
        if (StrUtil.isNotEmpty(sub_appid)) {
            paramMap.put("sub_appid", sub_appid);
        }
        paramMap.put("signtype", "RSA");
        String signStr = coverMap2String(paramMap);
//        String sign = DigestUtil.md5Hex(signStr).toUpperCase(Locale.ENGLISH);
//        paramMap.put("sign", sign);
        String sign = null;
        try {
            sign = SybPayUtil.rsaSign(signStr, key, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        paramMap.put("sign", sign);
        paramMap.remove("key");
//        System.out.println("is param:" + JSONUtil.parseObj(paramMap));
        String result = "";
        if (ServiceConstants.SERVICE_TYPE) {    //走服务调用
            String url = ServiceConstants.SERVICE_UNIFIED_URL;
            result = HttpUtil.post(url, paramMap);
        } else {
            result = HttpUtil.post(SybPayUrl.UNIFIED_ORDER_URL, paramMap);
        }
        System.out.println("is result:" + result);
        return result;
    }
    /**
     * æ ¹æ®æŽˆæƒç (付款码)获取用户ID
     * ä½¿ç”¨åœºæ™¯ï¼š
     * é€šè¿‡å¾®ä¿¡ä»˜æ¬¾ç æ¢å–openid
     * é€šè¿‡é“¶è”userAuth的code(非付款码)换取userid
     *
     * @param orgid:集团/代理商商户号
     * @param cusid:通联商户号
     * @param appid:通联appid
     * @param key:商户对应的key
     * @param authCode:支付授权码(微信、支付宝的授权码)
     * @param authType:授权码类型             01-微信付款码 02-银联userAuth
     * @param identify:云闪付UA标识           å½“authtype=02时选送
     * @param subAppid:微信支付appid         é’ˆå¯¹01有效
     */
    public static String authCode2Userid(String orgid, String cusid, String appid, String key, String authCode, String authType, String identify, String subAppid) {
        Map paramMap = new HashMap<String, String>();
        if (StrUtil.isNotEmpty(orgid)) {
            paramMap.put("orgid", orgid);
        }
        paramMap.put("cusid", cusid);
        paramMap.put("appid", appid);
        paramMap.put("version", version);
        paramMap.put("authcode", authCode);
        paramMap.put("authtype", authType);
        if (StringUtils.isNotBlank(identify)) {
            paramMap.put("identify", identify);
        }
        if (StringUtils.isNotBlank(subAppid)) {
            paramMap.put("sub_appid", subAppid);
        }
        paramMap.put("randomstr", IdGenerator.getUUID());
        paramMap.put("signtype", "RSA");
        String signStr = coverMap2String(paramMap);
        String sign = null;
        try {
            sign = SybPayUtil.rsaSign(signStr, key, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        paramMap.put("sign", sign);
        paramMap.remove("key");
        System.out.println("根据授权码(付款码)获取用户ID -->" + JSONUtil.toJsonStr(paramMap));
        String result = "";
        //走服务调用
        if (ServiceConstants.SERVICE_TYPE) {
            String url = ServiceConstants.SERVICE_AUTHCODE2USERID_URL;
            result = HttpUtil.post(url, paramMap);
        } else {
            result = HttpUtil.post(SybPayUrl.SERVICE_AUTHCODE2USERID_URL, paramMap);
        }
        return result;
    }
    /**
     * B扫C支付(商户扫用户)
     *
     * @param orgid:通联机构号
     * @param cusid:通联商户号
     * @param appid:通联appid
     * @param key:商户对应的key
     * @param trxamt:交易金额(分)
     * @param reqsn:商户交易单号
     * @param body:订单标题,
     * @param remark:订单备注
     * @param authcode:支付授权码(微信、支付宝的授权码)
     * @param limit_pay:支付限额
     * @Author: lc
     * @Date: 2019/8/27 15:25
     */
    public static String orderBsweepC(String orgid, String cusid, String appid, String key, Integer trxamt, String reqsn, String body, String remark, String authcode, String limit_pay) {
        Map paramMap = new HashMap<String, String>();
        if (StrUtil.isNotEmpty(orgid)) {
            paramMap.put("orgid", orgid);
        }
        paramMap.put("cusid", cusid);
        paramMap.put("appid", appid);
        paramMap.put("version", version);
        paramMap.put("randomstr", IdGenerator.getUUID());
        paramMap.put("trxamt", Convert.toStr(trxamt));
        paramMap.put("reqsn", reqsn);
        if (StrUtil.isNotEmpty(body)) {
            paramMap.put("body", body);
        }
        if (StrUtil.isNotEmpty(remark)) {
            paramMap.put("remark", remark);
        }
        paramMap.put("authcode", authcode);
        if (StrUtil.isNotEmpty(body)) {
            paramMap.put("body", body);
        }
        if (StrUtil.isNotEmpty(remark)) {
            paramMap.put("remark", remark);
        }
        if (StrUtil.isNotEmpty(limit_pay)) {
            paramMap.put("limit_pay", limit_pay);
        }
        paramMap.put("signtype", "RSA");
        String signStr = coverMap2String(paramMap);
        String sign = null;
        try {
            sign = SybPayUtil.rsaSign(signStr, key, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        paramMap.put("sign", sign);
        paramMap.remove("key");
        System.out.println("is tl b sweep c param -->" + JSONUtil.toJsonStr(paramMap));
        String result = "";
        //走服务调用
        if (ServiceConstants.SERVICE_TYPE) {
            String url = ServiceConstants.SERVICE_B_SWEEP_C_URL;
            result = HttpUtil.post(url, paramMap);
        } else {
            result = HttpUtil.post(SybPayUrl.ORDER_B_SWEEP_C_URL, paramMap);
        }
        Map resultMap = JSON.parseObject(result);
        if (null != resultMap && resultMap.size() > 0) {
            //返回码2000等待结果确认每隔10秒执行结果查询,最多4次
            if ("2000".equals(resultMap.get("trxstatus") + "")) {
                int index = 0;
                final int count = 4;
                do {
                    index++;
                    try {
                        result = getPayResult(orgid, cusid, appid, key, reqsn);
                        resultMap = JSON.parseObject(result);
                        Thread.sleep(10 * 1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } while (index < count && "2000".equals(resultMap.get("trxstatus") + ""));
            }
        }
        return result;
    }
    /**
     * æŸ¥è¯¢äº¤æ˜“支付结果
     *
     * @param orgid é€šè”机构号
     * @param cusid é€šè”商户号
     * @param appid é€šè”appid
     * @param key   å•†æˆ·å¯¹åº”çš„key
     * @param reqsn å•†æˆ·äº¤æ˜“单号
     * @Author: lc
     * @Date: 2019/8/27 15:25
     */
    public static String getPayResult(String orgid, String cusid, String appid, String key, String reqsn) {
        //组装数据
        Map paramMap = new HashMap();
        if (StrUtil.isNotEmpty(orgid)) {
            paramMap.put("orgid", orgid);
        }
        paramMap.put("cusid", cusid);
        paramMap.put("appid", appid);
        paramMap.put("version", version);
        paramMap.put("reqsn", reqsn);
        paramMap.put("randomstr", IdGenerator.getUUID());
        paramMap.put("signtype", "RSA");
        String signStr = coverMap2String(paramMap);
        String sign = null;
        try {
            sign = SybPayUtil.rsaSign(signStr, key, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        paramMap.put("sign", sign);
        paramMap.remove("key");
        String result = "";
        //走服务调用
        if (ServiceConstants.SERVICE_TYPE) {
            String url = ServiceConstants.SERVICE_PAY_RESULT_URL;
            result = HttpUtil.post(url, paramMap);
        } else {
            result = HttpUtil.post(SybPayUrl.PAY__RESULT_B_SWEEP_C_URL, paramMap);
        }
        System.out.println("is tl b sweep c æŸ¥è¯¢äº¤æ˜“结果 param -->" + JSONUtil.toJsonStr(paramMap));
        return result;
    }
    private static String checkCardUrl = "https://ccdcapi.alipay.com/validateAndCacheCardInfo.json?_input_charset=utf-8&cardBinCheck=true&cardNo=";
    /**
     * ç­¾çº¦ç”³è¯·
     *
     * @param key       ç§˜é’¥
     * @param cusid     é€šè”分配的商户号
     * @param appid     é€šè”分配的appid
     * @param meruserid å•†æˆ·ç”¨æˆ·å·(会员id)
     * @param accttype  00:借记卡02:准贷记卡/贷记卡
     * @param acctno    é“¶è¡Œå¡å·
     * @param idno      è¯ä»¶å·
     * @param acctname  æˆ·å
     * @param mobile    æ‰‹æœºå·ç 
     * @param validdate æœ‰æ•ˆæœŸMMyy信用卡不能为空
     * @param cvv2      Cvv2 ä¿¡ç”¨å¡ä¸èƒ½ä¸ºç©º
     * @param signtype  åŠ å¯†æ–¹å¼
     * @Author: lc
     * @Date: 2019/8/27 15:25
     */
    public static String agreeapply(String key, String cusid, String appid,
                                    String meruserid, String accttype, String acctno,
                                    String idno, String acctname, String mobile, String validdate, String cvv2
            , String signtype) {
        Map paramMap = new HashMap();
        paramMap.put("cusid", cusid);
        paramMap.put("appid", appid);
        paramMap.put("version", version);
        paramMap.put("randomstr", IdGenerator.getUUID());
//        å•†æˆ·ç”¨æˆ·å·
        paramMap.put("meruserid", meruserid);
        //商户用户号 00:借记卡 02:准贷记卡/贷记卡
        paramMap.put("accttype", accttype);
        // é“¶è¡Œå¡å·
        paramMap.put("acctno", acctno);
        // è¯ä»¶ç±»åž‹  0:身份证 2:护照 5:港澳通行证 6:台湾通行证
        paramMap.put("idtype", 0);
        //证件号
        paramMap.put("idno", idno);
        // æˆ·å
        paramMap.put("acctname", acctname);
        // æ‰‹æœºå·ç 
        paramMap.put("mobile", mobile);
        if ("02".equals(accttype)) {
            paramMap.put("validdate", validdate);
            paramMap.put("cvv2", cvv2);
        }
        paramMap.put("signtype", "RSA");
        String signStr = null;
        String sign = null;
        try {
            signStr = coverMap2String(paramMap);
            System.out.println("signStr==>" + signStr);
            sign = SybPayUtil.rsaSign(signStr, key, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        paramMap.put("sign", sign);
        System.out.println("is agreeapply url:" + SybPayUrl.AGREEAPPLY_URL);
        System.out.println("is agreeapply param:" + JSONUtil.toJsonStr(paramMap));
        System.out.println("is agreeapply sign:" + sign);
        String result = HttpUtil.post(SybPayUrl.AGREEAPPLY_URL, paramMap);
        System.out.println("is agreeapply result:" + result);
        return result;
    }
    /**
     * é‡å‘签约短信
     *
     * @param key       ç§˜é’¥
     * @param cusid     é€šè”分配的商户号
     * @param appid     é€šè”分配的appid
     * @param meruserid å•†æˆ·ç”¨æˆ·å·(会员id)
     * @param accttype  00:借记卡02:准贷记卡/贷记卡
     * @param acctno    é“¶è¡Œå¡å·
     * @param idno      è¯ä»¶å·
     * @param acctname  æˆ·å
     * @param mobile    æ‰‹æœºå·ç 
     * @param validdate æœ‰æ•ˆæœŸMMyy信用卡不能为空
     * @param cvv2      Cvv2 ä¿¡ç”¨å¡ä¸èƒ½ä¸ºç©º
     * @Author: lc
     * @Date: 2019/8/27 15:25
     */
    public static String agreems(String key, String cusid, String appid,
                                 String meruserid, String accttype, String acctno, String idno,
                                 String acctname, String mobile, String validdate, String cvv2, String signtype) {
        Map paramMap = new HashMap();
        if (PropertiesConstants.PAY_TYPE == 1) {
            paramMap.put("appid", tlappId);
//            paramMap.put("key", tlk);
            key = tlk;
        } else {
            paramMap.put("appid", appid);
//            paramMap.put("key", key);
        }
        paramMap.put("cusid", tlCusId);
//        paramMap.put("version", version);
        paramMap.put("randomstr", IdGenerator.getUUID());
        paramMap.put("meruserid", meruserid);
        paramMap.put("accttype", accttype);
        paramMap.put("acctno", acctno);
        paramMap.put("idno", idno);
        paramMap.put("mobile", mobile);
        paramMap.put("acctname", acctname);
        if ("02".equals(accttype)) {
            paramMap.put("validdate", validdate);
            paramMap.put("cvv2", cvv2);
        }
        String signStr = coverMap2String(paramMap);
        String sign = null;
        if ("RSA".equals(signtype)) {
            try {
                sign = SybPayUtil.rsaSign(key, sign, "utf-8");
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            paramMap.put("key", key);
            sign = DigestUtil.md5Hex(signStr).toUpperCase(Locale.ENGLISH);
            paramMap.remove("key");
        }
        paramMap.put("sign", sign);
        System.out.println("is agreeapply url:" + SybPayUrl.AGREEMS_URL);
        System.out.println("is agreeapply param:" + JSONUtil.toJsonStr(paramMap));
        String result = HttpUtil.post(SybPayUrl.AGREEMS_URL, paramMap);
        System.out.println("is agreeapply result:" + result);
        return result;
    }
    /**
     * è§£é™¤ç»‘定
     *
     * @param key     ç§˜é’¥
     * @param cusid   é€šè”分配的商户号
     * @param appid   é€šè”分配的appid
     * @param agreeid åè®®id
     * @Author: lc
     * @Date: 2019/8/27 15:25
     */
    public static String unbind(String key, String cusid, String appid,
                                String agreeid) {
        Map paramMap = new HashMap();
        paramMap.put("cusid", cusid);
        paramMap.put("appid", appid);
        paramMap.put("version", version);
        paramMap.put("randomstr", IdGenerator.getUUID());
        paramMap.put("signtype", "RSA");
        paramMap.put("agreeid", agreeid);
        String signStr = coverMap2String(paramMap);
        String sign = null;
        try {
            sign = SybPayUtil.rsaSign(signStr, key, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        paramMap.put("sign", sign);
        System.out.println("is unbind url:" + SybPayUrl.UNBIND_URL);
        System.out.println("is unbind param:" + JSONUtil.toJsonStr(paramMap));
        String result = HttpUtil.post(SybPayUrl.UNBIND_URL, paramMap);
        System.out.println("is unbind result:" + result);
        return result;
    }
    /**
     * ç­¾çº¦ç”³è¯·ç¡®è®¤
     *
     * @param key       ç§˜é’¥
     * @param cusid     é€šè”分配的商户号
     * @param appid     é€šè”分配的appid
     * @param meruserid å•†æˆ·ç”¨æˆ·å·(会员id)
     * @param accttype  00:借记卡02:准贷记卡/贷记卡
     * @param acctno    é“¶è¡Œå¡å·
     * @param idno      è¯ä»¶å·
     * @param acctname  æˆ·å
     * @param mobile    æ‰‹æœºå·ç 
     * @param validdate æœ‰æ•ˆæœŸMMyy信用卡不能为空
     * @param cvv2      Cvv2 ä¿¡ç”¨å¡ä¸èƒ½ä¸ºç©º
     * @param code      çŸ­ä¿¡éªŒè¯ç 
     * @param thpinfo   é€ä¼ ä¿¡æ¯ï¼ˆç­¾çº¦ç”³è¯·æŽ¥å£è¿”回)
     * @Author: lc
     * @Date: 2019/8/27 15:25
     */
    public static String agreeconfirm(String key, String cusid, String appid,
                                      String meruserid, String accttype, String acctno,
                                      String idno, String acctname, String mobile, String validdate,
                                      String cvv2, String code, String thpinfo, String signtype) {
        Map paramMap = new HashMap();
        paramMap.put("cusid", cusid);
        paramMap.put("appid", appid);
        paramMap.put("version", version);
        paramMap.put("randomstr", IdGenerator.getUUID());
        paramMap.put("meruserid", meruserid);
        paramMap.put("accttype", accttype);
        paramMap.put("acctno", acctno);
        paramMap.put("idtype", "0");
        paramMap.put("idno", idno);
        paramMap.put("acctname", acctname);
        paramMap.put("mobile", mobile);
        paramMap.put("smscode", code);
        if (StrUtil.isNotEmpty(thpinfo)) {
            paramMap.put("thpinfo", thpinfo);
        }
        if ("02".equals(accttype)) {
            paramMap.put("validdate", validdate);
            paramMap.put("cvv2", cvv2);
        }
        paramMap.put("signtype", "RSA");
        String signStr = null;
        String sign = null;
        if ("RSA".equals(signtype)) {
            try {
                signStr = coverMap2String(paramMap);
                System.out.println("signStr==>" + signStr);
                sign = SybPayUtil.rsaSign(signStr, key, "utf-8");
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            paramMap.put("key", key);
            signStr = coverMap2String(paramMap);
            sign = DigestUtil.md5Hex(signStr).toUpperCase(Locale.ENGLISH);
            paramMap.remove("key");
        }
        paramMap.put("sign", sign);
        System.out.println("is agreeconfirm url:" + SybPayUrl.AGREEAPPLY_URL);
        System.out.println("is agreeconfirm param:" + JSONUtil.toJsonStr(paramMap));
        System.out.println("is agreeconfirm sign:" + sign);
        String result = HttpUtil.post(SybPayUrl.AGREECONFIRM_URL, paramMap);
        System.out.println("is agreeconfirm result:" + result);
        return result;
    }
    /**
     * æ”¯ä»˜ç”³è¯·
     *
     * @param key       ç§˜é’¥
     * @param cusid     é€šè”分配的商户号
     * @param appid     é€šè”分配的appid
     * @param orderid   è®¢å•id
     * @param agreeid   åè®®id
     * @param amount    é‡‘额(单位分)
     * @param subject   è®¢å•的展示标题
     * @param notifyurl äº¤æ˜“结果通知地址
     * @Author: lc
     * @Date: 2019/8/27 15:25
     */
    public static String payapplyagree(String key, String cusid, String appid,
                                       String orderid, String agreeid, String amount,
                                       String subject, String notifyurl) {
        Map paramMap = new HashMap();
        paramMap.put("cusid", cusid);
        paramMap.put("appid", appid);
        paramMap.put("version", version);
        paramMap.put("randomstr", IdGenerator.getUUID());
        paramMap.put("signtype", "RSA");
        paramMap.put("reqsn", orderid);
        paramMap.put("agreeid", agreeid);
        paramMap.put("amount", amount);
        paramMap.put("currency", "CNY");
        paramMap.put("subject", subject);
        paramMap.put("notifyurl", notifyurl);
        String signStr = null;
        String sign = null;
        try {
            signStr = coverMap2String(paramMap);
            System.out.println("signStr==>" + signStr);
            sign = SybPayUtil.rsaSign(signStr, key, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        paramMap.put("sign", sign);
        System.out.println("is payapplyagree url:" + SybPayUrl.PAYAPPLYAGREE_URL);
        System.out.println("is payapplyagree param:" + JSONUtil.toJsonStr(paramMap));
        String result = HttpUtil.post(SybPayUrl.PAYAPPLYAGREE_URL, paramMap);
        System.out.println("is payapplyagree result:" + result);
        return result;
    }
    /**
     * æ”¯ä»˜ç¡®è®¤
     *
     * @param key     ç§˜é’¥
     * @param cusid   é€šè”分配的商户号
     * @param appid   é€šè”分配的appid
     * @param orderid è®¢å•id
     * @param agreeid åè®®id
     * @param smscode çŸ­ä¿¡æ”¯ä»˜éªŒè¯ç 
     * @param thpinfo é€ä¼ ä¿¡æ¯ï¼ˆæ”¯ä»˜ç”³è¯·æŽ¥å£è¿”回)
     * @Author: lc
     * @Date: 2019/8/27 15:25
     */
    public static String payagreeconfirm(String key, String cusid, String appid,
                                         String orderid, String agreeid, String smscode, String thpinfo) {
        Map paramMap = new HashMap();
        paramMap.put("cusid", cusid);
        paramMap.put("appid", appid);
        paramMap.put("version", version);
        paramMap.put("randomstr", IdGenerator.getUUID());
        paramMap.put("signtype", "RSA");
        paramMap.put("reqsn", orderid);
        paramMap.put("agreeid", agreeid);
        paramMap.put("smscode", smscode);
        if (StrUtil.isNotEmpty(thpinfo)) {
            paramMap.put("thpinfo", thpinfo);
        }
        String signStr = coverMap2String(paramMap);
        String sign = null;
        try {
            sign = SybPayUtil.rsaSign(signStr, key, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        paramMap.put("sign", sign);
        System.out.println("is payagreeconfirm url:" + SybPayUrl.PAYAGREECONFIRM_URL);
        System.out.println("is payagreeconfirm param:" + JSONUtil.toJsonStr(paramMap));
        String result = HttpUtil.post(SybPayUrl.PAYAGREECONFIRM_URL, paramMap);
        System.out.println("is payagreeconfirm result:" + result);
        return result;
    }
    /**
     * é‡å‘支付短信
     *
     * @param key     ç§˜é’¥
     * @param cusid   é€šè”分配的商户号
     * @param appid   é€šè”分配的appid
     * @param orderid è®¢å•id
     * @param agreeid åè®®id
     * @param thpinfo äº¤æ˜“透传信息(支付申请接口返回)
     * @Author: lc
     * @Date: 2019/8/27 15:25
     */
    public static String paysmsagree(String key, String cusid, String appid, String orderid, String agreeid, String thpinfo) {
        Map paramMap = new HashMap();
        paramMap.put("cusid", cusid);
        paramMap.put("appid", appid);
        paramMap.put("version", version);
        paramMap.put("signtype", "RSA");
        paramMap.put("orderid", orderid);
        paramMap.put("randomstr", IdGenerator.getUUID());
        paramMap.put("agreeid", agreeid);
        if (StrUtil.isNotEmpty(thpinfo)) {
            paramMap.put("thpinfo", thpinfo);
        }
        String signStr = coverMap2String(paramMap);
        String sign = null;
        try {
            sign = SybPayUtil.rsaSign(signStr, key, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        paramMap.put("sign", sign);
        System.out.println("is paysmsagree url:" + SybPayUrl.PAYSMSAGREE_URL);
        System.out.println("is paysmsagree param:" + JSONUtil.toJsonStr(paramMap));
        String result = HttpUtil.post(SybPayUrl.PAYSMSAGREE_URL, paramMap);
        System.out.println("is paysmsagree result:" + result);
        return result;
    }
    /**
     * æŸ¥è¯¢äº¤æ˜“结果
     *
     * @param key           ç§˜é’¥
     * @param cusid         é€šè”分配的商户号
     * @param appid         é€šè”分配的appid
     * @param orderid       è®¢å•id
     * @param transactionId å¹³å°è®¢å•
     */
    public static String query(String key, String cusid, String appid,
                               String orderid, String transactionId) {
        Map paramMap = new HashMap();
        paramMap.put("cusid", cusid);
        paramMap.put("appid", appid);
        paramMap.put("version", version);
        paramMap.put("reqsn", orderid);
        //收银宝交易单号
        paramMap.put("trxid", transactionId);
        paramMap.put("randomstr", IdGenerator.getUUID());
        paramMap.put("signtype", "RSA");
        String signStr = coverMap2String(paramMap);
        String sign = null;
        try {
            sign = SybPayUtil.rsaSign(key, signStr, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        paramMap.put("sign", sign);
        String result = HttpUtil.post(SybPayUrl.QUERY_URL, paramMap);
        System.out.println("is query result:" + result);
        return result;
    }
    /**
     * å°†Map中的数据转换成按照Key的ascii码排序后的key1=value1&key2=value2的形式
     *
     * @param data
     * @return
     */
    private static String coverMap2String(Map<String, String> data) {
        TreeMap<String, String> tree = new TreeMap<String, String>();
        Iterator<Map.Entry<String, String>> it = data.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, String> en = it.next();
            tree.put(en.getKey(), en.getValue());
        }
        it = tree.entrySet().iterator();
        StringBuffer sf = new StringBuffer(512);
        while (it.hasNext()) {
            Map.Entry<String, String> en = it.next();
            String value = en.getValue();
            if (StringUtils.isBlank(value)) {
                continue;
            }
            sf.append(en.getKey() + "=" + Convert.toStr(value)
                    + "&");
        }
        return sf.substring(0, sf.length() - 1);
    }
    public static String getMerchantPayResult(String appId, String cusId, String key, String id, Date createTime, String orgId) {
        //组装数据
        Map paramMap = new HashMap();
        if (PropertiesConstants.PAY_TYPE == 1) {
            paramMap.put("appid", tlappId);
        } else {
            paramMap.put("appid", appId);
        }
        paramMap.put("randomstr", IdGenerator.getUUID());
        paramMap.put("cusid", cusId);
        paramMap.put("resendnotify", "0");
        paramMap.put("signtype", "MD5");
        paramMap.put("orderid", id);
        paramMap.put("orgid", orgId);
        DateFormat format = new SimpleDateFormat("MMdd");
        paramMap.put("trxdate", format.format(createTime));
        paramMap.put("key", key);
        String signStr = coverMap2String(paramMap);
        String sign = DigestUtil.md5Hex(signStr).toUpperCase(Locale.ENGLISH);
        paramMap.put("sign", sign);
        paramMap.remove("key");
        String result = "";
        System.out.println(paramMap.toString());
        //走服务调用
        if (ServiceConstants.SERVICE_TYPE) {
            String url = ServiceConstants.MERCHANT_PAY_RESULT;
            result = HttpUtil.post(url, paramMap);
        } else {
            result = HttpUtil.post(SybPayUrl.MERCHANT_PAY_RESULT, paramMap);
        }
        System.out.println(result);
        return result;
    }
    /**
     * å•†åŸŽæ”¯ä»˜æ‰‹åŠ¨å›žè°ƒ
     *
     * @param cusorderid
     * @param trxid
     * @param trxstatus
     */
    public static void callBack(String cusorderid, String trxid, String trxstatus) {
        String url = SybPayUrl.SHOP_CALL_BACK;
        HashMap paramMap = new HashMap();
        paramMap.put("cusorderid", cusorderid);
        paramMap.put("trxid", trxid);
        paramMap.put("trxstatus", trxstatus);
        HttpUtil.get(url, paramMap);
    }
    public static PrivateKey getPrivateKeyFromPKCS8(String algorithm,
                                                    byte[] encodedKey) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
    }
    public static String rsaSign(String content, String privateKey,
                                 String charset) throws Exception {
        PrivateKey priKey = getPrivateKeyFromPKCS8("RSA",
                org.apache.commons.codec.binary.Base64.decodeBase64(privateKey.getBytes()));
        return rsaSign(content, priKey, charset);
    }
    public static String rsaSign(String content, byte[] privateKey,
                                 String charset) throws Exception {
        PrivateKey priKey = getPrivateKeyFromPKCS8("RSA", privateKey);
        return rsaSign(content, priKey, charset);
    }
    public static String rsaSign(String content, PrivateKey priKey,
                                 String charset) throws Exception {
        Signature signature = Signature
                .getInstance("SHA1WithRSA");
        signature.initSign(priKey);
        if (charset == null || "".equals(charset)) {
            signature.update(content.getBytes());
        } else {
            signature.update(content.getBytes(charset));
        }
        byte[] signed = signature.sign();
        String signStr = new String(Base64.encodeBase64(signed));
        System.out.println("明文:" + content);
        System.out.println("密文:" + signStr);
        return signStr;
    }
    /**
     * åˆ¤æ–­æ˜¯å¦ä½ä¿¡ç”¨å¡
     *
     * @param cardNo
     * @return true ä¿¡ç”¨å¡ false å‚¨è“„卡 null å¡å·ä¸æ­£ç¡®
     */
    public static Boolean checkCardType(String cardNo) {
        String resp = HttpUtil.get(checkCardUrl + cardNo, 30000);
        System.out.println(resp);
        try {
            JSONObject jsonObject = JSONObject.parseObject(resp);
            if (jsonObject.getBooleanValue("validated")) {
                return "CC".equals(jsonObject.getString("cardType"));
            }
            return null;
        } catch (Exception e) {
            return null;
        }
    }
    /**
     * å•†æˆ·è¿›ä»¶
     *
     * @param merchantAddParam
     * @param key              å•†æˆ·å¯¹åº”çš„key
     * @return
     */
    public static CommonResult merchantAdd(MerchantAddParam merchantAddParam, String key) {
        CommonResult validResult
                = validMerchantAddParam(merchantAddParam);
        if (validResult.getStatus() == CommonResult.STATUS_ERR) {
            return validResult;
        }
        Map paramMap = new HashMap<String, String>();
        Field[] merchantAddFields = MerchantAddParam.class.getDeclaredFields();
        try {
            for (Field field : merchantAddFields) {
                String fieldName = field.getName();
                field.setAccessible(true);
                Object o = field.get(merchantAddParam);
                if (o != null) {
                    paramMap.put(fieldName, o);
                }
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        paramMap.put("randomstr", IdGenerator.getUUID());
        paramMap.put("signtype", "RSA");
        paramMap.put("version", version);
        String signStr = coverMap2String(paramMap);
        String sign = null;
        try {
            sign = SybPayUtil.rsaSign(signStr, key, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        paramMap.put("sign", sign);
        paramMap.remove("key");
        System.out.println("商户进件参数 -->" + JSONUtil.toJsonStr(paramMap));
        System.out.println("商户进件参数 signStr -->" + signStr);
        String result = "";
        result = HttpUtil.post(SybPayUrl.SYB_MERCHANT_ADD_URL, paramMap);
        System.out.println("商户进件返回值 -->" + result);
        Map resultMap = JSON.parseObject(result);
        String retcode = Convert.toStr(resultMap.get("retcode"));
        if ("success".equalsIgnoreCase(retcode)) {
            return new CommonResult(result);
        } else {
            return new CommonResult(CommonResultEmnu.ERROR, Convert.toStr(resultMap.get("retmsg")));
        }
    }
    /***
     * å•†æˆ·å®¡æ ¸çŠ¶æ€æŸ¥è¯¢
     * @param
     * @param merchantid ä¸šåŠ¡ç³»ç»Ÿçš„id
     * @return
     */
    public static CommonResult<Map<String, String>> merchantAddStatusQuery(String orgid, String cusid, String appid, String key, String merchantid) {
        Map paramMap = new HashMap<String, String>();
        paramMap.put("orgid", orgid);
        paramMap.put("cusid", cusid);
        paramMap.put("appid", appid);
        paramMap.put("version", version);
        paramMap.put("randomstr", IdGenerator.getUUID());
        paramMap.put("signtype", "RSA");
        paramMap.put("merchantid", merchantid);
        String signStr = coverMap2String(paramMap);
        String sign = null;
        try {
            sign = SybPayUtil.rsaSign(signStr, key, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        paramMap.put("sign", sign);
        paramMap.remove("key");
        System.out.println("商户进件 å•†æˆ·å®¡æ ¸çŠ¶æ€ æŸ¥è¯¢å‚æ•° -->" + JSONUtil.toJsonStr(paramMap));
        String result = "";
        result = HttpUtil.post(SybPayUrl.SYB_MERCHANT_ADD_QUERYSTATUS_URL, paramMap);
        System.out.println("商户进件 å•†æˆ·å®¡æ ¸çŠ¶æ€ è¿”回值 -->" + result);
        Map resultMap = JSON.parseObject(result);
        String retcode = Convert.toStr(resultMap.get("retcode"));
        if ("success".equalsIgnoreCase(retcode)) {
            return new CommonResult(resultMap);
        } else {
            return new CommonResult(CommonResultEmnu.ERROR, Convert.toStr(resultMap.get("retmsg")));
        }
    }
    /**
     * 2.20 å¾®ä¿¡/支付宝认证状态查询
     *
     * @param orgid
     * @param cusid
     * @param appid
     * @param key
     * @param chnltype æ¸ é“类型 ä½¿ç”¨ä¸­æ–‡å¤§å†™ç¼©å†™ å¾®ä¿¡ï¼šWXP æ”¯ä»˜å®:ALP
     * @param pid      äº§å“ç±»åž‹ P0001、P0002、P0003 ==> æ”¶é“¶å®ã€å½“面付、网上收银
     * @return
     */
    public static CommonResult<Map<String, String>> merchantAddQueryWxVerifyState(String orgid, String cusid, String appid, String key, String chnltype, String pid) {
        Map paramMap = new HashMap<String, String>();
        paramMap.put("orgid", orgid);
        paramMap.put("cusid", cusid);
        paramMap.put("appid", appid);
        paramMap.put("version", version);
        paramMap.put("randomstr", IdGenerator.getUUID());
        paramMap.put("signtype", "RSA");
        paramMap.put("chnltype", chnltype);
        if (StringUtils.isNotBlank(pid)) {
            paramMap.put("pid", pid);
        }
        String signStr = coverMap2String(paramMap);
        String sign = null;
        try {
            sign = SybPayUtil.rsaSign(signStr, key, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        paramMap.put("sign", sign);
        paramMap.remove("key");
        System.out.println("微信/支付宝认证状态查询 æŸ¥è¯¢å‚æ•° -->" + JSONUtil.toJsonStr(paramMap));
        String result = "";
        result = HttpUtil.post(SybPayUrl.SYB_MERCHANT_ADD_QUERYWXVERIFYSTATE_URL, paramMap);
        System.out.println("微信/支付宝认证状态查询 è¿”回值 -->" + result);
        Map resultMap = JSON.parseObject(result);
        String retcode = Convert.toStr(resultMap.get("retcode"));
        if ("success".equalsIgnoreCase(retcode)) {
            return new CommonResult(resultMap);
        } else {
            return new CommonResult(CommonResultEmnu.ERROR, Convert.toStr(resultMap.get("retmsg")));
        }
    }
    /***
     * ç”¨äºŽå¯¹å‚数签名,生成可访问的收银包url
     * åˆè§„性审核补录统一h5接口 ã€ è®¤è¯ç»Ÿä¸€H5 å…±ç”¨
     * @param
     * @return
     */
    public static String merchantAddUrlSign(String orgid, String cusid, String appid, String key, String urlPrefix, String userid, String notifyurl, String pagetype) {
        Map paramMap = new HashMap<String, String>();
        paramMap.put("orgid", orgid);
        paramMap.put("cusid", cusid);
        paramMap.put("appid", appid);
        paramMap.put("version", version);
        paramMap.put("randomstr", IdGenerator.getUUID());
        paramMap.put("signtype", "RSA");
        if (StringUtils.isNotBlank(userid)) {
            paramMap.put("userid", userid);
        }
        if (StringUtils.isNotBlank(notifyurl)) {
            paramMap.put("notifyurl", notifyurl);
        }
        if (StringUtils.isNotBlank(pagetype)) {
            paramMap.put("pagetype", pagetype);
        }
        String signStr = coverMap2String(paramMap);
        String sign = null;
        try {
            sign = SybPayUtil.rsaSign(signStr, key, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        paramMap.put("sign", sign);
        paramMap.remove("key");
        System.out.println("url签名 æŸ¥è¯¢å‚æ•° -->" + JSONUtil.toJsonStr(paramMap));
        String result = urlPrefix + "?" + signStr + "&sign=" + sign;
        return result;
    }
    /***
     * æ— çº¸åŒ–进件协议签约状态查询
     * @param electsigntype 01/03 01表示收银宝业务协议 03表示结算委托协议(商户性质是企业且结算账户对私)
     * @return
     */
    public static CommonResult<Map<String, String>> merchantElectSignQuery(String orgid, String cusid, String appid, String key, String electsigntype) {
        Map paramMap = new HashMap<String, String>();
        paramMap.put("orgid", orgid);
        paramMap.put("cusid", cusid);
        paramMap.put("appid", appid);
        paramMap.put("version", version);
        paramMap.put("randomstr", IdGenerator.getUUID());
        paramMap.put("signtype", "RSA");
        paramMap.put("electsigntype", electsigntype);
        String signStr = coverMap2String(paramMap);
        String sign = null;
        try {
            sign = SybPayUtil.rsaSign(signStr, key, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        paramMap.put("sign", sign);
        paramMap.remove("key");
        System.out.println("无纸化进件协议签约状态查询 æŸ¥è¯¢å‚æ•° -->" + JSONUtil.toJsonStr(paramMap));
        String result = "";
        result = HttpUtil.post(SybPayUrl.SYB_MERCHANT_ADD_QUERYELECTSIGN_URL, paramMap);
        System.out.println("无纸化进件协议签约状态查询 è¿”回值 -->" + result);
        Map resultMap = JSON.parseObject(result);
        String retcode = Convert.toStr(resultMap.get("retcode"));
        if ("success".equalsIgnoreCase(retcode)) {
            return new CommonResult(resultMap);
        } else {
            return new CommonResult(CommonResultEmnu.ERROR, Convert.toStr(resultMap.get("retmsg")));
        }
    }
    /**
     * åˆè§„性状态查询接口
     * å•†æˆ·åˆè§„性状态查询,根据通联商户号查询商户对应合规性状态
     *
     * @param orgid
     * @param cusid
     * @param appid
     * @param key
     * @return
     */
    public static CommonResult<Map<String, String>> merchantAddQueryCusrGc(String orgid, String cusid, String appid, String key) {
        Map paramMap = new HashMap<String, String>();
        paramMap.put("orgid", orgid);
        paramMap.put("cusid", cusid);
        paramMap.put("appid", appid);
        paramMap.put("version", version);
        paramMap.put("randomstr", IdGenerator.getUUID());
        paramMap.put("signtype", "RSA");
        String signStr = coverMap2String(paramMap);
        String sign = null;
        try {
            sign = SybPayUtil.rsaSign(signStr, key, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        paramMap.put("sign", sign);
        paramMap.remove("key");
        System.out.println("合规性状态查询接口 æŸ¥è¯¢å‚æ•° -->" + JSONUtil.toJsonStr(paramMap));
        String result = "";
        result = HttpUtil.post(SybPayUrl.SYB_MERCHANT_ADD_QUERYCUSRGC_URL, paramMap);
        System.out.println("合规性状态查询接口 è¿”回值 -->" + result);
        Map resultMap = JSON.parseObject(result);
        String retcode = Convert.toStr(resultMap.get("retcode"));
        if ("success".equalsIgnoreCase(retcode)) {
            return new CommonResult(resultMap);
        } else {
            return new CommonResult(CommonResultEmnu.ERROR, Convert.toStr(resultMap.get("retmsg")));
        }
    }
    /***
     * æ— çº¸åŒ–进件协议重发接口
     * @return
     */
    public static CommonResult<Map<String, String>> merchantElectSign(String orgid, String cusid, String appid, String key) {
        Map paramMap = new HashMap<String, String>();
        paramMap.put("orgid", orgid);
        paramMap.put("cusid", cusid);
        paramMap.put("appid", appid);
        paramMap.put("version", version);
        paramMap.put("randomstr", IdGenerator.getUUID());
        paramMap.put("signtype", "RSA");
        String signStr = coverMap2String(paramMap);
        String sign = null;
        try {
            sign = SybPayUtil.rsaSign(signStr, key, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        paramMap.put("sign", sign);
        paramMap.remove("key");
        System.out.println("无纸化进件协议重发接口 æŸ¥è¯¢å‚æ•° -->" + JSONUtil.toJsonStr(paramMap));
        String result = "";
        result = HttpUtil.post(SybPayUrl.SYB_MERCHANT_ADD_ELECTSIGN_URL, paramMap);
        System.out.println("无纸化进件协议重发接口 è¿”回值 -->" + result);
        Map resultMap = JSON.parseObject(result);
        String retcode = Convert.toStr(resultMap.get("retcode"));
        if ("success".equalsIgnoreCase(retcode)) {
            return new CommonResult(resultMap);
        } else {
            return new CommonResult(CommonResultEmnu.ERROR, Convert.toStr(resultMap.get("retmsg")));
        }
    }
    /**
     * æ— çº¸åŒ–进件电子协议URL接口查询
     *
     * @param orgid
     * @param cusid
     * @param appid
     * @param key
     * @return
     */
    public static CommonResult merchantQueryElecturl(String orgid, String cusid, String appid, String key, String redirecturl) {
        Map paramMap = new HashMap<String, String>();
        paramMap.put("orgid", orgid);
        paramMap.put("cusid", cusid);
        paramMap.put("appid", appid);
        paramMap.put("version", version);
        paramMap.put("randomstr", IdGenerator.getUUID());
        paramMap.put("signtype", "RSA");
        paramMap.put("redirecturl", redirecturl);
        String signStr = coverMap2String(paramMap);
        String sign = null;
        try {
            sign = SybPayUtil.rsaSign(signStr, key, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        paramMap.put("sign", sign);
        paramMap.remove("key");
        System.out.println("无纸化进件电子协议URL接口查询 æŸ¥è¯¢å‚æ•° -->" + JSONUtil.toJsonStr(paramMap));
        String result = "";
        result = HttpUtil.post(SybPayUrl.SYB_MERCHANT_ADD_QUERYELECTURL_URL, paramMap);
        System.out.println("无纸化进件电子协议URL接口查询 è¿”回值 -->" + result);
        Map resultMap = JSON.parseObject(result);
        String retcode = Convert.toStr(resultMap.get("retcode"));
        if ("success".equalsIgnoreCase(retcode)) {
            return new CommonResult(result);
        } else {
            return new CommonResult(CommonResultEmnu.ERROR, Convert.toStr(resultMap.get("retmsg")));
        }
    }
    private static CommonResult validMerchantAddParam(MerchantAddParam merchantAddParam) {
        if (merchantAddParam == null) {
            return new CommonResult(CommonResultEmnu.INVALID_PARAMS);
        }
        if (StringUtils.isBlank(merchantAddParam.getRandomstr())) {
            merchantAddParam.setRandomstr(IdGenerator.getUUID());
        }
        if (StringUtils.isBlank(merchantAddParam.getSigntype())) {
            merchantAddParam.setSigntype("RSA");
        }
        //  *商户性质
        //1.企业  3.个体户 4.个人 6.事业单位
        String comproperty = merchantAddParam.getComproperty();
        if (StringUtils.isBlank(comproperty)) {
            return new CommonResult(CommonResultEmnu.INVALID_PARAMS, "商户性质需要填写");
        }
        //商户性质为企业
//        if ("1".equals(comproperty)) {
//            if (StringUtils.isBlank(merchantAddParam.getPubacctinfo())) {
//                return new CommonResult(CommonResultEmnu.INVALID_PARAMS, "商户性质为企业时需要填写对公账户信息");
//            }
//        }
        //商户性质为个人时必填
        if ("4".equals(comproperty)) {
            if (StringUtils.isBlank(merchantAddParam.getLegalpic())) {
                return new CommonResult(CommonResultEmnu.INVALID_PARAMS, "商户性质非个人时需要上传经营者手持身份证照片");
            }
        }
        if (!"4".equals(comproperty)) {
            if (StringUtils.isBlank(merchantAddParam.getCorpbusname())) {
                return new CommonResult(CommonResultEmnu.INVALID_PARAMS, "商户性质非个人时需要填写营业执照名称");
            }
            if (StringUtils.isBlank(merchantAddParam.getCreditcode())) {
                return new CommonResult(CommonResultEmnu.INVALID_PARAMS, "商户性质非个人时需要填写统一社会信用代码证");
            }
            if (StringUtils.isBlank(merchantAddParam.getCreditcodeexpire())) {
                return new CommonResult(CommonResultEmnu.INVALID_PARAMS, "商户性质非个人时需要填写社会信用代码证有效期");
            }
            if (StringUtils.isBlank(merchantAddParam.getCorpbuspic())) {
                return new CommonResult(CommonResultEmnu.INVALID_PARAMS, "商户性质非个人时需要填写营业执照照片");
            }
            if (StringUtils.isBlank(merchantAddParam.getBusconactperson())) {
                return new CommonResult(CommonResultEmnu.INVALID_PARAMS, "商户性质非个人时需要填写业务联系人姓名");
            }
            if (StringUtils.isBlank(merchantAddParam.getBusconacttel())) {
                return new CommonResult(CommonResultEmnu.INVALID_PARAMS, "商户性质非个人时需要填写业务联系人电话");
            }
        }
        //商户性质为企业、个体户时必填
        if ("1".equals(comproperty) || "3".equals(comproperty)) {
            if (StringUtils.isBlank(merchantAddParam.getHoldername())) {
                return new CommonResult(CommonResultEmnu.INVALID_PARAMS, "商户性质为企业、个体户时需要填写控股股东姓名");
            }
            if (StringUtils.isBlank(merchantAddParam.getHolderidno())) {
                return new CommonResult(CommonResultEmnu.INVALID_PARAMS, "商户性质为企业、个体户时需要填写控股股东身份证");
            }
            if (StringUtils.isBlank(merchantAddParam.getHolderexpire())) {
                return new CommonResult(CommonResultEmnu.INVALID_PARAMS, "商户性质为企业、个体户时需要填写控股股东有效期");
            }
            if (StringUtils.isBlank(merchantAddParam.getRegisterfund())) {
                return new CommonResult(CommonResultEmnu.INVALID_PARAMS, "商户性质为企业、个体户时需要填写注册资本");
            }
            if (StringUtils.isBlank(merchantAddParam.getStafftotal())) {
                return new CommonResult(CommonResultEmnu.INVALID_PARAMS, "商户性质为企业、个体户时需要填写员工人数");
            }
            if (StringUtils.isBlank(merchantAddParam.getOperatelimit())) {
                return new CommonResult(CommonResultEmnu.INVALID_PARAMS, "商户性质为企业、个体户时需要填写经营区域");
            }
            if (StringUtils.isBlank(merchantAddParam.getInspect())) {
                return new CommonResult(CommonResultEmnu.INVALID_PARAMS, "商户性质为企业、个体户时需要填写经营地段");
            }
        }
//        if (StringUtils.isBlank(merchantAddParam.getAddfacusid())) {
//            return new CommonResult(CommonResultEmnu.INVALID_PARAMS, "所在机构资金归集时,该字段不能为空");
//        }
        // ç»“算账户 0-对私 1-对公
        String accttype = merchantAddParam.getAccttype();
        if (StringUtils.isBlank(accttype)) {
            return new CommonResult(CommonResultEmnu.INVALID_PARAMS, "结算账户类型不能为空");
        }
        if ("0".equals(accttype)) {
            if (StringUtils.isBlank(merchantAddParam.getSettidno())) {
                return new CommonResult(CommonResultEmnu.INVALID_PARAMS, "结算账户对私时,结算人身份证号不能为空");
            }
        }
        return new CommonResult();
    }
    public static CommonResult<Map> uploadfile(String orgid, String cusid, String appid, String key, String ftpFilePath) throws Exception {
        Map paramMap = new HashMap();
        paramMap.put("orgid", orgid);
        paramMap.put("cusid", cusid);
        paramMap.put("appid", appid);
        paramMap.put("version", version);
        paramMap.put("randomstr", IdGenerator.getUUID());
        paramMap.put("signtype", "RSA");
        paramMap.put("filetype", "jpg");
        String signStr = coverMap2String(paramMap);
        String sign = null;
        try {
            sign = SybPayUtil.rsaSign(key, signStr, "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        }
        paramMap.put("sign", sign);
        System.out.println("上传文件参数 -->" + JSONUtil.toJsonStr(paramMap));
        String result = dorequest(SybPayUrl.SYB_FILE_UPLOAD_URL, paramMap, ftpFilePath);
        System.out.println("上传文件 è¿”回值 -->" + result);
        CommonResult<Map> mapCommonResult = handleResult(result);
        return mapCommonResult;
    }
    /**
     * åªåšretcode åˆ¤æ–­ ä¸åšä¸šåŠ¡çŠ¶æ€åˆ¤æ–­
     *
     * @param result
     * @return
     */
    private static CommonResult<Map> handleResult(String result) {
        Map resultMap = JSONObject.parseObject(result, Map.class);
        String retcode = Convert.toStr(resultMap.get("retcode"));
        if ("success".equalsIgnoreCase(retcode)) {
            return new CommonResult(resultMap);
        } else {
            return new CommonResult(CommonResultEmnu.ERROR, Convert.toStr(resultMap.get("retmsg")));
        }
    }
    private static String dorequest(String url, Map<String, String> params, String path) {
        CloseableHttpClient httpClient = null;
        CloseableHttpResponse response = null;
        try {
            httpClient = HttpClients.createDefault();
            // æŠŠä¸€ä¸ªæ™®é€šå‚数和文件上传给下面这个地址 æ˜¯ä¸€ä¸ªservlet
            HttpPost httpPost = new HttpPost(url);
            // æŠŠæ–‡ä»¶è½¬æ¢æˆæµå¯¹è±¡FileBody
            FileBody bin = new FileBody(new File(path));
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            builder.addPart("filecontent", bin);
            for (Map.Entry<String, String> entry : params.entrySet()) {
                builder.addTextBody(entry.getKey(), entry.getValue());
            }
            httpPost.setEntity(builder.build());
            // å‘起请求 å¹¶è¿”回请求的响应
            response = httpClient.execute(httpPost);
            // èŽ·å–å“åº”å¯¹è±¡
            HttpEntity resEntity = response.getEntity();
            if (resEntity != null) {
                String result = EntityUtils.toString(resEntity, Charset.forName("UTF-8"));
                return result;
            }
            // é”€æ¯
            EntityUtils.consume(resEntity);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                if (httpClient != null) {
                    httpClient.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
    /**
     * éªŒç­¾
     * @param param å‚æ•°
     * @param appKey appKey
     * @param signType åŠ å¯†ç±»åž‹
     * @return ç»“æžœ
     */
    public static boolean validSign(TreeMap<String, String> param,
                                    String appKey, String signType)  {
        if (param == null || param.isEmpty()) {
            return false;
        }
        if (!param.containsKey("sign")) {
            return false;
        }
        String sign = param.remove("sign");
        if ("MD5".equals(signType)) {// å¦‚果是md5则需要把md5的key加入到排序
            param.put("key", appKey);
        }
        String paramStr = content(param);
        byte[] paramByteArr = getByteUtf8(paramStr);
        if ("MD5".equals(signType)) {
            return sign.equalsIgnoreCase(
                    md5(paramByteArr));
        } else if("SM2".equals(signType)){
            PublicKey publicKey;
            try {
                publicKey = pubKeySM2FromBase64Str(appKey);
            } catch (GeneralSecurityException e) {
                return false;
            }
            return verifySM3SM2(publicKey, decodeBase64(sign), paramByteArr);
        }else {
            return rsaVerifyPublicKey(paramStr, sign, appKey);
        }
    }
    /**
     * å…¬é’¥éªŒç­¾
     * @param content å†…容
     * @param sign ç­¾å
     * @param publicKey å…¬é’¥key
     * @return ç»“æžœ
     */
    private static boolean rsaVerifyPublicKey(String content, String sign,
                                              String publicKey) {
        PublicKey pubKey;
        try {
            pubKey = getPublicKeyFromX509("RSA",
                    Base64.decodeBase64(publicKey.getBytes()));
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
            return false;
        }
        return rsaVerifyPublicKey(content, sign, pubKey);
    }
    /**
     * å…¬é’¥éªŒç­¾
     * @param content å†…容
     * @param sign ç­¾å
     * @param pubKey å…¬é’¥
     * @return ç»“æžœ
     */
    public static boolean rsaVerifyPublicKey(String content, String sign,
                                             PublicKey pubKey)  {
        Signature signature;
        try {
            signature = Signature
                    .getInstance("SHA1WithRSA");
        } catch (NoSuchAlgorithmException e) {
            return false;
        }
        try {
            signature.initVerify(pubKey);
        } catch (InvalidKeyException e) {
            return false;
        }
        try {
            signature.update(getByteUtf8(content));
        } catch (SignatureException e) {
            return false;
        }
        try {
            return signature.verify(decodeBase64(sign));
        } catch (SignatureException e) {
            return false;
        }
    }
    /**
     * æ‹¼æŽ¥éªŒç­¾/加签内容
     * @param param å‚æ•°
     * @return éªŒç­¾/加签字符串
     */
    private static String content(TreeMap<String, String> param) {
        //noinspection DuplicatedCode
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : param.entrySet()) {
            if (entry.getValue() != null && entry.getValue().length() > 0) {
                sb.append(entry.getKey()).append("=")
                        .append(entry.getValue()).append("&");
            }
        }
        if (sb.length() > 0) {
            sb.deleteCharAt(sb.length() - 1);
        }
        return sb.toString();
    }
    /**
     * md5
     *
     * @param b åŠ å¯†å­—ç¬¦é›†
     * @return åŠ å¯†å­—ç¬¦ä¸²
     */
    public static String md5(byte[] b) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.reset();
            md.update(b);
            byte[] hash = md.digest();
            StringBuilder outStrBuf = new StringBuilder(32);
            for (byte value : hash) {
                int v = value & 0xFF;
                if (v < 16) {
                    outStrBuf.append('0');
                }
                outStrBuf.append(Integer.toString(v, 16).toLowerCase());
            }
            return outStrBuf.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return new String(b);
        }
    }
    /**
     * åˆå§‹åŒ–公钥
     * @param algorithm æŒ‡å®šå…¬é’¥ç®—法
     * @return å…¬é’¥
     * @throws GeneralSecurityException åˆå§‹åŒ–异常
     */
    public static PublicKey getPublicKeyFromX509(String algorithm,
                                                 byte[] encodedKey) throws GeneralSecurityException {
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
    }
    /**
     * åˆå§‹åŒ–公钥
     * @param keyStr å…¬é’¥å­—符串
     * @return å…¬é’¥
     * @throws GeneralSecurityException åˆå§‹åŒ–异常
     */
    public static PublicKey pubKeySM2FromBase64Str(String keyStr) throws GeneralSecurityException {
//        KeyFactory keyFactory = KeyFactory.getInstance("EC");
//        return keyFactory.generatePublic(new X509EncodedKeySpec(decodeBase64(keyStr)));
        return getPublicKeyFromX509("EC", decodeBase64(keyStr));
    }
    /**
     * base64字节数组
     * @param str å­—符串
     * @return å­—节数组
     */
    private static byte[] decodeBase64(String str) {
        return Base64.decodeBase64(str.getBytes(StandardCharsets.UTF_8));
    }
    /**
     * è½¬byte
     * @param str å­—符串
     * @return å­—节数组
     */
    private static byte[] getByteUtf8(String str) {
        if (str == null) {
            return new byte[0];
        }
        return str.getBytes(StandardCharsets.UTF_8);
    }
    /** éªŒè¯ç­¾å-SM3WithSM2*/
    private static boolean verifySM3SM2(final PublicKey publicKey,final byte[] signData, final byte[] srcData) {
        SM2ParameterSpec parameterSpec = new SM2ParameterSpec(getByteUtf8("Allinpay"));
        Signature verifier;
        try {
            verifier = Signature.getInstance(ALGORITHM_SM3SM2_BCPROV, "BC");
        } catch (NoSuchAlgorithmException | NoSuchProviderException e) {
            return false;
        }
        try {
            verifier.setParameter(parameterSpec);
            verifier.initVerify(publicKey);
            verifier.update(srcData);
            return verifier.verify(bytePlain2ByteAsn1(signData));
        } catch (GeneralSecurityException e) {
            return false;
        }
    }
    /**
     * å°†æ™®é€šå­—节数组转换为ASN1字节数组 é€‚用于SM3withSM2验签时验签明文转换
     */
    private static byte[] bytePlain2ByteAsn1(byte[] data) {
        if (data.length != SM3withSM2_RS_LEN * 2) {
            throw new RuntimeException("err data. ");
        }
        BigInteger r = new BigInteger(1, Arrays.copyOfRange(data, 0, SM3withSM2_RS_LEN));
        BigInteger s = new BigInteger(1, Arrays.copyOfRange(data, SM3withSM2_RS_LEN, SM3withSM2_RS_LEN * 2));
        ASN1EncodableVector v = new ASN1EncodableVector();
        v.add(new ASN1Integer(r));
        v.add(new ASN1Integer(s));
        try {
            return new DERSequence(v).getEncoded("DER");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/syb/param/MerchantAddParam.java
New file
@@ -0,0 +1,375 @@
package com.nuvole.util.pay.allinPay.syb.param;
import lombok.Data;
/**
 * @ClassName MerchantAdd
 * @Author cy
 * @Date 2023/6/13
 * @Description å•†æˆ·è¿›ä»¶å‚æ•°
 * @Version 1.0
 **/
@Data
public class MerchantAddParam {
    /**
     *机构号
     *通联分配的代理商号*
     *
     */
    private String orgid;
    /**
     *商户号
     *通联分配的商户号*
     * 等于orgid
     */
    private String cusid;
    /**
     *应用ID
     *通联分配的代理商APPID*
     *
     */
    private String appid;
    /**
     *随机字符串
     *商户自行生成的随机字符串*
     *
     */
    private String randomstr;
    /**
     *代理商商户号
     * 代理商平台商户号*
     * 代理商系统商户唯一识别号
     */
    private String merchantid;
    /**
     *商户名称
     **
     *
     */
    private String merchantname;
    /**
     *商户简称
     **
     *无执照商户请按照实际场所的经营门店名称填写
     */
    private String shortname;
    /**
     *客服电话
     **
     *
     */
    private String servicephone;
    /**
     *所属行业
     *详见附录*
     *
     */
    private String mccid;
    /**
     *商户性质
     *1.企业  3.个体户 4.个人 6.事业单位
     */
    private String comproperty;
    /**
     * è¥ä¸šæ‰§ç…§åç§°
     * å•†æˆ·æ€§è´¨éžä¸ªäººæ—¶éœ€è¦å¡«å†™
     */
    private String corpbusname;
    /**
     * ç»Ÿä¸€ç¤¾ä¼šä¿¡ç”¨ä»£ç è¯
     * å•†æˆ·æ€§è´¨éžä¸ªäººæ—¶éœ€è¦å¡«å†™
     */
    private String creditcode;
    /**
     * ç¤¾ä¼šä¿¡ç”¨ä»£ç è¯æœ‰æ•ˆæœŸ
     * å•†æˆ·æ€§è´¨éžä¸ªäººæ—¶éœ€è¦å¡«å†™
     */
    private String creditcodeexpire;
    /**
     * æ³•人姓名
     * *
     */
    private String legal;
    /**
     * æ³•人代表证件类型
     * 01、04、05*
     * 01身份证
     */
    private String legalidtype;
    /**
     * æ³•人代表证件号
     */
    private String legalidno;
    /**
     * æ³•人身份证有效期
     * *
     * Â yyyy-mm-dd或长期
     */
    private String legalidexpire;
    /**
     * æ³¨å†Œåœ°å€
     * *
     * Â æ³¨å†Œåœ°å€éœ€åŒ…含省市
     */
    private String address;
    /**
     * å•†æˆ·è´Ÿè´£äºº
     * *
     * è´¢åŠ¡è”ç³»äººï¼ˆæ”¶çŸ­ä¿¡ç”¨ï¼‰
     */
    private String contactperson;
    /**
     * å•†æˆ·è´Ÿè´£äººç”µè¯
     * *
     * è´¢åŠ¡è”ç³»äººç”µè¯
     */
    private String contactphone;
    /**
     * ç»“算方式
     * 1*
     * 0-商户自主提现
     */
    private String clearmode;
    /**
     * è´¦æˆ·å·
     * *
     */
    private String acctid;
    /**
     * è´¦æˆ·å
     * *
     */
    private String acctname;
    /**
     * è´¦æˆ·ç±»åž‹
     * 0|1*
     * 0-对私
     */
    private String accttype;
    /**
     * å¡æŠ˜ç±»åž‹
     * 00|01*
     * 00-借记卡
     */
    private String accttp;
    /**
     * æ‰€å±žé“¶è¡Œ
     * è§é™„录*
     */
    private String bankcode;
    /**
     * æ”¯ä»˜è¡Œå·
     * è§é™„录*
     */
    private String cnapsno;
    /**
     * å›žè°ƒurl
     * è¿›ä»¶æˆåŠŸçš„å›žè°ƒé€šçŸ¥url*
     */
    private String notifyurl;
    /**
     * è¥ä¸šæ‰§ç…§ç…§ç‰‡
     * å•†æˆ·æ€§è´¨éžä¸ªäººæ—¶éœ€è¦å¡«å†™
     */
    private String corpbuspic;
    /**
     * æ³•人身份证肖像面
     * ç…§ç‰‡url*
     * Â äººåƒé¢
     */
    private String legalidpicfront;
    /**
     * æ³•人身份证国徽面
     * ç…§ç‰‡url*
     * Â å›½å¾½é¢
     */
    private String legalidpicback;
    /**
     * ç»è¥è€…手持身份证照片
     * ç…§ç‰‡url*
     * Â å•†æˆ·æ€§è´¨ä¸ºä¸ªäººæ—¶å¿…å¡«
     */
    private String legalpic;
    /**
     * å•†æˆ·é—¨å¤´ç…§ç‰‡
     * ç…§ç‰‡url*
     */
    private String storepic;
    /**
     * ç»è¥å†…景照片
     * ç…§ç‰‡url*
     */
    private String storeinnerpic;
    /**
     * ç»è¥åœºæ‰€è¯æ˜Žæ–‡ä»¶
     * ä¸é™äºŽè¥ä¸šåœºæ‰€ç§Ÿèµåè®®æˆ–者产权证明、集中经营场所管理方出具的证明文件等
     * <p>
     * å•†æˆ·æ€§è´¨ä¸ªäººæ—¶éœ€è¦å¡«å†™
     */
    private String bizplacepic;
    /**
     * æ‹“展人
     * *
     */
    private String expanduser;
    /**
     * é—¨åº—信息
     * é—¨åº—列表的json数组*
     */
    private String subbranchlist;
    /**
     * æ”¯ä»˜äº§å“ä¿¡æ¯åˆ—表
     * äº§å“åˆ—表的json数组*
     */
    private String prodlist;
    /**
     * æ”¯ä»˜æ‰€å±žçˆ¶å®¢æˆ·
     * æ‰€åœ¨æœºæž„资金归集时,该字段不能为空
     */
    private String addfacusid;
    /**
     * ç»“算人身份证号
     * ç»“算账户对私时,结算人身份证号不能为空
     */
    private String settidno;
    /**
     * æŽ§è‚¡è‚¡ä¸œå§“名
     * å•†æˆ·æ€§è´¨ä¸ºä¼ä¸šã€ä¸ªä½“户时必填
     */
    private String holdername;
    /**
     * æŽ§è‚¡è‚¡ä¸œèº«ä»½è¯
     * å•†æˆ·æ€§è´¨ä¸ºä¼ä¸šã€ä¸ªä½“户时必填
     */
    private String holderidno;
    /**
     * æŽ§è‚¡è‚¡ä¸œæœ‰æ•ˆæœŸ
     * å•†æˆ·æ€§è´¨ä¸ºä¼ä¸šã€ä¸ªä½“户时必填
     */
    private String holderexpire;
    /**
     * æ³¨å†Œèµ„本
     * 1: æ³¨å†Œèµ„本<10万元
     * 2: 10万元<注册资本<20万元
     * 3: 20万元<注册资本<50万元
     * 4: 50万元<注册资本<100万元
     * 5: æ³¨å†Œèµ„本>100万元
     */
    private String registerfund;
    /**
     * å‘˜å·¥äººæ•°
     * *商户性质为企业、个体户时必填
     * 1: å‘˜å·¥æ•°é‡<10
     * 2: 10<员工数量<20
     * 3: 20<员工数量<50
     * 4: 50<员工数量<100
     * 5: å‘˜å·¥æ•°é‡>100
     */
    private String stafftotal;
    /**
     * ç»è¥åŒºåŸŸ
     * å•†æˆ·æ€§è´¨ä¸ºä¼ä¸šã€ä¸ªä½“户时必填
     * 1:城区
     * 2: éƒŠåŒº
     * 3:边远地区
     */
    private String operatelimit;
    /**
     * ç»è¥åœ°æ®µ
     * å•†æˆ·æ€§è´¨ä¸ºä¼ä¸šã€ä¸ªä½“户时必填
     * 1:商业区
     * 2:工业区
     * 3:住宅区
     */
    private String inspect;
    /**对公账户信息
     *商户性质为企业,结算账户对私时必填,作为商户信息扩展字段,与结算信息无关
     */
    private String pubacctinfo;
    /**业务联系人姓名
     *非个人类商户必填
     */
    private String busconactperson;
    /**业务联系人电话
     *非个人类商户必填
     */
    private String busconacttel;
    /**网站url或下载地址或平台名称
     *开通网关(含B2B、APP)、快捷、云闪付APP或线上场景必填
     */
    private String cusurl = "";
    /**网站名称/应用名称
     *开通网关(含B2B、APP)、快捷、云闪付APP或线上场景必填
     */
    private String webname = "";
    /**
     *线上线下业务场景
     *0  çº¿ä¸‹*
     *为空时默认为线下场景
     */
    private String offlag;
    /**
     *法人信息json字符串
     **
     *json内详情见下说明
     */
    private String legaldetail;
    /**
     *受益人信息json字符串
     **
     *注:暂为非必填,5月18日生效为必填
     */
    private String bnfdetail;
    /**
     *税务登记详情json字符串
     * 在商户性质为企业,选择非三证合一时,税务登记证信息必填*
     *json内详情见下说明
     */
    private String taxdetail;
    /**
     *经营内容
     **
     *
     */
    private String busdetail;
    /**
     *签名类型
     **
     *RSA/SM2
     */
    private String signtype;
    /**
     *经营地址
     **
     *商户经营地址
     */
    private String busaddress;
    /**
     *所在区
     **
     *见附录
     */
    private String districtcode;
    /**
     * ç”µå­åè®®ç­¾çº¦å›žè°ƒåœ°å€ æ­¤å­—段为空时通知到进件回调url
     */
    private String electnotify;
    /**
     * å›¾ç‰‡json字符串
     */
    private String picurljson;
    /**
     * åº”用场景 01-PC网站 02-APP/公众号/小程序(可复选)
     */
    private String appscenario;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunst/ConsumeApply.java
New file
@@ -0,0 +1,60 @@
package com.nuvole.util.pay.allinPay.yunst;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Builder;
import lombok.Data;
import java.util.ArrayList;
/**
 * æ¶ˆè´¹ç”³è¯·å…¬ç”¨å‚æ•°
 *
 * @Author: lc
 * @Date: 2019/10/14 17:03
 */
@Data
@Builder
@ApiModel(value = "消费申请公用参数")
public class ConsumeApply {
    @ApiModelProperty("消费用户的bizUserId(付款方)")
    private String payerId;
    @ApiModelProperty("消费商户的bizUserId(收款方)平台自身,参数值为:#yunBizUserId_B2C#。")
    private String recieverId;
    @ApiModelProperty("订单号(支付订单)")
    private String bizOrderNo;
    @ApiModelProperty("订单金额(分)")
    private Long amount;
    @ApiModelProperty("手续费(分)")
    private Long fee;
    @ApiModelProperty("交易验签方式【0.无验证(渠道验证) 1.短信验证码 2.支付密码】")
    private Long validateType;
    @ApiModelProperty("前台通知地址(前台交易必传)")
    private String frontUrl;
    @ApiModelProperty("后台通知地址(必传)")
    private String backUrl;
    @ApiModelProperty("订单过期时间(可不传)")
    private String orderExpireDatetime;
    @ApiModelProperty("扩展参数 æŽ¥å£å°†åŽŸæ ·è¿”å›žï¼Œæœ€å¤š 50 ä¸ªå­—符(可不传)")
    private String extendInfo;
    @ApiModelProperty("交易内容摘要最多 20 ä¸ªå­—符(可不传)")
    private String summary;
    @ApiModelProperty("分账规则,分账层级数<=3,分账总会员数<=10 " +
            "[{bizUserId:唯一编号(如果是平台填#yunBizUserId_B2C#) accountSetNo:帐户集编号" +
            "amount:金额(分)fee:手续费(分)remark:备注 splitRuleList:分账列表}]")
    private ArrayList splitRule;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunst/MerchantApply.java
New file
@@ -0,0 +1,61 @@
package com.nuvole.util.pay.allinPay.yunst;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Builder;
import lombok.Data;
/**
 * è®¾ç½®ä¼ä¸šä¼šå‘˜å‚æ•°
 *
 * @Author: lc
 * @Date: 2019/10/14 17:03
 */
@Data
@Builder
@ApiModel(value = "设置企业会员参数(y:必传 n:非必传)")
public class MerchantApply {
    @ApiModelProperty("企业名称(y)")
    private String companyName;
    @ApiModelProperty("认证类型[1 ä¸‰è¯ 2 ä¸€è¯] é»˜è®¤1")
    private Long authType;
    @ApiModelProperty("统一社会信用(一证)认证类型2时必传")
    private String uniCredit;
    @ApiModelProperty("营业执照号(三证)认证类型为 1 æ—¶å¿…ä¼ ")
    private String businessLicense;
    @ApiModelProperty("组织机构(三证)认证类型为 1 æ—¶å¿…ä¼ ")
    private String organizationCode;
    @ApiModelProperty("税务登记证(三证)认证类型为 1 æ—¶å¿…ä¼ ")
    private String taxRegister;
    @ApiModelProperty("法人姓名(y)")
    private String legalName;
    @ApiModelProperty("法人证件类型[1.身份证 2.护照 3.军官证 4.回乡证 5.台胞证 6.警官证 7.士兵证 99.其他证件](y)")
    private Long identityType;
    @ApiModelProperty("法人证件号码(y)")
    private String legalIds;
    @ApiModelProperty("法人手机号码(y)")
    private String legalPhone;
    @ApiModelProperty("企业对公账户(y)")
    private String accountNo;
    @ApiModelProperty("开户银行名称(y)")
    private String parentBankName;
    @ApiModelProperty("开户行支行名称(y)")
    private String bankName;
    @ApiModelProperty("支付行号(y)")
    private String unionBank;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunst/SignContractApply.java
New file
@@ -0,0 +1,30 @@
package com.nuvole.util.pay.allinPay.yunst;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Builder;
import lombok.Data;
/**
 * @Description:
 * @Company: TOO (ps:公司名称)
 * @author: å”
 * @date: 2020/4/15 ä¸‹åˆ10:39
 * @version: V1.0.0
 */
@Data
@ApiModel("电子签约请求参数")
@Builder
public class SignContractApply {
    @ApiModelProperty(value = "商户系统用户标识")
    private String bizUserId;
    @ApiModelProperty(value = "签订后跳转返回的页 é¢åœ°å€")
    private String jumpUrl;
    @ApiModelProperty(value = "后台通知地址")
    private String backUrl;
    @ApiModelProperty(value = "终端访问类型1:手机 2:pc")
    private Long source;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunst/YunStParam.java
New file
@@ -0,0 +1,26 @@
package com.nuvole.util.pay.allinPay.yunst;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.NoArgsConstructor;
/**
 * äº‘商通公共参数
 *
 * @Author: lc
 * @Date: 2019/10/15 14:13
 */
@NoArgsConstructor
@ApiModel(value = "公共参数(通联云商通)")
public class YunStParam {
    @ApiModelProperty("行业代码")
    public static String industryCode = "1910";
    @ApiModelProperty("行业名称")
    public static String industryName = "其他";
    @ApiModelProperty("访问终端类型【 1:mobile 2:PC ã€‘")
    public static Long source = 2L;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunst/YunStResult.java
New file
@@ -0,0 +1,33 @@
package com.nuvole.util.pay.allinPay.yunst;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * æŽ¥å£è¿”回值(通联云商通)
 *
 * @Author: lc
 * @Date: 2019/10/14 16:37
 */
@Data
@ApiModel(value = "接口返回值(通联云商通)")
public class YunStResult {
    @ApiModelProperty("服务调用是否成功,“OK”表示成功,“error”表示失败。")
    private String status;
    @ApiModelProperty("返回内容( JSON å¯¹è±¡ï¼‰")
    private String signedValue;
    @ApiModelProperty("签名")
    private String sign;
    @ApiModelProperty("错误代码")
    private String errorCode;
    @ApiModelProperty("错误信息")
    private String message;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunst/YunStUtil.java
New file
@@ -0,0 +1,1092 @@
package com.nuvole.util.pay.allinPay.yunst;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.allinpay.yunst.sdk.YunClient;
import com.allinpay.yunst.sdk.bean.YunConfig;
import com.allinpay.yunst.sdk.bean.YunRequest;
import com.allinpay.yunst.sdk.util.RSAUtil;
import com.nuvole.common.domain.dto.AppDTO;
import com.nuvole.util.IPUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.util.Date;
import java.util.HashMap;
/**
 * æ”¯ä»˜å·¥å…·ç±»ï¼ˆé€šè”云商通)
 *
 * @Author: lc
 * @Date: 2019/10/12 11:49
 */
@Slf4j
public class YunStUtil {
    private Logger logger = LoggerFactory.getLogger(YunStUtil.class);
    //测试
    /*@Before
    public void initConfig() {
        final String serverUrl = "http://116.228.64.55:6900/service/soa";
        final String sysId = "1906061744156467038";
        final String pwd = "123456";
        final String alias = "1906061744156467038";
        final String path = "C:/Users/Administrator/Desktop/yunst/1906061744156467038/1906061744156467038.pfx";
        final String tlCertPath = "C:/Users/Administrator/Desktop/yunst/1906061744156467038/TLCert-test.cer";
        final String version = "2.0";
        final YunConfig config = new YunConfig(serverUrl, sysId, pwd, alias, version, path, tlCertPath);
        YunClient.configure(config);
    }
    @Test
    public void test() {
        String bizUserId = "lc201910171030";   //用户唯一标识 4806722d-3c3a-4137-bc6f-5982e2759dd5
        String acct = "oZN135B20y8KIUFMl4GaeRyuFyQ3";   //微信小程序openid
        String bizOrderNo = "123456789987654322";  //订单编号
        YunStResult yunStResult = new YunStResult();
        System.out.println("is Enter the test.............................创建会员");
        Long memberType = 3L;
        Long source = 2L;
        //创建会员
        yunStResult = createMember(bizUserId, memberType, source);
        if ("OK".equals(yunStResult.getStatus())) {
            log.info("is ok:-------------->");
            log.info(yunStResult.getSignedValue());
        } else {
            log.info("is error:-------------->");
            log.info(yunStResult.getErrorCode());
            log.info(yunStResult.getMessage());
        }
        System.out.println("is The end of the test.......................创建会员");
        System.out.println("is Enter the test.............................发送验证码");
        String phone = "17803846500";
        Long verificationCodeType = 9L;
        //创建会员
        yunStResult = sendVerificationCode(bizUserId, phone, verificationCodeType);
        if ("OK".equals(yunStResult.getStatus())) {
            log.info("is ok:-------------->");
            log.info(yunStResult.getSignedValue());
        } else {
            log.info("is error:-------------->");
            log.info(yunStResult.getErrorCode());
            log.info(yunStResult.getMessage());
        }
        System.out.println("is The end of the test.......................发送验证码");
        System.out.println("is Enter the test.............................绑定手机");
        String verificationCode = "544343";
        //创建会员
        yunStResult = bindPhone(bizUserId, phone, verificationCode);
        if ("OK".equals(yunStResult.getStatus())) {
            log.info("is ok:-------------->");
            log.info(yunStResult.getSignedValue());
        } else {
            log.info("is error:-------------->");
            log.info(yunStResult.getErrorCode());
            log.info(yunStResult.getMessage());
        }
        System.out.println("is The end of the test.......................绑定手机");
        System.out.println("is Enter the test.............................个人实名认证");
        //创建会员
        yunStResult = setRealName(bizUserId, "王莉", 1L, "410521199209010565");
        if ("OK".equals(yunStResult.getStatus())) {
            log.info("is ok:-------------->");
            log.info(yunStResult.getSignedValue());
        } else {
            log.info("is error:-------------->");
            log.info(yunStResult.getErrorCode());
            log.info(yunStResult.getMessage());
        }
        System.out.println("is The end of the test.......................个人实名认证");
        System.out.println("is Enter the test.............................绑定会员支付账户");
        //绑定会员支付账户
        String acctType = "weChatMiniProgram";
        YunStResult yunStResult1 = applyBindAcct(bizUserId, acctType, acct);
        if ("OK".equals(yunStResult1.getStatus())) {
            log.info("is ok:-------------->");
            log.info(yunStResult1.getSignedValue());
        } else {
            log.info("is error:-------------->");
            log.info(yunStResult1.getErrorCode());
            log.info(yunStResult1.getMessage());
        }
        System.out.println("is The end of the test.......................绑定会员支付账户");
        System.out.println("is Enter the test.............................个人实名认证");
        //绑定会员支付账户
        String name = "张三";
        Long identityType = 1L;
        String identityNo = "41000000000000000000";
        yunStResult = setRealName(bizUserId, name, identityType, identityNo);
        if ("OK".equals(yunStResult.getStatus())) {
            log.info("is ok:-------------->");
            log.info(yunStResult.getSignedValue());
        } else {
            log.info("is error:-------------->");
            log.info(yunStResult.getErrorCode());
            log.info(yunStResult.getMessage());
        }
        System.out.println("is The end of the test.......................个人实名认证");
        System.out.println("is Enter the test.............................请求绑定银行卡");
        //绑定会员支付账户
        String cardNo = "6228481111111111111";
        String phone = "17803846500";
        yunStResult = applyBindBankCard(bizUserId, cardNo, phone, name, identityType, identityNo);
        if ("OK".equals(yunStResult.getStatus())) {
            log.info("is ok:-------------->");
            log.info(yunStResult.getSignedValue());
        } else {
            log.info("is error:-------------->");
            log.info(yunStResult.getErrorCode());
            log.info(yunStResult.getMessage());
        }
        System.out.println("is The end of the test.......................请求绑定银行卡");
        System.out.println("is Enter the test.............................消费申请");
        //绑定会员支付账户
        String recieverId = "123456";
        Long validateType = 0L;  //交易验签方式【0.无验证 1.短信验证码 2.支付密码】
        String backUrl = "https://www.baudi.com";     //后台回调地址
        ConsumeApply consumeApply = new ConsumeApply() {{
            setPayerId(bizUserId);
            setRecieverId(recieverId);
            setBizOrderNo(bizOrderNo);
            setAmount(1L);
            setFee(0L);
            setValidateType(validateType);
            setBackUrl(backUrl);
            setSummary("商品交易");
        }};
        String vspCusid = "552651058145DRF";
        String subAppid = "00143623";
        Long amount = 1L;
        yunStResult = wechatMiniprogramPay(consumeApply, vspCusid, subAppid, amount, acct);
        if ("OK".equals(yunStResult.getStatus())) {
            log.info("is ok:-------------->");
            log.info(yunStResult.getSignedValue());
        } else {
            log.info("is error:-------------->");
            log.info(yunStResult.getErrorCode());
            log.info(yunStResult.getMessage());
        }
        System.out.println("is The end of the test.......................消费申请");
    }*/
    /**
     * å°ç¨‹åºæ”¯ä»˜
     */
   /* @Test
    public void wechatPay() {
        log.info("<-------------------------this is createMember operation åˆ›å»ºä¼šå‘˜ ------------------------->");
        //创建会员
        String bizUserId = "tz20200401111";  //普通会员
        //String shBizUserId = "shanghu001";  //普通会员会员(收款方,已实名)
        Long memberType = 3L;
        Long source = 1L;
        YunStResult result;
        result = createMember(bizUserId, memberType, source);
        logger.info("createMember result: status={},message={},signedValue={}", new Object[]{result.getStatus(), result.getMessage(), result.getSignedValue()});
        log.info("<-------------------------this is applyBindAcct operation ä¼šå‘˜ç»‘定支付账户用户标识------------------------->");
        //会员绑定支付账户用户标识(支付账户绑定小程序openId)
        String bizUserId = "tz20200401111";  //普通会员
        String acctType = "weChatMiniProgram";
        String acct = "tm001001";
        result = applyBindAcct(bizUserId, acctType, acct);
        logger.info("applyBindAcct result: status={}", new Object[]{result.getStatus()});
        log.info("<-------------------------this is wechatMiniprogramPay operation æ¶ˆè´¹ç”³è¯·------------------------->");
        //消费申请
        String bizUserId = "tz20200401111";  //普通会员
        String recieverId = "shanghu001";
        Long validateType = 0L;  //交易验签方式【0.无验证 1.短信验证码 2.支付密
        String bizOrderNo = "201200401111212";
        String backUrl = "https:localhost:8080";     //后台回调地址
        String acct = "tm001001";
        ConsumeApply consumeApply = ConsumeApply.builder()
                .payerId(bizUserId)
                .recieverId(recieverId)
                .bizOrderNo(bizOrderNo)
                .amount(1L)
                .fee(0L)
                .validateType(validateType)
                .backUrl(backUrl)
                .summary("商品交易").build();
        String vspCusid = "552651058145DRF";
        String subAppid = "00143623";
        Long amount = 1L;
        result = wechatMiniprogramPay(consumeApply, vspCusid, subAppid, amount, acct);
        //todo æµ‹è¯•子商户号未提供 é€šè”未反馈
        logger.info("consumeApply result: status={}, signedValue={}", new Object[]{result.getStatus(), result.getSignedValue()});
        log.info("<-------------------------this is callBack operation è®¢å•结果通知------------------------->");
        //订单结果通知
    }*/
    /**
     * æ”¶é“¶å®å¿«æ·æ”¯ä»˜
     *
     */
    /*@Test
    public void quickPay() throws Exception {
        log.info("<-------------------------this is createMember operation åˆ›å»ºä¼šå‘˜------------------------->");
        //创建会员
        String bizUserId = "tz20200401113";  //普通会员
        String shBizUserId = "shanghu001";  //普通会员会员(收款方,已实名)
        Long memberType = 3L;
        Long source = 1L;
        YunStResult result;
        result = createMember(bizUserId, memberType, source);
        logger.info("createMember result: status={},message={},signedValue={}", new Object[]{result.getStatus(), result.getMessage(), result.getSignedValue()});
        log.info("<-------------------------this is sendVerificationCode operation å‘送验证码------------------------->");
        //发送验证码
        String bizUserId = "tz20200401111";  //普通会员
        String phone = "17803846500";
        Long verificationCodeType = 9L;
        result = sendVerificationCode(bizUserId, phone, verificationCodeType);
        logger.info("sendVerificationCode result: status={},message={},signedValue={}",new Object[]{result.getStatus(),result.getMessage(),result.getSignedValue()});
        log.info("<-------------------------this is bindPhone operation ç»‘定手机------------------------->");
        //绑定手机
        String bizUserId = "tz20200401111";  //普通会员
        String verificationCode = "544343";
        result = bindPhone(bizUserId, phone, verificationCode);
        logger.info("bindPhone result: status={}",new Object[]{result.getStatus()});
        log.info("<-------------------------this is certification operation å®žåè®¤è¯------------------------->");
        //实名认证
        String bizUserId = "tz20200401113";  //普通会员
        String name = "唐宗旭";
        Long identityType = 1L;
        String identityNo = "511521199408143656";
        result = setRealName(bizUserId, name, identityType, identityNo);
        logger.info("certification result: status={}",new Object[]{result.getStatus()});
        log.info("<-------------------------this is applyBindBankCard operation ç”³è¯·ç»‘定的银行卡------------------------->");
        //申请绑定的银行卡(需用真实姓名,手机,身份证,银行卡)
        String bizUserId = "tz20200401111";  //普通会员
        String cardNo = "6217853100025227554"; //4结尾卡号返回姓名不匹配
        String phone = "17723341354";
        String name = "唐宗旭";
        Long identityType = 1L;
        String identityNo = "511521199408143656";
        result = applyBindBankCard(bizUserId, cardNo, phone, name, identityType, identityNo);
        logger.info("applyBindBankCard result:  status={} , signedValue= {}", new Object[]{result.getStatus()});
        log.info("<-------------------------this is bindBankCard operation ç¡®è®¤ç»‘定银行卡------------------------->");
        //确认绑定银行卡
        String bizUserId = "tz20200401111";  //普通会员
        String phone = "17803846500";
        String tranceNum = "123"; //流水号(请求绑定银行卡接口返回)
        String transDate = "2019-10-12"; //申请时间(请求绑定银行卡接口返回)
        String verificationCode = "123";
        //todo "errorCode":"9000","message":"确认超时或请求号错误,请重新调用绑卡申请接口" é€šè”未反馈
        result = bindBankCard(bizUserId,tranceNum,transDate,phone,verificationCode);
        logger.info("bindBankCard result: status={}", new Object[]{result.getStatus()});
        log.info("<-------------------------this is unbindBankCard operation è§£é™¤é“¶è¡Œå¡ç»‘定------------------------->");
        //解除银行卡绑定(需要时调用)
        String bizUserId = "tz20200401111";  //普通会员
        String cardNo = "6230943800000203604";
        result = unbindBankCard(bizUserId,cardNo);
        logger.info("unbindBankCard result: status={},message={}",new Object[]{result.getStatus(),result.getMessage()});
        log.info("<-------------------------this is quickPayVsp operation æ¶ˆè´¹ç”³è¯·(短信验证)------------------------->");
        String recieverId = "shanghu001";
        Long validateType = 1L;  //交易验签方式【0.无验证 1.短信验证码 2.支付密
        String bizOrderNo = "201200401111212";
        Long amount = 1L;
        Long fee = 1L;
        String backUrl = "http://localhost:8080";
        ConsumeApply consumeApply = ConsumeApply.builder()
                .payerId("tz20200401111")
                .recieverId("shanghu001")
                .validateType(1L)
                .bizOrderNo("201200401111212")
                .amount(1L)
                .fee(1L)
                .backUrl("http://localhost:8080").build();
        result = quickPayVsp(consumeApply,cardNo);
        log.info("consumeApply result: status = {},message = {}",new Object[]{result.getStatus(),result.getMessage()});
        log.info("<-------------------------this is pay operation ç¡®è®¤æ”¯ä»˜(短信+后台验证)------------------------->");
        String bizUserId = "tz20200401111";  //普通会员
        String bizOrderNo = "201200401111212";
        String tradeNo = "123";
        String verificationCode = "123";
        result = pay(bizUserId,bizOrderNo,tradeNo,verificationCode);
        log.info("pay result: status={},signedValue={}",new Object[]{result.getStatus(),result.getSignedValue()});
        log.info("<-------------------------this is getOrderDetail æŸ¥è¯¢è®¢å•状态(确认支付返回处理中时调用)------------------------->");
        String bizOrderNo = "201200401111212";
        result = getOrderDetail(bizOrderNo);
        log.info("getOrderDetail result: status={},signedValue={}",new Object[]{result.getStatus(),result.getSignedValue()});
    }*/
    /**
     * é¢æ‰«é¢æ”¯ä»˜(B扫c)
     *
     */
    /*@Test
    public void bussToCustPay(){
        log.info("<-------------------------this is createMember operation åˆ›å»ºä¼šå‘˜------------------------->");
        //创建会员
        String bizUserId = "tz20200401111";  //普通会员
        String shBizUserId = "shanghu001";  //普通会员会员(收款方,已实名)
        Long memberType = 3L;
        Long source = 1L;
        YunStResult result;
        result = createMember(bizUserId, memberType, source);
        logger.info("createMember result: status={},message={},signedValue={}", new Object[]{result.getStatus(), result.getMessage(), result.getSignedValue()});
        log.info("<-------------------------this is applyBindAcct operation ä¼šå‘˜ç»‘定支付账户用户标识(微信/支付宝/云闪付openId)------------------------->");
        //会员绑定支付账户用户标识(微信/支付宝/云闪付openId)
        String bizUserId = "tz20200401111";  //普通会员
        String acctType = "weChatMiniProgram";
        String acct = "tm001001";
        result = applyBindAcct(bizUserId, acctType, acct);
        logger.info("applyBindAcct result: status={}", new Object[]{result.getStatus(),result.getSignedValue()});
        log.info("<-------------------------this is quickPayVsp operation æ¶ˆè´¹ç”³è¯·(支付方式:收银宝刷卡支付(被扫)_集团——支持微信、支付宝、银联、手机QQ)------------------------->");
        String bizUserId = "tz20200401111";  //普通会员
        String shBizUserId = "shanghu001";  //普通会员会员(收款方,已实名)
        ConsumeApply consumeApply = ConsumeApply.builder()
                .payerId(bizUserId)
                .recieverId(shBizUserId)
                .bizOrderNo("123231231")
                .amount(1L)
                .fee(1L)
                .validateType(0L)
                .backUrl("localhost")
                .build();
        Long amount = 1L;
        String authcode = "124316162322111111"; //此处需用真实付款码
        String vspCusid = "zsh111111";
        result = doCodePay(consumeApply,vspCusid,amount,authcode);
        log.info("<-------------------------this is getOrderDetail æŸ¥è¯¢è®¢å•状态(确认支付返回处理中时调用)------------------------->");
        result = getOrderDetail("12312323");
        log.info("getOrderDetail result: status={},signedValue={}",new Object[]{result.getStatus(),result.getSignedValue()});
    }*/
    /**
     * é¢å¯¹é¢ä»˜æ¬¾c扫b
     */
   /* @Test
    public void custToBussPay(){
        log.info("<-------------------------this is createMember operation åˆ›å»ºä¼šå‘˜------------------------->");
        //创建会员
        String bizUserId = "tz20200401111";  //普通会员
        String shBizUserId = "shanghu001";  //普通会员会员(收款方,已实名)
        Long memberType = 3L;
        Long source = 1L;
        YunStResult result;
        result = createMember(bizUserId, memberType, source);
        logger.info("createMember result: status={},message={},signedValue={}", new Object[]{result.getStatus(), result.getMessage(), result.getSignedValue()});
        log.info("<-------------------------this is applyBindAcct operation ä¼šå‘˜ç»‘定支付账户用户标识(微信/支付宝/云闪付openId)------------------------->");
        //会员绑定支付账户用户标识(微信/支付宝/云闪付openId)
        String bizUserId = "tz20200401111";  //普通会员
        String acctType = "weChatMiniProgram";
        String acct = "tm001001";
        result = applyBindAcct(bizUserId, acctType, acct);
        logger.info("applyBindAcct result: status={}", new Object[]{result.getStatus(),result.getSignedValue()});
        log.info("<-------------------------this is quickPayVsp operation æ¶ˆè´¹ç”³è¯·(支付方式:收银宝刷卡支付(正扫)_)------------------------->");
        String bizUserId = "tz20200401111";  //普通会员
        ConsumeApply consumeApply = ConsumeApply.builder()
                .payerId(bizUserId)
                .recieverId(shBizUserId)
                .bizOrderNo("1232312311")
                .amount(1L)
                .fee(1L)
                .validateType(0L)
                .backUrl("localhost")
                .build();
        Long amount = 1L;
        String vspCusid = "zsh111111";
        result = doScanPay(consumeApply,vspCusid,amount,"SCAN_WEIXIN"); //正式环后加_ORG
        log.info("quickPayVsp result: status={},signedValue={}",new Object[]{result.getStatus(),result.getSignedValue()});
        log.info("<-------------------------this is getOrderDetail æŸ¥è¯¢è®¢å•状态(入金类交易(使用银行账户资金进行支付),只有订单支付成功情况下才会通知)------------------------->");
        result = getOrderDetail("12312323");
        log.info("getOrderDetail result: status={},signedValue={}",new Object[]{result.getStatus(),result.getSignedValue()});
    }*/
    /**
     * ä¼ä¸šå–家会员
     */
    /*@Test
    public void createOrgMember(){
        log.info("<-------------------------this is createOrgMember operation åˆ›å»ºä¼ä¸šä¼šå‘˜------------------------->");
        String bizUserId = "sh20200401111";  //企业会员
        Long memberType = 2L;
        Long source = 2L; //pc端
        YunStResult result;
        result = createMember(bizUserId, memberType, source);
        logger.info("createMember result: status={},message={},signedValue={}", new Object[]{result.getStatus(), result.getMessage(), result.getSignedValue()});
        log.info("<-------------------------this is createOrgMember operation åˆ›å»ºä¼ä¸šä¼šå‘˜------------------------->");
        String bizUserId = "sh20200401111";  //企业会员
        String backUrl = "localhost"; //通知地址
        Boolean isAuth = true;
        MerchantApply merchantApply = MerchantApply.builder()
                .companyName("company")
                .authType(2L)
                .uniCredit("112")
                .legalName("张三")
                .identityType(1L)
                .legalIds("122212121")  //RSA加密
                .legalPhone("13360881231")
                .accountNo("13360881231") //RSA加密
                .parentBankName("工商银行")
                .bankName("中国工商银行股份有限公司北京樱桃园支行") //需是父级直连银行
                .unionBank("111111111111")//12位数字
                .build();
        result = setCompanyInfo(bizUserId,backUrl,isAuth,merchantApply);
        log.info("<-------------------------this is sendVerificationCode operation å‘送验证码------------------------->");
        //发送验证码
        String bizUserId = "tz20200401111";  //企业会员
        String phone = "17803846500";
        Long verificationCodeType = 9L;
        result = sendVerificationCode(bizUserId, phone, verificationCodeType);
        logger.info("sendVerificationCode result: status={},message={},signedValue={}",new Object[]{result.getStatus(),result.getMessage(),result.getSignedValue()});
        log.info("<-------------------------this is bindPhone operation ç»‘定手机------------------------->");
        //绑定手机
        String bizUserId = "tz20200401111";  //企业通会员
        String verificationCode = "544343";
        result = bindPhone(bizUserId, phone, verificationCode);
        logger.info("bindPhone result: status={}",new Object[]{result.getStatus()});
        log.info("<-------------------------this is signContract operation ä¼šå‘˜ç”µå­ç­¾çº¦------------------------->");
        SignContractApply signContractApply = SignContractApply.builder()
                .bizUserId("tz20200401113")
                .jumpUrl("http://www.baidu.com")
                .backUrl("localhost")
                .source(2L)
                .build();
        String webParamUrl = "http://116.228.64.55:6900/yungateway/member/signContract.html?";
        String signUrl = signContract(signContractApply,webParamUrl); //以前台 H5 é¡µé¢å½¢å¼è¿›è¡Œè¯·æ±‚
        System.out.println("signUrl is " + signUrl);
    }*/
    /**
     * ä¸ªäººå–家会员
     *
     */
    /*@Test
    public void createSellerMember(){
        log.info("<-------------------------this is createOrgMember operation åˆ›å»ºä¸ªäººä¼šå‘˜------------------------->");
        String bizUserId = "sh20200401111";  //企业会员
        Long memberType = 3L;
        Long source = 2L; //pc端
        YunStResult result;
        result = createMember(bizUserId, memberType, source);
        logger.info("createMember result: status={},message={},signedValue={}", new Object[]{result.getStatus(), result.getMessage(), result.getSignedValue()});
        log.info("<-------------------------this is sendVerificationCode operation å‘送验证码------------------------->");
        //发送验证码
        String bizUserId = "tz20200401111";  //普通会员
        String phone = "17803846500";
        Long verificationCodeType = 9L;
        result = sendVerificationCode(bizUserId, phone, verificationCodeType);
        logger.info("sendVerificationCode result: status={},message={},signedValue={}",new Object[]{result.getStatus(),result.getMessage(),result.getSignedValue()});
        log.info("<-------------------------this is bindPhone operation ç»‘定手机------------------------->");
        //绑定手机
        String bizUserId = "tz20200401111";  //普通会员
        String verificationCode = "544343";
        result = bindPhone(bizUserId, phone, verificationCode);
        logger.info("bindPhone result: status={}",new Object[]{result.getStatus()});
        log.info("<-------------------------this is certification operation å®žåè®¤è¯------------------------->");
        //实名认证
        String bizUserId = "tz20200401113";  //普通会员
        String name = "唐宗旭";
        Long identityType = 1L;
        String identityNo = "511521199408143656";
        result = setRealName(bizUserId, name, identityType, identityNo);
        logger.info("certification result: status={}",new Object[]{result.getStatus()});
        log.info("<-------------------------this is applyBindBankCard operation ç”³è¯·ç»‘定的银行卡------------------------->");
        //申请绑定的银行卡(需用真实姓名,手机,身份证,银行卡)
        String bizUserId = "tz20200401111";  //普通会员
        String cardNo = "6217853100025227554"; //4结尾卡号返回姓名不匹配
        String phone = "17723341354";
        String name = "唐宗旭";
        Long identityType = 1L;
        String identityNo = "511521199408143656";
        result = applyBindBankCard(bizUserId, cardNo, phone, name, identityType, identityNo);
        logger.info("applyBindBankCard result:  status={} , signedValue= {}", new Object[]{result.getStatus()});
        log.info("<-------------------------this is bindBankCard operation ç¡®è®¤ç»‘定银行卡------------------------->");
        //确认绑定银行卡
        String bizUserId = "tz20200401111";  //普通会员
        String phone = "17803846500";
        String tranceNum = "123"; //流水号(请求绑定银行卡接口返回)
        String transDate = "2019-10-12"; //申请时间(请求绑定银行卡接口返回)
        String verificationCode = "123";
        //todo "errorCode":"9000","message":"确认超时或请求号错误,请重新调用绑卡申请接口" é€šè”未反馈
        result = bindBankCard(bizUserId,tranceNum,transDate,phone,verificationCode);
        logger.info("bindBankCard result: status={}", new Object[]{result.getStatus()});
        log.info("<-------------------------this is queryBankCard operation æŸ¥è¯¢ç»‘定银行卡------------------------->");
        String bizUserId = "tz20200401111";
        String cardNo = null; //为空则查询所有银行卡
        result = queryBankCard(bizUserId,cardNo);
        log.info("<-------------------------this is unbindBankCard operation è§£é™¤é“¶è¡Œå¡ç»‘定------------------------->");
        //解除银行卡绑定(需要时调用)
        String bizUserId = "tz20200401111";  //普通会员
        String cardNo = "6230943800000203604";
        result = unbindBankCard(bizUserId,cardNo);
        logger.info("unbindBankCard result: status={},message={}",new Object[]{result.getStatus(),result.getMessage()});
        log.info("<-------------------------this is signContract operation ä¼šå‘˜ç”µå­ç­¾çº¦------------------------->");
        SignContractApply signContractApply = SignContractApply.builder()
                .bizUserId("tz20200401113")
                .jumpUrl("http://www.baidu.com")
                .backUrl("localhost")
                .source(2L)
                .build();
        String webParamUrl = "http://116.228.64.55:6900/yungateway/member/signContract.html?";
        String signUrl = signContract(signContractApply,webParamUrl); //以前台 H5 é¡µé¢å½¢å¼è¿›è¡Œè¯·æ±‚
        System.out.println("signUrl is " + signUrl);
    }*/
    /**
     * ä¼šå‘˜ç”µå­ç­¾çº¦
     *
     * @param signContractApply
     * @return
     *
     */
    public static String signContract(SignContractApply signContractApply, String webParamUrl) {
        final YunRequest request = new YunRequest("MemberService", "signContract");
        request.put("bizUserId", signContractApply.getBizUserId());
        request.put("jumpUrl", signContractApply.getJumpUrl());
        request.put("backUrl", signContractApply.getBackUrl());
        request.put("source", signContractApply.getSource());
        try {
            webParamUrl += YunClient.encodeOnce(request);
            return webParamUrl;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * åˆ›å»ºä¼šå‘˜
     *
     * @param bizUserId  ç”¨æˆ·æ ‡è¯†ï¼ˆç”¨æˆ·ä¸»é”®id)
     * @param memberType ä¼šå‘˜ç±»åž‹ [2.企业会员 3.个人会员]
     * @param source     è®¿é—®ç»ˆç«¯ç±»åž‹[1.mobile 2.pc]
     * @Author: lc
     * @Date: 2019/10/14 16:12
     */
    public static YunStResult createMember(String bizUserId, Long memberType, Long source) {
        final YunRequest request = new YunRequest("MemberService", "createMember");
        request.put("bizUserId", bizUserId);
        request.put("memberType", memberType);
        request.put("source", source);
        try {
            return JSONUtil.toBean(YunClient.request(request), YunStResult.class);
        } catch (final Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * ä¼šå‘˜ç»‘定支付账户用户标识
     *
     * @param bizUserId ç”¨æˆ·æ ‡è¯†ï¼ˆç”¨æˆ·ä¸»é”®id)
     * @param acctType  æ”¯ä»˜è´¦æˆ·ç±»åž‹ã€weChatPublic:微信公众号 weChatMiniProgram:微信小程序 aliPayService:支付宝生活号】
     * @param acct      æ”¯ä»˜è´¦æˆ·ç”¨æˆ·æ ‡è¯†ã€å¾®ä¿¡å…¬ä¼—号openid/微信小程序openid/支付宝生活号user_id ã€‘
     * @Author: lc
     * @Date: 2019/10/14 16:12
     */
    public static YunStResult applyBindAcct(String bizUserId, String acctType, String acct) {
        final YunRequest request = new YunRequest("MemberService", "applyBindAcct");
        request.put("bizUserId", bizUserId);
        request.put("operationType", "set");
        request.put("acctType", acctType);
        request.put("acct", acct);
        try {
            return JSONUtil.toBean(YunClient.request(request), YunStResult.class);
        } catch (final Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * å‘送短信验证码
     *
     * @param bizUserId            ç”¨æˆ·æ ‡è¯†ï¼ˆç”¨æˆ·ä¸»é”®id)
     * @param phone                æ‰‹æœºå·ç 
     * @param verificationCodeType éªŒè¯ç ç±»åž‹[9-绑定手机 6-解绑手机]
     * @Author: lc
     * @Date: 2019/10/14 16:12
     */
    public static YunStResult sendVerificationCode(String bizUserId, String phone, Long verificationCodeType) {
        final YunRequest request = new YunRequest("MemberService", "sendVerificationCode");
        request.put("bizUserId", bizUserId);
        request.put("phone", phone);
        request.put("verificationCodeType", verificationCodeType);
        try {
            return JSONUtil.toBean(YunClient.request(request), YunStResult.class);
        } catch (final Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * ç»‘定手机
     *
     * @param bizUserId        ç”¨æˆ·æ ‡è¯†ï¼ˆç”¨æˆ·ä¸»é”®id)
     * @param phone            æ‰‹æœºå·ç 
     * @param verificationCode éªŒè¯ç 
     * @Author: lc
     * @Date: 2019/10/14 16:12
     */
    public static YunStResult bindPhone(String bizUserId, String phone, String verificationCode) {
        final YunRequest request = new YunRequest("MemberService", "bindPhone");
        request.put("bizUserId", bizUserId);
        request.put("phone", phone);
        request.put("verificationCode", verificationCode);
        try {
            return JSONUtil.toBean(YunClient.request(request), YunStResult.class);
        } catch (final Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * ä¸ªäººå®žåè®¤è¯
     *
     * @param bizUserId    ç”¨æˆ·æ ‡è¯†ï¼ˆç”¨æˆ·ä¸»é”®id)
     * @param name         å§“名
     * @param identityType è¯ä»¶ç±»åž‹ã€1.身份证 2.护照 3.军官证 4.回乡证 5.台胞证 6.警官证 7.士兵证 99.其他证件】
     * @param identityNo   è¯ä»¶å·ç 
     * @Author: lc
     * @Date: 2019/10/14 16:12
     */
    public static YunStResult setRealName(String bizUserId, String name, Long identityType, String identityNo) {
        final YunRequest request = new YunRequest("MemberService", "setRealName");
        try {
            request.put("bizUserId", bizUserId);
            request.put("name", name);
            request.put("identityType", identityType);
            request.put("identityNo", RSAUtil.encrypt(identityNo));
            return JSONUtil.toBean(YunClient.request(request), YunStResult.class);
        } catch (final Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * è¯·æ±‚绑定银行卡
     *
     * @param bizUserId    ç”¨æˆ·æ ‡è¯†ï¼ˆç”¨æˆ·ä¸»é”®id)
     * @param cardNo       é“¶è¡Œå¡å·
     * @param phone        é“¶è¡Œé¢„留手机
     * @param name         å§“名
     * @param identityType è¯ä»¶ç±»åž‹ã€1.身份证 2.护照 3.军官证 4.回乡证 5.台胞证 6.警官证 7.士兵证 99.其他证件】
     * @param identityNo   è¯ä»¶å·ç 
     * @Author: lc
     * @Date: 2019/10/14 16:12
     */
    public static YunStResult applyBindBankCard(String bizUserId, String cardNo, String phone, String name, Long identityType, String identityNo) {
        final YunRequest request = new YunRequest("MemberService", "applyBindBankCard");
        try {
            request.put("bizUserId", bizUserId);
            request.put("cardNo", RSAUtil.encrypt(cardNo));
            request.put("cardNo", YunClient.encrypt(cardNo));
            request.put("phone", phone);
            request.put("name", name);
            request.put("cardCheck", 7L); //默认7L快捷支付
            request.put("identityType", identityType);
            request.put("identityNo", RSAUtil.encrypt(identityNo));
            return JSONUtil.toBean(YunClient.request(request), YunStResult.class);
        } catch (final Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * ç¡®è®¤ç»‘定银行卡
     *
     * @param bizUserId        ç”¨æˆ·æ ‡è¯†ï¼ˆç”¨æˆ·ä¸»é”®id)
     * @param tranceNum        æµæ°´å·
     * @param transDate        ç”³è¯·æ—¶é—´
     * @param phone            é“¶è¡Œé¢„留手机
     * @param verificationCode æ‰‹æœºéªŒè¯ç 
     * @Author: lc
     * @Date: 2019/10/14 16:12
     */
    public static YunStResult bindBankCard(String bizUserId, String tranceNum, String transDate, String phone, String verificationCode) {
        final YunRequest request = new YunRequest("MemberService", "bindBankCard");
        try {
            request.put("bizUserId", bizUserId);
            request.put("tranceNum", tranceNum);
            request.put("transDate", transDate);
            request.put("phone", phone);
            request.put("verificationCode", verificationCode);
            return JSONUtil.toBean(YunClient.request(request), YunStResult.class);
        } catch (final Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    public static YunStResult queryBankCard(String bizUserId, String cardNo){
        final YunRequest request = new YunRequest("MemberService","queryBankCard");
        try {
            if (StrUtil.isNotEmpty(cardNo)){
                RSAUtil.encrypt(cardNo);
            };
            request.put("bizUserId",bizUserId);
            request.put("cardNo",cardNo);
            return JSONUtil.toBean(YunClient.request(request),YunStResult.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * è§£é™¤ç»‘定银行卡
     *
     * @param bizUserId ç”¨æˆ·æ ‡è¯†ï¼ˆç”¨æˆ·ä¸»é”®id)
     * @param cardNo    é“¶è¡Œå¡å·
     * @Author: lc
     * @Date: 2019/10/14 16:12
     */
    public static YunStResult unbindBankCard(String bizUserId, String cardNo) {
        final YunRequest request = new YunRequest("MemberService", "unbindBankCard");
        try {
            request.put("bizUserId", bizUserId);
            request.put("cardNo", RSAUtil.encrypt(cardNo));
            return JSONUtil.toBean(YunClient.request(request), YunStResult.class);
        } catch (final Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * è®¾ç½®ä¼ä¸šä¼šå‘˜ä¿¡æ¯ï¼ˆæš‚时不用)
     *
     * @param bizUserId:用户标识(用户主键id)
     * @param backUrl:企业会员审核结果通知url
     * @param isAuth:是否进行线上认证
     * @Author: lc
     * @Date: 2019/10/14 16:12
     */
    public static YunStResult setCompanyInfo(String bizUserId, String backUrl, Boolean isAuth, MerchantApply merchantApply) {
        final YunRequest request = new YunRequest("MemberService", "setCompanyInfo");
        try {
            merchantApply.setLegalIds(RSAUtil.encrypt(merchantApply.getLegalIds()));
            merchantApply.setAccountNo(RSAUtil.encrypt(merchantApply.getAccountNo()));
            request.put("companyBasicInfo", merchantApply);
            request.put("bizUserId", bizUserId);
            request.put("backUrl", backUrl);
            request.put("isAuth", isAuth);
            return JSONUtil.toBean(YunClient.request(request), YunStResult.class);
        } catch (final Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * æ¶ˆè´¹ç”³è¯·ï¼ˆæ”¶é“¶å®å¿«æ·æ”¯ä»˜ï¼‰
     *
     * @param consumeApply:消费公共实体
     * @param bankCardNo:银行卡号
     * @Author: lc
     * @Date: 2019/10/14 16:12
     */
    public static YunStResult quickPayVsp(ConsumeApply consumeApply, String bankCardNo) throws Exception {
        final YunRequest request = new YunRequest("OrderService", "consumeApply");
        HashMap<String, Object> params = new HashMap<>();
        params.put("limitPay", "no_credit");
        params.put("bankCardNo", RSAUtil.encrypt(bankCardNo));
        // ç»„装支付方式
        HashMap<String, Object> payMethod = new HashMap<>();
        payMethod.put("QUICKPAY_VSP", params);
        request.put("payerId", consumeApply.getPayerId());
        request.put("recieverId", consumeApply.getRecieverId());
        request.put("bizOrderNo", consumeApply.getBizOrderNo());
        request.put("amount", consumeApply.getAmount());
        request.put("fee", consumeApply.getFee());
        request.put("validateType", consumeApply.getValidateType());
        request.put("backUrl", consumeApply.getBackUrl());
        request.put("orderExpireDatetime", consumeApply.getOrderExpireDatetime());
        request.put("payMethod", payMethod);
        request.put("industryCode", YunStParam.industryCode);
        request.put("industryName", YunStParam.industryName);
        request.put("source", YunStParam.source);
        request.put("summary", consumeApply.getSummary());
        request.put("extendInfo", consumeApply.getExtendInfo());
        request.put("splitRule", consumeApply.getSplitRule());
        try {
            return JSONUtil.toBean(YunClient.request(request), YunStResult.class);
        } catch (final Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * ç¡®è®¤æ”¯ä»˜ï¼ˆåŽå°+短信验证码确认)
     *
     * @param bizUserId        ç”¨æˆ·æ ‡è¯†ï¼ˆç”¨æˆ·ä¸»é”®id)
     * @param bizOrderNo       è®¢å•编号(支付订单)
     * @param tradeNo          äº¤æ˜“编号
     * @param verificationCode çŸ­ä¿¡éªŒè¯ç 
     * @Author: lc
     * @Date: 2019/10/14 16:12
     */
    public static YunStResult pay(String bizUserId, String bizOrderNo, String tradeNo, String verificationCode) {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//        HttpServletRequest req = requestAttributes.getRequest();
//        String ipAddress = IPUtil.getIpAddr(req); //正式环境传用户ip
        final YunRequest request = new YunRequest("OrderService", "pay");
        try {
            request.put("bizUserId", bizUserId);
            request.put("bizOrderNo", bizOrderNo);
            request.put("tradeNo", tradeNo);
            request.put("verificationCode", verificationCode);
            request.put("bizOrderNo", bizOrderNo);
            request.put("consumerIp", IPUtil.getLocalHostIp());  //ip地址
            return JSONUtil.toBean(YunClient.request(request), YunStResult.class);
        } catch (final Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * æŸ¥è¯¢è®¢å•状态
     *
     * @param bizOrderNo è®¢å•编号(支付订单)
     * @Author: lc
     * @Date: 2019/10/14 16:12
     */
    public static YunStResult getOrderDetail(String bizOrderNo) {
        final YunRequest request = new YunRequest("OrderService", "getOrderDetail");
        try {
            request.put("bizOrderNo", bizOrderNo);
            return JSONUtil.toBean(YunClient.request(request), YunStResult.class);
        } catch (final Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * æ¶ˆè´¹ç”³è¯·ï¼ˆå¾®ä¿¡å°ç¨‹åºï¼‰
     *
     * @param consumeApply:消费公共实体
     * @param vspCusid:收银宝子商户号
     * @param subAppid:微信小程序支付appid参数
     * @param amount:支付金额,单位:分
     * @param acct:微信JS支付openid——微信分配
     * @Author: lc
     * @Date: 2019/10/14 16:12
     */
    public static YunStResult wechatMiniprogramPay(ConsumeApply consumeApply, String vspCusid, String subAppid, Long amount, String acct) {
        final YunRequest request = new YunRequest("OrderService", "consumeApply");
        HashMap<String, Object> params = new HashMap<>();
        params.put("vspCusid", vspCusid);
        params.put("subAppid", subAppid);   //正式环境请必传
        params.put("limitPay", "no_credit");
        params.put("amount", amount);
        params.put("acct", acct);
        // ç»„装支付方式
        HashMap<String, Object> payMethod = new HashMap<>();
        //payMethod.put("WECHATPAY_MINIPROGRAM", params);  //测试
        payMethod.put("WECHATPAY_MINIPROGRAM_ORG", params); //正式集团版
        request.put("payerId", consumeApply.getPayerId());
        request.put("recieverId", consumeApply.getRecieverId());
        request.put("bizOrderNo", consumeApply.getBizOrderNo());
        request.put("amount", consumeApply.getAmount());
        request.put("fee", consumeApply.getFee());
        request.put("validateType", consumeApply.getValidateType());
        request.put("backUrl", consumeApply.getBackUrl());
        request.put("orderExpireDatetime", consumeApply.getOrderExpireDatetime());
        request.put("payMethod", payMethod);
        request.put("industryCode", YunStParam.industryCode);
        request.put("industryName", YunStParam.industryName);
        request.put("source", YunStParam.source);
        request.put("summary", consumeApply.getSummary());
        request.put("extendInfo", consumeApply.getExtendInfo());
        request.put("splitRule", consumeApply.getSplitRule());
        try {
            return JSONUtil.toBean(YunClient.request(request), YunStResult.class);
        } catch (final Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * æ¶ˆè´¹ç”³è¯·ï¼ˆB扫C ç”¨æˆ·è¢«æ‰«ï¼‰
     *
     * @param consumeApply:消费公共实体
     * @param vspCusid:收银宝子商户号
     * @param amount:支付金额,单位:分
     * @param authcode:支付授权码(用户出示的二维码)
     * @Author: lc
     * @Date: 2019/10/14 16:12
     */
    public static YunStResult doCodePay(ConsumeApply consumeApply, String vspCusid, Long amount, String authcode) {
        final YunRequest request = new YunRequest("OrderService", "consumeApply");
        HashMap<String, Object> params = new HashMap<>();
        params.put("amount", amount);
        params.put("vspCusid", vspCusid);
        params.put("authcode", authcode);
        params.put("limitPay", "no_credit");
        // ç»„装支付方式
        HashMap<String, Object> payMethod = new HashMap<>();
        payMethod.put("CODEPAY_VSP", params);
        //payMethod.put("CODEPAY_VSP_ORG", params);  //正式集团版
        request.put("payerId", consumeApply.getPayerId());
        request.put("recieverId", consumeApply.getRecieverId());
        request.put("bizOrderNo", consumeApply.getBizOrderNo());
        request.put("amount", consumeApply.getAmount());
        request.put("fee", consumeApply.getFee());
        request.put("validateType", consumeApply.getValidateType());
        request.put("backUrl", consumeApply.getBackUrl());
        request.put("orderExpireDatetime", consumeApply.getOrderExpireDatetime());
        request.put("payMethod", payMethod);
        request.put("industryCode", YunStParam.industryCode);
        request.put("industryName", YunStParam.industryName);
        request.put("source", YunStParam.source);
        request.put("summary", consumeApply.getSummary());
        request.put("extendInfo", consumeApply.getExtendInfo());
        request.put("splitRule", consumeApply.getSplitRule());
        try {
            return JSONUtil.toBean(YunClient.request(request), YunStResult.class);
        } catch (final Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * æ¶ˆè´¹ç”³è¯·ï¼ˆC扫B ç”¨æˆ·ä¸»æ‰«ï¼‰
     *
     * @param consumeApply:消费公共实体
     * @param vspCusid:收银宝子商户号
     * @param amount:支付金额,单位:分
     * @param acctType:支付账户类型【SCAN_WEIXIN_ORG:微信 SCAN_ALIPAY_ORG:支付宝 SCAN_UNIONPAY_ORG:银联云闪付】   æµ‹è¯•环境不带_ORG
     * @Author: lc
     * @Date: 2019/10/14 16:12
     */
    public static YunStResult doScanPay(ConsumeApply consumeApply, String vspCusid, Long amount, String acctType) {
        final YunRequest request = new YunRequest("OrderService", "consumeApply");
        HashMap<String, Object> params = new HashMap<>();
        params.put("vspCusid", vspCusid);
        params.put("amount", amount);
        params.put("limitPay", "no_credit");
        // ç»„装支付方式
        HashMap<String, Object> payMethod = new HashMap<>();
        payMethod.put(acctType, params);
        request.put("payerId", consumeApply.getPayerId());
        request.put("recieverId", consumeApply.getRecieverId());
        request.put("bizOrderNo", consumeApply.getBizOrderNo());
        request.put("amount", consumeApply.getAmount());
        request.put("fee", consumeApply.getFee());
        request.put("validateType", consumeApply.getValidateType());
        request.put("backUrl", consumeApply.getBackUrl());
        request.put("orderExpireDatetime", consumeApply.getOrderExpireDatetime());
        request.put("payMethod", payMethod);
        request.put("industryCode", YunStParam.industryCode);
        request.put("industryName", YunStParam.industryName);
        request.put("source", YunStParam.source);
        request.put("summary", consumeApply.getSummary());
        request.put("extendInfo", consumeApply.getExtendInfo());
        request.put("splitRule", consumeApply.getSplitRule());
        try {
            return JSONUtil.toBean(YunClient.request(request), YunStResult.class);
        } catch (final Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunst/ϵͳ¶Ô½ÓÔÆÉÌͨ½Ó¿ÚÁ÷³Ì.txt
New file
@@ -0,0 +1,24 @@
lc(20191015)
一.个人会员买家线上支付:
1.使用微信小程序: åˆ›å»ºä¼šå‘˜ --》会员绑定支付账户用户标识(支付账户绑定小程序openId)--》消费申请 --》订单结果通知 --》完成。
2.使用收银宝快捷支付:创建会员 --》发送验证码  --》绑定手机  --》个人实名认证  --》请求绑定银行卡 --》确认绑定银行卡  --》解绑银行卡(需要时调用) --》
                      æ¶ˆè´¹ç”³è¯·ï¼ˆçŸ­ä¿¡éªŒè¯ç æ–¹å¼ï¼‰  --》确认支付(后台+短信验证码确认)--》查询订单状态(根据确认支付接口返回处理中再调用,成功/失败不调用)--》完成。
二.个人会员买家线下支付
3.线下面对面付(B扫c):创建会员 --》会员绑定支付账户用户标识(支付账户绑定微信/支付宝/云闪付openId) --》消费申请(支付方式:收银宝刷卡支付(被扫)_集团——支持微信、支付宝、银联、手机QQ)
                        --》订单结果通知(支付接口返回处理中再调用,成功/失败不调用)  --》完成。
4.线下面对面付(c扫b):创建会员  --》会员绑定支付账户用户标识(支付账户绑定微信/支付宝/云闪付openId) --》消费申请(微信/支付包/银联扫码支付(正扫) _集团)
                        --》订单结果通知(支付接口返回处理中再调用,成功/失败不调用)  --》完成
三.企业卖家会员(邮政机构)
1.收款方:创建会员 --》 è®¾ç½®ä¼ä¸šä¼šå‘˜ä¿¡æ¯  --》企业会员审核结果通知  --》发送短信验证码(类型绑定手机)  --》绑定手机  --》解绑手机(需要时调用) --》会员电子协议签约  --》完成。
四.个人卖家会员(邮政商户)
1.收款方 åˆ›å»ºä¼šå‘˜ ->  å‘送短信验证码  ->  ç»‘定手机  ->  è§£ç»‘手机  ->个人实名认证 -> è¯·æ±‚绑定银行卡 -> ç¡®è®¤ç»‘定银行卡 -> æŸ¥è¯¢ç»‘定银行卡 ->
         è§£ç»‘绑定银行卡 -> ä¼šå‘˜ç”µå­åè®®ç­¾çº¦
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/ApiPost.java
New file
@@ -0,0 +1,82 @@
package com.nuvole.util.pay.allinPay.yunstNew;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.nuvole.util.pay.allinPay.yunstNew.po.ResultVo;
import com.nuvole.util.pay.allinPay.yunstNew.po.YstPayUrl;
import java.util.*;
/**
 * Created by chenZhimin
 * Date:2020/8/24
 * time:10:09
 */
public class ApiPost {
    public static ResultVo apiPost(String url, Object obj) {
        System.out.println(url);
        System.out.println(getSignBody(obj));
        ResultVo result=new ResultVo();
        try {
             JSONObject data= JSONUtil.xmlToJson(HttpUtil.post(url,getSignBody(obj)));
             result=JSON.parseObject(JSON.toJSONString(data.get("ResultVo")),ResultVo.class);
            System.out.println("wwwwwwwwwwwwww"+result);
        } catch (Exception e) {
            System.out.println("wwwwwwwwwwwwww"+e);
            result.setCode("0");
            result.setMsg("接口请求失败");
            result.setData("");
        }
        return result;
    }
    /**
     * ç»„装带签名数据
     * @param body
     * @return
     */
    public static String getSignBody(Object body) {
         Map map= JSON.parseObject(JSON.toJSONString(body));
        String version=YstPayUrl.version;
        String terMerchantId= YstPayUrl.terMerchantId;
        map.put("version",version);
        map.put("terMerchantId",terMerchantId);
        String orgSign=createLinkStringByGet(map)+"&key="+YstPayUrl.ked;
        System.out.println("orgSign--------"+orgSign);
        String sign=SecureUtil.md5(orgSign);
        map.put("sign",sign.toUpperCase());
         return JSON.toJSONString(map);
    }
       /**
     ã€€ã€€* æŠŠæ•°ç»„所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
     ã€€ã€€* @param params éœ€è¦æŽ’序并参与字符拼接的参数组
     ã€€ã€€* @return æ‹¼æŽ¥åŽå­—符串
     ã€€ã€€* @throws UnsupportedEncodingExceptio
     ã€€ã€€*/
    public static String createLinkStringByGet(Map<String, String> params) {
        List<String> keys = new ArrayList<String>(params.keySet());
        Collections.sort(keys);
        String prestr = "";
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            Object value = params.get(key);
            if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
                prestr = prestr + key + "=" + value;
            } else {
                prestr = prestr + key + "=" + value + "&";
            }
        }
        return prestr;
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/YunStUtilNew.java
New file
@@ -0,0 +1,168 @@
package com.nuvole.util.pay.allinPay.yunstNew;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.nuvole.util.pay.allinPay.yunst.YunStUtil;
import com.nuvole.util.pay.allinPay.yunstNew.po.*;
import com.nuvole.util.pay.allinPay.yunstNew.po.payment.PaymentOrder;
import com.nuvole.util.pay.allinPay.yunstNew.po.payment.PaymentSubOrder;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
/**
 * Created by chenZhimin
 * Date:2020/8/24
 * time:10:45
 */
@Slf4j
public class YunStUtilNew {
    private Logger logger = LoggerFactory.getLogger(YunStUtil.class);
    //v1/shop/web/payBackYst å›žè°ƒæŽ¥å£
    /**
     * æµ‹è¯•会员创建
     */
    public void createSellerMember(){
        CreateMember merber=new CreateMember();
        merber.setExternalUserid("wl01");
        merber.setMerchantName("记忆不放假");
        // merber.setPhone("17839927203"); Acct传小程序 opeinid就行 ï¼Œä¸ç”¨ä¼ æ‰‹æœºå·
        merber.setAcctType("weChatMiniProgram");
        merber.setAcct("oZN135DrmaB3iCAvbZq_ShTM7FFQ");
        String bizUserId= createSellerMember(merber);
        System.out.println(bizUserId);
        //1341541084
        //{"ResultVo":{"msg":"创建成功","code":1,"data":{"freezeAmount":"","allAmount":"","externalUserid":"czm01","terUuid":"","companyName":"","memUuid":"","memberType":"","bizUserId":1336179677,"status":"","fileId":""}}}
    }
    /**
     * è°ƒç”¨æ‰˜ç®¡ä»£æ”¶æŽ¥å£
     */
    public void orderPayer(){
        OrderPay pay=new OrderPay();
        pay.setAmount("0.01");
        pay.setMerOrderNo("11ab_02");//订单号
        pay.setOrderType("5");
        pay.setPayerExId("czm02");//买家账号
        pay.setSource("1");
        pay.setType("2");
        pay.setAcct("oZN135DrmaB3iCAvbZq_ShTM7FFQ");  //微信openId ä¹°å®¶
        List list=new ArrayList();
        SubOrder order=new SubOrder();
        order.setAmount("0.01");
        order.setRecieverExId("yjp01");
        order.setSubMerOrderNo("11ab_02");
        list.add(order);
       /* SubOrder order2=new SubOrder();
        order2.setAmount("0.01");
        order2.setRecieverExId("1348216174");
        order2.setSubMerOrderNo("dd02");
        order2.setBody("分账订单02");
        list.add(order2);*/
        pay.setSubOrder(JSON.toJSONString(list));
        ResultVo result=orderPayer(pay);
        System.out.println("22222222222222222---"+JSON.toJSONString(result));
        //wwwwwwwwwwwwwwResultVo(msg=调用成功, code=1, data={"validateType":"","orderStatus":"","payWhereabouts":"","payInterfaceOutTradeNo":"","couponAmount":"","subBizOrderNo":{"subBizOrderNo":159834506278770},"termno":"","oriOrderNo":"","bizOrderNo":15983450627877,"refundWhereabouts":"","weChatAPPInfo":"","amount":"","orderNo":1298179292374536192,"tradeNo":"","merOrderNo":"11ab","traceno":"","errorMessage":"","freezenAmount":"","extendInfo":"","oriBizOrderNo":"","accttype":"","subMerOrderNo":{"subMerOrderNo":"11ab_01"},"url":"","bizUserId":1329222217,"feeAmount":"","buyerBizUserId":"","payFailMessage":"","allAmount":"","totalNum":"","cusid":"","bizBatchNo":"","payInterfacetrxcode":"","payCode":"","payStatus":"","payInfo":"{\"appId\":\"wx044ba657d536fa6a\",\"timeStamp\":\"1598345063\",\"nonceStr\":\"2f86b439742f4918b26093d76c599e51\",\"package\":\"prepay_id=wx251644234244923f718ac7e4abcb810000\",\"signType\":\"RSA\",\"paySign\":\"t0qNpWWHVx+sjNYNtiH/sYrULcXV/l88Ke2tKDH0XKHy8bAOW01EaM5Xye04+SrpJJkW/5IyVaAMXOt9mp0Bp1k+sWNYRkSozq+gKLWGTm8/zk1Pu/+exruEgnvK08o4UihXIkPD44zdR/AuYEe9YHwfV+3qrm0n+z5mch9JEdzeETuH6GVyFxBoJXL60GziVha3TSDrmsP02gdrBeyUTWjE0kYkLFoZztlxv7cAbqCKMiWQaIJ+dN/l4Nmx6k3zZgupErVLFjY9Rdas90SnOtB2HEAmBs62T82sVV7CaeMEBAxL9bkrGxMWtFYriPuPKqAsZAMmFrc+3Bs3QmQ0LQ==\"}","payDatetime":"","acct":""})
    }
    /**
     * è°ƒç”¨æ‰˜ç®¡ä»£ä»˜æŽ¥å£
     */
    @Test
    public void paymentPayerOrder(){
        PaymentOrder pay=new PaymentOrder();
        pay.setExternalUserid("czm02");//商户代收订单请求会员id
        pay.setMerOrderNo("11ab_02_df");  //商户代付支付订单号
        pay.setOldMerOrderNo("11ab_02");  //商户原始代收主订单号
        pay.setOrderType("6");
        pay.setSource("1"); //1 pc端  2 å¾®ä¿¡ç«¯
        pay.setExtendInfo("代付备注");
        List list=new ArrayList();
        PaymentSubOrder order=new PaymentSubOrder();
        order.setSubMerOrderNo("df_dd01"); //商户代付支付子订单号
        order.setSubOldMerOrderNo("11ab_02");
        list.add(order);
       /* SubOrder order2=new SubOrder();
        order2.setAmount("0.01");
        order2.setRecieverExId("1348216174");
        order2.setSubMerOrderNo("dd02");
        order2.setBody("分账订单02");
        list.add(order2);*/
        pay.setSubOrder(JSON.toJSONString(list));
        ResultVo result=orderPayer(pay);
        System.out.println("22222222222222222---"+JSON.toJSONString(result));
        //wwwwwwwwwwwwwwResultVo(msg=调用成功, code=1, data={"validateType":"","orderStatus":"","payWhereabouts":"","payInterfaceOutTradeNo":"","couponAmount":"","subBizOrderNo":{"subBizOrderNo":159834506278770},"termno":"","oriOrderNo":"","bizOrderNo":15983450627877,"refundWhereabouts":"","weChatAPPInfo":"","amount":"","orderNo":1298179292374536192,"tradeNo":"","merOrderNo":"11ab","traceno":"","errorMessage":"","freezenAmount":"","extendInfo":"","oriBizOrderNo":"","accttype":"","subMerOrderNo":{"subMerOrderNo":"11ab_01"},"url":"","bizUserId":1329222217,"feeAmount":"","buyerBizUserId":"","payFailMessage":"","allAmount":"","totalNum":"","cusid":"","bizBatchNo":"","payInterfacetrxcode":"","payCode":"","payStatus":"","payInfo":"{\"appId\":\"wx044ba657d536fa6a\",\"timeStamp\":\"1598345063\",\"nonceStr\":\"2f86b439742f4918b26093d76c599e51\",\"package\":\"prepay_id=wx251644234244923f718ac7e4abcb810000\",\"signType\":\"RSA\",\"paySign\":\"t0qNpWWHVx+sjNYNtiH/sYrULcXV/l88Ke2tKDH0XKHy8bAOW01EaM5Xye04+SrpJJkW/5IyVaAMXOt9mp0Bp1k+sWNYRkSozq+gKLWGTm8/zk1Pu/+exruEgnvK08o4UihXIkPD44zdR/AuYEe9YHwfV+3qrm0n+z5mch9JEdzeETuH6GVyFxBoJXL60GziVha3TSDrmsP02gdrBeyUTWjE0kYkLFoZztlxv7cAbqCKMiWQaIJ+dN/l4Nmx6k3zZgupErVLFjY9Rdas90SnOtB2HEAmBs62T82sVV7CaeMEBAxL9bkrGxMWtFYriPuPKqAsZAMmFrc+3Bs3QmQ0LQ==\"}","payDatetime":"","acct":""})
    }
    /**
     * åˆ›å»ºä¸ªäººå•†æˆ·
     */
    public void orderPayerSh(){
        Map map=new HashMap();
        map.put("externalUserid","yjp01");
        map.put("merchantName","个人商户叶");
        map.put("legalName","叶建鹏");
        map.put("phone","17321156857");
        map.put("identityType","1");
        map.put("legalIds","410221199004193031");
        map.put("acctType","aliPayService");
        map.put("acct","yjp");
        ResultVo result=ApiPost.apiPost(YstPayUrl.CREATE_SHOP_MEMBER,map);
        System.out.println("22222222222222222---"+result);
        // {"ResultVo":{"msg":"创建成功","code":1,"data":{"freezeAmount":"","allAmount":"","externalUserid":"yjp01","terUuid":"","companyName":"","memUuid":"","memberType":"","bizUserId":1325044892,"status":"","fileId":""}}}
    }
    /**
     * ä¼šå‘˜åˆ›å»ºï¼šæ¸¸å®¢æ¨¡å¼
     *
     *           //买家买家注册流程:会员创建:游客模式
     *         if (storeMemberInfo != null && StrUtil.isEmpty(storeMemberInfo.getYunstuserid())) {
     *             CreateMember merber=new CreateMember();
     *             merber.setExternalUserid(Convert.toStr(storeMemberInfo.getId()));
     *             merber.setMerchantName(storeMemberInfo.getMemberName());
     *             merber.setAcct(storeMemberInfo.getWechatOpenid());
     *             String yunStUserId=YunStUtilNew.createSellerMember(merber);
     *             if(!StrUtil.isEmpty(yunStUserId)){
     *                 storeMemberInfo.setYunstuserid(yunStUserId);
     *             }
     *         }
     */
    public static String createSellerMember(CreateMember merber){
        String bizUserId="";
        merber.setAcctType("weChatMiniProgram");
        ResultVo result=ApiPost.apiPost(YstPayUrl.CREATE_SELLER_MEMBER,merber);
        if(("1").equals(result.getCode())){
            Map map= (Map) JSONUtil.parse(result.getData());
            bizUserId=map.get("bizUserId").toString();
        }
        return bizUserId;
    }
    /**
     *  æ‰˜ç®¡ä»£æ”¶/托管代付
     */
        public static ResultVo orderPayer(Object pay){
            ResultVo result=ApiPost.apiPost(YstPayUrl.ORDER_PAYER,pay);
            return result;
        }
    }
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/po/CreateMember.java
New file
@@ -0,0 +1,18 @@
package com.nuvole.util.pay.allinPay.yunstNew.po;
import lombok.Data;
/**
 * Created by chenlong
 * Date:2020/8/24
 * time:10:57
 */
@Data
public class CreateMember {
    String  externalUserid;
    String  merchantName;
    String  phone;
    String  acctType;
    String  acct;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/po/OrderPay.java
New file
@@ -0,0 +1,73 @@
package com.nuvole.util.pay.allinPay.yunstNew.po;
import lombok.Data;
import com.alibaba.fastjson.JSONArray;
/**
 * Created by chenlong
 * Date:2020/8/24
 * time:14:30
 */
@Data
public class OrderPay {
    /**
     * æ”¯ä»˜å¹³å°ç”¨æˆ·æ ‡è¯†ï¼Œtype=2,11传输微信openid
     */
    String acct;
    /**
     *     å•位元
     */
    String amount;
    /**
     *     type=3时传入,用户付款二维码
     */
    String authCode;
    /**
     * å•†æˆ·appid,如果没有传输的时候就使用平台端配置的参数
     */
    String exAppId;
    /**
     * ä¸»è®¢å•备注
     */
    String extendInfo;
    /**
     * å•†æˆ·ä»£æ”¶æ”¯ä»˜ä¸»è®¢å•号
     */
    String merOrderNo;
    /**
     * ä¸»è®¢å•过期时间,type=14必传
     */
    String orderExpireDatetime;
    /**
     * è®¢å•交易类型,默认填写5(托管代收)
     */
    String orderType="5";
    /**
     * ä¸‰æ–¹å¹³å°ä»˜æ¬¾äººä¼šå‘˜å·
     */
    String payerExId;
    /**
     *     ç»ˆç«¯è®¿é—®ç±»åž‹ï¼Œ1 ç§»åŠ¨ç«¯   2 PC端
     */
    String source;
    /**
     *子订单信息,详情请见子订单信息
     */
    String subOrder;
    /**
     * ä¸»è®¢å•摘要
     */
    String summary;
    /**
     *     æ”¯ä»˜æ¸ é“,
     */
    String type;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/po/PayBack.java
New file
@@ -0,0 +1,61 @@
package com.nuvole.util.pay.allinPay.yunstNew.po;
import io.swagger.annotations.ApiImplicitParam;
import lombok.Data;
/**
 * Created by chenlong
 * Date:2020/8/25
 * time:14:34
 */
@Data
public class PayBack {
    /**
     * å•†æˆ·ä¸»è®¢å•号
     */
    public String merOrderNo;
    /**
     * ç³»ç»Ÿä¸»è®¢å•号
     */
    public String bizOrderNo;
    /**
     * å•†æˆ·åŽŸå§‹ä¸»è®¢å•å·ï¼Œé€€æ¬¾çš„æ—¶å€™å¿…ä¼ 
     */
    public String oriMerOrderNo;
    /**
     * ç³»ç»ŸåŽŸå§‹ä¸»è®¢å•å·ï¼Œé€€æ¬¾çš„æ—¶å€™å¿…ä¼ 
     */
    public String oriBizOrderNo;
    /**
     * è®¢å•类型 1:消费 2:充值 3:提现 4:退货 5:代收 6:代付
     */
    public String orderType;
    /**
     *主订单交易支付状态,针对于没有子订单的交易,success:成功,pending:进行中,fail:失败,success_collection:代付成功,collection_pending:代付进行中
     */
    public String transStatus;
    /**
     äº¤æ˜“请求时间 yyyyMMddhhssmm
     */
    public String payReqDataTime;
    /**
     * äº¤æ˜“完成时间 yyyyMMddhhssmm
     *
     */
    public String payDataTime;
    /**
     *代收子订单退货时代收子订单单号
     *
     */
    public String subOriMerOrderNo;
    /**
     * æ”¯ä»˜æ–¹å¼
     */
    public String paymethod;
    /**
     * å­è®¢å•,详情查看子订单信息
     */
    public String subOrder;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/po/PayBackChild.java
New file
@@ -0,0 +1,32 @@
package com.nuvole.util.pay.allinPay.yunstNew.po;
import lombok.Data;
/**
 * Created by chenlong
 * Date:2020/8/25
 * time:14:41
 */
@Data
public class PayBackChild {
    /**
     *    äº¤æ˜“支付状态,success(消费成功/分账成功【代付成功】),pending(进行中),fail(交易失败),success_collection(收款成功/代收成功),collection_pending(收款进行中/代收进行中)
     */
    public String transStatus;
    /**
     *    å•†æˆ·å­è®¢å•号
     */
    public String subMerOrderNo;
    /**
     *    ç³»ç»Ÿå­è®¢å•号
     */
    public String subBizOrderNo;
    /**
     *商户原始子订单号,退款的时候必传
     */
    public String subOldMerOrderNo;
    /**
     *系统原始只订单号,退款的时候必传
     */
    public String subOriBizOrderNo;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/po/ResultVo.java
New file
@@ -0,0 +1,15 @@
package com.nuvole.util.pay.allinPay.yunstNew.po;
import lombok.Data;
/**
 * Created by chenlong
 * Date:2020/8/25
 * time:13:32
 */
@Data
public class ResultVo {
    public String msg;
    public String code;
    public String data;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/po/SplitRule.java
New file
@@ -0,0 +1,32 @@
package com.nuvole.util.pay.allinPay.yunstNew.po;
import lombok.Data;
/**
 * Created by chenzhimin
 * Date:2020/9/8
 * time:20:27
 * åˆ†è´¦è§„则
 */
@Data
public class SplitRule {
    /**
     *    å¹³å°æ–¹åœ¨é€šå•†äº‘系统的id æ˜¯
     */
    public String terMerchantId;
    /**
     *    åˆ†è´¦æ”¶æ¬¾äººï¼Œå¡«å†™å•†æˆ·å¹³å°çš„会员id æ˜¯
     */
    public String externalUserid;
    /**
     *    å•位元 æ˜¯
     */
    public String amount;
    /**
     *  åˆ†è´¦è§„则 å¦
     */
    public String splitRule;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/po/SubOrder.java
New file
@@ -0,0 +1,40 @@
package com.nuvole.util.pay.allinPay.yunstNew.po;
import com.alibaba.fastjson.JSONArray;
import lombok.Data;
/**
 * Created by chenlong
 * Date:2020/8/24
 * time:16:23
 */
@Data
public class SubOrder {
    /**
     *     å­è®¢å•交易金额,单位为元 æ˜¯
     */
    String amount;
    /**
     *     è®¢å•详情  å¦
     */
    String body;
    /**
     *     å•†æˆ·æ”¶æ¬¾æ–¹id      æ˜¯
     */
    String recieverExId;
    /**
     *     åˆ†è´¦è§„则,见下方分账规则,最多三层,最多10人分账,不传输认为不分账,全部代付   å¦
     */
    JSONArray splitRule;
    /**
     *         å­è®¢å•自动分账时间,不传就一直挂起,直到主动调代付完成分账,整数,单位,天  å¦
     */
    String spTime;
    /**
     * å•†æˆ·å­æ”¯ä»˜è®¢å•号      æ˜¯
     */
    String subMerOrderNo;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/po/YstPayUrl.java
New file
@@ -0,0 +1,35 @@
package com.nuvole.util.pay.allinPay.yunstNew.po;
/**
 * Created by chenlong
 * Date:2020/8/25
 * time:14:01
 */
public class YstPayUrl {
    //平台方在行业版通商云系统中的id
    public static final String terMerchantId="1212908434073104385";
    //版本号
    public static final String version="1.0";
    //MD5加签key
    public static final String ked="test";
    public static final String url="https://tsytest.allinpaysc.com/api";
    /**
     * ä¼šå‘˜åˆ›å»ºï¼šæ¸¸å®¢æ¨¡å¼
     */
    public static final String CREATE_SELLER_MEMBER =url+ "/terrace-service/terrace/creat/tourists/member";
    /**
     * è°ƒç”¨æ‰˜ç®¡ä»£æ”¶æŽ¥å£ï¼ˆå¾®ä¿¡å°ç¨‹åºæ”¯ä»˜é›†å›¢æ¨¡å¼ï¼ˆtype:2)) /托管代付
     */
    public static final String ORDER_PAYER =url+ "/order-service/trans/order";
    /**
     *会员创建:商户(个人会员)
     */
    public static final String CREATE_SHOP_MEMBER =url+"/terrace-service/terrace/creat/personal/member";
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/po/payment/PaymentOrder.java
New file
@@ -0,0 +1,52 @@
package com.nuvole.util.pay.allinPay.yunstNew.po.payment;
import lombok.Data;
/**
 * Created by chenzhimin
 * Date:2020/9/8
 * time:20:15
 */
@Data
public class PaymentOrder {
    /**
     ä»£ä»˜ä¸»è®¢å•备注
     */
    public String extendInfo;
    /**
     *    å•†æˆ·ä»£æ”¶è®¢å•请求会员id
     */
    public String externalUserid;
    /**
     * å•†æˆ·ä»£ä»˜æ”¯ä»˜è®¢å•号
     */
    public String merOrderNo;
    /**
     * å•†æˆ·åŽŸå§‹ä»£æ”¶ä¸»è®¢å•å·ï¼ˆOldMerOrderNo和OriBizOrderNo必传一个)
     */
    public String oldMerOrderNo;
    /**
     * è®¢å•类型类型,默认填写6(托管代付)
     *
     */
    public String orderType;
    /**
     *系统原始代收主订单号(OldMerOrderNo和OriBizOrderNo必传一个)
     */
    public String oriBizOrderNo;
    /**
     * 1 ç§»åЍ 2 pc端
     */
    public String source;
    /**
     *     å­è®¢å•信息,详情请见子订单信息,不传输的话全部代付,全部代付的时候只传输系统订单号的时候商户子订单号易联通系统不自己生成
     */
    public String subOrder;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/po/payment/PaymentSplitRule.java
New file
@@ -0,0 +1,32 @@
package com.nuvole.util.pay.allinPay.yunstNew.po.payment;
import lombok.Data;
/**
 * Created by chenzhimin
 * Date:2020/9/8
 * time:20:27
 * åˆ†è´¦è§„则
 */
@Data
public class PaymentSplitRule {
    /**
     *    å¹³å°æ–¹åœ¨é€šå•†äº‘系统的id
     */
    public String terMerchantId;
    /**
     *    åˆ†è´¦æ”¶æ¬¾äººï¼Œå¡«å†™å•†æˆ·å¹³å°çš„会员id
     */
    public String externalUserid;
    /**
     *    å•位元 æ˜¯
     */
    public String amount;
    /**
     *  åˆ†è´¦è§„则 å¦
     */
    public String splitRule;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/pay/allinPay/yunstNew/po/payment/PaymentSubOrder.java
New file
@@ -0,0 +1,31 @@
package com.nuvole.util.pay.allinPay.yunstNew.po.payment;
import com.alibaba.fastjson.JSONArray;
import lombok.Data;
/**
 * Created by chenzhimin
 * Date:2020/9/8
 * time:20:21
 */
@Data
public class PaymentSubOrder {
    /**
     *     æ›´æ–°åˆ†è´¦è§„则,见下方分账规则,最多三层,最多10人分账,不传输的话按照原来设置的信息分账   å¦
     */
    String splitRule;
    /**
     *     å•†æˆ·ä»£ä»˜æ”¯ä»˜å­è®¢å•号 æ˜¯
     */
    String subMerOrderNo;
    /**
     * å•†æˆ·åŽŸå§‹ä»£æ”¶æ”¯ä»˜å­è®¢å•å·ï¼ˆsubOldMerOrderNo和subOriBizOrderNo必传一个)  å¦
     */
    String subOldMerOrderNo;
    /**
     *     ç³»ç»ŸåŽŸå§‹ä»£æ”¶æ”¯ä»˜å­è®¢å•å·ï¼ˆsubOldMerOrderNo和subOriBizOrderNo必传一个)     å¦
     */
    String subOriBizOrderNo;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/sc/client/domain/ScClient.java
New file
@@ -0,0 +1,36 @@
package com.nuvole.util.sc.client.domain;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * ä¼šå‘˜ä¿¡æ¯è¿”回类(客管系统)
 *
 * @Author: lc
 * @Date: 2019/7/11 17:50
 */
@Data
@ApiModel(value = "会员信息返回类(客管系统)")
public class ScClient {
    @ApiModelProperty(value = "客户等级")
    private String cust_lev;
    @ApiModelProperty(value = "标签客群(逗号分隔形式)")
    private String labelsstr;
    @ApiModelProperty(value = "客户经理编号")
    private String tlrno;
    @ApiModelProperty(value = "机构编号(对应会员表里的user_org_code)")
    private String inst_no;
    @ApiModelProperty(value = "客户姓名")
    private String cust_name;
    @ApiModelProperty(value = "手机号")
    private String tel;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/sc/client/domain/ScGroup.java
New file
@@ -0,0 +1,25 @@
package com.nuvole.util.sc.client.domain;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
 * å®¢ç¾¤è¿”回值(客管系统)
 *
 * @Author: lc
 * @Date: 2019/11/2 12:41
 */
@Data
@ApiModel(value = "客群返回值(客管系统)")
public class ScGroup {
    @ApiModelProperty(value = "客群名称")
    private String label_name;
    @ApiModelProperty(value = "客群编号")
    private String label_no;
    @ApiModelProperty(value = "上级标签")
    private String parent_label;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/sc/client/ËÄ´¨¿Í¹Üϵͳ½Ó¿ÚÎĵµ.docx
Binary files differ
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/sc/sms/ScSMSUtil.java
New file
@@ -0,0 +1,57 @@
package com.nuvole.util.sc.sms;
import cn.hutool.core.util.StrUtil;
import com.nuvole.common.domain.emnu.SMSResultEmnu;
import com.nuvole.common.domain.result.SMSResult;
import com.wisentsoft.service.sms.gsmp.GsmpCPSrv;
/**
 * çŸ­ä¿¡ï¼ˆå››å·çœï¼‰
 *
 * @Author: lc
 * @Date: 2019/6/1 11:09
 */
public class ScSMSUtil {
    private static String ip = "10.1.210.7";
    private static int port = 13013;
    private static String cpUser = "950013";
    private static String cpPass = "950013";
    private static int timeout = 30;
    private static String cpSrvId = "SCYYPDX950013";
    private static GsmpCPSrv gsmpCPSrv;
    static {
        try {
            if (gsmpCPSrv == null) {
                gsmpCPSrv = new GsmpCPSrv(ScSMSUtil.ip, ScSMSUtil.port, ScSMSUtil.cpUser, ScSMSUtil.cpPass, ScSMSUtil.timeout, "/yypdx.log", false);
                gsmpCPSrv.start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * å‘送短信
     *
     * @param mobile  æ‰‹æœºå·ç 
     * @param message å‘送消息文本
     * @return
     * @throws Exception
     */
    public static SMSResult sendSMS(String mobile, String message) {
        try {
            String result = gsmpCPSrv.submitMTSMS(mobile, message, cpSrvId);
            if (StrUtil.isEmpty(result)) {
                return new SMSResult(SMSResultEmnu.ERROR, "发送失败!");
            }
            return new SMSResult(SMSResultEmnu.OK);
        } catch (Exception e) {
            e.printStackTrace();
            return new SMSResult(SMSResultEmnu.ERROR, "发送异常!");
        }
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/sms/SMSCallUtil.java
New file
@@ -0,0 +1,67 @@
package com.nuvole.util.sms;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.nuvole.common.domain.emnu.SMSResultEmnu;
import com.nuvole.common.domain.result.SMSResult;
import com.nuvole.constants.ServiceConstants;
import com.nuvole.util.sc.sms.ScSMSUtil;
import java.util.HashMap;
import java.util.Map;
/**
 * å‘送短信(统一调度类)
 *
 * @Author: lc
 * @Date: 2019/6/1 11:09
 */
public class SMSCallUtil {
    /**
     * çŸ­ä¿¡æŽ¥å£ç±»åž‹ï¼ˆ1.云片 2.四川省内部接口)
     */
    private final static int SMS_TYPE = 1;
    /**
     * å‘送短信
     *
     * @param mobile  æ‰‹æœºå·ç å­—符串 å¤šä¸ªå·ç ä»¥é€—号分割
     * @param message çŸ­ä¿¡å†…容
     * @Author: lc
     * @Date: 2019/6/1 11:27
     */
    public static SMSResult sendSMS(String mobile, String message) {
        //走外网服务调用
        if (ServiceConstants.SERVICE_TYPE) {
            Map map = new HashMap() {{
                put("mobile", mobile);
                put("message", message);
                put("smsType", SMS_TYPE);
            }};
            String result = HttpUtil.get(ServiceConstants.SERVICE_SMS_URL, map);
            JSONObject jsonObject = JSONObject.parseObject(result);
            if (!"0".equals(jsonObject.getString("code"))) {
                return new SMSResult(SMSResultEmnu.ERROR, jsonObject.getString("msg"));
            }
            return new SMSResult(SMSResultEmnu.OK);
        } else {
            switch (SMS_TYPE) {
                case 1:
                    return YpSMSUtil.sendSMS(mobile, message);
                case 2:
                    return ScSMSUtil.sendSMS(mobile, message);
                default:
                    break;
            }
            return new SMSResult(SMSResultEmnu.ERROR);
        }
    }
    public static void main(String[] args) {
        System.out.println(sendSMS("17803846500", SMSTemplate.getVaildCodeMsg(RandomUtil.randomNumbers(6))));
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/sms/SMSHistory.java
New file
@@ -0,0 +1,29 @@
package com.nuvole.util.sms;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
/**
 * çŸ­ä¿¡å‘送记录
 *
 * @Author: lc
 * @Date: 2019/6/1 14:20
 */
@Data
public class SMSHistory {
    @ApiModelProperty(value = "手机号")
    private String mobile;
    @ApiModelProperty(value = "最后发送时间")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date lastTime;
    @ApiModelProperty(value = "次数")
    private Integer num;
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/sms/SMSTemplate.java
New file
@@ -0,0 +1,84 @@
package com.nuvole.util.sms;
/**
 * çŸ­ä¿¡æ¨¡æ¿
 *
 * @Author: lc
 * @Date: 2019/6/1 14:20
 */
public class SMSTemplate {
    /**
     * çŸ­ä¿¡éªŒè¯ç è®°å½•标识
     */
    public static final String SMS_MOILE_HISTORY_K = "SMS_MOILE_HISTORY_K:";
    /**
     * éªŒè¯ç è®°å½•有效期(1天)
     */
    public static final Long SMS_MOILE_HISTORY_TIME = Long.valueOf(1);
    /**
     * éªŒè¯ç ä¸€å°æ—¶å¯å‘送次数(次)
     */
    public static final int SMS_SEND_NUM_HOUR = 5;
    /**
     * éªŒè¯ç ä¸€å¤©å¯å‘送次数(次)
     */
    public static final int SMS_SEND_NUM_DAY = 10;
    /**
     * éªŒè¯ç æœ‰æ•ˆæœŸï¼ˆåˆ†é’Ÿï¼‰
     */
    public static final int CODE_VALIDITY_TIME = 5;
    /**
     * çŸ­ä¿¡éªŒè¯ç -商户重置密码-标识
     */
    public static final String SHOP_RESET_MIX_PD_CODE = "SHOP_RESET_MIX_PD_CODE";
    /**
     * çŸ­ä¿¡éªŒè¯ç -微信端修改手机号-标识
     */
    public static final String WECHAT_SET_MOBILE = "WECHAT_SET_MOBILE";
    /**
     * çŸ­ä¿¡éªŒè¯ç -H5公众号端支付时,注册并登陆 æ ‡è¯†
     */
    public static final String WECHAT_H5PAY_MOBILE = "WECHAT_H5PAY_MOBILE";
    /**
     * çŸ­ä¿¡éªŒè¯ç -H5版小程序登录,注册并登陆 æ ‡è¯†
     */
    public static final String H5_MIN_MOBILE = "H5_MIN_MOBILE";
    /**
     * çŸ­ä¿¡éªŒè¯ç -客户经理app重置密码-标识
     */
    public static final String MANAGER_RESET_MIX_PD_CODE = "MANAGER_RESET_MIX_PD_CODE";
    /**
     * çŸ­ä¿¡æ¨¡æ¿1
     */
//    private static String SEND_MSG = "【易邮铺】您的验证码是#code#。如非本人操作,请忽略本短信";
    private static String SEND_MSG = "【金明源】验证码:#code#(30分钟内有效)。请尽快完成验证。";
    //领取保险短信验证五分钟有效标识
    public static final String INSURANCE_SMS_MOBILE = "INSURANCE_SMS_MOBILE";
    //领保短信一分钟有效标识
    public static final String INSURANCE_SMS_MOBILE_REPLACE = "INSURANCE_SMS_MOBILE_REPLACE";
    /**
     * èŽ·å–çŸ­ä¿¡å†…å®¹1
     *
     * @Author: lc
     * @Date: 2019/6/1 14:23
     */
    public static String getVaildCodeMsg(String code) {
        String msg = SEND_MSG;
        return msg.replaceAll("#code#", code);
    }
}
ecosphere/ecosphere-common/src/main/java/com/nuvole/util/sms/YpSMSUtil.java
New file
@@ -0,0 +1,63 @@
package com.nuvole.util.sms;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.nuvole.common.domain.emnu.SMSResultEmnu;
import com.nuvole.common.domain.result.SMSResult;
import java.util.HashMap;
import java.util.Map;
/**
 * çŸ­ä¿¡ï¼ˆäº‘片)
 *
 * @Author: lc
 * @Date: 2019/6/1 11:09
 */
public class YpSMSUtil {
    private static String YP_SMS_K = "faf531146ca1e38abacd3862fb3fc32b";
    private static String YP_SMS_URL = "https://sms.yunpian.com/v2/sms/single_send.json";
    /**
     * å‘送短信
     *
     * @param mobile  æ‰‹æœºå·ç å­—符串 å¤šä¸ªå·ç ä»¥é€—号分割
     * @param message çŸ­ä¿¡å†…容
     * @Author: lc
     * @Date: 2019/6/1 11:27
     */
    public static SMSResult sendSMS(String mobile, String message) {
        if (StrUtil.isEmpty(mobile)) {
            return new SMSResult(SMSResultEmnu.ERROR, "手机号不能为空!");
        }
        if (StrUtil.isEmpty(message)) {
            return new SMSResult(SMSResultEmnu.ERROR, "短信内容不能为空!");
        }
        try {
            Map<String, Object> param = new HashMap<>();
            param.put("apikey", YP_SMS_K);
            param.put("mobile", mobile);
            param.put("text", message);
            String msg = HttpUtil.post(YP_SMS_URL, param);
            JSONObject jsonObject = JSONObject.parseObject(msg);
            if (!"0".equals(jsonObject.getString("code"))) {
                return new SMSResult(SMSResultEmnu.ERROR, jsonObject.getString("msg"));
            }
            return new SMSResult(SMSResultEmnu.OK);
        } catch (Exception e) {
            e.printStackTrace();
            return new SMSResult(SMSResultEmnu.ERROR, "发送异常!");
        }
    }
    public static void main(String[] args) {
        System.out.println(sendSMS("17803846500", SMSTemplate.getVaildCodeMsg(RandomUtil.randomNumbers(6))));
    }
}
ecosphere/ecosphere-common/src/main/resources/antisamy.xml
New file
@@ -0,0 +1,2789 @@
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!--
W3C rules retrieved from:
http://www.w3.org/TR/html401/struct/global.html
-->
<anti-samy-rules xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="antisamy.xsd">
    <directives>
        <directive name="omitXmlDeclaration" value="true"/>
        <directive name="omitDoctypeDeclaration" value="true"/>
        <directive name="maxInputSize" value="200000"/>
        <directive name="useXHTML" value="true"/>
        <directive name="formatOutput" value="true"/>
        <directive name="nofollowAnchors" value="true" />
        <directive name="validateParamAsEmbed" value="true" />
        <!--
        remember, this won't work for relative URIs - AntiSamy doesn't
        know anything about the URL or your web structure
        -->
        <directive name="embedStyleSheets" value="false"/>
        <directive name="connectionTimeout" value="5000"/>
        <directive name="maxStyleSheetImports" value="3"/>
        <!-- Allows the use of dynamic attributes (i.e. HTML5 "data-") -->
        <directive name="allowDynamicAttributes" value="true" />
    </directives>
    <common-regexps>
        <!--
        From W3C:
        This attribute assigns a class name or set of class names to an
        element. Any number of elements may be assigned the same class
        name or names. Multiple class names must be separated by white
        space characters.
        -->
        <!-- The 16 colors defined by the HTML Spec (also used by the CSS Spec) -->
        <regexp name="colorName" value="(aqua|black|blue|fuchsia|gray|grey|green|lime|maroon|navy|olive|purple|red|silver|teal|white|yellow)"/>
        <!-- HTML/CSS Spec allows 3 or 6 digit hex to specify color -->
        <regexp name="colorCode" value="(#([0-9a-fA-F]{6}|[0-9a-fA-F]{3}))"/>
        <regexp name="anything" value=".*"/>
        <regexp name="numberOrPercent" value="(\d)+(%{0,1})"/>
        <regexp name="paragraph" value="([\p{L}\p{N},'\.\s\-_\(\)\?]|&amp;[0-9]{2};)*"/>
        <regexp name="htmlId" value="[a-zA-Z0-9\:\-_\.]+"/>
        <regexp name="htmlTitle" value="[\p{L}\p{N}\s\-_',:\[\]!\./\\\(\)&amp;]*"/> <!-- force non-empty with a '+' at the end instead of '*' -->
        <regexp name="htmlClass" value="[a-zA-Z0-9\s,\-_]+"/>
        <regexp name="onsiteURL" value="^(?![\p{L}\p{N}\\\.\#@\$%\+&amp;;\-_~,\?=/!]*(&amp;colon))[\p{L}\p{N}\\\.\#@\$%\+&amp;;\-_~,\?=/!]*"/>
        <regexp name="anchoredURL" value="#(\w)+"/>
        <regexp name="offsiteURL" value="(\s)*((ht|f)tp(s?)://|mailto:)[\p{L}\p{N}]+[\p{L}\p{N}\p{Zs}\.\#@\$%\+&amp;;:\-_~,\?=/!\(\)]*(\s)*"/>
        <regexp name="boolean" value="(true|false)"/>
        <regexp name="singlePrintable" value="[a-zA-Z0-9]{1}"/> <!-- \w allows the '_' character -->
        <!-- This is for elements (ex: elemName { ... }) -->
        <regexp name="cssElementSelector" value="[a-zA-Z0-9\-_]+|\*"/>
        <!--  This is to list out any element names that are *not* valid -->
        <regexp name="cssElementExclusion" value=""/>
        <!--  This if for classes (ex: .className { ... }) -->
        <regexp name="cssClassSelector" value="\.[a-zA-Z0-9\-_]+"/>
        <!--  This is to list out any class names that are *not* valid -->
        <regexp name="cssClassExclusion" value=""/>
        <!--  This is for ID selectors (ex: #myId { ... } -->
        <regexp name="cssIDSelector" value="#[a-zA-Z0-9\-_]+"/>
        <!--  This is to list out any IDs that are *not* valid - FIXME: What should the default be to avoid div hijacking? *? -->
        <regexp name="cssIDExclusion" value=""/>
        <!--  This is for pseudo-element selector (ex. foo:pseudo-element { ... } -->
        <regexp name="cssPseudoElementSelector" value=":[a-zA-Z0-9\-_]+"/>
        <!--  This is to list out any psuedo-element names that are *not* valid -->
        <regexp name="cssPsuedoElementExclusion" value=""/>
        <!--  This is for attribute selectors (ex. foo[attr=value] { ... } -->
        <regexp name="cssAttributeSelector" value="\[[a-zA-Z0-9\-_]+((=|~=|\|=){1}[a-zA-Z0-9\-_]+){1}\]"/>
        <!--  This is to list out any attribute names that are *not* valid -->
        <regexp name="cssAttributeExclusion" value=""/>
        <!--  This is for resources referenced from CSS (such as background images and other imported stylesheets) -->
        <regexp name="cssOnsiteUri" value="url\(([\p{L}\p{N}\\/\.\?=\#&amp;;\-_~]+|\#(\w)+)\)"/>
        <regexp name="cssOffsiteUri" value="url\((\s)*((ht|f)tp(s?)://)[\p{L}\p{N}]+[~\p{L}\p{N}\p{Zs}\-_\.@#$%&amp;;:,\?=/\+!]*(\s)*\)"/>
        <!--  This if for CSS Identifiers -->
        <regexp name="cssIdentifier" value="[a-zA-Z0-9\-_]+"/>
        <!--  This is for comments within CSS (ex. /* comment */) -->
        <regexp name="cssCommentText" value="[\p{L}\p{N}\-_,\/\\\.\s\(\)!\?\=\$#%\^&amp;:&quot;']+"/>
        <regexp name="integer" value="(-|\+)?[0-9]+"/>
        <regexp name="positiveInteger" value="(\+)?[0-9]+"/>
        <regexp name="number" value="(-|\+)?([0-9]+(\.[0-9]+)?)"/>
        <regexp name="angle" value="(-|\+)?([0-9]+(\.[0-9]+)?)(deg|grads|rad)"/>
        <regexp name="time" value="([0-9]+(\.[0-9]+)?)(ms|s)"/>
        <regexp name="frequency" value="([0-9]+(\.[0-9]+)?)(hz|khz)"/>
        <regexp name="length" value="((-|\+)?0|(-|\+)?([0-9]+(\.[0-9]+)?)(em|ex|px|in|cm|mm|pt|pc))"/>
        <regexp name="positiveLength" value="((\+)?0|(\+)?([0-9]+(\.[0-9]+)?)(em|ex|px|in|cm|mm|pt|pc))"/>
        <regexp name="percentage" value="(-|\+)?([0-9]+(\.[0-9]+)?)%"/>
        <regexp name="positivePercentage" value="(\+)?([0-9]+(\.[0-9]+)?)%"/>
        <regexp name="absolute-size" value="(xx-small|x-small|small|medium|large|x-large|xx-large)"/>
        <regexp name="relative-size" value="(larger|smaller)"/>
        <!-- Used for CSS Color specifications (complex regexp expresses integer values of 0-255) -->
        <regexp name="rgbCode" value="rgb\(([1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5]),([1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5]),([1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5])\)"/>
        <!-- CSS2 Allowed System Color Values -->
        <regexp name="systemColor" value="(activeborder|activecaption|appworkspace|background|buttonface|buttonhighlight|buttonshadow|buttontext|captiontext|graytext|highlight|highlighttext|inactiveborder|inactivecaption|inactivecaptiontext|infobackground|infotext|menu|menutext|scrollbar|threeddarkshadow|threedface|threedhighlight|threedlightshadow|threedshadow|window|windowframe|windowtext)"/>
        <!-- This is where we specify what Flash src to allow -->
        <regexp name="flashSites" value="http://(download\.macromedia\.com/pub|www\.macromedia\.com/(go|shockwave)|c\.brightcove\.com/services|gamevideos\.1up\.com/swf|www\.youtube\.com/v|vimeo\.com|www\.gametrailers\.com|videomedia\.ign\.com/ev|image\.com\.com/gamespot|www\.hulu\.com/embed|embed\.break\.com|player\.ordienetworks\.com/flash|www\.adultswim\.com/video/vplayer|www\.dailymotion\.com/swf|www\.ustream\.tv/flash/video|cdn-i\.dmdentertainment\.com|media\.mtvnservices\.com|www\.justin\.tv/widgets|www\.viddler\.com/(player|simple_on_site)|static\.twitter\.com/flash|www\.gamepro\.com/bin|www\.divshare\.com/flash|www\.facebook\.com/v)/.*"/>
    </common-regexps>
    <!--
    Tag.name = a, b, div, body, etc.
    Tag.action = filter: remove tags, but keep content, validate: keep content as long as it passes rules, remove: remove tag and contents
    Attribute.name = id, class, href, align, width, etc.
    Attribute.onInvalid = what to do when the attribute is invalid, e.g., remove the tag (removeTag), remove the attribute (removeAttribute), filter the tag (filterTag)
    Attribute.description = What rules in English you want to tell the users they can have for this attribute. Include helpful things so they'll be able to tune their HTML
     -->
    <!--
    Some attributes are common to all (or most) HTML tags. There aren't many that qualify for this. You have to make sure there's no
    collisions between any of these attribute names with attribute names of other tags that are for different purposes.
    -->
    <common-attributes>
        <!-- Common to all HTML tags  -->
        <attribute name="id" description="The 'id' of any HTML attribute should not contain anything besides letters and numbers">
            <regexp-list>
                <regexp name="htmlId"/>
            </regexp-list>
        </attribute>
        <attribute name="classid">
            <regexp-list>
                <regexp name="anything" />
            </regexp-list>
        </attribute>
        <attribute name="codebase">
            <regexp-list>
                <regexp name="flashSites" />
            </regexp-list>
        </attribute>
        <attribute name="class" description="The 'class' of any HTML attribute is usually a single word, but it can also be a list of class names separated by spaces">
            <regexp-list>
                <regexp name="htmlClass"/>
            </regexp-list>
        </attribute>
        <attribute name="lang" description="The 'lang' attribute tells the browser what language the element's attribute values and content are written in">
             <regexp-list>
                 <regexp value="[a-zA-Z]{2,20}"/>
             </regexp-list>
         </attribute>
         <attribute name="title" description="The 'title' attribute provides text that shows up in a 'tooltip' when a user hovers their mouse over the element">
             <regexp-list>
                 <regexp name="htmlTitle"/>
             </regexp-list>
         </attribute>
         <attribute name="alt" description="The 'alt' attribute provides alternative text to users when its visual representation is not available">
             <regexp-list>
                 <regexp name="paragraph"/>
             </regexp-list>
         </attribute>
        <attribute name="data-" description="Allows the HTML5 'data-' attribute to be added to elements">
            <regexp-list>
                <regexp name="anything"/>
            </regexp-list>
        </attribute>
         <!-- the "style" attribute will be validated by an inline stylesheet scanner, so no need to define anything here - i hate having to special case this but no other choice -->
         <attribute name="style" description="The 'style' attribute provides the ability for users to change many attributes of the tag's contents using a strict syntax"/>
         <attribute name="media">
             <regexp-list>
                 <regexp value="[a-zA-Z0-9,\-\s]+"/>
             </regexp-list>
             <literal-list>
                 <literal value="screen"/>
                 <literal value="tty"/>
                 <literal value="tv"/>
                 <literal value="projection"/>
                 <literal value="handheld"/>
                 <literal value="print"/>
                 <literal value="braille"/>
                 <literal value="aural"/>
                 <literal value="all"/>
             </literal-list>
         </attribute>
         <!-- Anchor related -->
         <!--  onInvalid="filterTag" has been removed as per suggestion at OWASP SJ 2007 - just "name" is valid -->
        <attribute name="href">
            <regexp-list>
                <regexp name="onsiteURL"/>
                <regexp name="anchoredURL"/>
                <regexp name="offsiteURL"/>
            </regexp-list>
        </attribute>
        <attribute name="name">
             <regexp-list>
                 <regexp value="[a-zA-Z0-9-\_\$]+"/>
                 <!--
                 have to allow the $ for .NET controls - although,
                 will users be supplying input that has server-generated
                 .NET control names? methinks not, but i want to pass my
                 test cases
                 -->
             </regexp-list>
         </attribute>
        <attribute name="shape" description="The 'shape' attribute defines the shape of the selectable area">
            <literal-list>
                <literal value="default"/>
                <literal value="rect"/>
                <literal value="circle"/>
                <literal value="poly"/>
            </literal-list>
        </attribute>
        <!--  Table attributes  -->
        <attribute name="border">
            <regexp-list>
                <regexp name="number"/>
            </regexp-list>
        </attribute>
        <attribute name="cellpadding">
            <regexp-list>
                <regexp name="number"/>
            </regexp-list>
        </attribute>
        <attribute name="cellspacing">
            <regexp-list>
                <regexp name="number"/>
            </regexp-list>
        </attribute>
        <attribute name="colspan">
            <regexp-list>
                <regexp name="number"/>
            </regexp-list>
        </attribute>
        <attribute name="rowspan">
            <regexp-list>
                <regexp name="number"/>
            </regexp-list>
        </attribute>
        <attribute name="background">
            <regexp-list>
                <regexp name="onsiteURL"/>
            </regexp-list>
        </attribute>
        <attribute name="bgcolor">
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
            </regexp-list>
        </attribute>
         <attribute name="abbr">
            <regexp-list>
                 <regexp name="paragraph"/>
             </regexp-list>
         </attribute>
         <attribute name="headers" description="The 'headers' attribute is a space-separated list of cell IDs">
             <regexp-list>
                 <regexp value="[a-zA-Z0-9\s*]*"/>
             </regexp-list>
         </attribute>
         <attribute name="charoff">
             <regexp-list>
                 <regexp value="numberOrPercent"/>
             </regexp-list>
         </attribute>
         <attribute name="char">
            <regexp-list>
                <regexp value=".{0,1}"/>
            </regexp-list>
         </attribute>
        <attribute name="axis" description="The 'headers' attribute is a comma-separated list of related header cells">
             <regexp-list>
                 <regexp value="[a-zA-Z0-9\s*,]*"/>
             </regexp-list>
        </attribute>
        <attribute name="nowrap" description="The 'nowrap' attribute tells the browser not to wrap text that goes over one line">
            <regexp-list>
                <regexp name="anything"/>
                <!-- <regexp value="(nowrap){0,1}"/>  -->
            </regexp-list>
        </attribute>
        <!--  Common positioning attributes  -->
        <attribute name="width">
            <regexp-list>
                <regexp name="numberOrPercent"/>
            </regexp-list>
        </attribute>
        <attribute name="height">
            <regexp-list>
                <regexp name="numberOrPercent"/>
            </regexp-list>
        </attribute>
        <attribute name="align" description="The 'align' attribute of an HTML element is a direction word, like 'left', 'right' or 'center'">
            <literal-list>
                <literal value="center"/>
                <literal value="middle"/>
                <literal value="left"/>
                <literal value="right"/>
                <literal value="justify"/>
                <literal value="char"/>
            </literal-list>
        </attribute>
        <attribute name="valign" description="The 'valign' attribute of an HTML attribute is a direction word, like 'baseline','bottom','middle' or 'top'">
            <literal-list>
                <literal value="baseline"/>
                <literal value="bottom"/>
                <literal value="middle"/>
                <literal value="top"/>
            </literal-list>
        </attribute>
        <!-- Intrinsic JavaScript Events -->
        <attribute name="onFocus" description="The 'onFocus' event is executed when the control associated with the tag gains focus">
            <literal-list>
                <literal value="javascript:void(0)"/>
                <literal value="javascript:history.go(-1)"/>
            </literal-list>
        </attribute>
        <attribute name="onBlur" description="The 'onBlur' event is executed when the control associated with the tag loses focus">
            <literal-list>
                <literal value="javascript:void(0)"/>
                <literal value="javascript:history.go(-1)"/>
            </literal-list>
        </attribute>
         <attribute name="onClick" description="The 'onClick' event is executed when the control associated with the tag is clicked">
            <literal-list>
                <literal value="javascript:void(0)"/>
                <literal value="javascript:history.go(-1)"/>
            </literal-list>
         </attribute>
         <attribute name="onDblClick" description="The 'onDblClick' event is executed when the control associated with the tag is clicked twice immediately">
            <literal-list>
                <literal value="javascript:void(0)"/>
                <literal value="javascript:history.go(-1)"/>
            </literal-list>
         </attribute>
          <attribute name="onMouseDown" description="The 'onMouseDown' event is executed when the control associated with the tag is clicked but not yet released">
            <literal-list>
                <literal value="javascript:void(0)"/>
                <literal value="javascript:history.go(-1)"/>
            </literal-list>
         </attribute>
         <attribute name="onMouseUp" description="The 'onMouseUp' event is executed when the control associated with the tag is clicked after the button is released">
            <literal-list>
                <literal value="javascript:void(0)"/>
                <literal value="javascript:history.go(-1)"/>
            </literal-list>
         </attribute>
          <attribute name="onMouseOver" description="The 'onMouseOver' event is executed when the user's mouse hovers over the control associated with the tag">
            <literal-list>
                <literal value="javascript:void(0)"/>
                <literal value="javascript:history.go(-1)"/>
            </literal-list>
         </attribute>
         <attribute name="scope" description="The 'scope' attribute defines what's covered by the header cells">
             <literal-list>
                 <literal value="row"/>
                 <literal value="col"/>
                 <literal value="rowgroup"/>
                 <literal value="colgroup"/>
             </literal-list>
         </attribute>
         <!-- If you want users to be able to mess with tabindex, uncomment this -->
         <!--
         <attribute name="tabindex" description="...">
             <regexp-list>
                 <regexp name="number"/>
             </regexp-list>
         </attribute>
          -->
         <!-- Input/form related common attributes -->
         <attribute name="disabled">
             <regexp-list>
                 <regexp name="anything"/>
             </regexp-list>
         </attribute>
         <attribute name="readonly">
             <regexp-list>
                 <regexp name="anything"/>
             </regexp-list>
         </attribute>
         <attribute name="accesskey">
             <regexp-list>
                 <regexp name="anything"/>
             </regexp-list>
         </attribute>
         <attribute name="size">
             <regexp-list>
                 <regexp name="number"/>
             </regexp-list>
         </attribute>
        <attribute name="autocomplete">
            <literal-list>
                <literal value="on"/>
                <literal value="off"/>
            </literal-list>
        </attribute>
         <attribute name="rows">
             <regexp-list>
                 <regexp name="number"/>
             </regexp-list>
         </attribute>
         <attribute name="cols">
             <regexp-list>
                 <regexp name="number"/>
             </regexp-list>
         </attribute>
    </common-attributes>
    <!--
    This requires normal updates as browsers continue to diverge from the W3C and each other. As long as the browser wars continue
    this is going to continue. I'm not sure war is the right word for what's going on. Doesn't somebody have to win a war after
    a while? Even wars of attrition, surely?
     -->
    <global-tag-attributes>
        <!-- Not valid in base, head, html, meta, param, script, style, and title elements. -->
        <attribute name="id"/>
        <attribute name="style"/>
        <attribute name="title"/>
        <attribute name="class"/>
        <!-- Not valid in base, br, frame, frameset, hr, iframe, param, and script elements.  -->
        <attribute name="lang"/>
    </global-tag-attributes>
    <!-- Declare "dynamic" tag attributes here. The directive "allowDynamicAttributes" must be set to true -->
    <dynamic-tag-attributes>
        <attribute name="data-"/> <!-- HTML5 "data-" tag -->
    </dynamic-tag-attributes>
    <tags-to-encode>
        <tag>g</tag>
        <tag>grin</tag>
    </tags-to-encode>
    <tag-rules>
        <!-- You can mess with this stuff if you know what you're doing -->
        <tag name="html" action="validate"/>
        <tag name="body" action="validate">
            <attribute name="bgcolor"/>
        </tag>
        <tag name="meta" action="filter"/>
        <tag name="head" action="validate"/>
        <!-- since we're validating the style sheets this is safe to have - switch to "truncate" if the user's html will appear in the html body -->
        <tag name="title" action="truncate"/>
        <!-- Tags related to JavaScript -->
        <tag name="script" action="remove"/>
        <tag name="noscript" action="validate"/> <!-- although no javascript can fire inside a noscript tag, css is still a viable attack vector -->
        <!-- Frame & related tags -->
        <tag name="iframe" action="remove"/>
        <tag name="frameset" action="remove"/>
        <tag name="frame" action="remove"/>
        <!-- Form related tags -->
        <tag name="label" action="validate">
            <attribute name="for">
                <regexp-list>
                    <regexp name="htmlId"/>
                </regexp-list>
            </attribute>
        </tag>
        <!--
            If you wish to enable any of the form related tags, change the tag's action below from "filter" or "remove" to "validate". The attributes have been
            hardened so this is safe to do, if it's something you want to allow. Beware the <><ing possibilities!
         -->
        <tag name="form" action="validate">
            <attribute name="action">
                <regexp-list>
                    <regexp name="onsiteURL"/>
                    <regexp name="offsiteURL"/>
                </regexp-list>
            </attribute>
            <attribute name="name"/>
            <attribute name="autocomplete"/>
            <attribute name="method">
                <literal-list>
                    <literal value="post"/>
                    <literal value="get"/>
                </literal-list>
            </attribute>
        </tag>
        <tag name="button" action="validate">
            <attribute name="name"/>
            <attribute name="value">
                <regexp-list>
                    <regexp name="anything"/>
                </regexp-list>
            </attribute>
            <attribute name="disabled"/>
            <attribute name="accesskey"/>
            <attribute name="type">
                <literal-list>
                    <literal value="submit"/>
                    <literal value="reset"/>
                    <literal value="button"/>
                </literal-list>
            </attribute>
        </tag>
        <tag name="input" action="validate">
            <attribute name="name"/>
            <attribute name="size"/>
            <attribute name="maxlength">
                <regexp-list>
                    <regexp name="number"/>
                </regexp-list>
            </attribute>
            <attribute name="autocomplete"/>
            <attribute name="checked">
                <regexp-list>
                    <regexp name="anything"/>
                </regexp-list>
            </attribute>
            <attribute name="alt"/>
            <attribute name="src">
                <regexp-list>
                    <regexp name="onsiteURL"/>
                    <regexp name="offsiteURL"/>
                </regexp-list>
            </attribute>
            <attribute name="usemap">
                <regexp-list>
                    <regexp name="onsiteURL"/>
                    <regexp name="anchoredURL"/>
                </regexp-list>
            </attribute>
            <attribute name="type">
                <literal-list>
                    <literal value="hidden"/>
                    <literal value="text"/>
                    <literal value="password"/>
                    <literal value="radio"/>
                    <literal value="checkbox"/>
                    <literal value="submit"/>
                    <literal value="button"/>
                    <literal value="image"/>
                    <literal value="file"/>
                    <literal value="reset"/>
                </literal-list>
            </attribute>
            <attribute name="value">
                <regexp-list>
                    <regexp name="anything"/>
                </regexp-list>
            </attribute>
            <attribute name="disabled"/>
            <attribute name="readonly"/>
            <attribute name="accesskey"/>
            <attribute name="border"/>
        </tag>
        <tag name="select" action="validate">
            <attribute name="name"/>
            <attribute name="disabled"/>
            <attribute name="multiple">
                <regexp-list>
                    <regexp name="anything"/>
                </regexp-list>
            </attribute>
            <attribute name="size"/>
        </tag>
        <tag name="option" action="validate">
            <attribute name="disabled"/>
            <attribute name="value">
                <regexp-list>
                    <regexp name="anything"/>
                </regexp-list>
            </attribute>
            <attribute name="label">
                <regexp-list>
                    <regexp name="anything"/>
                </regexp-list>
            </attribute>
            <attribute name="selected">
                <regexp-list>
                    <regexp name="anything"/>
                </regexp-list>
            </attribute>
        </tag>
        <tag name="textarea" action="validate">
            <attribute name="rows"/>
            <attribute name="cols"/>
            <attribute name="name"/>
            <attribute name="disabled"/>
            <attribute name="readonly"/>
            <attribute name="accesskey"/>
        </tag>
        <!-- All formatting tags -->
        <tag name="h1" action="validate"/>
        <tag name="h2" action="validate"/>
        <tag name="h3" action="validate"/>
        <tag name="h4" action="validate"/>
        <tag name="h5" action="validate"/>
        <tag name="h6" action="validate"/>
        <tag name="p" action="validate">
            <attribute name="align"/>
        </tag>
        <tag name="i" action="validate"/>
        <tag name="b" action="validate"/>
        <tag name="u" action="validate"/>
        <tag name="strong" action="validate"/>
        <tag name="em" action="validate"/>
        <tag name="small" action="validate"/>
        <tag name="big" action="validate"/>
        <tag name="pre" action="validate"/>
        <tag name="code" action="validate"/>
        <tag name="cite" action="validate"/>
        <tag name="samp" action="validate"/>
        <tag name="sub" action="validate"/>
        <tag name="sup" action="validate"/>
        <tag name="strike" action="validate"/>
        <tag name="center" action="validate"/>
        <tag name="blockquote" action="validate"/>
        <tag name="hr" action="validate"/>
        <tag name="br" action="validate"/>
        <tag name="col" action="validate"/>
        <tag name="font" action="validate">
            <attribute name="color">
                <regexp-list>
                    <regexp name="colorName"/>
                    <regexp name="colorCode"/>
                </regexp-list>
            </attribute>
            <attribute name="face">
                <regexp-list>
                    <regexp value="[\w;, \-]+"/>
                </regexp-list>
            </attribute>
            <attribute name="size">
                <regexp-list>
                    <regexp value="(\+|-){0,1}(\d)+"/>
                </regexp-list>
            </attribute>
        </tag>
        <!-- Anchor and anchor related tags -->
        <tag name="a" action="validate">
            <!--  onInvalid="filterTag" has been removed as per suggestion at OWASP SJ 2007 - just "name" is valid -->
            <attribute name="href"/>
            <attribute name="onFocus"/>
            <attribute name="onBlur"/>
            <attribute name="nohref">
                <regexp-list>
                    <regexp name="anything"/>
                </regexp-list>
            </attribute>
            <attribute name="rel">
                <literal-list>
                    <literal value="nofollow"/>
                </literal-list>
            </attribute>
            <attribute name="name"/>
        </tag>
        <tag name="map" action="validate"/>
        <!-- base tag removed per demo - this could be enabled with literal-list values you allow -->
        <!--
        <tag name="base" action="validate">
            <attribute name="href"/>
        </tag>
        -->
        <!-- Stylesheet Tags -->
        <tag name="style" action="validate">
            <attribute name="type">
                <literal-list>
                    <literal value="text/css"/>
                </literal-list>
            </attribute>
            <attribute name="media"/>
        </tag>
        <tag name="span" action="validate"/>
        <tag name="div" action="validate">
            <attribute name="align"/>
        </tag>
        <!-- Image & image related tags -->
        <tag name="img" action="validate">
            <attribute name="src" onInvalid="removeTag">
                <regexp-list>
                    <regexp name="onsiteURL"/>
                    <regexp name="offsiteURL"/>
                </regexp-list>
            </attribute>
            <attribute name="name"/>
            <attribute name="alt"/>
            <attribute name="height"/>
            <attribute name="width"/>
            <attribute name="border"/>
            <attribute name="align"/>
            <attribute name="hspace">
                <regexp-list>
                    <regexp name="number"/>
                </regexp-list>
            </attribute>
            <attribute name="vspace">
                <regexp-list>
                    <regexp name="number"/>
                </regexp-list>
            </attribute>
        </tag>
        <!-- no way to do this safely without hooking up the same code to @import to embed the remote stylesheet (malicious user could change offsite resource to be malicious after validation -->
        <!-- <attribute name="href" onInvalid="removeTag"/>  -->
        <tag name="link" action="validate">
            <!-- <attribute name="href" onInvalid="removeTag"/>  -->
            <attribute name="media"/>
            <attribute name="type" onInvalid="removeTag">
                <literal-list>
                    <literal value="text/css"/>
                    <literal value="application/rss+xml"/>
                    <literal value="image/x-icon"/>
                </literal-list>
            </attribute>
            <attribute name="rel">
                <literal-list>
                    <literal value="stylesheet"/>
                    <literal value="shortcut icon"/>
                    <literal value="search"/>
                    <literal value="copyright"/>
                    <literal value="top"/>
                    <literal value="alternate"/>
                </literal-list>
            </attribute>
        </tag>
        <!-- List tags -->
        <tag name="ul" action="validate"/>
        <tag name="ol" action="validate"/>
        <tag name="li" action="validate"/>
        <!-- Dictionary tags -->
        <tag name="dd" action="truncate"/>
        <tag name="dl" action="truncate"/>
        <tag name="dt" action="truncate"/>
        <!-- Table tags (tbody, thead, tfoot)-->
        <tag name="thead" action="validate">
            <attribute name="align"/>
            <attribute name="char"/>
            <attribute name="charoff"/>
            <attribute name="valign"/>
        </tag>
        <tag name="tbody" action="validate">
            <attribute name="align"/>
            <attribute name="char"/>
            <attribute name="charoff"/>
            <attribute name="valign"/>
        </tag>
        <tag name="tfoot" action="validate">
            <attribute name="align"/>
            <attribute name="char"/>
            <attribute name="charoff"/>
            <attribute name="valign"/>
        </tag>
        <tag name="table" action="validate">
            <attribute name="height"/>
            <attribute name="width"/>
            <attribute name="border"/>
            <attribute name="bgcolor"/>
            <attribute name="cellpadding"/>
            <attribute name="cellspacing"/>
            <attribute name="background"/>
            <attribute name="align"/>
            <attribute name="noresize">
                <literal-list>
                    <literal value="noresize"/>
                    <literal value=""/>
                </literal-list>
            </attribute>
        </tag>
        <tag name="td" action="validate">
            <attribute name="background"/>
            <attribute name="bgcolor"/>
            <attribute name="abbr"/>
            <attribute name="axis"/>
            <attribute name="headers"/>
            <attribute name="scope"/>
            <attribute name="nowrap"/>
            <attribute name="height"/>
            <attribute name="width"/>
            <attribute name="align"/>
            <attribute name="char"/>
            <attribute name="charoff"/>
            <attribute name="valign"/>
            <attribute name="colspan"/>
            <attribute name="rowspan"/>
        </tag>
        <tag name="th" action="validate">
            <attribute name="abbr"/>
            <attribute name="axis"/>
            <attribute name="headers"/>
            <attribute name="scope"/>
            <attribute name="nowrap"/>
            <attribute name="bgcolor"/>
            <attribute name="height"/>
            <attribute name="width"/>
            <attribute name="align"/>
            <attribute name="char"/>
            <attribute name="charoff"/>
            <attribute name="valign"/>
            <attribute name="colspan"/>
            <attribute name="rowspan"/>
        </tag>
        <tag name="tr" action="validate">
            <attribute name="height"/>
            <attribute name="width"/>
            <attribute name="align"/>
            <attribute name="valign"/>
            <attribute name="char"/>
            <attribute name="charoff"/>
            <attribute name="background"/>
        </tag>
        <tag name="colgroup" action="validate">
            <attribute name="span">
                <regexp-list>
                    <regexp name="number"/>
                </regexp-list>
            </attribute>
            <attribute name="width"/>
            <attribute name="align"/>
            <attribute name="char"/>
            <attribute name="charoff"/>
            <attribute name="valign"/>
        </tag>
        <tag name="col" action="validate">
            <attribute name="align"/>
            <attribute name="char"/>
            <attribute name="charoff"/>
            <attribute name="valign"/>
            <attribute name="span">
                <regexp-list>
                    <regexp name="number"/>
                </regexp-list>
            </attribute>
            <attribute name="width"/>
        </tag>
        <tag name="fieldset" action="validate"/>
        <tag name="legend" action="validate"/>
        <!-- tags for popular Flash embeds -->
        <tag name="object" action="validate">
            <attribute name="id" />
            <attribute name="classid" />
            <attribute name="codebase" />
            <attribute name="type" onInvalid="removeTag">
                <literal-list>
                    <literal value="application/x-shockwave-flash" />
                </literal-list>
            </attribute>
            <attribute name="data" onInvalid="removeTag">
                <regexp-list>
                    <regexp name="flashSites" />
                </regexp-list>
            </attribute>
            <attribute name="align" />
            <attribute name="height" />
            <attribute name="width" />
            <attribute name="alt" />
            <attribute name="bgcolor">
                <regexp-list>
                    <regexp name="colorCode" />
                </regexp-list>
            </attribute>
        </tag>
        <!-- with validateParamAsEmbed=true, this tag rule also covers <param> name/value pairs -->
        <tag name="embed" action="validate">
            <attribute name="src" onInvalid="removeTag">
                <regexp-list>
                    <regexp name="flashSites" />
                </regexp-list>
            </attribute>
            <attribute name="movie" onInvalid="removeTag">
                <regexp-list>
                    <regexp name="flashSites" />
                </regexp-list>
            </attribute>
            <attribute name="pluginspage">
                <regexp-list>
                    <regexp name="flashSites" />
                </regexp-list>
            </attribute>
            <attribute name="bgcolor">
                <regexp-list>
                    <regexp name="colorCode" />
                </regexp-list>
            </attribute>
            <attribute name="base">
                <literal-list>
                    <literal value="http://admin.brightcove.com" />
                </literal-list>
            </attribute>
            <attribute name="type">
                <literal-list>
                    <literal value="application/x-shockwave-flash" />
                </literal-list>
            </attribute>
            <attribute name="name">
                <regexp-list>
                    <regexp name="anything" />
                </regexp-list>
            </attribute>
            <attribute name="flashvars">
                <regexp-list>
                    <regexp name="anything" /><!-- we could put something complex in here, but this is prolly fine for now-->
                </regexp-list>
            </attribute>
            <attribute name="align" />
            <attribute name="height" />
            <attribute name="width" />
            <attribute name="allowfullscreen">
                <regexp-list>
                    <regexp name="boolean" />
                </regexp-list>
            </attribute>
            <attribute name="quality">
                <literal-list>
                    <literal value="high" />
                </literal-list>
            </attribute>
            <attribute name="allowscriptaccess">
                <literal-list>
                    <literal value="always" />
                    <literal value="samedomain" />
                </literal-list>
            </attribute>
            <attribute name="seamlesstabbing">
                <regexp-list>
                    <regexp name="boolean" />
                </regexp-list>
            </attribute>
            <attribute name="swliveconnect">
                <regexp-list>
                    <regexp name="boolean" />
                </regexp-list>
            </attribute>
            <attribute name="wmode">
                <literal-list>
                    <literal value="transparent" />
                    <literal value="window" />
                </literal-list>
            </attribute>
            <attribute name="allownetworking">
                <literal-list>
                    <literal value="all" />
                </literal-list>
            </attribute>
        </tag>
    </tag-rules>
    <!--  CSS validation processing rules  -->
    <css-rules>
        <property name="azimuth" description="This property is most likely to be implemented by mixing the same signal into different channels at differing volumes.">
            <literal-list>
                <literal value="left-side"/>
                <literal value="far-left"/>
                <literal value="left"/>
                <literal value="center-left"/>
                <literal value="center"/>
                <literal value="center-right"/>
                <literal value="right"/>
                <literal value="far-right"/>
                <literal value="right-side"/>
                <literal value="behind"/>
                <literal value="leftwards"/>
                <literal value="rightwards"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="angle"/>
            </regexp-list>
        </property>
        <property name="background" description="The 'background' property is a shorthand property for setting the individual background properties (i.e., 'background-color', 'background-image', 'background-repeat', 'background-attachment' and 'background-position') at the same place in the style sheet.">
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="background-color"/>
                <shorthand name="background-image"/>
                <shorthand name="background-repeat"/>
                <shorthand name="background-attachment"/>
                <shorthand name="background-position"/>
            </shorthand-list>
        </property>
        <property name="background-attachment" description="If a background image is specified, this property specifies whether it is fixed with regard to the viewport ('fixed') or scrolls along with the document ('scroll').">
            <literal-list>
                <literal value="scroll"/>
                <literal value="fixed"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="background-color" description="This property sets the background color of an element, either a &lt;color&gt; value or the keyword 'transparent', to make the underlying colors shine through.">
            <literal-list>
                <literal value="transparent"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
        </property>
        <property name="background-image" description="This property sets the background image of an element.">
            <literal-list>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="cssOffsiteUri"/>
                <regexp name="cssOnsiteUri"/>
            </regexp-list>
        </property>
        <property name="background-position" description="If a background image has been specified, this property specifies its initial position.">
            <literal-list>
                <literal value="top"/>
                <literal value="center"/>
                <literal value="bottom"/>
                <literal value="left"/>
                <literal value="center"/>
                <literal value="right"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="percentage"/>
                <regexp name="length"/>
            </regexp-list>
        </property>
        <property name="background-repeat" description="If a background image is specified, this property specifies whether the image is repeated (tiled), and how.">
            <literal-list>
                <literal value="repeat"/>
                <literal value="repeat-x"/>
                <literal value="repeat-y"/>
                <literal value="no-repeat"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <!-- Begin simple properties -->
        <property name="border-collapse" default="collapse" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="collapse"/>
                <literal value="separate"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="border-color" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="transparent"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
        </property>
        <property name="border-top-color" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
        </property>
        <property name="border-right-color" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
        </property>
        <property name="border-bottom-color" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
        </property>
        <property name="border-left-color" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
        </property>
        <property name="bottom" default="auto" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="caption-side" default="top" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="top"/>
                <literal value="bottom"/>
                <literal value="left"/>
                <literal value="right"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="clear" default="none" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="none"/>
                <literal value="left"/>
                <literal value="right"/>
                <literal value="both"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="color" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
        </property>
        <property name="cue-after" default="none" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="cssOffsiteUri"/>
                <regexp name="cssOnsiteUri"/>
            </regexp-list>
        </property>
        <property name="cue-before" default="none" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="cssOffsiteUri"/>
                <regexp name="cssOnsiteUri"/>
            </regexp-list>
        </property>
        <property name="direction" default="ltr" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="ltr"/>
                <literal value="rtl"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="display" default="inline" description="">
            <category-list>
                <category value="all"/>
            </category-list>
            <literal-list>
                <literal value="inline"/>
                <literal value="block"/>
                <literal value="list-item"/>
                <literal value="run-in"/>
                <literal value="compact"/>
                <literal value="marker"/>
                <literal value="table"/>
                <literal value="inline-table"/>
                <literal value="table-row-group"/>
                <literal value="table-header-group"/>
                <literal value="table-footer-group"/>
                <literal value="table-row"/>
                <literal value="table-column-group"/>
                <literal value="table-column"/>
                <literal value="table-cell"/>
                <literal value="table-caption"/>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="elevation" default="level" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="below"/>
                <literal value="level"/>
                <literal value="above"/>
                <literal value="higher"/>
                <literal value="lower"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="angle"/>
            </regexp-list>
        </property>
        <property name="empty-cells" default="show" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="show"/>
                <literal value="hide"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="float" default="none" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="left"/>
                <literal value="right"/>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="font-size" default="medium" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="absolute-size"/>
                <regexp name="relative-size"/>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="font-size-adjust" default="none" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="number"/>
            </regexp-list>
        </property>
        <property name="font-stretch" default="normal" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="normal"/>
                <literal value="wider"/>
                <literal value="narrower"/>
                <literal value="ultra-condensed"/>
                <literal value="extra-condensed"/>
                <literal value="condensed"/>
                <literal value="semi-condensed"/>
                <literal value="semi-expanded"/>
                <literal value="expanded"/>
                <literal value="extra-expanded"/>
                <literal value="ultra-expanded"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="font-style" default="normal" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="normal"/>
                <literal value="italic"/>
                <literal value="oblique"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="font-variant" default="normal" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="normal"/>
                <literal value="small-caps"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="font-weight" default="normal" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="normal"/>
                <literal value="bold"/>
                <literal value="bolder"/>
                <literal value="lighter"/>
                <literal value="100"/>
                <literal value="200"/>
                <literal value="300"/>
                <literal value="400"/>
                <literal value="500"/>
                <literal value="600"/>
                <literal value="700"/>
                <literal value="800"/>
                <literal value="900"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="height" default="auto" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="left" default="auto" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="letter-spacing" default="normal" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="normal"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
            </regexp-list>
        </property>
        <property name="line-height" default="normal" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="normal"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="number"/>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="list-style-image" default="none" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="cssOffsiteUri"/>
                <regexp name="cssOnsiteUri"/>
            </regexp-list>
        </property>
        <property name="list-style-position" default="outside" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inside"/>
                <literal value="outside"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="list-style-type" default="disc" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="disc"/>
                <literal value="circle"/>
                <literal value="square"/>
                <literal value="decimal"/>
                <literal value="decimal-leading-zero"/>
                <literal value="lower-roman"/>
                <literal value="upper-roman"/>
                <literal value="lower-greek"/>
                <literal value="lower-alpha"/>
                <literal value="lower-latin"/>
                <literal value="upper-alpha"/>
                <literal value="upper-latin"/>
                <literal value="hebrew"/>
                <literal value="armenian"/>
                <literal value="georgian"/>
                <literal value="cjk-ideographic"/>
                <literal value="hiragana"/>
                <literal value="katakana"/>
                <literal value="hiragana-iroha"/>
                <literal value="katakana-iroha"/>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="marker-offset" default="auto" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
            </regexp-list>
        </property>
        <property name="max-height" default="none" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="max-width" default="none" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="min-height" default="0" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="min-width" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="orphans" default="2" description="">
            <category-list>
                <category value="visual"/>
                <category value="paged"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="integer"/>
            </regexp-list>
        </property>
        <property name="outline-color" default="invert" description="">
            <category-list>
                <category value="visual"/>
                <category value="interactive"/>
            </category-list>
            <literal-list>
                <literal value="invert"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
        </property>
        <property name="overflow" default="visible" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="visible"/>
                <literal value="hidden"/>
                <literal value="scroll"/>
                <literal value="auto"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="page-break-after" default="auto" description="">
            <category-list>
                <category value="visual"/>
                <category value="paged"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="always"/>
                <literal value="avoid"/>
                <literal value="left"/>
                <literal value="right"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="page-break-before" default="auto" description="">
            <category-list>
                <category value="visual"/>
                <category value="paged"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="always"/>
                <literal value="avoid"/>
                <literal value="left"/>
                <literal value="right"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="page-break-inside" default="auto" description="">
            <category-list>
                <category value="visual"/>
                <category value="paged"/>
            </category-list>
            <literal-list>
                <literal value="avoid"/>
                <literal value="auto"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="pause-after" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="time"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="pause-before" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="time"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="pitch" default="medium" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="x-low"/>
                <literal value="low"/>
                <literal value="medium"/>
                <literal value="high"/>
                <literal value="x-high"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="frequency"/>
            </regexp-list>
        </property>
        <property name="pitch-range" default="50" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="number"/>
            </regexp-list>
        </property>
        <property name="position" default="static" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="static"/>
                <!-- possible to perform phishing attacks with the following -->
                <!--
                <literal value="relative"/>
                <literal value="absolute"/>
                <literal value="fixed"/>
                 -->
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="richness" default="50" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="number"/>
            </regexp-list>
        </property>
        <property name="right" default="auto" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="size" default="auto" description="">
            <category-list>
                <category value="visual"/>
                <category value="paged"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="portrait"/>
                <literal value="landscape"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
            </regexp-list>
        </property>
        <property name="speak" default="normal" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="normal"/>
                <literal value="none"/>
                <literal value="spell-out"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="speak-header" default="once" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="once"/>
                <literal value="always"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="speak-numeral" default="continuous" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="digits"/>
                <literal value="continuous"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="speak-punctuation" default="none" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="code"/>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="speech-rate" default="medium" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="x-slow"/>
                <literal value="slow"/>
                <literal value="medium"/>
                <literal value="fast"/>
                <literal value="x-fast"/>
                <literal value="faster"/>
                <literal value="slower"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="number"/>
            </regexp-list>
        </property>
        <property name="stress" default="50" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="number"/>
            </regexp-list>
        </property>
        <property name="table-layout" default="auto" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="fixed"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="text-indent" default="0" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="text-transform" default="none" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="capitalize"/>
                <literal value="uppercase"/>
                <literal value="lowercase"/>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="top" default="auto" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="unicode-bidi" default="normal" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="normal"/>
                <literal value="embed"/>
                <literal value="bidi-override"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="vertical-align" default="baseline" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="baseline"/>
                <literal value="sub"/>
                <literal value="super"/>
                <literal value="top"/>
                <literal value="text-top"/>
                <literal value="middle"/>
                <literal value="bottom"/>
                <literal value="text-bottom"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="percentage"/>
                <regexp name="length"/>
            </regexp-list>
        </property>
        <property name="visibility" default="inherit" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="visible"/>
                <literal value="hidden"/>
                <literal value="collapse"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="volume" default="medium" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="silent"/>
                <literal value="x-soft"/>
                <literal value="soft"/>
                <literal value="medium"/>
                <literal value="loud"/>
                <literal value="x-loud"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="number"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="white-space" default="normal" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="normal"/>
                <literal value="pre"/>
                <literal value="nowrap"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="widows" default="2" description="">
            <category-list>
                <category value="visual"/>
                <category value="paged"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="integer"/>
            </regexp-list>
        </property>
        <property name="width" default="auto" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="word-spacing" default="normal" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="normal"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
            </regexp-list>
        </property>
        <!-- end simple properties -->
        <!-- begin medium properties -->
        <property name="border-style" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
                <literal value="none"/>
                <literal value="hidden"/>
                <literal value="dotted"/>
                <literal value="dashed"/>
                <literal value="solid"/>
                <literal value="double"/>
                <literal value="groove"/>
                <literal value="ridge"/>
                <literal value="inset"/>
                <literal value="outset"/>
            </literal-list>
        </property>
        <property name="border-top-style" default="none" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="border-right-style" default="none" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="border-style"/>
            </shorthand-list>
        </property>
        <property name="border-bottom-style" default="none" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="border-style"/>
            </shorthand-list>
        </property>
        <property name="border-left-style" default="none" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="border-style"/>
            </shorthand-list>
        </property>
        <property name="border-top-width" default="medium" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="border-width"/>
            </shorthand-list>
        </property>
        <property name="border-right-width" default="medium" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="border-width"/>
            </shorthand-list>
        </property>
        <property name="border-bottom-width" default="medium" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="border-width"/>
            </shorthand-list>
        </property>
        <property name="border-left-width" default="medium" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="border-width"/>
            </shorthand-list>
        </property>
        <property name="border-width" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
                <literal value="thin"/>
                <literal value="medium"/>
                <literal value="thick"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
            </regexp-list>
        </property>
        <property name="margin" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
                <literal value="auto"/>
            </literal-list>
            <regexp-list>
                <regexp name="positiveLength"/>
                <regexp name="positivePercentage"/>
            </regexp-list>
        </property>
        <property name="margin-top" default="0" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="margin"/>
            </shorthand-list>
        </property>
        <property name="margin-right" default="0" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="margin"/>
            </shorthand-list>
        </property>
        <property name="margin-bottom" default="0" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="margin"/>
            </shorthand-list>
        </property>
        <property name="margin-left" default="0" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="margin"/>
            </shorthand-list>
        </property>
        <property name="outline-style" default="none" description="">
            <category-list>
                <category value="visual"/>
                <category value="interactive"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="border-style"/>
            </shorthand-list>
        </property>
        <property name="outline-width" default="medium" description="">
            <category-list>
                <category value="visual"/>
                <category value="interactive"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="border-width"/>
            </shorthand-list>
        </property>
        <property name="padding" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="padding-top" default="0" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="padding"/>
            </shorthand-list>
        </property>
        <property name="padding-right" default="0" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="padding"/>
            </shorthand-list>
        </property>
        <property name="padding-bottom" default="0" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="padding"/>
            </shorthand-list>
        </property>
        <property name="padding-left" default="0" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="padding"/>
            </shorthand-list>
        </property>
        <!-- end medium properties -->
        <!-- begin hard properties -->
        <property name="border" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
            <shorthand-list>
                <shorthand name="border-width"/>
                <shorthand name="border-style"/>
            </shorthand-list>
        </property>
        <property name="border-top" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
            <shorthand-list>
                <shorthand name="border-top-width"/>
                <shorthand name="border-style"/>
            </shorthand-list>
        </property>
        <property name="border-right" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
            <shorthand-list>
                <shorthand name="border-top-width"/>
                <shorthand name="border-style"/>
            </shorthand-list>
        </property>
        <property name="border-bottom" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
            <shorthand-list>
                <shorthand name="border-top-width"/>
                <shorthand name="border-style"/>
            </shorthand-list>
        </property>
        <property name="border-left" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
            <shorthand-list>
                <shorthand name="border-top-width"/>
                <shorthand name="border-style"/>
            </shorthand-list>
        </property>
        <property name="cue" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="cue-before"/>
                <shorthand name="cue-after"/>
            </shorthand-list>
        </property>
        <property name="list-style" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="list-style-type"/>
                <shorthand name="list-style-position"/>
                <shorthand name="list-style-image"/>
            </shorthand-list>
        </property>
        <property name="marks" default="none" description="">
            <category-list>
                <category value="visual"/>
                <category value="paged"/>
            </category-list>
            <literal-list>
                <literal value="crop"/>
                <literal value="cross"/>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="outline" description="">
            <category-list>
                <category value="visual"/>
                <category value="interactive"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="outline-color"/>
                <shorthand name="outline-style"/>
                <shorthand name="outline-width"/>
            </shorthand-list>
        </property>
        <property name="pause" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="time"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="text-decoration" default="none" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="none"/>
                <literal value="underline"/>
                <literal value="overline"/>
                <literal value="line-through"/>
                <literal value="blink"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <!-- end hard properties -->
        <!--  begin manual properties -->
        <property name="border-spacing" default="0" description="The lengths specify the distance that separates adjacent cell borders. If one length is specified, it gives both the horizontal and vertical spacing. If two are specified, the first gives the horizontal spacing and the second the vertical spacing. Lengths may not be negative.">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
            </regexp-list>
        </property>
        <property name="clip" default="auto" description="The 'clip' property applies to elements that have a 'overflow' property with a value other than 'visible'.">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
            </regexp-list>
        </property>
        <property name="counter-increment" default="none" description="The 'counter-increment' property accepts one or more names of counters (identifiers), each one optionally followed by an integer.">
            <category-list>
                <category value="all"/>
            </category-list>
            <literal-list>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="cssIdentifier"/>
                <regexp name="integer"/>
            </regexp-list>
        </property>
        <property name="clip" default="auto" description="The 'clip' property applies to elements that have a 'overflow' property with a value other than 'visible'.">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
            </regexp-list>
        </property>
        <property name="cursor" default="auto" description="This property specifies the type of cursor to be displayed for the pointing device.">
            <category-list>
                <category value="visual"/>
                <category value="interactive"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="inherit"/>
                <literal value="crosshair"/>
                <literal value="default"/>
                <literal value="pointer"/>
                <literal value="move"/>
                <literal value="e-resize"/>
                <literal value="ne-resize"/>
                <literal value="nw-resize"/>
                <literal value="n-resize"/>
                <literal value="se-resize"/>
                <literal value="sw-resize"/>
                <literal value="s-resize"/>
                <literal value="w-resize| text"/>
                <literal value="wait"/>
                <literal value="help"/>
            </literal-list>
            <regexp-list>
                <regexp name="cssOffsiteUri"/>
                <regexp name="cssOnsiteUri"/>
            </regexp-list>
        </property>
        <property name="text-shadow" default="none" description="This property accepts a comma-separated list of shadow effects to be applied to the text of the element.">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
                <regexp name="length"/>
            </regexp-list>
        </property>
        <property name="font" description="The 'font' property is, except as described below, a shorthand property for setting 'font-style', 'font-variant', 'font-weight', 'font-size', 'line-height', and 'font-family', at the same place in the style sheet.">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="/"/>
                <literal value="caption"/>
                <literal value="icon"/>
                <literal value="menu"/>
                <literal value="message-box"/>
                <literal value="small-caption"/>
                <literal value="status-bar"/>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="font-style"/>
                <shorthand name="font-variant"/>
                <shorthand name="font-weight"/>
                <shorthand name="font-size"/>
                <shorthand name="line-height"/>
                <shorthand name="font-family"/>
            </shorthand-list>
        </property>
        <property name="font-family" description="This property specifies a prioritized list of font family names and/or generic family names.">
            <category-list>
                <category value="visual"/>
            </category-list>
            <!-- allowing only generic font families -->
            <literal-list>
                <literal value="serif"/>
                <literal value="arial"/>
                <literal value="lucida console"/>
                <literal value="sans-serif"/>
                <literal value="cursive"/>
                <literal value="verdana"/>
                <literal value="fantasy"/>
                <literal value="monospace"/>
            </literal-list>
            <regexp-list>
                <regexp value="[\w,\-&apos;&quot; ]+"/>
            </regexp-list>
        </property>
        <property name="page" description="The 'page' property can be used to specify a particular type of page where an element should be displayed.">
            <category-list>
                <category value="visual"/>
                <category value="paged"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
            </literal-list>
            <regexp-list>
                <regexp name="cssIdentifier"/>
            </regexp-list>
        </property>
        <property name="play-during" default="auto" description="Similar to the 'cue-before' and 'cue-after' properties, this property specifies a sound to be played as a background while an element's content is spoken.">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="mix"/>
                <literal value="repeat"/>
                <literal value="none"/>
                <literal value="auto"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="cssOffsiteUri"/>
                <regexp name="cssOnsiteUri"/>
            </regexp-list>
        </property>
        <property name="text-align" description="This property describes how inline content of a block is aligned.">
            <category-list>
                <category value="visual"/>
            </category-list>
            <!--  For safety, ignoring string alignment which can be used to line table cells on characters -->
            <literal-list>
                <literal value="left"/>
                <literal value="right"/>
                <literal value="center"/>
                <literal value="justify"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="voice-family" description="The value is a comma-separated, prioritized list of voice family names (compare with 'font-family').">
            <category-list>
                <category value="aural"/>
            </category-list>
            <!--  Allowing only generic voice family -->
            <literal-list>
                <literal value="male"/>
                <literal value="female"/>
                <literal value="child"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <!--  end manual properties -->
    </css-rules>
    <allowed-empty-tags>
        <literal-list>
            <literal value="br"/>
            <literal value="hr"/>
            <literal value="a"/>
            <literal value="img"/>
            <literal value="link"/>
            <literal value="iframe"/>
            <literal value="script"/>
            <literal value="object"/>
            <literal value="applet"/>
            <literal value="frame"/>
            <literal value="base"/>
            <literal value="param"/>
            <literal value="meta"/>
            <literal value="input"/>
            <literal value="textarea"/>
            <literal value="embed"/>
            <literal value="basefont"/>
            <literal value="col"/>
            <literal value="div"/>
        </literal-list>
    </allowed-empty-tags>
</anti-samy-rules>
ecosphere/ecosphere-common/src/main/resources/poscom.properties
New file
@@ -0,0 +1,6 @@
##商户编码
memberCode=6A6229EEB35D992DD541598313373233
##请求APIKEY
apiKey=4SC9154KRE0K7PA8X29FHUHVK0ZP6KNS
##模板编号
templetId=2c0071f98c9a4bc2b11ff7fdeae9e649
ecosphere/ecosphere-common/src/main/resources/yunsdk.properties
New file
@@ -0,0 +1,11 @@
#通联通商云系统配置参数
#生产环境
#serverUrl=https://fintech.allinpay.com/service/soa
#测试环境
serverUrl=http://116.228.64.55:6900/service/soa
sysId=1906061744156467038
alias=1906061744156467038
pwd=123456
version=2.0
path=C:/Users/Administrator/Desktop/yunst/1906061744156467038/1906061744156467038.pfx
tlCertPath=C:/Users/Administrator/Desktop/yunst/1906061744156467038/TLCert-test.cer
ecosphere/ecosphere-common/src/test/java/com/nuvole/util/FileUtilTest.java
New file
@@ -0,0 +1,19 @@
package com.nuvole.util;
import cn.hutool.core.io.FileUtil;
import org.junit.Test;
/**
 * @author ChenLong
 * @version 1.0
 * @ClassName FileUtilTest
 * @date 2019/8/2 17:40
 */
public class FileUtilTest {
    @Test
    public void testTouch() {
        FileUtil.touch("d://test1/test.txt");
    }
}
ecosphere/ecosphere-common/src/test/java/com/nuvole/util/IdTest.java
New file
@@ -0,0 +1,106 @@
package com.nuvole.util;
import org.junit.Test;
import java.util.*;
public class IdTest {
    @Test
    public void test() {
        List<Long> list = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            Long id = IdGenerator.getId();
            System.out.println(i + ":======》" + id);
            list.add(id);
        }
        for (int i = 0; i < 100000; i++) {
            Long id = IdGenerator.getId();
            System.out.println(i + ":======》" + id);
            list.add(id);
        }
        System.out.println(cheakIsRepeat(list));
    }
    @Test
    public void test1() {
        List<Long> list = new ArrayList<>();
        Thread thread=new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {
                    Long id = IdGenerator.getId();
                    System.out.println(i + ":======》" + id);
                    list.add(id);
                }
            }
        });
        Thread thread2=new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10000; i++) {
                    Long id = IdGenerator.getId();
                    System.out.println(i + ":======》" + id);
                    list.add(id);
                }
            }
        });
        thread.start();
        thread2.start();
        Map<Long,Integer> map = findRepetition(list);
        if(map!=null){
            for (Map.Entry<Long,Integer> entry : map.entrySet()){
                if(entry.getValue()>1){
                    System.out.println("元素 "+entry.getKey()+" é‡å¤å‡ºçް"+entry.getValue()+"次");
                }else{
                }
            }
        }
    }
    private Map<Long, Integer> findRepetition(List<Long> arr){
        try{
            Thread.sleep(1000L);
        }catch (Exception e){
            e.printStackTrace();
        }
        Map<Long, Integer> map = new HashMap<>();
        if(arr == null || arr.size() <= 0){
            return null;
        }
        for(int i = 0; i < arr.size(); i ++){
            if(map.containsKey(arr.get(i))){
                map.put(arr.get(i), map.get(arr.get(i))+1);
            }else{
                map.put(arr.get(i), 1);
            }
        }
        return map;
    }
    public static boolean cheakIsRepeat(List<Long> list) {
        try{
            Thread.sleep(1000L);
        }catch (Exception e){
            e.printStackTrace();
        }
        HashSet<Long> hashSet = new HashSet<Long>();
        for (int i = 0; i < list.size(); i++) {
            hashSet.add(list.get(i));
        }
        if (hashSet.size() == list.size()) {
            return true;
        } else {
            return false;
        }
    }
}
ecosphere/ecosphere-common/src/test/java/com/nuvole/util/JWTUtilTest.java
New file
@@ -0,0 +1,28 @@
package com.nuvole.util;
import org.junit.Test;
import java.util.HashMap;
/**
 * @ClassName JWTUtilTest
 * @Description TODO
 * @Author Chen Long
 * @Date 2019/8/21
 * @Version 1.0
 */
public class JWTUtilTest {
    @Test
    public void generateJwt() {
        HashMap<String, Object> claims = new HashMap<>();
        claims.put("sub", "zhangsan");
        System.out.println(JWTUtil.generateJwt(JWTUtil.JWT_TYPE_PC, claims));
    }
    @Test
    public void checkJWT() {
        System.out.println(JWTUtil.checkJWT("o6t48fVSqCUCueyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiIyMWU2OTU4NWE5OGQ3MjRlMTE4YWZmMTYzZDM4NWQyOSIsImlhdCI6MTU2NjQzOTQ4NywiZXhwIjoxNTY2NDM5NDg4fQ.2PqL9bDqdtmIEvIOTN3ME5pATxST5aHWwirRhrMi4jews4YqlDkKGsc0Xj-UFxEa1pIW2sSws2KqmzeJpDPI6w"));
    }
}
ecosphere/ecosphere-common/src/test/java/com/nuvole/util/JsonTest.java
New file
@@ -0,0 +1,19 @@
package com.nuvole.util;
import com.alibaba.fastjson.JSON;
import com.nuvole.common.domain.dataFile.DataFile;
import org.junit.Test;
import java.util.List;
public class JsonTest {
    @Test
    public void TestParse(){
        String image = "[{\"uid\":1562829586751,\"path\":\"/ecosphereBase/2019/7/11/8cc0253719484a768668c35175d57694.jpg\",\"name\":\"90346996.jpg\",\"url\":\"https://echftp.yqzhfw.com/ecosphereBase/2019/7/11/8cc0253719484a768668c35175d57694.jpg\"}]";
        List<DataFile> dataFiles = JSON.parseArray(image, DataFile.class);
        System.out.println(dataFiles.get(0).getPath());
        System.out.println(dataFiles.size());
    }
}
ecosphere/ecosphere-common/src/test/java/com/nuvole/util/MapTest.java
New file
@@ -0,0 +1,23 @@
package com.nuvole.util;
import org.junit.Test;
import java.util.LinkedHashMap;
import java.util.Map;
/**
 * @author ChenLong
 * @version 1.0
 * @ClassName MapText
 * @date 2019/5/8 18:31
 */
public class MapTest {
    @Test
    public void testMap() {
        Map<String, String> h = new LinkedHashMap<>();
        h.put("name", "test");
        System.out.println(h.get("NAME"));
    }
}
ecosphere/ecosphere-common/src/test/java/com/nuvole/util/MixPdTest.java
New file
@@ -0,0 +1,20 @@
package com.nuvole.util;
import cn.hutool.crypto.SecureUtil;
import org.junit.Test;
/**
 * @author ChenLong
 * @version 1.0
 * @ClassName MixPdTest
 * @date 2019/5/7 14:37
 */
public class MixPdTest {
    @Test
    public void generateMixPd() throws Exception {
        String a = "zhangsan1122671457474842950";
        System.out.println(SecureUtil.md5(a));
    }
}
ecosphere/ecosphere-common/src/test/java/com/nuvole/util/TreeUtilTest.java
New file
@@ -0,0 +1,82 @@
package com.nuvole.util;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.util.ArrayList;
import java.util.HashMap;
/**
 * @author ChenLong
 * @version 1.0
 * @ClassName TreeUtilTest
 * @date 2019/4/23 19:04
 */
@Slf4j
public class TreeUtilTest {
    @Test
    public void convert2Tree() throws Exception {
        ArrayList list = new ArrayList();
        //list.add(new Node(1L, 0L, "1", ""));
        list.add(new Node(2L, 1L, "1.1", ""));
        list.add(new Node(3L, 1L, "1.2", ""));
        list.add(new Node(4L, 3L, "1.2.1", ""));
        HashMap<String, String> mapping = new HashMap<>();
        mapping.put("byReplace", "label");
        log.info(JSON.toJSONString(TreeUtil.convert2Tree(list ,"")));
        log.info(JSON.toJSONString(TreeUtil.convert2Tree(list ,mapping)));
    }
    class Node{
        public Node(Long id,Long pid,String name,String byReplace) {
            this.id = id;
            this.pid = pid;
            this.name = name;
            this.byReplace = byReplace;
        }
        private Long id;
        private Long pid;
        private String name;
        private String byReplace;
        public Long getId() {
            return id;
        }
        public void setId(Long id) {
            this.id = id;
        }
        public Long getPid() {
            return pid;
        }
        public void setPid(Long pid) {
            this.pid = pid;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getByReplace() {
            return byReplace;
        }
        public void setByReplace(String byReplace) {
            this.byReplace = byReplace;
        }
    }
}
ecosphere/ecosphere-common/src/test/java/com/nuvole/util/XssUtilTest.java
New file
@@ -0,0 +1,31 @@
package com.nuvole.util;
import org.apache.commons.lang.CharEncoding;
import org.junit.Test;
/**
 * @author ChenLong
 * @version 1.0
 * @ClassName XssUtilTest
 * @date 2019/7/16 18:42
 */
public class XssUtilTest {
    @Test
    public void clearXss() throws Exception {
        String val = "<p style=\"text-align: center;\"><strong>qqq<em>qxxxx<span style=\"text-decoration: underline;\">ffffff<span style=\"text-decoration: line-through;\">fffff</span></span></em></strong></p>\n" +
                "<p style=\"text-align: center;\"><strong><em><span style=\"text-decoration: underline;\"><span style=\"text-decoration: line-through;\"><img src=\"https://echftp.yqzhfw.com/ecosphereBaseDev/2019/7/16/0262f69df57f4f68acf763cacd362879.jpg\" alt=\"lalalal\" width=\"1920\" height=\"1080\" /></span></span></em></strong></p>";
        System.out.println(XssUtil.clearXss(val));
    }
    @Test
    public void test() throws Exception {
        String b = "aaaa";
        byte[] a = b.getBytes(CharEncoding.ISO_8859_1);
        System.out.println("is a:" + a);
        String s2 = XssUtil.clearXss(new String(a, CharEncoding.ISO_8859_1));
        System.out.println("s2:" + s2);
        System.out.println("s2 byte:" + s2.getBytes(CharEncoding.ISO_8859_1));
    }
}
ecosphere/ecosphere-common/src/test/resources/antisamy.xml
New file
@@ -0,0 +1,2789 @@
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!--
W3C rules retrieved from:
http://www.w3.org/TR/html401/struct/global.html
-->
<anti-samy-rules xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="antisamy.xsd">
    <directives>
        <directive name="omitXmlDeclaration" value="true"/>
        <directive name="omitDoctypeDeclaration" value="true"/>
        <directive name="maxInputSize" value="200000"/>
        <directive name="useXHTML" value="true"/>
        <directive name="formatOutput" value="true"/>
        <directive name="nofollowAnchors" value="true" />
        <directive name="validateParamAsEmbed" value="true" />
        <!--
        remember, this won't work for relative URIs - AntiSamy doesn't
        know anything about the URL or your web structure
        -->
        <directive name="embedStyleSheets" value="false"/>
        <directive name="connectionTimeout" value="5000"/>
        <directive name="maxStyleSheetImports" value="3"/>
        <!-- Allows the use of dynamic attributes (i.e. HTML5 "data-") -->
        <directive name="allowDynamicAttributes" value="true" />
    </directives>
    <common-regexps>
        <!--
        From W3C:
        This attribute assigns a class name or set of class names to an
        element. Any number of elements may be assigned the same class
        name or names. Multiple class names must be separated by white
        space characters.
        -->
        <!-- The 16 colors defined by the HTML Spec (also used by the CSS Spec) -->
        <regexp name="colorName" value="(aqua|black|blue|fuchsia|gray|grey|green|lime|maroon|navy|olive|purple|red|silver|teal|white|yellow)"/>
        <!-- HTML/CSS Spec allows 3 or 6 digit hex to specify color -->
        <regexp name="colorCode" value="(#([0-9a-fA-F]{6}|[0-9a-fA-F]{3}))"/>
        <regexp name="anything" value=".*"/>
        <regexp name="numberOrPercent" value="(\d)+(%{0,1})"/>
        <regexp name="paragraph" value="([\p{L}\p{N},'\.\s\-_\(\)\?]|&amp;[0-9]{2};)*"/>
        <regexp name="htmlId" value="[a-zA-Z0-9\:\-_\.]+"/>
        <regexp name="htmlTitle" value="[\p{L}\p{N}\s\-_',:\[\]!\./\\\(\)&amp;]*"/> <!-- force non-empty with a '+' at the end instead of '*' -->
        <regexp name="htmlClass" value="[a-zA-Z0-9\s,\-_]+"/>
        <regexp name="onsiteURL" value="^(?![\p{L}\p{N}\\\.\#@\$%\+&amp;;\-_~,\?=/!]*(&amp;colon))[\p{L}\p{N}\\\.\#@\$%\+&amp;;\-_~,\?=/!]*"/>
        <regexp name="anchoredURL" value="#(\w)+"/>
        <regexp name="offsiteURL" value="(\s)*((ht|f)tp(s?)://|mailto:)[\p{L}\p{N}]+[\p{L}\p{N}\p{Zs}\.\#@\$%\+&amp;;:\-_~,\?=/!\(\)]*(\s)*"/>
        <regexp name="boolean" value="(true|false)"/>
        <regexp name="singlePrintable" value="[a-zA-Z0-9]{1}"/> <!-- \w allows the '_' character -->
        <!-- This is for elements (ex: elemName { ... }) -->
        <regexp name="cssElementSelector" value="[a-zA-Z0-9\-_]+|\*"/>
        <!--  This is to list out any element names that are *not* valid -->
        <regexp name="cssElementExclusion" value=""/>
        <!--  This if for classes (ex: .className { ... }) -->
        <regexp name="cssClassSelector" value="\.[a-zA-Z0-9\-_]+"/>
        <!--  This is to list out any class names that are *not* valid -->
        <regexp name="cssClassExclusion" value=""/>
        <!--  This is for ID selectors (ex: #myId { ... } -->
        <regexp name="cssIDSelector" value="#[a-zA-Z0-9\-_]+"/>
        <!--  This is to list out any IDs that are *not* valid - FIXME: What should the default be to avoid div hijacking? *? -->
        <regexp name="cssIDExclusion" value=""/>
        <!--  This is for pseudo-element selector (ex. foo:pseudo-element { ... } -->
        <regexp name="cssPseudoElementSelector" value=":[a-zA-Z0-9\-_]+"/>
        <!--  This is to list out any psuedo-element names that are *not* valid -->
        <regexp name="cssPsuedoElementExclusion" value=""/>
        <!--  This is for attribute selectors (ex. foo[attr=value] { ... } -->
        <regexp name="cssAttributeSelector" value="\[[a-zA-Z0-9\-_]+((=|~=|\|=){1}[a-zA-Z0-9\-_]+){1}\]"/>
        <!--  This is to list out any attribute names that are *not* valid -->
        <regexp name="cssAttributeExclusion" value=""/>
        <!--  This is for resources referenced from CSS (such as background images and other imported stylesheets) -->
        <regexp name="cssOnsiteUri" value="url\(([\p{L}\p{N}\\/\.\?=\#&amp;;\-_~]+|\#(\w)+)\)"/>
        <regexp name="cssOffsiteUri" value="url\((\s)*((ht|f)tp(s?)://)[\p{L}\p{N}]+[~\p{L}\p{N}\p{Zs}\-_\.@#$%&amp;;:,\?=/\+!]*(\s)*\)"/>
        <!--  This if for CSS Identifiers -->
        <regexp name="cssIdentifier" value="[a-zA-Z0-9\-_]+"/>
        <!--  This is for comments within CSS (ex. /* comment */) -->
        <regexp name="cssCommentText" value="[\p{L}\p{N}\-_,\/\\\.\s\(\)!\?\=\$#%\^&amp;:&quot;']+"/>
        <regexp name="integer" value="(-|\+)?[0-9]+"/>
        <regexp name="positiveInteger" value="(\+)?[0-9]+"/>
        <regexp name="number" value="(-|\+)?([0-9]+(\.[0-9]+)?)"/>
        <regexp name="angle" value="(-|\+)?([0-9]+(\.[0-9]+)?)(deg|grads|rad)"/>
        <regexp name="time" value="([0-9]+(\.[0-9]+)?)(ms|s)"/>
        <regexp name="frequency" value="([0-9]+(\.[0-9]+)?)(hz|khz)"/>
        <regexp name="length" value="((-|\+)?0|(-|\+)?([0-9]+(\.[0-9]+)?)(em|ex|px|in|cm|mm|pt|pc))"/>
        <regexp name="positiveLength" value="((\+)?0|(\+)?([0-9]+(\.[0-9]+)?)(em|ex|px|in|cm|mm|pt|pc))"/>
        <regexp name="percentage" value="(-|\+)?([0-9]+(\.[0-9]+)?)%"/>
        <regexp name="positivePercentage" value="(\+)?([0-9]+(\.[0-9]+)?)%"/>
        <regexp name="absolute-size" value="(xx-small|x-small|small|medium|large|x-large|xx-large)"/>
        <regexp name="relative-size" value="(larger|smaller)"/>
        <!-- Used for CSS Color specifications (complex regexp expresses integer values of 0-255) -->
        <regexp name="rgbCode" value="rgb\(([1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5]),([1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5]),([1]?[0-9]{1,2}|2[0-4][0-9]|25[0-5])\)"/>
        <!-- CSS2 Allowed System Color Values -->
        <regexp name="systemColor" value="(activeborder|activecaption|appworkspace|background|buttonface|buttonhighlight|buttonshadow|buttontext|captiontext|graytext|highlight|highlighttext|inactiveborder|inactivecaption|inactivecaptiontext|infobackground|infotext|menu|menutext|scrollbar|threeddarkshadow|threedface|threedhighlight|threedlightshadow|threedshadow|window|windowframe|windowtext)"/>
        <!-- This is where we specify what Flash src to allow -->
        <regexp name="flashSites" value="http://(download\.macromedia\.com/pub|www\.macromedia\.com/(go|shockwave)|c\.brightcove\.com/services|gamevideos\.1up\.com/swf|www\.youtube\.com/v|vimeo\.com|www\.gametrailers\.com|videomedia\.ign\.com/ev|image\.com\.com/gamespot|www\.hulu\.com/embed|embed\.break\.com|player\.ordienetworks\.com/flash|www\.adultswim\.com/video/vplayer|www\.dailymotion\.com/swf|www\.ustream\.tv/flash/video|cdn-i\.dmdentertainment\.com|media\.mtvnservices\.com|www\.justin\.tv/widgets|www\.viddler\.com/(player|simple_on_site)|static\.twitter\.com/flash|www\.gamepro\.com/bin|www\.divshare\.com/flash|www\.facebook\.com/v)/.*"/>
    </common-regexps>
    <!--
    Tag.name = a, b, div, body, etc.
    Tag.action = filter: remove tags, but keep content, validate: keep content as long as it passes rules, remove: remove tag and contents
    Attribute.name = id, class, href, align, width, etc.
    Attribute.onInvalid = what to do when the attribute is invalid, e.g., remove the tag (removeTag), remove the attribute (removeAttribute), filter the tag (filterTag)
    Attribute.description = What rules in English you want to tell the users they can have for this attribute. Include helpful things so they'll be able to tune their HTML
     -->
    <!--
    Some attributes are common to all (or most) HTML tags. There aren't many that qualify for this. You have to make sure there's no
    collisions between any of these attribute names with attribute names of other tags that are for different purposes.
    -->
    <common-attributes>
        <!-- Common to all HTML tags  -->
        <attribute name="id" description="The 'id' of any HTML attribute should not contain anything besides letters and numbers">
            <regexp-list>
                <regexp name="htmlId"/>
            </regexp-list>
        </attribute>
        <attribute name="classid">
            <regexp-list>
                <regexp name="anything" />
            </regexp-list>
        </attribute>
        <attribute name="codebase">
            <regexp-list>
                <regexp name="flashSites" />
            </regexp-list>
        </attribute>
        <attribute name="class" description="The 'class' of any HTML attribute is usually a single word, but it can also be a list of class names separated by spaces">
            <regexp-list>
                <regexp name="htmlClass"/>
            </regexp-list>
        </attribute>
        <attribute name="lang" description="The 'lang' attribute tells the browser what language the element's attribute values and content are written in">
             <regexp-list>
                 <regexp value="[a-zA-Z]{2,20}"/>
             </regexp-list>
         </attribute>
         <attribute name="title" description="The 'title' attribute provides text that shows up in a 'tooltip' when a user hovers their mouse over the element">
             <regexp-list>
                 <regexp name="htmlTitle"/>
             </regexp-list>
         </attribute>
         <attribute name="alt" description="The 'alt' attribute provides alternative text to users when its visual representation is not available">
             <regexp-list>
                 <regexp name="paragraph"/>
             </regexp-list>
         </attribute>
        <attribute name="data-" description="Allows the HTML5 'data-' attribute to be added to elements">
            <regexp-list>
                <regexp name="anything"/>
            </regexp-list>
        </attribute>
         <!-- the "style" attribute will be validated by an inline stylesheet scanner, so no need to define anything here - i hate having to special case this but no other choice -->
         <attribute name="style" description="The 'style' attribute provides the ability for users to change many attributes of the tag's contents using a strict syntax"/>
         <attribute name="media">
             <regexp-list>
                 <regexp value="[a-zA-Z0-9,\-\s]+"/>
             </regexp-list>
             <literal-list>
                 <literal value="screen"/>
                 <literal value="tty"/>
                 <literal value="tv"/>
                 <literal value="projection"/>
                 <literal value="handheld"/>
                 <literal value="print"/>
                 <literal value="braille"/>
                 <literal value="aural"/>
                 <literal value="all"/>
             </literal-list>
         </attribute>
         <!-- Anchor related -->
         <!--  onInvalid="filterTag" has been removed as per suggestion at OWASP SJ 2007 - just "name" is valid -->
        <attribute name="href">
            <regexp-list>
                <regexp name="onsiteURL"/>
                <regexp name="anchoredURL"/>
                <regexp name="offsiteURL"/>
            </regexp-list>
        </attribute>
        <attribute name="name">
             <regexp-list>
                 <regexp value="[a-zA-Z0-9-\_\$]+"/>
                 <!--
                 have to allow the $ for .NET controls - although,
                 will users be supplying input that has server-generated
                 .NET control names? methinks not, but i want to pass my
                 test cases
                 -->
             </regexp-list>
         </attribute>
        <attribute name="shape" description="The 'shape' attribute defines the shape of the selectable area">
            <literal-list>
                <literal value="default"/>
                <literal value="rect"/>
                <literal value="circle"/>
                <literal value="poly"/>
            </literal-list>
        </attribute>
        <!--  Table attributes  -->
        <attribute name="border">
            <regexp-list>
                <regexp name="number"/>
            </regexp-list>
        </attribute>
        <attribute name="cellpadding">
            <regexp-list>
                <regexp name="number"/>
            </regexp-list>
        </attribute>
        <attribute name="cellspacing">
            <regexp-list>
                <regexp name="number"/>
            </regexp-list>
        </attribute>
        <attribute name="colspan">
            <regexp-list>
                <regexp name="number"/>
            </regexp-list>
        </attribute>
        <attribute name="rowspan">
            <regexp-list>
                <regexp name="number"/>
            </regexp-list>
        </attribute>
        <attribute name="background">
            <regexp-list>
                <regexp name="onsiteURL"/>
            </regexp-list>
        </attribute>
        <attribute name="bgcolor">
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
            </regexp-list>
        </attribute>
         <attribute name="abbr">
            <regexp-list>
                 <regexp name="paragraph"/>
             </regexp-list>
         </attribute>
         <attribute name="headers" description="The 'headers' attribute is a space-separated list of cell IDs">
             <regexp-list>
                 <regexp value="[a-zA-Z0-9\s*]*"/>
             </regexp-list>
         </attribute>
         <attribute name="charoff">
             <regexp-list>
                 <regexp value="numberOrPercent"/>
             </regexp-list>
         </attribute>
         <attribute name="char">
            <regexp-list>
                <regexp value=".{0,1}"/>
            </regexp-list>
         </attribute>
        <attribute name="axis" description="The 'headers' attribute is a comma-separated list of related header cells">
             <regexp-list>
                 <regexp value="[a-zA-Z0-9\s*,]*"/>
             </regexp-list>
        </attribute>
        <attribute name="nowrap" description="The 'nowrap' attribute tells the browser not to wrap text that goes over one line">
            <regexp-list>
                <regexp name="anything"/>
                <!-- <regexp value="(nowrap){0,1}"/>  -->
            </regexp-list>
        </attribute>
        <!--  Common positioning attributes  -->
        <attribute name="width">
            <regexp-list>
                <regexp name="numberOrPercent"/>
            </regexp-list>
        </attribute>
        <attribute name="height">
            <regexp-list>
                <regexp name="numberOrPercent"/>
            </regexp-list>
        </attribute>
        <attribute name="align" description="The 'align' attribute of an HTML element is a direction word, like 'left', 'right' or 'center'">
            <literal-list>
                <literal value="center"/>
                <literal value="middle"/>
                <literal value="left"/>
                <literal value="right"/>
                <literal value="justify"/>
                <literal value="char"/>
            </literal-list>
        </attribute>
        <attribute name="valign" description="The 'valign' attribute of an HTML attribute is a direction word, like 'baseline','bottom','middle' or 'top'">
            <literal-list>
                <literal value="baseline"/>
                <literal value="bottom"/>
                <literal value="middle"/>
                <literal value="top"/>
            </literal-list>
        </attribute>
        <!-- Intrinsic JavaScript Events -->
        <attribute name="onFocus" description="The 'onFocus' event is executed when the control associated with the tag gains focus">
            <literal-list>
                <literal value="javascript:void(0)"/>
                <literal value="javascript:history.go(-1)"/>
            </literal-list>
        </attribute>
        <attribute name="onBlur" description="The 'onBlur' event is executed when the control associated with the tag loses focus">
            <literal-list>
                <literal value="javascript:void(0)"/>
                <literal value="javascript:history.go(-1)"/>
            </literal-list>
        </attribute>
         <attribute name="onClick" description="The 'onClick' event is executed when the control associated with the tag is clicked">
            <literal-list>
                <literal value="javascript:void(0)"/>
                <literal value="javascript:history.go(-1)"/>
            </literal-list>
         </attribute>
         <attribute name="onDblClick" description="The 'onDblClick' event is executed when the control associated with the tag is clicked twice immediately">
            <literal-list>
                <literal value="javascript:void(0)"/>
                <literal value="javascript:history.go(-1)"/>
            </literal-list>
         </attribute>
          <attribute name="onMouseDown" description="The 'onMouseDown' event is executed when the control associated with the tag is clicked but not yet released">
            <literal-list>
                <literal value="javascript:void(0)"/>
                <literal value="javascript:history.go(-1)"/>
            </literal-list>
         </attribute>
         <attribute name="onMouseUp" description="The 'onMouseUp' event is executed when the control associated with the tag is clicked after the button is released">
            <literal-list>
                <literal value="javascript:void(0)"/>
                <literal value="javascript:history.go(-1)"/>
            </literal-list>
         </attribute>
          <attribute name="onMouseOver" description="The 'onMouseOver' event is executed when the user's mouse hovers over the control associated with the tag">
            <literal-list>
                <literal value="javascript:void(0)"/>
                <literal value="javascript:history.go(-1)"/>
            </literal-list>
         </attribute>
         <attribute name="scope" description="The 'scope' attribute defines what's covered by the header cells">
             <literal-list>
                 <literal value="row"/>
                 <literal value="col"/>
                 <literal value="rowgroup"/>
                 <literal value="colgroup"/>
             </literal-list>
         </attribute>
         <!-- If you want users to be able to mess with tabindex, uncomment this -->
         <!--
         <attribute name="tabindex" description="...">
             <regexp-list>
                 <regexp name="number"/>
             </regexp-list>
         </attribute>
          -->
         <!-- Input/form related common attributes -->
         <attribute name="disabled">
             <regexp-list>
                 <regexp name="anything"/>
             </regexp-list>
         </attribute>
         <attribute name="readonly">
             <regexp-list>
                 <regexp name="anything"/>
             </regexp-list>
         </attribute>
         <attribute name="accesskey">
             <regexp-list>
                 <regexp name="anything"/>
             </regexp-list>
         </attribute>
         <attribute name="size">
             <regexp-list>
                 <regexp name="number"/>
             </regexp-list>
         </attribute>
        <attribute name="autocomplete">
            <literal-list>
                <literal value="on"/>
                <literal value="off"/>
            </literal-list>
        </attribute>
         <attribute name="rows">
             <regexp-list>
                 <regexp name="number"/>
             </regexp-list>
         </attribute>
         <attribute name="cols">
             <regexp-list>
                 <regexp name="number"/>
             </regexp-list>
         </attribute>
    </common-attributes>
    <!--
    This requires normal updates as browsers continue to diverge from the W3C and each other. As long as the browser wars continue
    this is going to continue. I'm not sure war is the right word for what's going on. Doesn't somebody have to win a war after
    a while? Even wars of attrition, surely?
     -->
    <global-tag-attributes>
        <!-- Not valid in base, head, html, meta, param, script, style, and title elements. -->
        <attribute name="id"/>
        <attribute name="style"/>
        <attribute name="title"/>
        <attribute name="class"/>
        <!-- Not valid in base, br, frame, frameset, hr, iframe, param, and script elements.  -->
        <attribute name="lang"/>
    </global-tag-attributes>
    <!-- Declare "dynamic" tag attributes here. The directive "allowDynamicAttributes" must be set to true -->
    <dynamic-tag-attributes>
        <attribute name="data-"/> <!-- HTML5 "data-" tag -->
    </dynamic-tag-attributes>
    <tags-to-encode>
        <tag>g</tag>
        <tag>grin</tag>
    </tags-to-encode>
    <tag-rules>
        <!-- You can mess with this stuff if you know what you're doing -->
        <tag name="html" action="validate"/>
        <tag name="body" action="validate">
            <attribute name="bgcolor"/>
        </tag>
        <tag name="meta" action="filter"/>
        <tag name="head" action="validate"/>
        <!-- since we're validating the style sheets this is safe to have - switch to "truncate" if the user's html will appear in the html body -->
        <tag name="title" action="truncate"/>
        <!-- Tags related to JavaScript -->
        <tag name="script" action="remove"/>
        <tag name="noscript" action="validate"/> <!-- although no javascript can fire inside a noscript tag, css is still a viable attack vector -->
        <!-- Frame & related tags -->
        <tag name="iframe" action="remove"/>
        <tag name="frameset" action="remove"/>
        <tag name="frame" action="remove"/>
        <!-- Form related tags -->
        <tag name="label" action="validate">
            <attribute name="for">
                <regexp-list>
                    <regexp name="htmlId"/>
                </regexp-list>
            </attribute>
        </tag>
        <!--
            If you wish to enable any of the form related tags, change the tag's action below from "filter" or "remove" to "validate". The attributes have been
            hardened so this is safe to do, if it's something you want to allow. Beware the <><ing possibilities!
         -->
        <tag name="form" action="validate">
            <attribute name="action">
                <regexp-list>
                    <regexp name="onsiteURL"/>
                    <regexp name="offsiteURL"/>
                </regexp-list>
            </attribute>
            <attribute name="name"/>
            <attribute name="autocomplete"/>
            <attribute name="method">
                <literal-list>
                    <literal value="post"/>
                    <literal value="get"/>
                </literal-list>
            </attribute>
        </tag>
        <tag name="button" action="validate">
            <attribute name="name"/>
            <attribute name="value">
                <regexp-list>
                    <regexp name="anything"/>
                </regexp-list>
            </attribute>
            <attribute name="disabled"/>
            <attribute name="accesskey"/>
            <attribute name="type">
                <literal-list>
                    <literal value="submit"/>
                    <literal value="reset"/>
                    <literal value="button"/>
                </literal-list>
            </attribute>
        </tag>
        <tag name="input" action="validate">
            <attribute name="name"/>
            <attribute name="size"/>
            <attribute name="maxlength">
                <regexp-list>
                    <regexp name="number"/>
                </regexp-list>
            </attribute>
            <attribute name="autocomplete"/>
            <attribute name="checked">
                <regexp-list>
                    <regexp name="anything"/>
                </regexp-list>
            </attribute>
            <attribute name="alt"/>
            <attribute name="src">
                <regexp-list>
                    <regexp name="onsiteURL"/>
                    <regexp name="offsiteURL"/>
                </regexp-list>
            </attribute>
            <attribute name="usemap">
                <regexp-list>
                    <regexp name="onsiteURL"/>
                    <regexp name="anchoredURL"/>
                </regexp-list>
            </attribute>
            <attribute name="type">
                <literal-list>
                    <literal value="hidden"/>
                    <literal value="text"/>
                    <literal value="password"/>
                    <literal value="radio"/>
                    <literal value="checkbox"/>
                    <literal value="submit"/>
                    <literal value="button"/>
                    <literal value="image"/>
                    <literal value="file"/>
                    <literal value="reset"/>
                </literal-list>
            </attribute>
            <attribute name="value">
                <regexp-list>
                    <regexp name="anything"/>
                </regexp-list>
            </attribute>
            <attribute name="disabled"/>
            <attribute name="readonly"/>
            <attribute name="accesskey"/>
            <attribute name="border"/>
        </tag>
        <tag name="select" action="validate">
            <attribute name="name"/>
            <attribute name="disabled"/>
            <attribute name="multiple">
                <regexp-list>
                    <regexp name="anything"/>
                </regexp-list>
            </attribute>
            <attribute name="size"/>
        </tag>
        <tag name="option" action="validate">
            <attribute name="disabled"/>
            <attribute name="value">
                <regexp-list>
                    <regexp name="anything"/>
                </regexp-list>
            </attribute>
            <attribute name="label">
                <regexp-list>
                    <regexp name="anything"/>
                </regexp-list>
            </attribute>
            <attribute name="selected">
                <regexp-list>
                    <regexp name="anything"/>
                </regexp-list>
            </attribute>
        </tag>
        <tag name="textarea" action="validate">
            <attribute name="rows"/>
            <attribute name="cols"/>
            <attribute name="name"/>
            <attribute name="disabled"/>
            <attribute name="readonly"/>
            <attribute name="accesskey"/>
        </tag>
        <!-- All formatting tags -->
        <tag name="h1" action="validate"/>
        <tag name="h2" action="validate"/>
        <tag name="h3" action="validate"/>
        <tag name="h4" action="validate"/>
        <tag name="h5" action="validate"/>
        <tag name="h6" action="validate"/>
        <tag name="p" action="validate">
            <attribute name="align"/>
        </tag>
        <tag name="i" action="validate"/>
        <tag name="b" action="validate"/>
        <tag name="u" action="validate"/>
        <tag name="strong" action="validate"/>
        <tag name="em" action="validate"/>
        <tag name="small" action="validate"/>
        <tag name="big" action="validate"/>
        <tag name="pre" action="validate"/>
        <tag name="code" action="validate"/>
        <tag name="cite" action="validate"/>
        <tag name="samp" action="validate"/>
        <tag name="sub" action="validate"/>
        <tag name="sup" action="validate"/>
        <tag name="strike" action="validate"/>
        <tag name="center" action="validate"/>
        <tag name="blockquote" action="validate"/>
        <tag name="hr" action="validate"/>
        <tag name="br" action="validate"/>
        <tag name="col" action="validate"/>
        <tag name="font" action="validate">
            <attribute name="color">
                <regexp-list>
                    <regexp name="colorName"/>
                    <regexp name="colorCode"/>
                </regexp-list>
            </attribute>
            <attribute name="face">
                <regexp-list>
                    <regexp value="[\w;, \-]+"/>
                </regexp-list>
            </attribute>
            <attribute name="size">
                <regexp-list>
                    <regexp value="(\+|-){0,1}(\d)+"/>
                </regexp-list>
            </attribute>
        </tag>
        <!-- Anchor and anchor related tags -->
        <tag name="a" action="validate">
            <!--  onInvalid="filterTag" has been removed as per suggestion at OWASP SJ 2007 - just "name" is valid -->
            <attribute name="href"/>
            <attribute name="onFocus"/>
            <attribute name="onBlur"/>
            <attribute name="nohref">
                <regexp-list>
                    <regexp name="anything"/>
                </regexp-list>
            </attribute>
            <attribute name="rel">
                <literal-list>
                    <literal value="nofollow"/>
                </literal-list>
            </attribute>
            <attribute name="name"/>
        </tag>
        <tag name="map" action="validate"/>
        <!-- base tag removed per demo - this could be enabled with literal-list values you allow -->
        <!--
        <tag name="base" action="validate">
            <attribute name="href"/>
        </tag>
        -->
        <!-- Stylesheet Tags -->
        <tag name="style" action="validate">
            <attribute name="type">
                <literal-list>
                    <literal value="text/css"/>
                </literal-list>
            </attribute>
            <attribute name="media"/>
        </tag>
        <tag name="span" action="validate"/>
        <tag name="div" action="validate">
            <attribute name="align"/>
        </tag>
        <!-- Image & image related tags -->
        <tag name="img" action="validate">
            <attribute name="src" onInvalid="removeTag">
                <regexp-list>
                    <regexp name="onsiteURL"/>
                    <regexp name="offsiteURL"/>
                </regexp-list>
            </attribute>
            <attribute name="name"/>
            <attribute name="alt"/>
            <attribute name="height"/>
            <attribute name="width"/>
            <attribute name="border"/>
            <attribute name="align"/>
            <attribute name="hspace">
                <regexp-list>
                    <regexp name="number"/>
                </regexp-list>
            </attribute>
            <attribute name="vspace">
                <regexp-list>
                    <regexp name="number"/>
                </regexp-list>
            </attribute>
        </tag>
        <!-- no way to do this safely without hooking up the same code to @import to embed the remote stylesheet (malicious user could change offsite resource to be malicious after validation -->
        <!-- <attribute name="href" onInvalid="removeTag"/>  -->
        <tag name="link" action="validate">
            <!-- <attribute name="href" onInvalid="removeTag"/>  -->
            <attribute name="media"/>
            <attribute name="type" onInvalid="removeTag">
                <literal-list>
                    <literal value="text/css"/>
                    <literal value="application/rss+xml"/>
                    <literal value="image/x-icon"/>
                </literal-list>
            </attribute>
            <attribute name="rel">
                <literal-list>
                    <literal value="stylesheet"/>
                    <literal value="shortcut icon"/>
                    <literal value="search"/>
                    <literal value="copyright"/>
                    <literal value="top"/>
                    <literal value="alternate"/>
                </literal-list>
            </attribute>
        </tag>
        <!-- List tags -->
        <tag name="ul" action="validate"/>
        <tag name="ol" action="validate"/>
        <tag name="li" action="validate"/>
        <!-- Dictionary tags -->
        <tag name="dd" action="truncate"/>
        <tag name="dl" action="truncate"/>
        <tag name="dt" action="truncate"/>
        <!-- Table tags (tbody, thead, tfoot)-->
        <tag name="thead" action="validate">
            <attribute name="align"/>
            <attribute name="char"/>
            <attribute name="charoff"/>
            <attribute name="valign"/>
        </tag>
        <tag name="tbody" action="validate">
            <attribute name="align"/>
            <attribute name="char"/>
            <attribute name="charoff"/>
            <attribute name="valign"/>
        </tag>
        <tag name="tfoot" action="validate">
            <attribute name="align"/>
            <attribute name="char"/>
            <attribute name="charoff"/>
            <attribute name="valign"/>
        </tag>
        <tag name="table" action="validate">
            <attribute name="height"/>
            <attribute name="width"/>
            <attribute name="border"/>
            <attribute name="bgcolor"/>
            <attribute name="cellpadding"/>
            <attribute name="cellspacing"/>
            <attribute name="background"/>
            <attribute name="align"/>
            <attribute name="noresize">
                <literal-list>
                    <literal value="noresize"/>
                    <literal value=""/>
                </literal-list>
            </attribute>
        </tag>
        <tag name="td" action="validate">
            <attribute name="background"/>
            <attribute name="bgcolor"/>
            <attribute name="abbr"/>
            <attribute name="axis"/>
            <attribute name="headers"/>
            <attribute name="scope"/>
            <attribute name="nowrap"/>
            <attribute name="height"/>
            <attribute name="width"/>
            <attribute name="align"/>
            <attribute name="char"/>
            <attribute name="charoff"/>
            <attribute name="valign"/>
            <attribute name="colspan"/>
            <attribute name="rowspan"/>
        </tag>
        <tag name="th" action="validate">
            <attribute name="abbr"/>
            <attribute name="axis"/>
            <attribute name="headers"/>
            <attribute name="scope"/>
            <attribute name="nowrap"/>
            <attribute name="bgcolor"/>
            <attribute name="height"/>
            <attribute name="width"/>
            <attribute name="align"/>
            <attribute name="char"/>
            <attribute name="charoff"/>
            <attribute name="valign"/>
            <attribute name="colspan"/>
            <attribute name="rowspan"/>
        </tag>
        <tag name="tr" action="validate">
            <attribute name="height"/>
            <attribute name="width"/>
            <attribute name="align"/>
            <attribute name="valign"/>
            <attribute name="char"/>
            <attribute name="charoff"/>
            <attribute name="background"/>
        </tag>
        <tag name="colgroup" action="validate">
            <attribute name="span">
                <regexp-list>
                    <regexp name="number"/>
                </regexp-list>
            </attribute>
            <attribute name="width"/>
            <attribute name="align"/>
            <attribute name="char"/>
            <attribute name="charoff"/>
            <attribute name="valign"/>
        </tag>
        <tag name="col" action="validate">
            <attribute name="align"/>
            <attribute name="char"/>
            <attribute name="charoff"/>
            <attribute name="valign"/>
            <attribute name="span">
                <regexp-list>
                    <regexp name="number"/>
                </regexp-list>
            </attribute>
            <attribute name="width"/>
        </tag>
        <tag name="fieldset" action="validate"/>
        <tag name="legend" action="validate"/>
        <!-- tags for popular Flash embeds -->
        <tag name="object" action="validate">
            <attribute name="id" />
            <attribute name="classid" />
            <attribute name="codebase" />
            <attribute name="type" onInvalid="removeTag">
                <literal-list>
                    <literal value="application/x-shockwave-flash" />
                </literal-list>
            </attribute>
            <attribute name="data" onInvalid="removeTag">
                <regexp-list>
                    <regexp name="flashSites" />
                </regexp-list>
            </attribute>
            <attribute name="align" />
            <attribute name="height" />
            <attribute name="width" />
            <attribute name="alt" />
            <attribute name="bgcolor">
                <regexp-list>
                    <regexp name="colorCode" />
                </regexp-list>
            </attribute>
        </tag>
        <!-- with validateParamAsEmbed=true, this tag rule also covers <param> name/value pairs -->
        <tag name="embed" action="validate">
            <attribute name="src" onInvalid="removeTag">
                <regexp-list>
                    <regexp name="flashSites" />
                </regexp-list>
            </attribute>
            <attribute name="movie" onInvalid="removeTag">
                <regexp-list>
                    <regexp name="flashSites" />
                </regexp-list>
            </attribute>
            <attribute name="pluginspage">
                <regexp-list>
                    <regexp name="flashSites" />
                </regexp-list>
            </attribute>
            <attribute name="bgcolor">
                <regexp-list>
                    <regexp name="colorCode" />
                </regexp-list>
            </attribute>
            <attribute name="base">
                <literal-list>
                    <literal value="http://admin.brightcove.com" />
                </literal-list>
            </attribute>
            <attribute name="type">
                <literal-list>
                    <literal value="application/x-shockwave-flash" />
                </literal-list>
            </attribute>
            <attribute name="name">
                <regexp-list>
                    <regexp name="anything" />
                </regexp-list>
            </attribute>
            <attribute name="flashvars">
                <regexp-list>
                    <regexp name="anything" /><!-- we could put something complex in here, but this is prolly fine for now-->
                </regexp-list>
            </attribute>
            <attribute name="align" />
            <attribute name="height" />
            <attribute name="width" />
            <attribute name="allowfullscreen">
                <regexp-list>
                    <regexp name="boolean" />
                </regexp-list>
            </attribute>
            <attribute name="quality">
                <literal-list>
                    <literal value="high" />
                </literal-list>
            </attribute>
            <attribute name="allowscriptaccess">
                <literal-list>
                    <literal value="always" />
                    <literal value="samedomain" />
                </literal-list>
            </attribute>
            <attribute name="seamlesstabbing">
                <regexp-list>
                    <regexp name="boolean" />
                </regexp-list>
            </attribute>
            <attribute name="swliveconnect">
                <regexp-list>
                    <regexp name="boolean" />
                </regexp-list>
            </attribute>
            <attribute name="wmode">
                <literal-list>
                    <literal value="transparent" />
                    <literal value="window" />
                </literal-list>
            </attribute>
            <attribute name="allownetworking">
                <literal-list>
                    <literal value="all" />
                </literal-list>
            </attribute>
        </tag>
    </tag-rules>
    <!--  CSS validation processing rules  -->
    <css-rules>
        <property name="azimuth" description="This property is most likely to be implemented by mixing the same signal into different channels at differing volumes.">
            <literal-list>
                <literal value="left-side"/>
                <literal value="far-left"/>
                <literal value="left"/>
                <literal value="center-left"/>
                <literal value="center"/>
                <literal value="center-right"/>
                <literal value="right"/>
                <literal value="far-right"/>
                <literal value="right-side"/>
                <literal value="behind"/>
                <literal value="leftwards"/>
                <literal value="rightwards"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="angle"/>
            </regexp-list>
        </property>
        <property name="background" description="The 'background' property is a shorthand property for setting the individual background properties (i.e., 'background-color', 'background-image', 'background-repeat', 'background-attachment' and 'background-position') at the same place in the style sheet.">
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="background-color"/>
                <shorthand name="background-image"/>
                <shorthand name="background-repeat"/>
                <shorthand name="background-attachment"/>
                <shorthand name="background-position"/>
            </shorthand-list>
        </property>
        <property name="background-attachment" description="If a background image is specified, this property specifies whether it is fixed with regard to the viewport ('fixed') or scrolls along with the document ('scroll').">
            <literal-list>
                <literal value="scroll"/>
                <literal value="fixed"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="background-color" description="This property sets the background color of an element, either a &lt;color&gt; value or the keyword 'transparent', to make the underlying colors shine through.">
            <literal-list>
                <literal value="transparent"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
        </property>
        <property name="background-image" description="This property sets the background image of an element.">
            <literal-list>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="cssOffsiteUri"/>
                <regexp name="cssOnsiteUri"/>
            </regexp-list>
        </property>
        <property name="background-position" description="If a background image has been specified, this property specifies its initial position.">
            <literal-list>
                <literal value="top"/>
                <literal value="center"/>
                <literal value="bottom"/>
                <literal value="left"/>
                <literal value="center"/>
                <literal value="right"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="percentage"/>
                <regexp name="length"/>
            </regexp-list>
        </property>
        <property name="background-repeat" description="If a background image is specified, this property specifies whether the image is repeated (tiled), and how.">
            <literal-list>
                <literal value="repeat"/>
                <literal value="repeat-x"/>
                <literal value="repeat-y"/>
                <literal value="no-repeat"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <!-- Begin simple properties -->
        <property name="border-collapse" default="collapse" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="collapse"/>
                <literal value="separate"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="border-color" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="transparent"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
        </property>
        <property name="border-top-color" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
        </property>
        <property name="border-right-color" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
        </property>
        <property name="border-bottom-color" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
        </property>
        <property name="border-left-color" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
        </property>
        <property name="bottom" default="auto" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="caption-side" default="top" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="top"/>
                <literal value="bottom"/>
                <literal value="left"/>
                <literal value="right"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="clear" default="none" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="none"/>
                <literal value="left"/>
                <literal value="right"/>
                <literal value="both"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="color" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
        </property>
        <property name="cue-after" default="none" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="cssOffsiteUri"/>
                <regexp name="cssOnsiteUri"/>
            </regexp-list>
        </property>
        <property name="cue-before" default="none" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="cssOffsiteUri"/>
                <regexp name="cssOnsiteUri"/>
            </regexp-list>
        </property>
        <property name="direction" default="ltr" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="ltr"/>
                <literal value="rtl"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="display" default="inline" description="">
            <category-list>
                <category value="all"/>
            </category-list>
            <literal-list>
                <literal value="inline"/>
                <literal value="block"/>
                <literal value="list-item"/>
                <literal value="run-in"/>
                <literal value="compact"/>
                <literal value="marker"/>
                <literal value="table"/>
                <literal value="inline-table"/>
                <literal value="table-row-group"/>
                <literal value="table-header-group"/>
                <literal value="table-footer-group"/>
                <literal value="table-row"/>
                <literal value="table-column-group"/>
                <literal value="table-column"/>
                <literal value="table-cell"/>
                <literal value="table-caption"/>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="elevation" default="level" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="below"/>
                <literal value="level"/>
                <literal value="above"/>
                <literal value="higher"/>
                <literal value="lower"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="angle"/>
            </regexp-list>
        </property>
        <property name="empty-cells" default="show" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="show"/>
                <literal value="hide"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="float" default="none" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="left"/>
                <literal value="right"/>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="font-size" default="medium" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="absolute-size"/>
                <regexp name="relative-size"/>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="font-size-adjust" default="none" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="number"/>
            </regexp-list>
        </property>
        <property name="font-stretch" default="normal" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="normal"/>
                <literal value="wider"/>
                <literal value="narrower"/>
                <literal value="ultra-condensed"/>
                <literal value="extra-condensed"/>
                <literal value="condensed"/>
                <literal value="semi-condensed"/>
                <literal value="semi-expanded"/>
                <literal value="expanded"/>
                <literal value="extra-expanded"/>
                <literal value="ultra-expanded"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="font-style" default="normal" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="normal"/>
                <literal value="italic"/>
                <literal value="oblique"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="font-variant" default="normal" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="normal"/>
                <literal value="small-caps"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="font-weight" default="normal" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="normal"/>
                <literal value="bold"/>
                <literal value="bolder"/>
                <literal value="lighter"/>
                <literal value="100"/>
                <literal value="200"/>
                <literal value="300"/>
                <literal value="400"/>
                <literal value="500"/>
                <literal value="600"/>
                <literal value="700"/>
                <literal value="800"/>
                <literal value="900"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="height" default="auto" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="left" default="auto" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="letter-spacing" default="normal" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="normal"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
            </regexp-list>
        </property>
        <property name="line-height" default="normal" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="normal"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="number"/>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="list-style-image" default="none" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="cssOffsiteUri"/>
                <regexp name="cssOnsiteUri"/>
            </regexp-list>
        </property>
        <property name="list-style-position" default="outside" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inside"/>
                <literal value="outside"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="list-style-type" default="disc" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="disc"/>
                <literal value="circle"/>
                <literal value="square"/>
                <literal value="decimal"/>
                <literal value="decimal-leading-zero"/>
                <literal value="lower-roman"/>
                <literal value="upper-roman"/>
                <literal value="lower-greek"/>
                <literal value="lower-alpha"/>
                <literal value="lower-latin"/>
                <literal value="upper-alpha"/>
                <literal value="upper-latin"/>
                <literal value="hebrew"/>
                <literal value="armenian"/>
                <literal value="georgian"/>
                <literal value="cjk-ideographic"/>
                <literal value="hiragana"/>
                <literal value="katakana"/>
                <literal value="hiragana-iroha"/>
                <literal value="katakana-iroha"/>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="marker-offset" default="auto" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
            </regexp-list>
        </property>
        <property name="max-height" default="none" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="max-width" default="none" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="min-height" default="0" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="min-width" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="orphans" default="2" description="">
            <category-list>
                <category value="visual"/>
                <category value="paged"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="integer"/>
            </regexp-list>
        </property>
        <property name="outline-color" default="invert" description="">
            <category-list>
                <category value="visual"/>
                <category value="interactive"/>
            </category-list>
            <literal-list>
                <literal value="invert"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
        </property>
        <property name="overflow" default="visible" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="visible"/>
                <literal value="hidden"/>
                <literal value="scroll"/>
                <literal value="auto"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="page-break-after" default="auto" description="">
            <category-list>
                <category value="visual"/>
                <category value="paged"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="always"/>
                <literal value="avoid"/>
                <literal value="left"/>
                <literal value="right"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="page-break-before" default="auto" description="">
            <category-list>
                <category value="visual"/>
                <category value="paged"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="always"/>
                <literal value="avoid"/>
                <literal value="left"/>
                <literal value="right"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="page-break-inside" default="auto" description="">
            <category-list>
                <category value="visual"/>
                <category value="paged"/>
            </category-list>
            <literal-list>
                <literal value="avoid"/>
                <literal value="auto"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="pause-after" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="time"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="pause-before" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="time"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="pitch" default="medium" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="x-low"/>
                <literal value="low"/>
                <literal value="medium"/>
                <literal value="high"/>
                <literal value="x-high"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="frequency"/>
            </regexp-list>
        </property>
        <property name="pitch-range" default="50" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="number"/>
            </regexp-list>
        </property>
        <property name="position" default="static" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="static"/>
                <!-- possible to perform phishing attacks with the following -->
                <!--
                <literal value="relative"/>
                <literal value="absolute"/>
                <literal value="fixed"/>
                 -->
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="richness" default="50" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="number"/>
            </regexp-list>
        </property>
        <property name="right" default="auto" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="size" default="auto" description="">
            <category-list>
                <category value="visual"/>
                <category value="paged"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="portrait"/>
                <literal value="landscape"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
            </regexp-list>
        </property>
        <property name="speak" default="normal" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="normal"/>
                <literal value="none"/>
                <literal value="spell-out"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="speak-header" default="once" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="once"/>
                <literal value="always"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="speak-numeral" default="continuous" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="digits"/>
                <literal value="continuous"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="speak-punctuation" default="none" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="code"/>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="speech-rate" default="medium" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="x-slow"/>
                <literal value="slow"/>
                <literal value="medium"/>
                <literal value="fast"/>
                <literal value="x-fast"/>
                <literal value="faster"/>
                <literal value="slower"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="number"/>
            </regexp-list>
        </property>
        <property name="stress" default="50" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="number"/>
            </regexp-list>
        </property>
        <property name="table-layout" default="auto" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="fixed"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="text-indent" default="0" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="text-transform" default="none" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="capitalize"/>
                <literal value="uppercase"/>
                <literal value="lowercase"/>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="top" default="auto" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="unicode-bidi" default="normal" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="normal"/>
                <literal value="embed"/>
                <literal value="bidi-override"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="vertical-align" default="baseline" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="baseline"/>
                <literal value="sub"/>
                <literal value="super"/>
                <literal value="top"/>
                <literal value="text-top"/>
                <literal value="middle"/>
                <literal value="bottom"/>
                <literal value="text-bottom"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="percentage"/>
                <regexp name="length"/>
            </regexp-list>
        </property>
        <property name="visibility" default="inherit" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="visible"/>
                <literal value="hidden"/>
                <literal value="collapse"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="volume" default="medium" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="silent"/>
                <literal value="x-soft"/>
                <literal value="soft"/>
                <literal value="medium"/>
                <literal value="loud"/>
                <literal value="x-loud"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="number"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="white-space" default="normal" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="normal"/>
                <literal value="pre"/>
                <literal value="nowrap"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="widows" default="2" description="">
            <category-list>
                <category value="visual"/>
                <category value="paged"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="integer"/>
            </regexp-list>
        </property>
        <property name="width" default="auto" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="word-spacing" default="normal" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="normal"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
            </regexp-list>
        </property>
        <!-- end simple properties -->
        <!-- begin medium properties -->
        <property name="border-style" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
                <literal value="none"/>
                <literal value="hidden"/>
                <literal value="dotted"/>
                <literal value="dashed"/>
                <literal value="solid"/>
                <literal value="double"/>
                <literal value="groove"/>
                <literal value="ridge"/>
                <literal value="inset"/>
                <literal value="outset"/>
            </literal-list>
        </property>
        <property name="border-top-style" default="none" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="border-right-style" default="none" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="border-style"/>
            </shorthand-list>
        </property>
        <property name="border-bottom-style" default="none" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="border-style"/>
            </shorthand-list>
        </property>
        <property name="border-left-style" default="none" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="border-style"/>
            </shorthand-list>
        </property>
        <property name="border-top-width" default="medium" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="border-width"/>
            </shorthand-list>
        </property>
        <property name="border-right-width" default="medium" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="border-width"/>
            </shorthand-list>
        </property>
        <property name="border-bottom-width" default="medium" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="border-width"/>
            </shorthand-list>
        </property>
        <property name="border-left-width" default="medium" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="border-width"/>
            </shorthand-list>
        </property>
        <property name="border-width" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
                <literal value="thin"/>
                <literal value="medium"/>
                <literal value="thick"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
            </regexp-list>
        </property>
        <property name="margin" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
                <literal value="auto"/>
            </literal-list>
            <regexp-list>
                <regexp name="positiveLength"/>
                <regexp name="positivePercentage"/>
            </regexp-list>
        </property>
        <property name="margin-top" default="0" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="margin"/>
            </shorthand-list>
        </property>
        <property name="margin-right" default="0" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="margin"/>
            </shorthand-list>
        </property>
        <property name="margin-bottom" default="0" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="margin"/>
            </shorthand-list>
        </property>
        <property name="margin-left" default="0" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="margin"/>
            </shorthand-list>
        </property>
        <property name="outline-style" default="none" description="">
            <category-list>
                <category value="visual"/>
                <category value="interactive"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="border-style"/>
            </shorthand-list>
        </property>
        <property name="outline-width" default="medium" description="">
            <category-list>
                <category value="visual"/>
                <category value="interactive"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="border-width"/>
            </shorthand-list>
        </property>
        <property name="padding" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="padding-top" default="0" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="padding"/>
            </shorthand-list>
        </property>
        <property name="padding-right" default="0" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="padding"/>
            </shorthand-list>
        </property>
        <property name="padding-bottom" default="0" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="padding"/>
            </shorthand-list>
        </property>
        <property name="padding-left" default="0" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="padding"/>
            </shorthand-list>
        </property>
        <!-- end medium properties -->
        <!-- begin hard properties -->
        <property name="border" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
            <shorthand-list>
                <shorthand name="border-width"/>
                <shorthand name="border-style"/>
            </shorthand-list>
        </property>
        <property name="border-top" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
            <shorthand-list>
                <shorthand name="border-top-width"/>
                <shorthand name="border-style"/>
            </shorthand-list>
        </property>
        <property name="border-right" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
            <shorthand-list>
                <shorthand name="border-top-width"/>
                <shorthand name="border-style"/>
            </shorthand-list>
        </property>
        <property name="border-bottom" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
            <shorthand-list>
                <shorthand name="border-top-width"/>
                <shorthand name="border-style"/>
            </shorthand-list>
        </property>
        <property name="border-left" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
            </regexp-list>
            <shorthand-list>
                <shorthand name="border-top-width"/>
                <shorthand name="border-style"/>
            </shorthand-list>
        </property>
        <property name="cue" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="cue-before"/>
                <shorthand name="cue-after"/>
            </shorthand-list>
        </property>
        <property name="list-style" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="list-style-type"/>
                <shorthand name="list-style-position"/>
                <shorthand name="list-style-image"/>
            </shorthand-list>
        </property>
        <property name="marks" default="none" description="">
            <category-list>
                <category value="visual"/>
                <category value="paged"/>
            </category-list>
            <literal-list>
                <literal value="crop"/>
                <literal value="cross"/>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="outline" description="">
            <category-list>
                <category value="visual"/>
                <category value="interactive"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="outline-color"/>
                <shorthand name="outline-style"/>
                <shorthand name="outline-width"/>
            </shorthand-list>
        </property>
        <property name="pause" description="">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="time"/>
                <regexp name="percentage"/>
            </regexp-list>
        </property>
        <property name="text-decoration" default="none" description="">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="none"/>
                <literal value="underline"/>
                <literal value="overline"/>
                <literal value="line-through"/>
                <literal value="blink"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <!-- end hard properties -->
        <!--  begin manual properties -->
        <property name="border-spacing" default="0" description="The lengths specify the distance that separates adjacent cell borders. If one length is specified, it gives both the horizontal and vertical spacing. If two are specified, the first gives the horizontal spacing and the second the vertical spacing. Lengths may not be negative.">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
            </regexp-list>
        </property>
        <property name="clip" default="auto" description="The 'clip' property applies to elements that have a 'overflow' property with a value other than 'visible'.">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
            </regexp-list>
        </property>
        <property name="counter-increment" default="none" description="The 'counter-increment' property accepts one or more names of counters (identifiers), each one optionally followed by an integer.">
            <category-list>
                <category value="all"/>
            </category-list>
            <literal-list>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="cssIdentifier"/>
                <regexp name="integer"/>
            </regexp-list>
        </property>
        <property name="clip" default="auto" description="The 'clip' property applies to elements that have a 'overflow' property with a value other than 'visible'.">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="length"/>
            </regexp-list>
        </property>
        <property name="cursor" default="auto" description="This property specifies the type of cursor to be displayed for the pointing device.">
            <category-list>
                <category value="visual"/>
                <category value="interactive"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
                <literal value="inherit"/>
                <literal value="crosshair"/>
                <literal value="default"/>
                <literal value="pointer"/>
                <literal value="move"/>
                <literal value="e-resize"/>
                <literal value="ne-resize"/>
                <literal value="nw-resize"/>
                <literal value="n-resize"/>
                <literal value="se-resize"/>
                <literal value="sw-resize"/>
                <literal value="s-resize"/>
                <literal value="w-resize| text"/>
                <literal value="wait"/>
                <literal value="help"/>
            </literal-list>
            <regexp-list>
                <regexp name="cssOffsiteUri"/>
                <regexp name="cssOnsiteUri"/>
            </regexp-list>
        </property>
        <property name="text-shadow" default="none" description="This property accepts a comma-separated list of shadow effects to be applied to the text of the element.">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="none"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="colorName"/>
                <regexp name="colorCode"/>
                <regexp name="rgbCode"/>
                <regexp name="systemColor"/>
                <regexp name="length"/>
            </regexp-list>
        </property>
        <property name="font" description="The 'font' property is, except as described below, a shorthand property for setting 'font-style', 'font-variant', 'font-weight', 'font-size', 'line-height', and 'font-family', at the same place in the style sheet.">
            <category-list>
                <category value="visual"/>
            </category-list>
            <literal-list>
                <literal value="/"/>
                <literal value="caption"/>
                <literal value="icon"/>
                <literal value="menu"/>
                <literal value="message-box"/>
                <literal value="small-caption"/>
                <literal value="status-bar"/>
                <literal value="inherit"/>
            </literal-list>
            <shorthand-list>
                <shorthand name="font-style"/>
                <shorthand name="font-variant"/>
                <shorthand name="font-weight"/>
                <shorthand name="font-size"/>
                <shorthand name="line-height"/>
                <shorthand name="font-family"/>
            </shorthand-list>
        </property>
        <property name="font-family" description="This property specifies a prioritized list of font family names and/or generic family names.">
            <category-list>
                <category value="visual"/>
            </category-list>
            <!-- allowing only generic font families -->
            <literal-list>
                <literal value="serif"/>
                <literal value="arial"/>
                <literal value="lucida console"/>
                <literal value="sans-serif"/>
                <literal value="cursive"/>
                <literal value="verdana"/>
                <literal value="fantasy"/>
                <literal value="monospace"/>
            </literal-list>
            <regexp-list>
                <regexp value="[\w,\-&apos;&quot; ]+"/>
            </regexp-list>
        </property>
        <property name="page" description="The 'page' property can be used to specify a particular type of page where an element should be displayed.">
            <category-list>
                <category value="visual"/>
                <category value="paged"/>
            </category-list>
            <literal-list>
                <literal value="auto"/>
            </literal-list>
            <regexp-list>
                <regexp name="cssIdentifier"/>
            </regexp-list>
        </property>
        <property name="play-during" default="auto" description="Similar to the 'cue-before' and 'cue-after' properties, this property specifies a sound to be played as a background while an element's content is spoken.">
            <category-list>
                <category value="aural"/>
            </category-list>
            <literal-list>
                <literal value="mix"/>
                <literal value="repeat"/>
                <literal value="none"/>
                <literal value="auto"/>
                <literal value="inherit"/>
            </literal-list>
            <regexp-list>
                <regexp name="cssOffsiteUri"/>
                <regexp name="cssOnsiteUri"/>
            </regexp-list>
        </property>
        <property name="text-align" description="This property describes how inline content of a block is aligned.">
            <category-list>
                <category value="visual"/>
            </category-list>
            <!--  For safety, ignoring string alignment which can be used to line table cells on characters -->
            <literal-list>
                <literal value="left"/>
                <literal value="right"/>
                <literal value="center"/>
                <literal value="justify"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <property name="voice-family" description="The value is a comma-separated, prioritized list of voice family names (compare with 'font-family').">
            <category-list>
                <category value="aural"/>
            </category-list>
            <!--  Allowing only generic voice family -->
            <literal-list>
                <literal value="male"/>
                <literal value="female"/>
                <literal value="child"/>
                <literal value="inherit"/>
            </literal-list>
        </property>
        <!--  end manual properties -->
    </css-rules>
    <allowed-empty-tags>
        <literal-list>
            <literal value="br"/>
            <literal value="hr"/>
            <literal value="a"/>
            <literal value="img"/>
            <literal value="link"/>
            <literal value="iframe"/>
            <literal value="script"/>
            <literal value="object"/>
            <literal value="applet"/>
            <literal value="frame"/>
            <literal value="base"/>
            <literal value="param"/>
            <literal value="meta"/>
            <literal value="input"/>
            <literal value="textarea"/>
            <literal value="embed"/>
            <literal value="basefont"/>
            <literal value="col"/>
            <literal value="div"/>
        </literal-list>
    </allowed-empty-tags>
</anti-samy-rules>
Diff truncated after the above file
ecosphere/pom.xml