From e8e6c3bf222df50cce71681491f3f36e723035b2 Mon Sep 17 00:00:00 2001 From: RuicyWu <1063154311@qq.com> Date: Thu, 15 Jan 2026 17:35:00 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 39 +++ extLib/chinaumsdk/.gitignore | 1 + extLib/chinaumsdk/.idea/.gitignore | 5 + extLib/chinaumsdk/.idea/compiler.xml | 13 + extLib/chinaumsdk/.idea/encodings.xml | 7 + extLib/chinaumsdk/.idea/jarRepositories.xml | 25 ++ extLib/chinaumsdk/.idea/misc.xml | 12 + extLib/chinaumsdk/chinaumsdk.jar | Bin 0 -> 57279 bytes extLib/chinaumsdk/pom.xml | 52 ++++ .../open/api/DefaultOpenApiClient.java | 105 +++++++ .../com/chinaums/open/api/OpenApiCache.java | 40 +++ .../com/chinaums/open/api/OpenApiClient.java | 13 + .../com/chinaums/open/api/OpenApiContext.java | 151 ++++++++++ .../chinaums/open/api/OpenApiException.java | 49 +++ .../com/chinaums/open/api/OpenApiParser.java | 27 ++ .../com/chinaums/open/api/OpenApiRequest.java | 25 ++ .../chinaums/open/api/OpenApiResponse.java | 27 ++ .../open/api/annotation/ApiField.java | 22 ++ .../open/api/constants/ConfigBean.java | 82 ++++++ .../open/api/constants/Constants.java | 24 ++ .../open/api/internal/util/DateUtils.java | 40 +++ .../open/api/internal/util/FieldUtils.java | 203 +++++++++++++ .../open/api/internal/util/OpenApiLogger.java | 56 ++++ .../api/internal/util/OpenBodySigUtil.java | 68 +++++ .../open/api/internal/util/OpenTokenUtil.java | 135 +++++++++ .../internal/util/converter/Converter.java | 14 + .../util/converter/JsonConverter.java | 37 +++ .../api/internal/util/http/HttpTransport.java | 160 ++++++++++ .../internal/util/http/IHttpTransport.java | 11 + .../api/parser/json/ObjectJsonParser.java | 100 +++++++ .../api/request/AcpInstallmentRequest.java | 95 ++++++ .../open/api/request/BankVerifyRequest.java | 46 +++ .../open/api/request/CourtQueryRequest.java | 44 +++ .../request/EducationInfoVerifyRequest.java | 45 +++ .../FacerecognitionParamComposeRequest.java | 44 +++ ...acerecognitionParamResultQueryRequest.java | 44 +++ .../FacerecognitionParamResultSetRequest.java | 44 +++ .../api/request/GenericTagQueryRequest.java | 45 +++ .../open/api/request/IdCardVerifyRequest.java | 46 +++ .../api/request/IdCheckSimpleInfoRequest.java | 56 ++++ .../request/Mobile3factorVerifyRequest.java | 47 +++ .../api/request/NyBankCardTagRequest.java | 46 +++ .../api/request/RealNameVerifyRequest.java | 46 +++ .../open/api/request/TokenRequest.java | 111 +++++++ .../api/request/YsBankCardTagRequest.java | 46 +++ .../api/response/AcpInstallmentResponse.java | 89 ++++++ .../open/api/response/BankVerifyResponse.java | 40 +++ .../open/api/response/CourtQueryResponse.java | 42 +++ .../response/EducationInfoVerifyResponse.java | 42 +++ .../FacerecognitionParamComposeResponse.java | 42 +++ ...cerecognitionParamResultQueryResponse.java | 42 +++ ...FacerecognitionParamResultSetResponse.java | 42 +++ .../api/response/GenericTagQueryResponse.java | 42 +++ .../api/response/IdCardVerifyResponse.java | 42 +++ .../response/IdCheckSimpleInfoResponse.java | 52 ++++ .../response/Mobile3factorVerifyResponse.java | 42 +++ .../api/response/NyBankCardTagResponse.java | 42 +++ .../api/response/RealNameVerifyResponse.java | 42 +++ .../open/api/response/TokenResponse.java | 78 +++++ .../api/response/YsBankCardTagResponse.java | 42 +++ .../internal/util/http/HttpTransportTest.java | 49 +++ .../chinaums/test/BankCardTagTestCase.java | 49 +++ .../chinaums/test/FacerecognitionTest.java | 57 ++++ .../test/IdCheckSimpleInfoTestCase.java | 63 ++++ .../com/chinaums/test/InstallmentTest.java | 33 +++ .../com/chinaums/test/PosLinkTestCase.java | 36 +++ .../chinaums/test/RealNameVerifyTestCase.java | 78 +++++ .../test/SmartverificationTestCase.java | 152 ++++++++++ .../java/com/chinaums/test/TokenTestCase.java | 29 ++ .../com/chinaums/test/TokenTestCaseDev.java | 29 ++ .../com/chinaums/test/UniqueTestCase.java | 33 +++ extLib/commons-codec-1.9.jar | Bin 0 -> 263965 bytes pom.xml | 241 +++++++++++++++ src/main/java/org/chenyon/WepApplication.java | 13 + .../org/chenyon/assets/AssetsController.java | 66 +++++ .../chenyon/assets/AssetsQueryService.java | 88 ++++++ .../assets/vo/AssetsPageQueryCondition.java | 88 ++++++ .../java/org/chenyon/assets/vo/AssetsVo.java | 199 +++++++++++++ .../java/org/chenyon/auth/AuthController.java | 51 ++++ .../java/org/chenyon/bill/BillController.java | 98 ++++++ .../org/chenyon/bill/BillQueryCondition.java | 34 +++ .../java/org/chenyon/bill/BillService.java | 42 +++ .../chenyon/bill/PayRecordQueryConditon.java | 42 +++ .../java/org/chenyon/cache/WxTokenCache.java | 23 ++ .../chenyon/config/SpringMvcConfigurer.java | 64 ++++ .../java/org/chenyon/constants/OaApiUrl.java | 116 ++++++++ .../chenyon/contract/ContractAssetsVo.java | 68 +++++ .../chenyon/contract/ContractController.java | 103 +++++++ .../contract/ContractQueryCondition.java | 52 ++++ .../org/chenyon/contract/ContractService.java | 149 ++++++++++ .../java/org/chenyon/contract/ContractVo.java | 107 +++++++ .../java/org/chenyon/contract/FeeUnit.java | 6 + .../org/chenyon/contract/RentFeeInfo.java | 59 ++++ .../DisChargeApplyQueryCondition.java | 15 + .../chenyon/discharge/DisChargeApplyVo.java | 87 ++++++ .../discharge/DisChargeController.java | 60 ++++ .../chenyon/discharge/DisChargeRecordVo.java | 58 ++++ .../chenyon/fallback/FallbackController.java | 73 +++++ .../fallback/FallbackQueryCondition.java | 24 ++ .../chenyon/fallback/FallbackSubmitVo.java | 67 +++++ .../java/org/chenyon/fallback/FallbackVo.java | 58 ++++ .../org/chenyon/file/OaFileFindCondition.java | 43 +++ .../chenyon/file/OaFileHandlerService.java | 147 +++++++++ .../java/org/chenyon/file/OaFileLocalRef.java | 65 ++++ .../org/chenyon/file/OaFileLocalRefDao.java | 7 + .../org/chenyon/file/OaFileLocalRefDao.xml | 28 ++ .../org/chenyon/file/OaFileLocalRefVo.java | 79 +++++ .../org/chenyon/file/OaFileLocalSubRef.java | 38 +++ .../chenyon/file/OaFileLocalSubRefDao.java | 10 + .../org/chenyon/file/OaFileLocalSubRefDao.xml | 12 + src/main/java/org/chenyon/file/OaFileVo.java | 26 ++ .../global/GlobalExceptionHandler.java | 24 ++ .../interceptor/LoginCheckInterceptor.java | 96 ++++++ .../chenyon/location/IpLocationService.java | 25 ++ .../chenyon/location/LocateController.java | 28 ++ .../java/org/chenyon/message/Message.java | 74 +++++ .../chenyon/message/MessageController.java | 80 +++++ .../java/org/chenyon/message/MessageDao.java | 10 + .../java/org/chenyon/message/MessageDao.xml | 31 ++ .../message/MessageQueryCondition.java | 16 + .../org/chenyon/message/MessageService.java | 73 +++++ .../java/org/chenyon/message/MessageType.java | 11 + .../java/org/chenyon/message/MessageVo.java | 76 +++++ .../org/chenyon/notice/NoticeController.java | 40 +++ .../chenyon/notice/NoticeQueryCondition.java | 6 + .../java/org/chenyon/notice/NoticeVo.java | 115 ++++++++ .../java/org/chenyon/oa/OaAssetService.java | 52 ++++ .../java/org/chenyon/oa/OaBillService.java | 94 ++++++ .../org/chenyon/oa/OaContractService.java | 77 +++++ .../java/org/chenyon/oa/OaCusService.java | 61 ++++ .../org/chenyon/oa/OaDisChargeService.java | 49 +++ .../org/chenyon/oa/OaFallBackService.java | 57 ++++ .../java/org/chenyon/oa/OaNoticeService.java | 47 +++ .../org/chenyon/oa/OaPotentialService.java | 21 ++ .../org/chenyon/oa/OaReservationService.java | 59 ++++ src/main/java/org/chenyon/oa/OaResp.java | 40 +++ .../java/org/chenyon/oa/SeeyonHttpClient.java | 147 +++++++++ .../java/org/chenyon/oa/asset/OaAssetsVo.java | 243 +++++++++++++++ .../java/org/chenyon/oa/bill/OaBillVo.java | 112 +++++++ .../org/chenyon/oa/bill/OaPayRecordVo.java | 59 ++++ .../org/chenyon/oa/contract/OaContractVo.java | 99 +++++++ src/main/java/org/chenyon/oa/cus/OaCusVo.java | 59 ++++ .../org/chenyon/oa/notice/OaNoticeVo.java | 4 + src/main/java/org/chenyon/pay/Goods.java | 110 +++++++ src/main/java/org/chenyon/pay/Order.java | 52 ++++ .../java/org/chenyon/pay/RetCommParams.java | 32 ++ src/main/java/org/chenyon/pay/SubOrder.java | 37 +++ .../chenyon/pay/TmPayApiContextBuilder.java | 27 ++ .../java/org/chenyon/pay/TmPayService.java | 44 +++ .../org/chenyon/pay/UnifiedOrderRequest.java | 198 +++++++++++++ .../potential/PotentialController.java | 51 ++++ .../chenyon/potential/PotentialService.java | 17 ++ .../org/chenyon/potential/ViewRecordVo.java | 41 +++ .../reservation/ReservateController.java | 74 +++++ .../ReservationQueryCondition.java | 15 + .../reservation/ReservationSubmitVo.java | 58 ++++ .../chenyon/reservation/ReservationVo.java | 94 ++++++ .../java/org/chenyon/user/AuthInfoVo.java | 23 ++ src/main/java/org/chenyon/user/CusVo.java | 25 ++ .../java/org/chenyon/user/LoginCheck.java | 9 + .../org/chenyon/user/LoginController.java | 94 ++++++ src/main/java/org/chenyon/user/LoginVo.java | 34 +++ src/main/java/org/chenyon/user/User.java | 84 ++++++ .../java/org/chenyon/user/UserContext.java | 70 +++++ src/main/java/org/chenyon/user/UserDao.java | 8 + src/main/java/org/chenyon/user/UserDao.xml | 9 + .../java/org/chenyon/user/UserService.java | 78 +++++ src/main/java/org/chenyon/user/UserVo.java | 61 ++++ .../org/chenyon/utils/HmacSha256Util.java | 85 ++++++ src/main/java/org/chenyon/utils/RSAUtil.java | 28 ++ .../java/org/chenyon/wx/AesException.java | 59 ++++ src/main/java/org/chenyon/wx/ByteGroup.java | 26 ++ .../java/org/chenyon/wx/PKCS7Encoder.java | 59 ++++ src/main/java/org/chenyon/wx/SHA1.java | 53 ++++ .../java/org/chenyon/wx/WXBizMsgCrypt.java | 278 ++++++++++++++++++ .../chenyon/wx/WeChatAccessTokenService.java | 71 +++++ src/main/java/org/chenyon/wx/WeChatApi.java | 31 ++ .../java/org/chenyon/wx/WeChatAuthInfo.java | 31 ++ .../java/org/chenyon/wx/WxUserSession.java | 72 +++++ .../java/org/chenyon/wx/WxUserSessionDao.java | 9 + .../java/org/chenyon/wx/WxUserSessionDao.xml | 20 ++ .../org/chenyon/wx/WxUserSessionService.java | 79 +++++ src/main/java/org/chenyon/wx/XMLParse.java | 64 ++++ src/main/scripts/shutdown.bat | 40 +++ src/main/scripts/shutdown.sh | 47 +++ src/main/scripts/startup.bat | 37 +++ src/main/scripts/startup.sh | 19 ++ 187 files changed, 10721 insertions(+) create mode 100644 .gitignore create mode 100644 extLib/chinaumsdk/.gitignore create mode 100644 extLib/chinaumsdk/.idea/.gitignore create mode 100644 extLib/chinaumsdk/.idea/compiler.xml create mode 100644 extLib/chinaumsdk/.idea/encodings.xml create mode 100644 extLib/chinaumsdk/.idea/jarRepositories.xml create mode 100644 extLib/chinaumsdk/.idea/misc.xml create mode 100644 extLib/chinaumsdk/chinaumsdk.jar create mode 100644 extLib/chinaumsdk/pom.xml create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/DefaultOpenApiClient.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiCache.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiClient.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiContext.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiException.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiParser.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiRequest.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiResponse.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/annotation/ApiField.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/constants/ConfigBean.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/constants/Constants.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/DateUtils.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/FieldUtils.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/OpenApiLogger.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/OpenBodySigUtil.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/OpenTokenUtil.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/converter/Converter.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/converter/JsonConverter.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/http/HttpTransport.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/http/IHttpTransport.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/parser/json/ObjectJsonParser.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/AcpInstallmentRequest.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/BankVerifyRequest.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/CourtQueryRequest.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/EducationInfoVerifyRequest.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/FacerecognitionParamComposeRequest.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/FacerecognitionParamResultQueryRequest.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/FacerecognitionParamResultSetRequest.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/GenericTagQueryRequest.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/IdCardVerifyRequest.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/IdCheckSimpleInfoRequest.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/Mobile3factorVerifyRequest.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/NyBankCardTagRequest.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/RealNameVerifyRequest.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/TokenRequest.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/YsBankCardTagRequest.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/AcpInstallmentResponse.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/BankVerifyResponse.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/CourtQueryResponse.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/EducationInfoVerifyResponse.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/FacerecognitionParamComposeResponse.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/FacerecognitionParamResultQueryResponse.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/FacerecognitionParamResultSetResponse.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/GenericTagQueryResponse.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/IdCardVerifyResponse.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/IdCheckSimpleInfoResponse.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/Mobile3factorVerifyResponse.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/NyBankCardTagResponse.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/RealNameVerifyResponse.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/TokenResponse.java create mode 100644 extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/YsBankCardTagResponse.java create mode 100644 extLib/chinaumsdk/src/test/java/com/chinaums/open/api/internal/util/http/HttpTransportTest.java create mode 100644 extLib/chinaumsdk/src/test/java/com/chinaums/test/BankCardTagTestCase.java create mode 100644 extLib/chinaumsdk/src/test/java/com/chinaums/test/FacerecognitionTest.java create mode 100644 extLib/chinaumsdk/src/test/java/com/chinaums/test/IdCheckSimpleInfoTestCase.java create mode 100644 extLib/chinaumsdk/src/test/java/com/chinaums/test/InstallmentTest.java create mode 100644 extLib/chinaumsdk/src/test/java/com/chinaums/test/PosLinkTestCase.java create mode 100644 extLib/chinaumsdk/src/test/java/com/chinaums/test/RealNameVerifyTestCase.java create mode 100644 extLib/chinaumsdk/src/test/java/com/chinaums/test/SmartverificationTestCase.java create mode 100644 extLib/chinaumsdk/src/test/java/com/chinaums/test/TokenTestCase.java create mode 100644 extLib/chinaumsdk/src/test/java/com/chinaums/test/TokenTestCaseDev.java create mode 100644 extLib/chinaumsdk/src/test/java/com/chinaums/test/UniqueTestCase.java create mode 100644 extLib/commons-codec-1.9.jar create mode 100644 pom.xml create mode 100644 src/main/java/org/chenyon/WepApplication.java create mode 100644 src/main/java/org/chenyon/assets/AssetsController.java create mode 100644 src/main/java/org/chenyon/assets/AssetsQueryService.java create mode 100644 src/main/java/org/chenyon/assets/vo/AssetsPageQueryCondition.java create mode 100644 src/main/java/org/chenyon/assets/vo/AssetsVo.java create mode 100644 src/main/java/org/chenyon/auth/AuthController.java create mode 100644 src/main/java/org/chenyon/bill/BillController.java create mode 100644 src/main/java/org/chenyon/bill/BillQueryCondition.java create mode 100644 src/main/java/org/chenyon/bill/BillService.java create mode 100644 src/main/java/org/chenyon/bill/PayRecordQueryConditon.java create mode 100644 src/main/java/org/chenyon/cache/WxTokenCache.java create mode 100644 src/main/java/org/chenyon/config/SpringMvcConfigurer.java create mode 100644 src/main/java/org/chenyon/constants/OaApiUrl.java create mode 100644 src/main/java/org/chenyon/contract/ContractAssetsVo.java create mode 100644 src/main/java/org/chenyon/contract/ContractController.java create mode 100644 src/main/java/org/chenyon/contract/ContractQueryCondition.java create mode 100644 src/main/java/org/chenyon/contract/ContractService.java create mode 100644 src/main/java/org/chenyon/contract/ContractVo.java create mode 100644 src/main/java/org/chenyon/contract/FeeUnit.java create mode 100644 src/main/java/org/chenyon/contract/RentFeeInfo.java create mode 100644 src/main/java/org/chenyon/discharge/DisChargeApplyQueryCondition.java create mode 100644 src/main/java/org/chenyon/discharge/DisChargeApplyVo.java create mode 100644 src/main/java/org/chenyon/discharge/DisChargeController.java create mode 100644 src/main/java/org/chenyon/discharge/DisChargeRecordVo.java create mode 100644 src/main/java/org/chenyon/fallback/FallbackController.java create mode 100644 src/main/java/org/chenyon/fallback/FallbackQueryCondition.java create mode 100644 src/main/java/org/chenyon/fallback/FallbackSubmitVo.java create mode 100644 src/main/java/org/chenyon/fallback/FallbackVo.java create mode 100644 src/main/java/org/chenyon/file/OaFileFindCondition.java create mode 100644 src/main/java/org/chenyon/file/OaFileHandlerService.java create mode 100644 src/main/java/org/chenyon/file/OaFileLocalRef.java create mode 100644 src/main/java/org/chenyon/file/OaFileLocalRefDao.java create mode 100644 src/main/java/org/chenyon/file/OaFileLocalRefDao.xml create mode 100644 src/main/java/org/chenyon/file/OaFileLocalRefVo.java create mode 100644 src/main/java/org/chenyon/file/OaFileLocalSubRef.java create mode 100644 src/main/java/org/chenyon/file/OaFileLocalSubRefDao.java create mode 100644 src/main/java/org/chenyon/file/OaFileLocalSubRefDao.xml create mode 100644 src/main/java/org/chenyon/file/OaFileVo.java create mode 100644 src/main/java/org/chenyon/global/GlobalExceptionHandler.java create mode 100644 src/main/java/org/chenyon/interceptor/LoginCheckInterceptor.java create mode 100644 src/main/java/org/chenyon/location/IpLocationService.java create mode 100644 src/main/java/org/chenyon/location/LocateController.java create mode 100644 src/main/java/org/chenyon/message/Message.java create mode 100644 src/main/java/org/chenyon/message/MessageController.java create mode 100644 src/main/java/org/chenyon/message/MessageDao.java create mode 100644 src/main/java/org/chenyon/message/MessageDao.xml create mode 100644 src/main/java/org/chenyon/message/MessageQueryCondition.java create mode 100644 src/main/java/org/chenyon/message/MessageService.java create mode 100644 src/main/java/org/chenyon/message/MessageType.java create mode 100644 src/main/java/org/chenyon/message/MessageVo.java create mode 100644 src/main/java/org/chenyon/notice/NoticeController.java create mode 100644 src/main/java/org/chenyon/notice/NoticeQueryCondition.java create mode 100644 src/main/java/org/chenyon/notice/NoticeVo.java create mode 100644 src/main/java/org/chenyon/oa/OaAssetService.java create mode 100644 src/main/java/org/chenyon/oa/OaBillService.java create mode 100644 src/main/java/org/chenyon/oa/OaContractService.java create mode 100644 src/main/java/org/chenyon/oa/OaCusService.java create mode 100644 src/main/java/org/chenyon/oa/OaDisChargeService.java create mode 100644 src/main/java/org/chenyon/oa/OaFallBackService.java create mode 100644 src/main/java/org/chenyon/oa/OaNoticeService.java create mode 100644 src/main/java/org/chenyon/oa/OaPotentialService.java create mode 100644 src/main/java/org/chenyon/oa/OaReservationService.java create mode 100644 src/main/java/org/chenyon/oa/OaResp.java create mode 100644 src/main/java/org/chenyon/oa/SeeyonHttpClient.java create mode 100644 src/main/java/org/chenyon/oa/asset/OaAssetsVo.java create mode 100644 src/main/java/org/chenyon/oa/bill/OaBillVo.java create mode 100644 src/main/java/org/chenyon/oa/bill/OaPayRecordVo.java create mode 100644 src/main/java/org/chenyon/oa/contract/OaContractVo.java create mode 100644 src/main/java/org/chenyon/oa/cus/OaCusVo.java create mode 100644 src/main/java/org/chenyon/oa/notice/OaNoticeVo.java create mode 100644 src/main/java/org/chenyon/pay/Goods.java create mode 100644 src/main/java/org/chenyon/pay/Order.java create mode 100644 src/main/java/org/chenyon/pay/RetCommParams.java create mode 100644 src/main/java/org/chenyon/pay/SubOrder.java create mode 100644 src/main/java/org/chenyon/pay/TmPayApiContextBuilder.java create mode 100644 src/main/java/org/chenyon/pay/TmPayService.java create mode 100644 src/main/java/org/chenyon/pay/UnifiedOrderRequest.java create mode 100644 src/main/java/org/chenyon/potential/PotentialController.java create mode 100644 src/main/java/org/chenyon/potential/PotentialService.java create mode 100644 src/main/java/org/chenyon/potential/ViewRecordVo.java create mode 100644 src/main/java/org/chenyon/reservation/ReservateController.java create mode 100644 src/main/java/org/chenyon/reservation/ReservationQueryCondition.java create mode 100644 src/main/java/org/chenyon/reservation/ReservationSubmitVo.java create mode 100644 src/main/java/org/chenyon/reservation/ReservationVo.java create mode 100644 src/main/java/org/chenyon/user/AuthInfoVo.java create mode 100644 src/main/java/org/chenyon/user/CusVo.java create mode 100644 src/main/java/org/chenyon/user/LoginCheck.java create mode 100644 src/main/java/org/chenyon/user/LoginController.java create mode 100644 src/main/java/org/chenyon/user/LoginVo.java create mode 100644 src/main/java/org/chenyon/user/User.java create mode 100644 src/main/java/org/chenyon/user/UserContext.java create mode 100644 src/main/java/org/chenyon/user/UserDao.java create mode 100644 src/main/java/org/chenyon/user/UserDao.xml create mode 100644 src/main/java/org/chenyon/user/UserService.java create mode 100644 src/main/java/org/chenyon/user/UserVo.java create mode 100644 src/main/java/org/chenyon/utils/HmacSha256Util.java create mode 100644 src/main/java/org/chenyon/utils/RSAUtil.java create mode 100644 src/main/java/org/chenyon/wx/AesException.java create mode 100644 src/main/java/org/chenyon/wx/ByteGroup.java create mode 100644 src/main/java/org/chenyon/wx/PKCS7Encoder.java create mode 100644 src/main/java/org/chenyon/wx/SHA1.java create mode 100644 src/main/java/org/chenyon/wx/WXBizMsgCrypt.java create mode 100644 src/main/java/org/chenyon/wx/WeChatAccessTokenService.java create mode 100644 src/main/java/org/chenyon/wx/WeChatApi.java create mode 100644 src/main/java/org/chenyon/wx/WeChatAuthInfo.java create mode 100644 src/main/java/org/chenyon/wx/WxUserSession.java create mode 100644 src/main/java/org/chenyon/wx/WxUserSessionDao.java create mode 100644 src/main/java/org/chenyon/wx/WxUserSessionDao.xml create mode 100644 src/main/java/org/chenyon/wx/WxUserSessionService.java create mode 100644 src/main/java/org/chenyon/wx/XMLParse.java create mode 100644 src/main/scripts/shutdown.bat create mode 100644 src/main/scripts/shutdown.sh create mode 100644 src/main/scripts/startup.bat create mode 100644 src/main/scripts/startup.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1e2867e --- /dev/null +++ b/.gitignore @@ -0,0 +1,39 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store +/config/ diff --git a/extLib/chinaumsdk/.gitignore b/extLib/chinaumsdk/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/extLib/chinaumsdk/.gitignore @@ -0,0 +1 @@ +/target diff --git a/extLib/chinaumsdk/.idea/.gitignore b/extLib/chinaumsdk/.idea/.gitignore new file mode 100644 index 0000000..a0ccf77 --- /dev/null +++ b/extLib/chinaumsdk/.idea/.gitignore @@ -0,0 +1,5 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Environment-dependent path to Maven home directory +/mavenHomeManager.xml diff --git a/extLib/chinaumsdk/.idea/compiler.xml b/extLib/chinaumsdk/.idea/compiler.xml new file mode 100644 index 0000000..9cc5329 --- /dev/null +++ b/extLib/chinaumsdk/.idea/compiler.xml @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/extLib/chinaumsdk/.idea/encodings.xml b/extLib/chinaumsdk/.idea/encodings.xml new file mode 100644 index 0000000..aa00ffa --- /dev/null +++ b/extLib/chinaumsdk/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/extLib/chinaumsdk/.idea/jarRepositories.xml b/extLib/chinaumsdk/.idea/jarRepositories.xml new file mode 100644 index 0000000..c7ea920 --- /dev/null +++ b/extLib/chinaumsdk/.idea/jarRepositories.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/extLib/chinaumsdk/.idea/misc.xml b/extLib/chinaumsdk/.idea/misc.xml new file mode 100644 index 0000000..d5cd614 --- /dev/null +++ b/extLib/chinaumsdk/.idea/misc.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/extLib/chinaumsdk/chinaumsdk.jar b/extLib/chinaumsdk/chinaumsdk.jar new file mode 100644 index 0000000000000000000000000000000000000000..5633aa80faad29f9802710e6c7c776538ac85796 GIT binary patch literal 57279 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 K?@imq|NbAGX^AfY literal 0 HcmV?d00001 diff --git a/extLib/chinaumsdk/pom.xml b/extLib/chinaumsdk/pom.xml new file mode 100644 index 0000000..a6f774a --- /dev/null +++ b/extLib/chinaumsdk/pom.xml @@ -0,0 +1,52 @@ + + 4.0.0 + com.chinaums.open + open-api-sdk + jar + 1.0-SNAPSHOT + open-api-sdk + http://maven.apache.org + + UTF-8 + + + + net.sf.json-lib + json-lib + 2.4 + jdk15 + + + commons-logging + commons-logging + 1.1.1 + + + com.squareup.okhttp3 + okhttp + 3.5.0 + + + org.apache.commons + commons-lang3 + 3.4 + + + com.google.guava + guava + 19.0 + + + junit + junit + 4.11 + test + + + commons-codec + commons-codec + 1.15 + + + diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/DefaultOpenApiClient.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/DefaultOpenApiClient.java new file mode 100644 index 0000000..84e212d --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/DefaultOpenApiClient.java @@ -0,0 +1,105 @@ +package com.chinaums.open.api; + +import com.chinaums.open.api.constants.ConfigBean; +import com.chinaums.open.api.internal.util.OpenApiLogger; +import com.chinaums.open.api.internal.util.http.HttpTransport; +import com.chinaums.open.api.parser.json.ObjectJsonParser; +import org.apache.commons.lang3.StringUtils; + +import java.util.UUID; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/2 + * Time: 14:22 + * 所属模块: + * 功能说明:开放平台客户端 + */ +public class DefaultOpenApiClient implements OpenApiClient { + private static final String constant_classname=DefaultOpenApiClient.class.getSimpleName(); + /** + * 开放平台URL + */ + private String serverUrl; + /** + * appId + */ + private String appId; + /** + * appKey + */ + private String appKey; + /** + * 字符集格式 + */ + private String encodeCharSet; + + public DefaultOpenApiClient(String serverUrl, String appId, String appKey) { + this.serverUrl = serverUrl; + this.appId = appId; + this.appKey = appKey; + } + + public DefaultOpenApiClient(String serverUrl, String appId, String appKey, String encodeCharSet) { + this.serverUrl = serverUrl; + this.appId = appId; + this.appKey = appKey; + this.encodeCharSet = encodeCharSet; + } + + public T execute(OpenApiRequest openApiRequest) throws OpenApiException { + return execute(openApiRequest,null,null); + } + + public T execute(OpenApiRequest openApiRequest, String token) throws OpenApiException { + return execute(openApiRequest,token,null); + } + + public T execute(OpenApiRequest openApiRequest, String token,String encodeCharSet) throws OpenApiException { + OpenApiParser openApiParser = new ObjectJsonParser(openApiRequest.responseClass()); + return execute_(openApiRequest,openApiParser,token,encodeCharSet); + } + + public T execute_(OpenApiRequest openApiRequest,OpenApiParser openApiParser,String token,String encodeCharSet){ + ConfigBean configBean = new ConfigBean(); + OpenApiContext context = new OpenApiContext(); + T trsp = null; + String response = ""; + try { + if(StringUtils.isBlank(serverUrl)) throw new OpenApiException("通讯地址未设置"); + if(StringUtils.isBlank(appId)) throw new OpenApiException("开发者appId未设置"); + if(StringUtils.isBlank(appKey)) throw new OpenApiException("开发者appKey未设置"); + String request = openApiParser.validRequest(openApiRequest); + context.setStartTime(System.currentTimeMillis()); + context.setRequestId(UUID.randomUUID().toString().replace("-","")); + context.setOpenServUrl(serverUrl); + String url = serverUrl.concat(openApiRequest.apiVersion()).concat(openApiRequest.serviceCode()); + context.setApiServiceUrl(url); + context.setApiMethodName(openApiRequest.apiMethodName()); + context.setVersion(openApiRequest.apiVersion()); + context.setAppId(appId); + context.setAppKey(appKey); + context.setConfigBean(configBean); + context.setServiceCode(openApiRequest.serviceCode()); + if(openApiRequest.needToken()){ + OpenApiCache.getCurrentToken(context); + response = HttpTransport.getInstance().doPost(context,request); + }else{ + response = HttpTransport.getInstance().doPost(configBean.isProd(),url,token,request); + } + if(StringUtils.isBlank(response)) throw new OpenApiException("服务提供方未返回"); + if(StringUtils.isNotBlank(encodeCharSet)){ + //encodeCharSet = configBean.getCharSet(); + trsp = openApiParser.parse(new String(response.getBytes(),encodeCharSet)); + }else{ + trsp = openApiParser.parse(response); + } + } catch (Exception e) { + OpenApiLogger.logError(constant_classname +" SDK异常:"+e.getStackTrace()); + e.printStackTrace(); + } + context.setEndTime(System.currentTimeMillis()); + return trsp; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiCache.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiCache.java new file mode 100644 index 0000000..ddf99ec --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiCache.java @@ -0,0 +1,40 @@ +package com.chinaums.open.api; + +import com.chinaums.open.api.internal.util.OpenTokenUtil; +import com.chinaums.open.api.response.TokenResponse; +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; + +import java.util.concurrent.TimeUnit; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/6 + * Time: 11:01 + * 所属模块: + * 功能说明:cache缓存 + */ +public class OpenApiCache { + + public final static int MAX_PROCESS_TIMEOUT = 3600; + + public static Cache contextCache = CacheBuilder.newBuilder() + .expireAfterWrite(MAX_PROCESS_TIMEOUT, TimeUnit.SECONDS).build(); + + /** + * 获取当前有效的token + * @param context + * @return + */ + public static TokenResponse getCurrentToken(OpenApiContext context){ + String appId = context.getAppId(); + TokenResponse token = (TokenResponse)contextCache.getIfPresent(appId); + if(token==null){ + token = OpenTokenUtil.getToken(context); + contextCache.put(context.getAppId(), token); + } + context.setCurrentToken(token); + return token; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiClient.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiClient.java new file mode 100644 index 0000000..c326c1e --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiClient.java @@ -0,0 +1,13 @@ +package com.chinaums.open.api; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/2 + * Time: 14:18 + * 所属模块: + * 功能说明: + */ +public abstract interface OpenApiClient { + public abstract T execute(OpenApiRequest openApiRequest) throws OpenApiException; +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiContext.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiContext.java new file mode 100644 index 0000000..03ed7c1 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiContext.java @@ -0,0 +1,151 @@ +package com.chinaums.open.api; + +import com.chinaums.open.api.constants.ConfigBean; +import com.chinaums.open.api.response.TokenResponse; + +import java.util.Map; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/6 + * Time: 10:17 + * 所属模块: + * 功能说明:api 处理报文上下文 + */ +public class OpenApiContext { + private String requestId; + private TokenResponse currentToken; + private long startTime; + private long endTime; + private String request; + private String response; + private Map params; + private String apiMethodName; + private String serviceCode; + private String openServUrl; + private String version; + private String appId; + private String appKey; + private ConfigBean configBean; + private String apiServiceUrl; + public String getRequestId() { + return requestId; + } + + public void setRequestId(String requestId) { + this.requestId = requestId; + } + + public TokenResponse getCurrentToken() { + return currentToken; + } + + public void setCurrentToken(TokenResponse currentToken) { + this.currentToken = currentToken; + } + + public long getStartTime() { + return startTime; + } + + public void setStartTime(long startTime) { + this.startTime = startTime; + } + + public long getEndTime() { + return endTime; + } + + public void setEndTime(long endTime) { + this.endTime = endTime; + } + + public String getRequest() { + return request; + } + + public void setRequest(String request) { + this.request = request; + } + + public String getResponse() { + return response; + } + + public void setResponse(String response) { + this.response = response; + } + + public Map getParams() { + return params; + } + + public void setParams(Map params) { + this.params = params; + } + + public String getServiceCode() { + return serviceCode; + } + + public void setServiceCode(String serviceCode) { + this.serviceCode = serviceCode; + } + + public String getApiMethodName() { + return apiMethodName; + } + + public void setApiMethodName(String apiMethodName) { + this.apiMethodName = apiMethodName; + } + + public String getOpenServUrl() { + return openServUrl; + } + + public void setOpenServUrl(String openServUrl) { + this.openServUrl = openServUrl; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getAppKey() { + return appKey; + } + + public void setAppKey(String appKey) { + this.appKey = appKey; + } + + public ConfigBean getConfigBean() { + return configBean; + } + + public void setConfigBean(ConfigBean configBean) { + this.configBean = configBean; + } + + public String getApiServiceUrl() { + return apiServiceUrl; + } + + public void setApiServiceUrl(String apiServiceUrl) { + this.apiServiceUrl = apiServiceUrl; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiException.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiException.java new file mode 100644 index 0000000..8bbd6cd --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiException.java @@ -0,0 +1,49 @@ +package com.chinaums.open.api; + +import java.io.Serializable; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/2 + * Time: 10:11 + * 所属模块: + * 功能说明: + */ +public class OpenApiException extends Exception implements Serializable{ + private String errCode; + private String errInfo; + public OpenApiException() {} + + public OpenApiException(String message, Throwable cause) + { + super(message, cause); + } + + public OpenApiException(String message) + { + super(message); + } + + public OpenApiException(Throwable cause) + { + super(cause); + } + + public OpenApiException(String errCode, String errInfo) + { + super(errCode + ":" + errInfo); + this.errCode = errCode; + this.errInfo = errInfo; + } + + public String getErrCode() + { + return this.errCode; + } + + public String getErrMsg() + { + return this.errInfo; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiParser.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiParser.java new file mode 100644 index 0000000..81e38c8 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiParser.java @@ -0,0 +1,27 @@ +package com.chinaums.open.api; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/2 + * Time: 14:27 + * 所属模块: + * 功能说明: + */ +public abstract interface OpenApiParser { + /** + * 返回内容格式转换 + * @param paramString + * @return + * @throws OpenApiException + */ + public abstract T parse(String paramString) throws OpenApiException; + + /** + * 请求参数检查 + * @param openApiRequest + * @return + * @throws OpenApiException + */ + public abstract String validRequest(OpenApiRequest openApiRequest) throws OpenApiException; +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiRequest.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiRequest.java new file mode 100644 index 0000000..c83335b --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiRequest.java @@ -0,0 +1,25 @@ +package com.chinaums.open.api; + +/** + * Created by ZHANGWEI on 2016/12/2. + */ +public abstract interface OpenApiRequest { + public abstract Class responseClass(); + /* + api版本号 + */ + public abstract String apiVersion(); + /* + api接口名称定义 + */ + public abstract String apiMethodName(); + /* + 开放平台分配servicecode + */ + public abstract String serviceCode(); + + /* + 是否需要获取token + */ + public abstract boolean needToken(); +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiResponse.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiResponse.java new file mode 100644 index 0000000..c7b8bf7 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/OpenApiResponse.java @@ -0,0 +1,27 @@ +package com.chinaums.open.api; + +import java.io.Serializable; + +/** + * Created by ZHANGWEI on 2016/12/2. + */ +public abstract class OpenApiResponse implements Serializable{ + private String errCode; + private String errInfo; + + public String getErrCode() { + return errCode; + } + + public void setErrCode(String errCode) { + this.errCode = errCode; + } + + public String getErrInfo() { + return errInfo; + } + + public void setErrInfo(String errInfo) { + this.errInfo = errInfo; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/annotation/ApiField.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/annotation/ApiField.java new file mode 100644 index 0000000..864d0a6 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/annotation/ApiField.java @@ -0,0 +1,22 @@ +package com.chinaums.open.api.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Created by ZHANGWEI on 2016/12/2. + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ApiField { + String key() default ""; + String name() default ""; + boolean required() default false; + int length() default -1; + int minLength() default -1; + int maxLength() default -1; + String index() default "0"; + String desc() default ""; +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/constants/ConfigBean.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/constants/ConfigBean.java new file mode 100644 index 0000000..add43c1 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/constants/ConfigBean.java @@ -0,0 +1,82 @@ +package com.chinaums.open.api.constants; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/4 + * Time: 21:22 + * 所属模块: + * 功能说明: + */ +public class ConfigBean { + /* + 字符集格式 + */ + private String charSet = "UTF-8"; + /* + 是否是生产环境 + */ + private boolean isProd = false; + + private String version = "v2"; + /** + * token申请失效后,重试次数 + */ + private int tokenAcquireReties = 3; + /** + * token提前申请的时间 + */ + private int tokenAcquireAheadInterval = 600; + /* + 获取token servicecode + */ + private String tokenServiceCode="/token/access"; + + public String getCharSet() { + return charSet; + } + + public void setCharSet(String charSet) { + this.charSet = charSet; + } + + public boolean isProd() { + return isProd; + } + + public void setProd(boolean prod) { + isProd = prod; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public int getTokenAcquireReties() { + return tokenAcquireReties; + } + + public void setTokenAcquireReties(int tokenAcquireReties) { + this.tokenAcquireReties = tokenAcquireReties; + } + + public int getTokenAcquireAheadInterval() { + return tokenAcquireAheadInterval; + } + + public void setTokenAcquireAheadInterval(int tokenAcquireAheadInterval) { + this.tokenAcquireAheadInterval = tokenAcquireAheadInterval; + } + + public String getTokenServiceCode() { + return tokenServiceCode; + } + + public void setTokenServiceCode(String tokenServiceCode) { + this.tokenServiceCode = tokenServiceCode; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/constants/Constants.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/constants/Constants.java new file mode 100644 index 0000000..28aae83 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/constants/Constants.java @@ -0,0 +1,24 @@ +package com.chinaums.open.api.constants; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/5 + * Time: 18:46 + * 所属模块: + * 功能说明: + */ +public class Constants { + public static class ERR_CODE { + public static final String NORMAL = "0000"; + public static final String ILLEGAL_CALL = "9000"; + public static final String ILLEGAL_PARAMETER = "9001"; + public static final String FATAL = "9999"; + } + public static class ERR_INFO { + public static final String NORMAL = "正常"; + public static final String ILLEGAL_CALL = "非法访问"; + public static final String ILLEGAL_PARAMETER = "请求参数校验失败"; + public static final String FATAL = "系统错误"; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/DateUtils.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/DateUtils.java new file mode 100644 index 0000000..b61ef29 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/DateUtils.java @@ -0,0 +1,40 @@ +/** + * Project:TODO ADD PROJECT NAME + * Modify Information: + * ================================================================ + * Author Date Description + * ------------ ---------- -------------------------------- + * wmshen 2022/10/20 TODO: + * ================================================================ + * Copyright (c) 银联商务股份有限公司 www.chinaums.com + */ +package com.chinaums.open.api.internal.util; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Desc: TODO ADD DESC + *

+ * Function: + *

+ *
核心功能点1
+ *
核心功能点1说明
+ *
核心功能点2
+ *
核心功能点2说明
+ *
+ * + * @app <服务名称英文缩写> + * @layer <代码所在分层> + * @refApp <依赖服务的英文缩写> + * @author
wmshen + * @since 2022/10/20 + * @version 2022/10/20 + */ +public class DateUtils { + public static String getFormatDate(){ + Date date = new Date(); + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); + return sdf.format(date); + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/FieldUtils.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/FieldUtils.java new file mode 100644 index 0000000..dd87b6e --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/FieldUtils.java @@ -0,0 +1,203 @@ +package com.chinaums.open.api.internal.util; + +import net.sf.json.JSONArray; +import net.sf.json.JSONObject; + +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.math.BigDecimal; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/2 + * Time: 16:17 + * 所属模块: + * 功能说明: + */ +public class FieldUtils { + public static Object getFieldValueByTypeAndFormat(Field field, Object bean, + String format) throws ParseException, IllegalArgumentException, + IllegalAccessException { + field.setAccessible(true); + Object objValue = field.get(bean); + Object ret = null; + if (objValue == null) + return ret; + String type = field.getType().getName(); + if ("java.lang.String".equals(type)) { + ret = field.get(bean).toString().trim(); + } else if ("java.lang.Integer".equals(type) || "int".equals(type)) { + if (objValue instanceof Integer) { + ret = ((Integer) objValue).toString(); + } + } else if ("java.lang.Float".equals(type) || "float".equals(type)) { + if (objValue instanceof Float) { + ret = ((Float) objValue).toString(); + } + } else if ("java.lang.Double".equals(type) || "double".equals(type)) { + if (objValue instanceof Double) { + ret = ((Double) objValue).toString(); + } + } else if ("java.math.BigDecimal".equals(type)) { + if (objValue instanceof BigDecimal) { + ret = ((BigDecimal) objValue).toString(); + } + } else if ("java.util.Date".equals(type)) { + if (objValue instanceof Date) { + Date dateValue = (Date) objValue; + ret = new SimpleDateFormat(format).format(dateValue); + } + } else if ("java.lang.Boolean".equals(type)) { + if (objValue instanceof Boolean) { + ret = ((Boolean) objValue).toString(); + } + } else if ("java.lang.Long".equals(type) || "long".equals(type)) { + if (objValue instanceof Long) { + ret = ((Long) objValue).toString(); + } + } else { + ret = objValue; + } + return ret; + } + + public static void setFieldValueByType(Field field, Object bean, + String value) throws IllegalArgumentException, + IllegalAccessException, ParseException, ClassNotFoundException { + setFieldValueByTypeAndFormat(field,bean,value,null); + } + + public static void setFieldValueByTypeAndFormat(Field field, Object bean, + String value, String format) throws IllegalArgumentException, + IllegalAccessException, ParseException, ClassNotFoundException { + if (value == null) + return; + field.setAccessible(true); + String type = field.getType().getName(); + if ("java.lang.String".equals(type)) { + field.set(bean, value); + } else if ("java.lang.Integer".equals(type)) { + field.set(bean, Integer.valueOf(value)); + } else if ("int".equals(type)) { + field.set(bean, Integer.valueOf(value).intValue()); + } else if ("java.lang.Float".equals(type)) { + field.set(bean, Float.valueOf(value)); + } else if ("float".equals(type)) { + field.set(bean, Float.valueOf(value).floatValue()); + } else if ("java.lang.Double".equals(type)) { + field.set(bean, Double.valueOf(value)); + } else if ("double".equals(type)) { + field.set(bean, Double.valueOf(value).doubleValue()); + } else if ("java.math.BigDecimal".equals(type)) { + field.set(bean, new BigDecimal(value)); + } else if ("java.util.Date".equals(type)) { + Date date = new SimpleDateFormat(format).parse(value.toString()); + field.set(bean, date); + } else if ("java.lang.Boolean".equals(type)) { + field.set(bean, Boolean.valueOf(value)); + } else if ("java.lang.Long".equals(type)) { + field.set(bean, Long.valueOf(value)); + } else if ("java.lang.Object".equals(type)) { + field.set(bean, value); + } else if ("long".equals(type)) { + field.set(bean, Long.valueOf(value).longValue()); + } else if ("java.util.Map".equals(type)) { + JSONObject mapObj = JSONObject.fromObject(value); + field.set(bean,mapObj); + } else if ("java.util.List".equals(type)) { + JSONArray arr = JSONArray.fromObject(value); + ParameterizedType genericType = (ParameterizedType) field.getGenericType(); + Type listType = genericType.getActualTypeArguments()[0]; + if (listType instanceof ParameterizedType) { + ParameterizedType paraType = (ParameterizedType) listType; + if ("java.util.Map".equals(((Class)paraType.getRawType()).getName())) { + List> list = new ArrayList>(); + for (int i = 0; i < arr.size(); i++) { + Map classMap = new HashMap(); + Map map = (Map) JSONObject + .toBean(JSONObject.fromObject(arr.optString(i)), + Map.class, classMap); + list.add(map); + } + field.set(bean, list); + } + } else if(List.class.isAssignableFrom(field.getType())){ + String argCalssName = listType.toString().substring(listType.toString().lastIndexOf(" ") + 1); + Class clazz = Class.forName(argCalssName); + List list = new ArrayList(); + for (int index = 0; index < arr.size(); index++) { + Object element = arr.get(index); + if (clazz == element.getClass()) { + list.add(element); + } else { + Object obj = JSONObject.toBean(JSONObject.fromObject(arr.optString(index)), clazz); + list.add(obj); + } + } + field.set(bean, list); + } else { + field.set(bean, arr); + } + } + + } + + public static Field getFieldByName(Object obj, String key) { + if (obj == null || key == null) + return null; + for (Class clazz = obj.getClass(); !clazz.getName().equals(Object.class.getName()); clazz = clazz + .getSuperclass()) { + Field[] fields = clazz.getDeclaredFields(); + for (Field f : fields) { + if (f.getName().equals(key)) { + return f; + } + } + } + return null; + + } + + public static Field getFieldByNameIgnoreCase(Class clazz, String key) { + if (clazz == null || key == null) + return null; + for (; !clazz.getName().equals(Object.class.getName()); clazz = clazz + .getSuperclass()) { + Field[] fields = clazz.getDeclaredFields(); + for (Field f : fields) { + if (f.getName().equalsIgnoreCase(key)) { + return f; + } + } + } + return null; + + } + + public static Object getFieldValueByNameIgnoreCase(Object obj, String key) { + if (obj == null || key == null) + return null; + Class clazz = obj.getClass(); + for (; !clazz.getName().equals(Object.class.getName()); clazz = clazz + .getSuperclass()) { + Field[] fields = clazz.getDeclaredFields(); + for (Field f : fields) { + if (f.getName().equalsIgnoreCase(key)) { + f.setAccessible(true); + try { + return f.get(obj); + } catch (Exception e) { + + } + } + } + } + return null; + } + +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/OpenApiLogger.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/OpenApiLogger.java new file mode 100644 index 0000000..a361805 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/OpenApiLogger.java @@ -0,0 +1,56 @@ +package com.chinaums.open.api.internal.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/2 + * Time: 10:21 + * 所属模块: + * 功能说明: + */ +public class OpenApiLogger { + private static final Log blog = LogFactory.getLog("sdk.biz.err"); + private static final Log clog = LogFactory.getLog("sdk.biz.info"); + private static boolean needEnableLogger = true; + + public static void logInfo(String rsp){ + DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + df.setTimeZone(TimeZone.getTimeZone("GMT+8")); + StringBuilder sb = new StringBuilder(); + sb.append(df.format(new Date())); + sb.append("#"); + sb.append(rsp); + clog.info(sb.toString()); + } + + public static void logError(String rsp) + { + if (!needEnableLogger) { + return; + } + DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + df.setTimeZone(TimeZone.getTimeZone("GMT+8")); + StringBuilder sb = new StringBuilder(); + sb.append(df.format(new Date())); + sb.append("###"); + sb.append(rsp); + blog.error(sb.toString()); + } + + public static void logError(Throwable t) + { + if (!needEnableLogger) { + return; + } + blog.error(t); + } + +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/OpenBodySigUtil.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/OpenBodySigUtil.java new file mode 100644 index 0000000..07b0131 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/OpenBodySigUtil.java @@ -0,0 +1,68 @@ +package com.chinaums.open.api.internal.util; + +import com.chinaums.open.api.OpenApiContext; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.codec.digest.DigestUtils; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.net.URLEncoder; +import java.security.InvalidKeyException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.UUID; + +/** + * Created with IntelliJ IDEA. + * User: + * Date: + * Time: + * 所属模块: + * 功能说明:Open body sig相关 + */ +public class OpenBodySigUtil { + + /** + * open-body-sig算法 + * @param context + * @param request + * @param method + * @return + */ + public static String generateSignature(OpenApiContext context, String request,String method) { + + try { + String appId=context.getAppId(); + String appKey=context.getAppKey(); + String timestamp = new SimpleDateFormat("yyyyMMddHHmmss") + .format(new Date()); + String nonce = UUID.randomUUID().toString().replace("-", ""); + String testSH = DigestUtils.sha256Hex(request); + + String s1 = appId+timestamp+nonce+testSH; + + String algorithm = "HmacSHA256"; + Mac mac = Mac.getInstance(algorithm); + mac.init(new SecretKeySpec(appKey.getBytes(), algorithm)); + byte[] localSignature =mac.doFinal(s1.getBytes("utf-8")); + + String localSignatureStr = Base64.encodeBase64String(localSignature); + OpenApiLogger.logInfo("SHA256(签名内容):"+testSH); + OpenApiLogger.logInfo("s1"+s1); + + if(method.equals("POST")){ + OpenApiLogger.logInfo( "OPEN-BODY-SIG AppId=" + "\"" + appId + "\"" + ", Timestamp=" + "\"" + timestamp + "\"" + ", Nonce=" + "\"" + nonce + "\"" + ", Signature=" + "\"" + localSignatureStr + "\""); + return "OPEN-BODY-SIG AppId=" + "\"" + appId + "\"" + ", Timestamp=" + "\"" + timestamp + "\"" + ", Nonce=" + "\"" + nonce + "\"" + ", Signature=" + "\"" + localSignatureStr + "\""; + } + return "authorization=OPEN-FORM-PARAM" + "&appId=" + appId + "×tamp=" + timestamp + "&nonce=" + nonce + "&content=" + URLEncoder.encode(request.toString(), "UTF-8") + "&signature=" + URLEncoder.encode(localSignatureStr, "UTF-8"); + } catch (Exception e) { + OpenApiLogger.logError(e.getCause()); + return ""; + } + } + +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/OpenTokenUtil.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/OpenTokenUtil.java new file mode 100644 index 0000000..bb5a1bc --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/OpenTokenUtil.java @@ -0,0 +1,135 @@ +package com.chinaums.open.api.internal.util; + +import com.chinaums.open.api.OpenApiContext; +import com.chinaums.open.api.constants.ConfigBean; +import com.chinaums.open.api.internal.util.converter.Converter; +import com.chinaums.open.api.internal.util.converter.JsonConverter; +import com.chinaums.open.api.internal.util.http.HttpTransport; +import com.chinaums.open.api.request.TokenRequest; +import com.chinaums.open.api.response.TokenResponse; +import net.sf.json.JSONObject; +import org.apache.commons.lang3.StringUtils; + +import java.security.MessageDigest; +import java.util.Date; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/5 + * Time: 15:41 + * 所属模块: + * 功能说明:Open Token相关 + */ +public class OpenTokenUtil { + private static final String constant_classname=OpenTokenUtil.class.getSimpleName(); + + /** + * token sha256签名算法 + * @param appId + * @param timestamp + * @param nonce + * @param appKey + * @return + */ + public static String generateSignature(String appId, String timestamp, + String nonce, String appKey) { + String plaintext = appId + timestamp + nonce + appKey; + try { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + digest.update(plaintext.getBytes()); + byte messageDigest[] = digest.digest(); + StringBuffer hexString = new StringBuffer(); + for (int i = 0; i < messageDigest.length; i++) { + String shaHex = Integer.toHexString(messageDigest[i] & 0xFF); + if (shaHex.length() < 2) { + hexString.append(0); + } + hexString.append(shaHex); + } + return hexString.toString(); + + } catch (Exception e) { + OpenApiLogger.logError(e.getCause()); + } + return ""; + } + + + + /** + * 获取token + * @param context + * @return + */ + public static TokenResponse getToken(OpenApiContext context){ + int retry = 0; + ConfigBean configBean = context.getConfigBean(); + TokenResponse acquiredToken = null; + if (isTokenValid(context.getCurrentToken()) + && !isTokenTimeout(context.getCurrentToken())) { + return context.getCurrentToken(); + } + while (retry++ < configBean.getTokenAcquireReties()) { + acquiredToken = acquireAccessToken(context); + if (null != acquiredToken) { //如果想根据请求token是否成功 用于重试 判断用if (null != acquiredToken.getAccessToken()) + break; + } else if (retry < configBean.getTokenAcquireReties()) { + try { + Thread.sleep(200); + } catch (Exception e) { + OpenApiLogger.logError(constant_classname +" 重试token申请出错:"+e.getCause()); + } + } else { + OpenApiLogger.logError(constant_classname +" 申请token超过重试次数 bye-bye"); + break; + } + } + return acquiredToken; + } + + private static TokenResponse acquireAccessToken(OpenApiContext context){ + String appId = context.getAppId(); + String appKey = context.getAppKey(); + ConfigBean configBean = context.getConfigBean(); + TokenRequest tokenRequest = new TokenRequest(appId,appKey); + JSONObject jsonObj = JSONObject.fromObject(tokenRequest); + TokenResponse tokenResponse; + String url = context.getOpenServUrl().concat(configBean.getVersion()).concat(configBean.getTokenServiceCode()); + try { + String response = HttpTransport.getInstance().doPost(configBean.isProd(),url,null,jsonObj.toString()); + if(StringUtils.isBlank(response)) throw new Exception(constant_classname+":服务提供方未返回"); + Converter converter = new JsonConverter(); + tokenResponse = converter.toResponse(response,TokenResponse.class); + tokenResponse.setEffectTime(new Date()); + tokenResponse.setTimeout(tokenResponse.getExpiresIn()); + tokenResponse.setAheadInterval(configBean.getTokenAcquireAheadInterval()); + return tokenResponse; + } catch (Exception e) { + OpenApiLogger.logError(constant_classname +" exception:"+e.getCause()); + } + return null; + } + + private static boolean isTokenValid(TokenResponse tokenBean) { + return (null != tokenBean + && org.apache.commons.lang.StringUtils.isNotBlank(tokenBean.getAccessToken()) + && null != tokenBean.getEffectTime() + && tokenBean.getTimeout() > 0 + && tokenBean.getAheadInterval() > 0 && tokenBean.getTimeout() > tokenBean + .getAheadInterval()); + } + + private static boolean isTokenTimeout(TokenResponse tokenBean) { + int elapseInterval = (int) ((new Date().getTime() - tokenBean + .getEffectTime().getTime()) / 1000); + int maxEffectiveInterval = tokenBean.getTimeout() + - tokenBean.getAheadInterval(); + boolean isTimeout = (elapseInterval > maxEffectiveInterval); + if (isTimeout) { + OpenApiLogger.logError(constant_classname +" exception:token过期了"); + } + return isTimeout; + } + +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/converter/Converter.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/converter/Converter.java new file mode 100644 index 0000000..1f23918 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/converter/Converter.java @@ -0,0 +1,14 @@ +package com.chinaums.open.api.internal.util.converter; + +import com.chinaums.open.api.OpenApiException; +import com.chinaums.open.api.OpenApiResponse; + +import java.text.ParseException; + +/** + * Created by ZHANGWEI on 2016/12/2. + */ +public abstract interface Converter { + public abstract T toResponse(String paramString, Class paramClass) + throws OpenApiException, IllegalAccessException, InstantiationException, ParseException, ClassNotFoundException; +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/converter/JsonConverter.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/converter/JsonConverter.java new file mode 100644 index 0000000..d0c0e2c --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/converter/JsonConverter.java @@ -0,0 +1,37 @@ +package com.chinaums.open.api.internal.util.converter; + +import com.chinaums.open.api.OpenApiException; +import com.chinaums.open.api.OpenApiResponse; +import com.chinaums.open.api.internal.util.FieldUtils; +import net.sf.json.JSONObject; + +import java.lang.reflect.Field; +import java.text.ParseException; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/2 + * Time: 14:50 + * 所属模块: + * 功能说明: + */ +public class JsonConverter implements Converter { + public T toResponse(String paramString, Class paramClass) throws OpenApiException, IllegalAccessException, InstantiationException, ParseException, ClassNotFoundException { + JSONObject jsonObj = JSONObject.fromObject(paramString); + Object bean = paramClass.newInstance(); + for (Class clazz = bean.getClass(); !clazz.getName().equals( + Object.class.getName()); clazz = clazz.getSuperclass()) { + Field[] fields = clazz.getDeclaredFields(); + for (Field field : fields) { + String fieldName = field.getName(); + String name = fieldName; + String key = fieldName; + String value = jsonObj.get(key) == null ? null : jsonObj + .get(key).toString().trim(); + FieldUtils.setFieldValueByTypeAndFormat(field, bean, value, null); + } + } + return (T) bean; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/http/HttpTransport.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/http/HttpTransport.java new file mode 100644 index 0000000..b069ce6 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/http/HttpTransport.java @@ -0,0 +1,160 @@ +package com.chinaums.open.api.internal.util.http; + +import com.chinaums.open.api.OpenApiContext; +import com.chinaums.open.api.constants.ConfigBean; +import com.chinaums.open.api.internal.util.OpenApiLogger; +import com.chinaums.open.api.response.TokenResponse; +import okhttp3.*; +import org.apache.commons.lang3.StringUtils; + +import static com.chinaums.open.api.internal.util.OpenBodySigUtil.generateSignature; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/5 + * Time: 13:56 + * 所属模块: + * 功能说明:http通用处理 + */ +public class HttpTransport implements IHttpTransport { + + private static OkHttpClient okHttpClient; + private static HttpTransport httpUtils; + public static final MediaType JSON=MediaType.parse("application/json; charset=utf-8"); + + private HttpTransport() { + } + + public static synchronized HttpTransport getInstance() { + if (httpUtils == null) { + httpUtils = new HttpTransport(); + initialize(); + } + return httpUtils; + } + + private static void initialize() { + okHttpClient = new OkHttpClient(); + } + + /** + * http post + * @param isProd + * @param url + * @param token + * @param requestString + * @return + */ + public String doPost(boolean isProd,String url, String token, String requestString) throws Exception { + Request request = null; + RequestBody requestBody = RequestBody.create(JSON,requestString); + Response response; + String responseInfo = ""; + if(!isProd){ + OpenApiLogger.logInfo("url:"+url); + OpenApiLogger.logInfo("requst params:"+requestString); + } + if(StringUtils.isNotBlank(token)){ + request = new Request.Builder().url(url).addHeader("Authorization", "OPEN-ACCESS-TOKEN AccessToken=" + token).post(requestBody).build(); + }else{ + request = new Request.Builder().url(url).post(requestBody).build(); + } + try { + response = okHttpClient.newCall(request).execute(); + responseInfo = response.body().source().readUtf8(); + OpenApiLogger.logInfo("response :"+responseInfo); + return responseInfo; + } catch (Exception e) { + OpenApiLogger.logError("通讯网络异常: "+e.getStackTrace()); + throw e; + } + } + + + /** + * http post token方式 + * @param context + * @param resquest_ + * @return + * @throws Throwable + */ + public String doPost(OpenApiContext context, String resquest_) throws Exception { + String url = context.getApiServiceUrl(); + String appId=context.getAppId(); + ConfigBean configBean = context.getConfigBean(); + context.setRequest(resquest_); + Request request = null; + RequestBody requestBody = RequestBody.create(JSON,resquest_); + Response response; + String responseInfo = ""; + if(!configBean.isProd()){ + OpenApiLogger.logInfo("url:"+url); + OpenApiLogger.logInfo("requst params:"+resquest_); + + } + TokenResponse token = context.getCurrentToken(); + request = new Request.Builder().url(url). + addHeader("Authorization","OPEN-ACCESS-TOKEN AccessToken=" + token.getAccessToken()+",AppId="+appId) +// .addHeader("X-Access-Model","NEW") + .post(requestBody).build(); + OpenApiLogger.logInfo("requst header:"+"OPEN-ACCESS-TOKEN AccessToken=" + token.getAccessToken()+",AppId="+appId); + try { + response = okHttpClient.newCall(request).execute(); + OpenApiLogger.logInfo("服务端返回code:"+response.code()+" message:"+response.message()); + responseInfo = response.body().source().readUtf8(); + context.setResponse(responseInfo); + OpenApiLogger.logInfo("response :"+responseInfo); + return responseInfo; + } catch (Exception e) { + OpenApiLogger.logError("通讯网络异常: "+e.getStackTrace()); + throw e; + } + } + + + /** + * http post signature方式 + * @param context + * @param resquest_ + * @return + * @throws Throwable + */ + public String doPostSignature(OpenApiContext context, String resquest_) throws Exception { + String url = context.getApiServiceUrl(); + ConfigBean configBean = context.getConfigBean(); + context.setRequest(resquest_); + Request request = null; + RequestBody requestBody = RequestBody.create(JSON,resquest_); + Response response; + String responseInfo = ""; + if(!configBean.isProd()){ + OpenApiLogger.logInfo("url:"+url); + OpenApiLogger.logInfo("requst params:"+resquest_); + + } + String authoriztion=generateSignature(context,resquest_,"POST"); + request = new Request.Builder().url(url). + addHeader("Authorization",authoriztion) + .post(requestBody).build(); + OpenApiLogger.logInfo("requst header:"+authoriztion); + try { + response = okHttpClient.newCall(request).execute(); + OpenApiLogger.logInfo("服务端返回code:"+response.code()+" message:"+response.message()); + responseInfo = response.body().source().readUtf8(); + context.setResponse(responseInfo); + OpenApiLogger.logInfo("response :"+responseInfo); + return responseInfo; + } catch (Exception e) { + OpenApiLogger.logError("通讯网络异常: "+e.getStackTrace()); + throw e; + } + } + + public String doGet(OpenApiContext context, String request) { + String url = context.getApiServiceUrl(); + String authoriztion=generateSignature(context,request,"GET"); + OpenApiLogger.logInfo("拼接的url :"+url+"?"+authoriztion); + return url+"?"+authoriztion; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/http/IHttpTransport.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/http/IHttpTransport.java new file mode 100644 index 0000000..3b091ad --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/internal/util/http/IHttpTransport.java @@ -0,0 +1,11 @@ +package com.chinaums.open.api.internal.util.http; + +import com.chinaums.open.api.OpenApiContext; + +/** + * Created by ZHANGWEI on 2016/12/4. + */ +public interface IHttpTransport { + public abstract String doPost(boolean isDebug,String url, String token, String request) throws Throwable; + public abstract String doPost(OpenApiContext context, String request) throws Throwable; +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/parser/json/ObjectJsonParser.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/parser/json/ObjectJsonParser.java new file mode 100644 index 0000000..3efe00c --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/parser/json/ObjectJsonParser.java @@ -0,0 +1,100 @@ +package com.chinaums.open.api.parser.json; + +import com.chinaums.open.api.OpenApiException; +import com.chinaums.open.api.OpenApiParser; +import com.chinaums.open.api.OpenApiRequest; +import com.chinaums.open.api.OpenApiResponse; +import com.chinaums.open.api.annotation.ApiField; +import com.chinaums.open.api.internal.util.OpenApiLogger; +import com.chinaums.open.api.internal.util.converter.Converter; +import com.chinaums.open.api.internal.util.converter.JsonConverter; +import net.sf.json.JSONObject; +import org.apache.commons.lang.StringUtils; + +import java.lang.reflect.Field; +import java.text.ParseException; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/2 + * Time: 14:37 + * 所属模块: + * 功能说明: + */ +public class ObjectJsonParser implements OpenApiParser { + + private Class class_; + + public ObjectJsonParser(Class tClass) { + this.class_ = tClass; + } + + public T parse(String paramString) throws OpenApiException { + Converter converter = new JsonConverter(); + try { + return converter.toResponse(paramString,this.class_); + } catch (IllegalAccessException e) { + OpenApiLogger.logError(e.getCause()); + } catch (InstantiationException e) { + OpenApiLogger.logError(e.getCause()); + } catch (ParseException e) { + OpenApiLogger.logError(e.getCause()); + } catch (ClassNotFoundException e) { + OpenApiLogger.logError(e.getCause()); + } + return null; + } + + public String validRequest(OpenApiRequest openApiRequest) throws OpenApiException { + JSONObject jsonObj = JSONObject.fromObject(openApiRequest); + for (Class clazz = openApiRequest.getClass(); !clazz.getName().equals( + Object.class.getName()); clazz = clazz.getSuperclass()) { + Field[] fields = clazz.getDeclaredFields(); + for (Field field : fields) { + String fieldName = field.getName(); + String name = fieldName; + String key = fieldName; + boolean required = false; + int length = -1; + int minLength = -1; + int maxLength = -1; + if (field.isAnnotationPresent(ApiField.class)) { + ApiField requestMark = field + .getAnnotation(ApiField.class); + String markKey = requestMark.key(); + if (markKey != null && !markKey.equals("")) { + key = markKey; + } + name = requestMark.name(); + required = requestMark.required(); + length = requestMark.length(); + minLength = requestMark.minLength(); + maxLength = requestMark.maxLength(); + String value = jsonObj.get(key) == null ? null : jsonObj + .get(key).toString().trim(); + if (StringUtils.isBlank(value) && required) + throw new OpenApiException(name + "[" + key + "]不能为空"); + if (StringUtils.isNotBlank(value)) { + if (length != -1) { + if (value.length() != length) + throw new OpenApiException(name + "[" + key + + "]长度必须为:" + length); + } + if (minLength != -1) { + if (value.length() < minLength) + throw new OpenApiException(name + "[" + key + + "]长度必须大于等于:" + minLength); + } + if (maxLength != -1) { + if (value.length() > maxLength) + throw new OpenApiException(name + "[" + key + + "]长度必须小于等于:" + maxLength); + } + } + } + } + } + return jsonObj.toString(); + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/AcpInstallmentRequest.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/AcpInstallmentRequest.java new file mode 100644 index 0000000..4a30401 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/AcpInstallmentRequest.java @@ -0,0 +1,95 @@ +package com.chinaums.open.api.request; + +import com.chinaums.open.api.OpenApiRequest; +import com.chinaums.open.api.annotation.ApiField; +import com.chinaums.open.api.response.AcpInstallmentResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/12/12 + * Time: 14:51 + * To change this template use File | Settings | File Templates. + */ +public class AcpInstallmentRequest implements OpenApiRequest { + @ApiField(key = "merchantCode",required = true,desc = "商户号") + private String merchantCode; + @ApiField(key = "terminalCode",required = true,desc = "终端号") + private String terminalCode; + @ApiField(key = "systemTraceNum",required = true,desc = "系统跟踪号") + private String systemTraceNum; + @ApiField(key = "transactionAmount",required = true,desc = "交易金额") + private String transactionAmount; + @ApiField(key = "transactionCurrencyCode",required = true,desc = "交易币种") + private String transactionCurrencyCode; + @ApiField(key = "encryptedData",required = true,desc = "加密数据") + private String encryptedData; + + public Class responseClass() { + return AcpInstallmentResponse.class; + } + + public String apiVersion() { + return "v1"; + } + + public String apiMethodName() { + return "一次性分期"; + } + + public String serviceCode() { + return "/unionpay/acp/installment/request"; + } + + public boolean needToken() { + return true; + } + + public String getMerchantCode() { + return merchantCode; + } + + public void setMerchantCode(String merchantCode) { + this.merchantCode = merchantCode; + } + + public String getTerminalCode() { + return terminalCode; + } + + public void setTerminalCode(String terminalCode) { + this.terminalCode = terminalCode; + } + + public String getSystemTraceNum() { + return systemTraceNum; + } + + public void setSystemTraceNum(String systemTraceNum) { + this.systemTraceNum = systemTraceNum; + } + + public String getTransactionAmount() { + return transactionAmount; + } + + public void setTransactionAmount(String transactionAmount) { + this.transactionAmount = transactionAmount; + } + + public String getTransactionCurrencyCode() { + return transactionCurrencyCode; + } + + public void setTransactionCurrencyCode(String transactionCurrencyCode) { + this.transactionCurrencyCode = transactionCurrencyCode; + } + + public String getEncryptedData() { + return encryptedData; + } + + public void setEncryptedData(String encryptedData) { + this.encryptedData = encryptedData; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/BankVerifyRequest.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/BankVerifyRequest.java new file mode 100644 index 0000000..8ca01f5 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/BankVerifyRequest.java @@ -0,0 +1,46 @@ +package com.chinaums.open.api.request; + +import com.chinaums.open.api.OpenApiRequest; +import com.chinaums.open.api.response.BankVerifyResponse; +import com.chinaums.open.api.annotation.ApiField; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/2 + * Time: 14:17 + * 所属模块: + * 功能说明:银行卡验证 + */ +public class BankVerifyRequest implements OpenApiRequest { + + @ApiField(key = "data",required = true,desc = "json格式字符") + private Object data; + + public Class responseClass() { + return BankVerifyResponse.class; + } + + public String apiVersion() { + return "v1"; + } + + public String apiMethodName() { + return "银行卡实名认证"; + } + + public String serviceCode() { + return "/datacenter/smartverification/bankcard/verify"; + } + + public boolean needToken() { + return true; + } + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/CourtQueryRequest.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/CourtQueryRequest.java new file mode 100644 index 0000000..adfdffe --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/CourtQueryRequest.java @@ -0,0 +1,44 @@ +package com.chinaums.open.api.request; + +import com.chinaums.open.api.OpenApiRequest; +import com.chinaums.open.api.annotation.ApiField; +import com.chinaums.open.api.response.CourtQueryResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/6/6 + * Time: 15:21 + * 所属模块: + * 功能说明:法院信息查询 + */ +public class CourtQueryRequest implements OpenApiRequest { + @ApiField(key = "data",required = true,desc = "json格式字符") + private Object data; + public Class responseClass() { + return CourtQueryResponse.class; + } + + public String apiVersion() { + return "v1"; + } + + public String apiMethodName() { + return "法院信息查询"; + } + + public String serviceCode() { + return "/datacenter/smartverification/court/query"; + } + + public boolean needToken() { + return true; + } + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/EducationInfoVerifyRequest.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/EducationInfoVerifyRequest.java new file mode 100644 index 0000000..2f1063e --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/EducationInfoVerifyRequest.java @@ -0,0 +1,45 @@ +package com.chinaums.open.api.request; + +import com.chinaums.open.api.OpenApiRequest; +import com.chinaums.open.api.annotation.ApiField; +import com.chinaums.open.api.response.EducationInfoVerifyResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/5/8 + * Time: 17:02 + * 所属模块: + * 功能说明:学历信息验证 + */ +public class EducationInfoVerifyRequest implements OpenApiRequest { + @ApiField(key = "data",required = true,desc = "json格式字符") + private Object data; + public Class responseClass() { + return EducationInfoVerifyResponse.class; + } + + public String apiVersion() { + return "v1"; + } + + public String apiMethodName() { + return "学历信息验证查询"; + } + + public String serviceCode() { + return "/datacenter/smartverification/education/query"; + } + + public boolean needToken() { + return true; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/FacerecognitionParamComposeRequest.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/FacerecognitionParamComposeRequest.java new file mode 100644 index 0000000..c5a181b --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/FacerecognitionParamComposeRequest.java @@ -0,0 +1,44 @@ +package com.chinaums.open.api.request; + +import com.chinaums.open.api.OpenApiRequest; +import com.chinaums.open.api.annotation.ApiField; +import com.chinaums.open.api.response.FacerecognitionParamComposeResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/6/5 + * Time: 14:33 + * 所属模块: + * 功能说明:人脸识别参数拼装 + */ +public class FacerecognitionParamComposeRequest implements OpenApiRequest { + @ApiField(key = "data",required = true,desc = "json格式字符") + private Object data; + public Class responseClass() { + return FacerecognitionParamComposeResponse.class; + } + + public String apiVersion() { + return "v1"; + } + + public String apiMethodName() { + return "人脸识别参数拼装"; + } + + public String serviceCode() { + return "/datacenter/smartverification/facerecognition/param/compose"; + } + + public boolean needToken() { + return true; + } + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/FacerecognitionParamResultQueryRequest.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/FacerecognitionParamResultQueryRequest.java new file mode 100644 index 0000000..7f30cf0 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/FacerecognitionParamResultQueryRequest.java @@ -0,0 +1,44 @@ +package com.chinaums.open.api.request; + +import com.chinaums.open.api.OpenApiRequest; +import com.chinaums.open.api.annotation.ApiField; +import com.chinaums.open.api.response.FacerecognitionParamResultQueryResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/6/5 + * Time: 14:34 + * 所属模块: + * 功能说明:人脸识别结果查询 + */ +public class FacerecognitionParamResultQueryRequest implements OpenApiRequest { + @ApiField(key = "data",required = true,desc = "json格式字符") + private Object data; + public Class responseClass() { + return FacerecognitionParamResultQueryResponse.class; + } + + public String apiVersion() { + return "v1"; + } + + public String apiMethodName() { + return "人脸识别结果查询"; + } + + public String serviceCode() { + return "/datacenter/smartverification/facerecognition/result/query"; + } + + public boolean needToken() { + return true; + } + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/FacerecognitionParamResultSetRequest.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/FacerecognitionParamResultSetRequest.java new file mode 100644 index 0000000..bd95830 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/FacerecognitionParamResultSetRequest.java @@ -0,0 +1,44 @@ +package com.chinaums.open.api.request; + +import com.chinaums.open.api.OpenApiRequest; +import com.chinaums.open.api.annotation.ApiField; +import com.chinaums.open.api.response.FacerecognitionParamResultSetResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/6/5 + * Time: 14:35 + * 所属模块: + * 功能说明:人脸识别结果获取 + */ +public class FacerecognitionParamResultSetRequest implements OpenApiRequest { + @ApiField(key = "data",required = true,desc = "json格式字符") + private Object data; + public Class responseClass() { + return FacerecognitionParamResultSetResponse.class; + } + + public String apiVersion() { + return "v1"; + } + + public String apiMethodName() { + return "人脸识别结果获取"; + } + + public String serviceCode() { + return "/datacenter/smartverification/facerecognition/result/set"; + } + + public boolean needToken() { + return true; + } + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/GenericTagQueryRequest.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/GenericTagQueryRequest.java new file mode 100644 index 0000000..13f086e --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/GenericTagQueryRequest.java @@ -0,0 +1,45 @@ +package com.chinaums.open.api.request; + +import com.chinaums.open.api.OpenApiRequest; +import com.chinaums.open.api.annotation.ApiField; +import com.chinaums.open.api.response.GenericTagQueryResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/6/6 + * Time: 15:18 + * 所属模块: + * 功能说明:实时标签查询 + */ +public class GenericTagQueryRequest implements OpenApiRequest{ + @ApiField(key = "data",required = true,desc = "json格式字符") + private Object data; + public Class responseClass() { + return GenericTagQueryResponse.class; + } + + public String apiVersion() { + return "v1"; + } + + public String apiMethodName() { + return "实时标签查询"; + } + + public String serviceCode() { + return "/datacenter/smartverification/tag/generic/query"; + } + + public boolean needToken() { + return true; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/IdCardVerifyRequest.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/IdCardVerifyRequest.java new file mode 100644 index 0000000..aa49063 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/IdCardVerifyRequest.java @@ -0,0 +1,46 @@ +package com.chinaums.open.api.request; + +import com.chinaums.open.api.OpenApiRequest; +import com.chinaums.open.api.annotation.ApiField; +import com.chinaums.open.api.response.IdCardVerifyResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/13 + * Time: 14:07 + * 所属模块: + * 功能说明:身份证核查 + */ +public class IdCardVerifyRequest implements OpenApiRequest{ + + @ApiField(key = "data",required = true,desc = "json格式字符") + private Object data; + public Class responseClass() { + return IdCardVerifyResponse.class; + } + + public String apiVersion() { + return "v1"; + } + + public String apiMethodName() { + return "身份证核查(政通实名认证)"; + } + + public String serviceCode() { + return "/datacenter/smartverification/idcard/verify"; + } + + public boolean needToken() { + return true; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/IdCheckSimpleInfoRequest.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/IdCheckSimpleInfoRequest.java new file mode 100644 index 0000000..90597f0 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/IdCheckSimpleInfoRequest.java @@ -0,0 +1,56 @@ +package com.chinaums.open.api.request; + +import com.chinaums.open.api.OpenApiRequest; +import com.chinaums.open.api.annotation.ApiField; +import com.chinaums.open.api.response.IdCheckSimpleInfoResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/2/21 + * Time: 14:49 + * 所属模块: + * 功能说明:简项公民身份证信息核查请求报文 + */ +public class IdCheckSimpleInfoRequest implements OpenApiRequest { + + @ApiField(name = "certifId",required = true ,desc = "公民身份号码") + private String certifId; + @ApiField(name = "name",required = true ,desc = "姓名") + private String name; + public Class responseClass() { + return IdCheckSimpleInfoResponse.class; + } + + public String apiVersion() { + return "v1"; + } + + public String apiMethodName() { + return "身份证验证"; + } + + public String serviceCode() { + return "/creditcheck/idcheck/simpleinfo"; + } + + public boolean needToken() { + return true; + } + + public String getCertifId() { + return certifId; + } + + public void setCertifId(String certifId) { + this.certifId = certifId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/Mobile3factorVerifyRequest.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/Mobile3factorVerifyRequest.java new file mode 100644 index 0000000..5f6cac2 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/Mobile3factorVerifyRequest.java @@ -0,0 +1,47 @@ +package com.chinaums.open.api.request; + +import com.chinaums.open.api.OpenApiRequest; +import com.chinaums.open.api.annotation.ApiField; +import com.chinaums.open.api.response.Mobile3factorVerifyResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/13 + * Time: 14:11 + * 所属模块: + * 功能说明:运营商三要素验证 + */ +public class Mobile3factorVerifyRequest implements OpenApiRequest{ + + @ApiField(key = "data",required = true,desc = "json格式字符") + private Object data; + + public Class responseClass() { + return Mobile3factorVerifyResponse.class; + } + + public String apiVersion() { + return "v1"; + } + + public String apiMethodName() { + return "运营商三要素验证"; + } + + public String serviceCode() { + return "/datacenter/smartverification/mobile/3factor/verify"; + } + + public boolean needToken() { + return true; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/NyBankCardTagRequest.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/NyBankCardTagRequest.java new file mode 100644 index 0000000..8ce65c6 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/NyBankCardTagRequest.java @@ -0,0 +1,46 @@ +package com.chinaums.open.api.request; + +import com.chinaums.open.api.OpenApiRequest; +import com.chinaums.open.api.annotation.ApiField; +import com.chinaums.open.api.response.NyBankCardTagResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/3/21 + * Time: 18:07 + * 所属模块: + * 功能说明:楠云银行卡标签提取 + */ +public class NyBankCardTagRequest implements OpenApiRequest { + @ApiField(key = "data",required = true,desc = "json格式字符") + private Object data; + + public Class responseClass() { + return NyBankCardTagResponse.class; + } + + public String apiVersion() { + return "v1"; + } + + public String apiMethodName() { + return "楠云银行卡标签提取查询"; + } + + public String serviceCode() { + return "/datacenter/smartverification/bankcardtag/query"; + } + + public boolean needToken() { + return true; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/RealNameVerifyRequest.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/RealNameVerifyRequest.java new file mode 100644 index 0000000..e6b9506 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/RealNameVerifyRequest.java @@ -0,0 +1,46 @@ +package com.chinaums.open.api.request; + +import com.chinaums.open.api.OpenApiRequest; +import com.chinaums.open.api.response.RealNameVerifyResponse; +import com.chinaums.open.api.annotation.ApiField; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/6 + * Time: 15:23 + * 所属模块: + * 功能说明:实名认证 + */ +public class RealNameVerifyRequest implements OpenApiRequest { + @ApiField(key = "data",required = true,desc = "json格式字符") + private Object data; + + public Class responseClass() { + return RealNameVerifyResponse.class; + } + + public String apiVersion() { + return "v1"; + } + + public String apiMethodName() { + return "实名认证"; + } + + public String serviceCode() { + return "/datacenter/smartverification/realname/verify"; + } + + public boolean needToken() { + return true; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/TokenRequest.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/TokenRequest.java new file mode 100644 index 0000000..0476259 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/TokenRequest.java @@ -0,0 +1,111 @@ +package com.chinaums.open.api.request; + +import com.chinaums.open.api.OpenApiRequest; +import com.chinaums.open.api.annotation.ApiField; +import com.chinaums.open.api.internal.util.OpenTokenUtil; +import com.chinaums.open.api.response.TokenResponse; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.UUID; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/5 + * Time: 15:42 + * 所属模块: + * 功能说明:token + */ +public class TokenRequest implements OpenApiRequest { + @ApiField(name = "appId",required = true ,desc = "开放平台开发者id") + private String appId; + @ApiField(name = "appKey",required = true,desc = "开放平台开发者key") + private String appKey; + @ApiField(name = "时间戳",required = true) + private String timestamp; + @ApiField(name = "随机数",required = true) + private String nonce; + @ApiField(name = "加密方法",required = true) + private String signMethod; + @ApiField(name = "SHA256签名字符",required = true) + private String signature; + + public Class responseClass() { + return TokenResponse.class; + } + + public String apiVersion() { + return "v2"; + } //新入驻商户需要使用v2方式 + + public String apiMethodName() { + return "获取开放平台token"; + } + + public String serviceCode() { + return "/token/access"; + } + + public boolean needToken() { + return false; + } + + public TokenRequest(String appId, String appKey) { + this.appId = appId; + this.appKey = appKey; + this.timestamp = new SimpleDateFormat("yyyyMMddHHmmss") + .format(new Date()); + this.nonce = UUID.randomUUID().toString(); + this.signMethod = "SHA256"; + this.signature = OpenTokenUtil.generateSignature(getAppId(),getTimestamp(),getNonce(),getAppKey()); + } + + public String getAppId() { + return appId; + } + + public void setAppId(String appId) { + this.appId = appId; + } + + public String getAppKey() { + return appKey; + } + + public void setAppKey(String appKey) { + this.appKey = appKey; + } + + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public String getNonce() { + return nonce; + } + + public void setNonce(String nonce) { + this.nonce = nonce; + } + + public String getSignMethod() { + return signMethod; + } + + public void setSignMethod(String signMethod) { + this.signMethod = signMethod; + } + + public String getSignature() { + return signature; + } + + public void setSignature(String signature) { + this.signature = signature; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/YsBankCardTagRequest.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/YsBankCardTagRequest.java new file mode 100644 index 0000000..7e55ef8 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/request/YsBankCardTagRequest.java @@ -0,0 +1,46 @@ +package com.chinaums.open.api.request; + +import com.chinaums.open.api.OpenApiRequest; +import com.chinaums.open.api.annotation.ApiField; +import com.chinaums.open.api.response.YsBankCardTagResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/5/3 + * Time: 18:21 + * 所属模块: + * 功能说明:盐商科技用户标签查询 + */ +public class YsBankCardTagRequest implements OpenApiRequest { + + @ApiField(key = "data",required = true,desc = "json格式字符") + private Object data; + + public Class responseClass() { + return YsBankCardTagResponse.class; + } + + public String apiVersion() { + return "v1"; + } + + public String apiMethodName() { + return "盐商科技用户标签查询"; + } + + public String serviceCode() { + return "/datacenter/smartverification/ysbankcardtag/query"; + } + + public boolean needToken() { + return true; + } + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/AcpInstallmentResponse.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/AcpInstallmentResponse.java new file mode 100644 index 0000000..5425cc4 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/AcpInstallmentResponse.java @@ -0,0 +1,89 @@ +package com.chinaums.open.api.response; + +import com.chinaums.open.api.OpenApiResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/12/12 + * Time: 14:51 + * To change this template use File | Settings | File Templates. + */ +public class AcpInstallmentResponse extends OpenApiResponse { + /** + * 错误代码 + */ + private String errCode; + /** + * 错误信息 + */ + private String errInfo; + /** + * 交易时间 HHmmss + */ + private String transactionTime; + /** + * 交易日期 MMdd + */ + private String transactionDate; + /** + * 结算日期 MMdd + */ + private String settlementDate; + /** + * 检索参考号 + */ + private String retrievalRefNum; + + @Override + public String getErrCode() { + return errCode; + } + + @Override + public void setErrCode(String errCode) { + this.errCode = errCode; + } + + @Override + public String getErrInfo() { + return errInfo; + } + + @Override + public void setErrInfo(String errInfo) { + this.errInfo = errInfo; + } + + public String getTransactionTime() { + return transactionTime; + } + + public void setTransactionTime(String transactionTime) { + this.transactionTime = transactionTime; + } + + public String getTransactionDate() { + return transactionDate; + } + + public void setTransactionDate(String transactionDate) { + this.transactionDate = transactionDate; + } + + public String getSettlementDate() { + return settlementDate; + } + + public void setSettlementDate(String settlementDate) { + this.settlementDate = settlementDate; + } + + public String getRetrievalRefNum() { + return retrievalRefNum; + } + + public void setRetrievalRefNum(String retrievalRefNum) { + this.retrievalRefNum = retrievalRefNum; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/BankVerifyResponse.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/BankVerifyResponse.java new file mode 100644 index 0000000..096d855 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/BankVerifyResponse.java @@ -0,0 +1,40 @@ +package com.chinaums.open.api.response; + +import com.chinaums.open.api.OpenApiResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/2 + * Time: 14:14 + * 所属模块: + * 功能说明:银行卡验证 + */ +public class BankVerifyResponse extends OpenApiResponse { + private String resultCode; + private String resultInfo; + private Object data; + public Object getData() { + return data; + } + public void setData(Object data) { + this.data = data; + } + + public String getResultCode() { + return resultCode; + } + + public void setResultCode(String resultCode) { + this.resultCode = resultCode; + } + + public String getResultInfo() { + return resultInfo; + } + + public void setResultInfo(String resultInfo) { + this.resultInfo = resultInfo; + } + +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/CourtQueryResponse.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/CourtQueryResponse.java new file mode 100644 index 0000000..61861a4 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/CourtQueryResponse.java @@ -0,0 +1,42 @@ +package com.chinaums.open.api.response; + +import com.chinaums.open.api.OpenApiResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/6/6 + * Time: 15:21 + * 所属模块: + * 功能说明:法院信息查询 + */ +public class CourtQueryResponse extends OpenApiResponse { + private String resultCode; + private String resultInfo; + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + private Object data; + + public String getResultCode() { + return resultCode; + } + + public void setResultCode(String resultCode) { + this.resultCode = resultCode; + } + + public String getResultInfo() { + return resultInfo; + } + + public void setResultInfo(String resultInfo) { + this.resultInfo = resultInfo; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/EducationInfoVerifyResponse.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/EducationInfoVerifyResponse.java new file mode 100644 index 0000000..7b80add --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/EducationInfoVerifyResponse.java @@ -0,0 +1,42 @@ +package com.chinaums.open.api.response; + +import com.chinaums.open.api.OpenApiResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/5/8 + * Time: 17:03 + * 所属模块: + * 功能说明:学历信息验证 + */ +public class EducationInfoVerifyResponse extends OpenApiResponse { + private String resultCode; + private String resultInfo; + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + private Object data; + + public String getResultCode() { + return resultCode; + } + + public void setResultCode(String resultCode) { + this.resultCode = resultCode; + } + + public String getResultInfo() { + return resultInfo; + } + + public void setResultInfo(String resultInfo) { + this.resultInfo = resultInfo; + } +} \ No newline at end of file diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/FacerecognitionParamComposeResponse.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/FacerecognitionParamComposeResponse.java new file mode 100644 index 0000000..e9b5b76 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/FacerecognitionParamComposeResponse.java @@ -0,0 +1,42 @@ +package com.chinaums.open.api.response; + +import com.chinaums.open.api.OpenApiResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/6/5 + * Time: 14:34 + * 所属模块: + * 功能说明:人脸识别参数拼装 + */ +public class FacerecognitionParamComposeResponse extends OpenApiResponse { + private String resultCode; + private String resultInfo; + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + private Object data; + + public String getResultCode() { + return resultCode; + } + + public void setResultCode(String resultCode) { + this.resultCode = resultCode; + } + + public String getResultInfo() { + return resultInfo; + } + + public void setResultInfo(String resultInfo) { + this.resultInfo = resultInfo; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/FacerecognitionParamResultQueryResponse.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/FacerecognitionParamResultQueryResponse.java new file mode 100644 index 0000000..3aad3f0 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/FacerecognitionParamResultQueryResponse.java @@ -0,0 +1,42 @@ +package com.chinaums.open.api.response; + +import com.chinaums.open.api.OpenApiResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/6/5 + * Time: 14:34 + * 所属模块: + * 功能说明:人脸识别结果查询 + */ +public class FacerecognitionParamResultQueryResponse extends OpenApiResponse { + private String resultCode; + private String resultInfo; + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + private Object data; + + public String getResultCode() { + return resultCode; + } + + public void setResultCode(String resultCode) { + this.resultCode = resultCode; + } + + public String getResultInfo() { + return resultInfo; + } + + public void setResultInfo(String resultInfo) { + this.resultInfo = resultInfo; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/FacerecognitionParamResultSetResponse.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/FacerecognitionParamResultSetResponse.java new file mode 100644 index 0000000..ce081b9 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/FacerecognitionParamResultSetResponse.java @@ -0,0 +1,42 @@ +package com.chinaums.open.api.response; + +import com.chinaums.open.api.OpenApiResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/6/5 + * Time: 14:35 + * 所属模块: + * 功能说明:人脸识别结果获取 + */ +public class FacerecognitionParamResultSetResponse extends OpenApiResponse { + private String resultCode; + private String resultInfo; + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + private Object data; + + public String getResultCode() { + return resultCode; + } + + public void setResultCode(String resultCode) { + this.resultCode = resultCode; + } + + public String getResultInfo() { + return resultInfo; + } + + public void setResultInfo(String resultInfo) { + this.resultInfo = resultInfo; + } +} \ No newline at end of file diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/GenericTagQueryResponse.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/GenericTagQueryResponse.java new file mode 100644 index 0000000..67e9ff6 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/GenericTagQueryResponse.java @@ -0,0 +1,42 @@ +package com.chinaums.open.api.response; + +import com.chinaums.open.api.OpenApiResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/6/6 + * Time: 15:18 + * 所属模块: + * 功能说明:实时标签查询 + */ +public class GenericTagQueryResponse extends OpenApiResponse { + private String resultCode; + private String resultInfo; + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + private Object data; + + public String getResultCode() { + return resultCode; + } + + public void setResultCode(String resultCode) { + this.resultCode = resultCode; + } + + public String getResultInfo() { + return resultInfo; + } + + public void setResultInfo(String resultInfo) { + this.resultInfo = resultInfo; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/IdCardVerifyResponse.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/IdCardVerifyResponse.java new file mode 100644 index 0000000..c1f0b2c --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/IdCardVerifyResponse.java @@ -0,0 +1,42 @@ +package com.chinaums.open.api.response; + +import com.chinaums.open.api.OpenApiResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/13 + * Time: 14:06 + * 所属模块: + * 功能说明:身份证核查 + */ +public class IdCardVerifyResponse extends OpenApiResponse { + private String resultCode; + private String resultInfo; + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + private Object data; + + public String getResultCode() { + return resultCode; + } + + public void setResultCode(String resultCode) { + this.resultCode = resultCode; + } + + public String getResultInfo() { + return resultInfo; + } + + public void setResultInfo(String resultInfo) { + this.resultInfo = resultInfo; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/IdCheckSimpleInfoResponse.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/IdCheckSimpleInfoResponse.java new file mode 100644 index 0000000..513f4de --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/IdCheckSimpleInfoResponse.java @@ -0,0 +1,52 @@ +package com.chinaums.open.api.response; + +import com.chinaums.open.api.OpenApiResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/2/21 + * Time: 14:49 + * 所属模块: + * 功能说明:核查平台-身份证验证 + */ +public class IdCheckSimpleInfoResponse extends OpenApiResponse { + /** + * 公民身份号码核查结果 + */ + private String resultCertifId; + + /** + * 姓名核查结果 + */ + private String resultName; + + /** + * base64编码的照片 + */ + private String photo; + + public String getResultCertifId() { + return resultCertifId; + } + + public void setResultCertifId(String resultCertifId) { + this.resultCertifId = resultCertifId; + } + + public String getResultName() { + return resultName; + } + + public void setResultName(String resultName) { + this.resultName = resultName; + } + + public String getPhoto() { + return photo; + } + + public void setPhoto(String photo) { + this.photo = photo; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/Mobile3factorVerifyResponse.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/Mobile3factorVerifyResponse.java new file mode 100644 index 0000000..cd5d418 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/Mobile3factorVerifyResponse.java @@ -0,0 +1,42 @@ +package com.chinaums.open.api.response; + +import com.chinaums.open.api.OpenApiResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/13 + * Time: 16:58 + * 所属模块: + * 功能说明:运营商三要素验证 + */ +public class Mobile3factorVerifyResponse extends OpenApiResponse { + private String resultCode; + private String resultInfo; + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + private Object data; + + public String getResultCode() { + return resultCode; + } + + public void setResultCode(String resultCode) { + this.resultCode = resultCode; + } + + public String getResultInfo() { + return resultInfo; + } + + public void setResultInfo(String resultInfo) { + this.resultInfo = resultInfo; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/NyBankCardTagResponse.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/NyBankCardTagResponse.java new file mode 100644 index 0000000..5bf3e9e --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/NyBankCardTagResponse.java @@ -0,0 +1,42 @@ +package com.chinaums.open.api.response; + +import com.chinaums.open.api.OpenApiResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/3/21 + * Time: 18:07 + * 所属模块: + * 功能说明:楠云银行卡标签提取 + */ +public class NyBankCardTagResponse extends OpenApiResponse { + private String resultCode; + private String resultInfo; + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + private Object data; + + public String getResultCode() { + return resultCode; + } + + public void setResultCode(String resultCode) { + this.resultCode = resultCode; + } + + public String getResultInfo() { + return resultInfo; + } + + public void setResultInfo(String resultInfo) { + this.resultInfo = resultInfo; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/RealNameVerifyResponse.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/RealNameVerifyResponse.java new file mode 100644 index 0000000..296ca75 --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/RealNameVerifyResponse.java @@ -0,0 +1,42 @@ +package com.chinaums.open.api.response; + +import com.chinaums.open.api.OpenApiResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/6 + * Time: 15:23 + * 所属模块: + * 功能说明: + */ +public class RealNameVerifyResponse extends OpenApiResponse{ + private String resultCode; + private String resultInfo; + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + private Object data; + + public String getResultCode() { + return resultCode; + } + + public void setResultCode(String resultCode) { + this.resultCode = resultCode; + } + + public String getResultInfo() { + return resultInfo; + } + + public void setResultInfo(String resultInfo) { + this.resultInfo = resultInfo; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/TokenResponse.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/TokenResponse.java new file mode 100644 index 0000000..3a7365e --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/TokenResponse.java @@ -0,0 +1,78 @@ +package com.chinaums.open.api.response; + +import com.chinaums.open.api.OpenApiResponse; + +import java.util.Date; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/5 + * Time: 15:42 + * 所属模块: + * 功能说明: + */ +public class TokenResponse extends OpenApiResponse{ + /** + * 服务授权令牌 + */ + private String accessToken; + /** + * 有效期 + */ + private int expiresIn; + /** + * 令牌开始生效的时间,以收到时间为准 + */ + private Date effectTime; + + /** + * 令牌的过期时间,单位为秒,由数据中心返回 + */ + private int timeout; + + /** + * 在令牌过期前,要提前重新申请 + */ + private int aheadInterval; + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public int getExpiresIn() { + return expiresIn; + } + + public void setExpiresIn(int expiresIn) { + this.expiresIn = expiresIn; + } + + public Date getEffectTime() { + return effectTime; + } + + public void setEffectTime(Date effectTime) { + this.effectTime = effectTime; + } + + public int getTimeout() { + return timeout; + } + + public void setTimeout(int timeout) { + this.timeout = timeout; + } + + public int getAheadInterval() { + return aheadInterval; + } + + public void setAheadInterval(int aheadInterval) { + this.aheadInterval = aheadInterval; + } +} diff --git a/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/YsBankCardTagResponse.java b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/YsBankCardTagResponse.java new file mode 100644 index 0000000..afb94eb --- /dev/null +++ b/extLib/chinaumsdk/src/main/java/com/chinaums/open/api/response/YsBankCardTagResponse.java @@ -0,0 +1,42 @@ +package com.chinaums.open.api.response; + +import com.chinaums.open.api.OpenApiResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/5/3 + * Time: 18:21 + * 所属模块: + * 功能说明:盐商科技用户标签查询 + */ +public class YsBankCardTagResponse extends OpenApiResponse { + private String resultCode; + private String resultInfo; + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + private Object data; + + public String getResultCode() { + return resultCode; + } + + public void setResultCode(String resultCode) { + this.resultCode = resultCode; + } + + public String getResultInfo() { + return resultInfo; + } + + public void setResultInfo(String resultInfo) { + this.resultInfo = resultInfo; + } +} diff --git a/extLib/chinaumsdk/src/test/java/com/chinaums/open/api/internal/util/http/HttpTransportTest.java b/extLib/chinaumsdk/src/test/java/com/chinaums/open/api/internal/util/http/HttpTransportTest.java new file mode 100644 index 0000000..7cd2346 --- /dev/null +++ b/extLib/chinaumsdk/src/test/java/com/chinaums/open/api/internal/util/http/HttpTransportTest.java @@ -0,0 +1,49 @@ +package com.chinaums.open.api.internal.util.http; + +import com.chinaums.open.api.OpenApiCache; +import com.chinaums.open.api.OpenApiContext; +import com.chinaums.open.api.constants.ConfigBean; +import org.junit.Test; + +import java.util.HashMap; +import java.util.UUID; + +import static org.junit.Assert.*; + +/** + * Project:TODO ADD PROJECT NAME + * Modify Information: + * ================================================================ + * Author Date Description + * ------------ ---------- -------------------------------- + * wmshen 2022/10/20 TODO: + * ================================================================ + * Copyright (c) 银联商务股份有限公司 www.chinaums.com + */ +public class HttpTransportTest { + + @Test + public void doGet() throws Exception { + + String url = "https://test-api-open.chinaums.com/v1/netpay/trade/h5-pay"; + //开发者ID + String appId = "10037e6f6a4e6da4016a670fd4530012"; + //开发者秘钥 + String appKey = "f7a74b6c02ae4e1e94aaba311c04acf2"; + //实例化客户端 + ConfigBean configBean = new ConfigBean(); + OpenApiContext context = new OpenApiContext(); + String request = "{\"tid\":\"88880001\",\"totalAmount\":\"1\",\"mid\":\"898310148160568\",\"merOrderId\":\"wf12421741298471284\"}"; + context.setStartTime(System.currentTimeMillis()); + context.setRequestId(UUID.randomUUID().toString().replace("-", "")); + context.setOpenServUrl(url.split("/v")[0].concat("/")); + context.setApiServiceUrl(url); + context.setVersion(url.split("/")[3]); + context.setAppId(appId); + context.setAppKey(appKey); + context.setConfigBean(configBean); + context.setServiceCode(url.split("/v")[1].substring(1)); + OpenApiCache.getCurrentToken(context); + System.out.println(HttpTransport.getInstance().doGet(context, request)); + } +} \ No newline at end of file diff --git a/extLib/chinaumsdk/src/test/java/com/chinaums/test/BankCardTagTestCase.java b/extLib/chinaumsdk/src/test/java/com/chinaums/test/BankCardTagTestCase.java new file mode 100644 index 0000000..6c3171a --- /dev/null +++ b/extLib/chinaumsdk/src/test/java/com/chinaums/test/BankCardTagTestCase.java @@ -0,0 +1,49 @@ +package com.chinaums.test; + +import com.chinaums.open.api.DefaultOpenApiClient; +import com.chinaums.open.api.OpenApiClient; +import com.chinaums.open.api.OpenApiException; +import com.chinaums.open.api.request.NyBankCardTagRequest; +import com.chinaums.open.api.request.YsBankCardTagRequest; +import com.chinaums.open.api.response.NyBankCardTagResponse; +import com.chinaums.open.api.response.YsBankCardTagResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/3/21 + * Time: 19:08 + * 所属模块: + * 功能说明:标签查询相关testcase + */ +public class BankCardTagTestCase { + @org.junit.Test + public void testNyBankCardTag() throws OpenApiException { + String url = "https://api-mop.chinaums.com/"; + String appId = ""; + String appKey = ""; + OpenApiClient openApiClient = new DefaultOpenApiClient(url,appId,appKey); + NyBankCardTagRequest nyBankCardTagRequest = new NyBankCardTagRequest(); + nyBankCardTagRequest.setData("{\"userNo\":\"\",\"priAcctNo\":\"\",\"riskflag\":\"1\"}"); + NyBankCardTagResponse nyBankCardTagResponse; + nyBankCardTagResponse = openApiClient.execute(nyBankCardTagRequest); + System.out.println(nyBankCardTagResponse.getData()); + System.out.println(nyBankCardTagResponse.getResultCode()); + System.out.println(nyBankCardTagResponse.getResultInfo()); + } + + @org.junit.Test + public void testYsBankCardTag() throws OpenApiException { + String url = "https://api-mop.chinaums.com/"; + String appId = ""; + String appKey = ""; + OpenApiClient openApiClient = new DefaultOpenApiClient(url,appId,appKey); + YsBankCardTagRequest ysBankCardTagRequest = new YsBankCardTagRequest(); + ysBankCardTagRequest.setData("{\"phoneNo\":\"\",\"priAcctNo\":\"\"}"); + YsBankCardTagResponse ysBankCardTagResponse; + ysBankCardTagResponse = openApiClient.execute(ysBankCardTagRequest); + System.out.println(ysBankCardTagResponse.getData()); + System.out.println(ysBankCardTagResponse.getResultCode()); + System.out.println(ysBankCardTagResponse.getResultInfo()); + } +} diff --git a/extLib/chinaumsdk/src/test/java/com/chinaums/test/FacerecognitionTest.java b/extLib/chinaumsdk/src/test/java/com/chinaums/test/FacerecognitionTest.java new file mode 100644 index 0000000..6965f73 --- /dev/null +++ b/extLib/chinaumsdk/src/test/java/com/chinaums/test/FacerecognitionTest.java @@ -0,0 +1,57 @@ +package com.chinaums.test; + +import com.chinaums.open.api.DefaultOpenApiClient; +import com.chinaums.open.api.OpenApiClient; +import com.chinaums.open.api.OpenApiException; +import com.chinaums.open.api.request.FacerecognitionParamComposeRequest; +import com.chinaums.open.api.request.FacerecognitionParamResultQueryRequest; +import com.chinaums.open.api.request.FacerecognitionParamResultSetRequest; +import com.chinaums.open.api.response.FacerecognitionParamComposeResponse; +import com.chinaums.open.api.response.FacerecognitionParamResultQueryResponse; +import com.chinaums.open.api.response.FacerecognitionParamResultSetResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/6/5 + * Time: 14:41 + * 所属模块: + * 功能说明:人脸识别相关测试案例 + */ +public class FacerecognitionTest { + @org.junit.Test + public void testFacerecognitionParamCompose() throws OpenApiException { + String url = "https://api-mop.chinaums.com/"; + String appId = ""; + String appKey = ""; + OpenApiClient openApiClient = new DefaultOpenApiClient(url,appId,appKey); + FacerecognitionParamComposeRequest facerecognitionParamComposeRequest = new FacerecognitionParamComposeRequest(); + facerecognitionParamComposeRequest.setData("{\"certNo\" : \"\",\"idCardUserName\" : \"\",\"orderId\" : '',\"orderDate\" : '',\"deviceID\" : '',\"deviceOs\" : ''}"); + FacerecognitionParamComposeResponse response = openApiClient.execute(facerecognitionParamComposeRequest); + System.out.println(response.getErrCode()); + } + + @org.junit.Test + public void testFacerecognitionParamResultQuery() throws OpenApiException { + String url = "https://api-mop.chinaums.com/"; + String appId = ""; + String appKey = ""; + OpenApiClient openApiClient = new DefaultOpenApiClient(url,appId,appKey); + FacerecognitionParamResultQueryRequest request = new FacerecognitionParamResultQueryRequest(); + request.setData("{\"orderId\":\"\",\"deviceID\":\"\",\"orderDate\":\"\"}"); + FacerecognitionParamResultQueryResponse response = openApiClient.execute(request); + System.out.println(response.getErrCode()); + } + + @org.junit.Test + public void testFacerecognitionParamResultSet() throws OpenApiException { + String url = "https://api-mop.chinaums.com/"; + String appId = ""; + String appKey = ""; + OpenApiClient openApiClient = new DefaultOpenApiClient(url,appId,appKey); + FacerecognitionParamResultSetRequest request = new FacerecognitionParamResultSetRequest(); + request.setData("{\"signature\":\"\",\"merNo\":\"\",\"respData\":\"\"}"); + FacerecognitionParamResultSetResponse response = openApiClient.execute(request); + System.out.println(response.getErrCode()); + } +} diff --git a/extLib/chinaumsdk/src/test/java/com/chinaums/test/IdCheckSimpleInfoTestCase.java b/extLib/chinaumsdk/src/test/java/com/chinaums/test/IdCheckSimpleInfoTestCase.java new file mode 100644 index 0000000..05723e3 --- /dev/null +++ b/extLib/chinaumsdk/src/test/java/com/chinaums/test/IdCheckSimpleInfoTestCase.java @@ -0,0 +1,63 @@ +package com.chinaums.test; + +import com.chinaums.open.api.DefaultOpenApiClient; +import com.chinaums.open.api.OpenApiClient; +import com.chinaums.open.api.OpenApiException; +import com.chinaums.open.api.request.EducationInfoVerifyRequest; +import com.chinaums.open.api.request.IdCheckSimpleInfoRequest; +import com.chinaums.open.api.response.EducationInfoVerifyResponse; +import com.chinaums.open.api.response.IdCheckSimpleInfoResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/2/21 + * Time: 15:00 + * 所属模块: + * 功能说明: + */ +public class IdCheckSimpleInfoTestCase { + @org.junit.Test + public void testIdCheck() throws OpenApiException { + String url = "https://api-mop.chinaums.com/"; + String appId = ""; + String appKey = ""; + OpenApiClient openApiClient = new DefaultOpenApiClient(url,appId,appKey); + IdCheckSimpleInfoRequest request = new IdCheckSimpleInfoRequest(); + request.setCertifId(""); + request.setName(""); + IdCheckSimpleInfoResponse response = openApiClient.execute(request); + System.out.println(response.getErrCode()); + } + + + @org.junit.Test + public void testEducation() throws OpenApiException { + String url = "https://api-mop.chinaums.com/"; + String appId = ""; + String appKey = ""; + OpenApiClient openApiClient = new DefaultOpenApiClient(url,appId,appKey); + EducationInfoVerifyRequest ysBankCardTagRequest = new EducationInfoVerifyRequest(); + ysBankCardTagRequest.setData("{\"certNo\":\"\",\"name\":\"\"}"); + EducationInfoVerifyResponse ysBankCardTagResponse; + ysBankCardTagResponse = openApiClient.execute(ysBankCardTagRequest); + System.out.println(ysBankCardTagResponse.getData()); + System.out.println(ysBankCardTagResponse.getResultCode()); + System.out.println(ysBankCardTagResponse.getResultInfo()); + } + + @org.junit.Test + public void testface001() throws OpenApiException { + String url = "https://api-mop.chinaums.com/"; + String appId = ""; + String appKey = ""; + OpenApiClient openApiClient = new DefaultOpenApiClient(url,appId,appKey); + EducationInfoVerifyRequest ysBankCardTagRequest = new EducationInfoVerifyRequest(); + ysBankCardTagRequest.setData("{\"orderId\":\"\",\"deviceID\":\"\"}"); + EducationInfoVerifyResponse ysBankCardTagResponse; + ysBankCardTagResponse = openApiClient.execute(ysBankCardTagRequest); + System.out.println(ysBankCardTagResponse.getData()); + System.out.println(ysBankCardTagResponse.getResultCode()); + System.out.println(ysBankCardTagResponse.getResultInfo()); + } +} diff --git a/extLib/chinaumsdk/src/test/java/com/chinaums/test/InstallmentTest.java b/extLib/chinaumsdk/src/test/java/com/chinaums/test/InstallmentTest.java new file mode 100644 index 0000000..46c842f --- /dev/null +++ b/extLib/chinaumsdk/src/test/java/com/chinaums/test/InstallmentTest.java @@ -0,0 +1,33 @@ +package com.chinaums.test; + +import com.chinaums.open.api.DefaultOpenApiClient; +import com.chinaums.open.api.OpenApiClient; +import com.chinaums.open.api.OpenApiException; +import com.chinaums.open.api.request.AcpInstallmentRequest; +import com.chinaums.open.api.response.AcpInstallmentResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/12/12 + * Time: 15:05 + * To change this template use File | Settings | File Templates. + */ +public class InstallmentTest { + @org.junit.Test + public void testVerifyBankCard() throws OpenApiException { + String url = "https://api-mop.chinaums.com/"; + String appId = ""; + String appKey = ""; + OpenApiClient openApiClient = new DefaultOpenApiClient(url, appId, appKey); + AcpInstallmentRequest acpInstallmentRequest = new AcpInstallmentRequest(); + acpInstallmentRequest.setMerchantCode(""); + acpInstallmentRequest.setTerminalCode(""); + acpInstallmentRequest.setSystemTraceNum(""); + acpInstallmentRequest.setTransactionCurrencyCode("156"); + acpInstallmentRequest.setTransactionAmount(""); + acpInstallmentRequest.setEncryptedData(""); + AcpInstallmentResponse acpInstallmentResponse = openApiClient.execute(acpInstallmentRequest); + System.out.println(acpInstallmentResponse.getErrCode()); + } +} diff --git a/extLib/chinaumsdk/src/test/java/com/chinaums/test/PosLinkTestCase.java b/extLib/chinaumsdk/src/test/java/com/chinaums/test/PosLinkTestCase.java new file mode 100644 index 0000000..16b0541 --- /dev/null +++ b/extLib/chinaumsdk/src/test/java/com/chinaums/test/PosLinkTestCase.java @@ -0,0 +1,36 @@ +package com.chinaums.test; + +import com.chinaums.open.api.DefaultOpenApiClient; +import com.chinaums.open.api.OpenApiClient; +import com.chinaums.open.api.OpenApiException; +import com.chinaums.open.api.request.TokenRequest; +import com.chinaums.open.api.response.TokenResponse; +import org.junit.Test; + +import java.util.Random; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/8/2 + * Time: 11:06 + * To change this template use File | Settings | File Templates. + */ +public class PosLinkTestCase { + @org.junit.Test + public void testGetToken() throws OpenApiException { + String url = "https://api-mop.chinaums.com/"; + String appId = ""; + String appKey = ""; + OpenApiClient openApiClient = new DefaultOpenApiClient(url,appId,appKey); + TokenRequest tokenRequest = new TokenRequest(appId,appKey); + TokenResponse response = openApiClient.execute(tokenRequest); + System.out.print(response.getAccessToken()); + } + @Test + public void testCreateRadom(){ + Random random = new Random(); + System.out.println(System.currentTimeMillis()+random.nextInt()); + System.out.println((int)((Math.random()*9+1)*100000)); + } +} diff --git a/extLib/chinaumsdk/src/test/java/com/chinaums/test/RealNameVerifyTestCase.java b/extLib/chinaumsdk/src/test/java/com/chinaums/test/RealNameVerifyTestCase.java new file mode 100644 index 0000000..517bb80 --- /dev/null +++ b/extLib/chinaumsdk/src/test/java/com/chinaums/test/RealNameVerifyTestCase.java @@ -0,0 +1,78 @@ +package com.chinaums.test; + +import com.chinaums.open.api.DefaultOpenApiClient; +import com.chinaums.open.api.OpenApiClient; +import com.chinaums.open.api.OpenApiException; +import com.chinaums.open.api.request.BankVerifyRequest; +import com.chinaums.open.api.request.IdCardVerifyRequest; +import com.chinaums.open.api.request.Mobile3factorVerifyRequest; +import com.chinaums.open.api.request.RealNameVerifyRequest; +import com.chinaums.open.api.response.BankVerifyResponse; +import com.chinaums.open.api.response.IdCardVerifyResponse; +import com.chinaums.open.api.response.Mobile3factorVerifyResponse; +import com.chinaums.open.api.response.RealNameVerifyResponse; +import org.junit.Test; +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/13 + * Time: 17:10 + * 所属模块: + * 功能说明: + */ +public class RealNameVerifyTestCase { + @Test + public void testVerifyBankCard() throws OpenApiException { + String url = "https://api-mop.chinaums.com/"; + String appId = ""; + String appKey = ""; + OpenApiClient openApiClient = new DefaultOpenApiClient(url,appId,appKey); + BankVerifyRequest bankVerifyRequest = new BankVerifyRequest(); + bankVerifyRequest.setData("{\"cardNo\":\"\",\"phoneNo\":\"\"}"); + BankVerifyResponse bankVerifyResponse; + for(int i=0;i<5;i++){ + bankVerifyResponse = openApiClient.execute(bankVerifyRequest); + System.out.println(bankVerifyResponse.getData()); + System.out.println(bankVerifyResponse.getResultCode()); + System.out.println(bankVerifyResponse.getResultInfo()); + } + } + + @Test + public void testRealNameVerify() throws OpenApiException { + String url = "http://116.228.21.162:29015/"; + String appId = "10037e6f57c304d2015824085de80058"; + String appKey = "4e921d76ffc045d98e14999a1f67d1ea"; + OpenApiClient openApiClient = new DefaultOpenApiClient(url,appId,appKey); + RealNameVerifyRequest realNameVerifyRequest = new RealNameVerifyRequest(); + realNameVerifyRequest.setData("{\"userNo\":\"370203\",\"acctNo\":\"6214852107267879\",\"acctName\":\"李铁柱\",\"certNo\":\"370203199809012323\",\"certType\":\"00\",\"phone\":\"18970718908\"}"); + RealNameVerifyResponse realNameVerifyResponse = openApiClient.execute(realNameVerifyRequest); + } + @Test + public void carreopratorVerify() throws OpenApiException { + String url = "http://116.228.21.162:29015/"; + String appId = "10037e6f57c304d2015824085de80058"; + String appKey = "4e921d76ffc045d98e14999a1f67d1ea"; + OpenApiClient openApiClient = new DefaultOpenApiClient(url,appId,appKey); + Mobile3factorVerifyRequest request = new Mobile3factorVerifyRequest(); + request.setData("{\"userNo\":\"370203\",\"userName\":\"李铁柱\",\"certCode\":\"370203199809012323\",\"certType\":\"01\",\"phoneNo\":\"18970718908\"}"); + Mobile3factorVerifyResponse response = openApiClient.execute(request); + System.out.println(response.getData()); + System.out.println(response.getResultInfo()); + System.out.println(response.getResultInfo()); + } + + @Test + public void idcardVerify() throws OpenApiException { + String url = "https://api-mop.chinaums.com/"; + String appId = "9ed4dfed9540423fa04842916c54e0d1"; + String appKey = "20f00a8b37aa4ddda56e7eed2ef6fe2b"; + OpenApiClient openApiClient = new DefaultOpenApiClient(url,appId,appKey); + IdCardVerifyRequest request = new IdCardVerifyRequest(); + request.setData("{\"userNo\":\"370203\",\"userName\":\"李铁柱\",\"certCode\":\"370203199809012323\"}"); + IdCardVerifyResponse response = openApiClient.execute(request); + System.out.println(response.getData()); + System.out.println(response.getResultInfo()); + System.out.println(response.getResultInfo()); + } +} diff --git a/extLib/chinaumsdk/src/test/java/com/chinaums/test/SmartverificationTestCase.java b/extLib/chinaumsdk/src/test/java/com/chinaums/test/SmartverificationTestCase.java new file mode 100644 index 0000000..0427abe --- /dev/null +++ b/extLib/chinaumsdk/src/test/java/com/chinaums/test/SmartverificationTestCase.java @@ -0,0 +1,152 @@ +package com.chinaums.test; + +import com.chinaums.open.api.DefaultOpenApiClient; +import com.chinaums.open.api.OpenApiClient; +import com.chinaums.open.api.OpenApiException; +import com.chinaums.open.api.request.*; +import com.chinaums.open.api.response.*; +import org.junit.*; +import org.junit.Test; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/6/5 + * Time: 16:18 + * 所属模块: + * 功能说明:智慧验证相关接口验证测试 + */ +public class SmartverificationTestCase { + + /** + * 银行卡验证 + * @throws OpenApiException + */ + @org.junit.Test + public void testVerifyBankCard() throws OpenApiException { + String url = "https://api-mop.chinaums.com/"; + String appId = ""; + String appKey = ""; + OpenApiClient openApiClient = new DefaultOpenApiClient(url, appId, appKey); + BankVerifyRequest bankVerifyRequest = new BankVerifyRequest(); + bankVerifyRequest.setData("{\"userNo\":\"\",\"acctNo\":\"\",\"acctName\":\"\",\"certNo\":\"\",\"certType\":\"\",\"phone\":\"\"}"); + BankVerifyResponse bankVerifyResponse; + for (int i = 0; i < 5; i++) { + bankVerifyResponse = openApiClient.execute(bankVerifyRequest); + System.out.println(bankVerifyResponse.getData()); + System.out.println(bankVerifyResponse.getResultCode()); + System.out.println(bankVerifyResponse.getResultInfo()); + } + } + + /** + * 实名验证 + * @throws OpenApiException + */ + @org.junit.Test + public void testRealNameVerify() throws OpenApiException { + String url = "https://api-mop.chinaums.com/"; + String appId = "9ed4dfed9540423fa04842916c54e0d1"; + String appKey = "20f00a8b37aa4ddda56e7eed2ef6fe2b"; + OpenApiClient openApiClient = new DefaultOpenApiClient(url, appId, appKey); + RealNameVerifyRequest request = new RealNameVerifyRequest(); + request.setData("{\"userNo\":\"370203\",\"acctNo\":\"6214852107267879\",\"acctName\":\"李铁柱\",\"certNo\":\"370203199809012323\",\"certType\":\"00\",\"phone\":\"18970718908\"}"); + RealNameVerifyResponse response; + for (int i = 0; i < 5; i++) { + response = openApiClient.execute(request); + System.out.println(response.getData()); + System.out.println(response.getResultCode()); + System.out.println(response.getResultInfo()); + } + } + + /** + * 移动3要素 + * @throws OpenApiException + */ + @Test + public void carreopratorVerify() throws OpenApiException { + String url = "https://api-mop.chinaums.com/"; + String appId = "9ed4dfed9540423fa04842916c54e0d1"; + String appKey = "20f00a8b37aa4ddda56e7eed2ef6fe2b"; + OpenApiClient openApiClient = new DefaultOpenApiClient(url,appId,appKey); + Mobile3factorVerifyRequest request = new Mobile3factorVerifyRequest(); + request.setData("{\"userNo\":\"370203\",\"userName\":\"李铁柱\",\"certCode\":\"370203199809012323\",\"certType\":\"01\",\"phoneNo\":\"18970718908\"}"); + Mobile3factorVerifyResponse response = openApiClient.execute(request); + System.out.println(response.getData()); + System.out.println(response.getResultInfo()); + System.out.println(response.getResultInfo()); + } + + /** + * 身份证验证 + * @throws OpenApiException + */ + @Test + public void idcardVerify() throws OpenApiException { + String url = "https://api-mop.chinaums.com/"; + String appId = "9ed4dfed9540423fa04842916c54e0d1"; + String appKey = "20f00a8b37aa4ddda56e7eed2ef6fe2b"; + OpenApiClient openApiClient = new DefaultOpenApiClient(url,appId,appKey); + IdCardVerifyRequest request = new IdCardVerifyRequest(); + request.setData("{\"userNo\":\"370203\",\"userName\":\"李铁柱\",\"certCode\":\"370203199809012323\"}"); + IdCardVerifyResponse response = openApiClient.execute(request); + System.out.println(response.getData()); + System.out.println(response.getResultInfo()); + System.out.println(response.getResultInfo()); + } + + /** + * 楠云标签查询 + * @throws OpenApiException + */ + @org.junit.Test + public void testNyBankCardTag() throws OpenApiException { + String url = "https://api-mop.chinaums.com/"; + String appId = "9ed4dfed9540423fa04842916c54e0d1"; + String appKey = "20f00a8b37aa4ddda56e7eed2ef6fe2b"; + OpenApiClient openApiClient = new DefaultOpenApiClient(url,appId,appKey); + NyBankCardTagRequest nyBankCardTagRequest = new NyBankCardTagRequest(); + nyBankCardTagRequest.setData("{\"userNo\":\"000000003\",\"priAcctNo\":\"6228480028307505074\",\"riskflag\":\"1\"}"); + NyBankCardTagResponse nyBankCardTagResponse; + nyBankCardTagResponse = openApiClient.execute(nyBankCardTagRequest); + System.out.println(nyBankCardTagResponse.getData()); + System.out.println(nyBankCardTagResponse.getResultCode()); + System.out.println(nyBankCardTagResponse.getResultInfo()); + } + + /** + * 盐商标签查询 + * @throws OpenApiException + */ + @org.junit.Test + public void testYsBankCardTag() throws OpenApiException { + String url = "https://api-mop.chinaums.com/"; + String appId = "9ed4dfed9540423fa04842916c54e0d1"; + String appKey = "20f00a8b37aa4ddda56e7eed2ef6fe2b"; + OpenApiClient openApiClient = new DefaultOpenApiClient(url,appId,appKey); + YsBankCardTagRequest ysBankCardTagRequest = new YsBankCardTagRequest(); + ysBankCardTagRequest.setData("{\"phoneNo\":\"18771059056\",\"priAcctNo\":\"3568570112914437\"}"); + YsBankCardTagResponse ysBankCardTagResponse; + ysBankCardTagResponse = openApiClient.execute(ysBankCardTagRequest); + System.out.println(ysBankCardTagResponse.getData()); + System.out.println(ysBankCardTagResponse.getResultCode()); + System.out.println(ysBankCardTagResponse.getResultInfo()); + } + + + @org.junit.Test + public void testEducation() throws OpenApiException { + String url = "https://api-mop.chinaums.com/"; + String appId = "9ed4dfed9540423fa04842916c54e0d1"; + String appKey = "20f00a8b37aa4ddda56e7eed2ef6fe2b"; + OpenApiClient openApiClient = new DefaultOpenApiClient(url,appId,appKey); + EducationInfoVerifyRequest ysBankCardTagRequest = new EducationInfoVerifyRequest(); + ysBankCardTagRequest.setData("{\"certNo\":\"342529198702131248\",\"name\":\"徐紫燕\"}"); + EducationInfoVerifyResponse ysBankCardTagResponse; + ysBankCardTagResponse = openApiClient.execute(ysBankCardTagRequest); + System.out.println(ysBankCardTagResponse.getData()); + System.out.println(ysBankCardTagResponse.getResultCode()); + System.out.println(ysBankCardTagResponse.getResultInfo()); + } +} \ No newline at end of file diff --git a/extLib/chinaumsdk/src/test/java/com/chinaums/test/TokenTestCase.java b/extLib/chinaumsdk/src/test/java/com/chinaums/test/TokenTestCase.java new file mode 100644 index 0000000..125f243 --- /dev/null +++ b/extLib/chinaumsdk/src/test/java/com/chinaums/test/TokenTestCase.java @@ -0,0 +1,29 @@ +package com.chinaums.test; + +import com.chinaums.open.api.DefaultOpenApiClient; +import com.chinaums.open.api.OpenApiClient; +import com.chinaums.open.api.OpenApiException; +import com.chinaums.open.api.response.TokenResponse; +import com.chinaums.open.api.request.TokenRequest; +import org.junit.Test; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/5 + * Time: 17:05 + * 所属模块: + * 功能说明: + */ +public class TokenTestCase { + @Test + public void getToken() throws OpenApiException { + String url = "https://api-mop.chinaums.com/"; + String appId = ""; + String appKey = ""; + OpenApiClient openApiClient = new DefaultOpenApiClient(url,appId,appKey); + TokenRequest tokenRequest = new TokenRequest(appId,appKey); + TokenResponse response = openApiClient.execute(tokenRequest); + System.out.print(response.getAccessToken()); + } +} diff --git a/extLib/chinaumsdk/src/test/java/com/chinaums/test/TokenTestCaseDev.java b/extLib/chinaumsdk/src/test/java/com/chinaums/test/TokenTestCaseDev.java new file mode 100644 index 0000000..6b751e0 --- /dev/null +++ b/extLib/chinaumsdk/src/test/java/com/chinaums/test/TokenTestCaseDev.java @@ -0,0 +1,29 @@ +package com.chinaums.test; + +import com.chinaums.open.api.DefaultOpenApiClient; +import com.chinaums.open.api.OpenApiClient; +import com.chinaums.open.api.OpenApiException; +import com.chinaums.open.api.request.TokenRequest; +import com.chinaums.open.api.response.TokenResponse; +import org.junit.Test; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2016/12/5 + * Time: 17:05 + * 所属模块: + * 功能说明: + */ +public class TokenTestCaseDev { + @Test + public void getToken() throws OpenApiException { + String url = "https://api-mop.chinaums.com/"; + String appId = ""; + String appKey = ""; + OpenApiClient openApiClient = new DefaultOpenApiClient(url,appId,appKey); + TokenRequest tokenRequest = new TokenRequest(appId,appKey); + TokenResponse response = openApiClient.execute(tokenRequest); + System.out.print(response.getAccessToken()); + } +} diff --git a/extLib/chinaumsdk/src/test/java/com/chinaums/test/UniqueTestCase.java b/extLib/chinaumsdk/src/test/java/com/chinaums/test/UniqueTestCase.java new file mode 100644 index 0000000..489448b --- /dev/null +++ b/extLib/chinaumsdk/src/test/java/com/chinaums/test/UniqueTestCase.java @@ -0,0 +1,33 @@ +package com.chinaums.test; + +import com.chinaums.open.api.DefaultOpenApiClient; +import com.chinaums.open.api.OpenApiClient; +import com.chinaums.open.api.OpenApiException; +import com.chinaums.open.api.request.BankVerifyRequest; +import com.chinaums.open.api.response.BankVerifyResponse; + +/** + * Created with IntelliJ IDEA. + * User: ZHANGWEI + * Date: 2017/2/13 + * Time: 14:13 + * 所属模块: + * 功能说明: + */ +public class UniqueTestCase { + public static void main(String[]args) throws OpenApiException { + String url = "https://api-mop.chinaums.com/"; + String appId = ""; + String appKey = ""; + OpenApiClient openApiClient = new DefaultOpenApiClient(url,appId,appKey); + BankVerifyRequest bankVerifyRequest = new BankVerifyRequest(); + bankVerifyRequest.setData("{\"cardNo\":\"\",\"phoneNo\":\"\"}"); + BankVerifyResponse bankVerifyResponse; + for(int i=0;i<5;i++){ + bankVerifyResponse = openApiClient.execute(bankVerifyRequest); + System.out.println(bankVerifyResponse.getData()); + System.out.println(bankVerifyResponse.getResultCode()); + System.out.println(bankVerifyResponse.getResultInfo()); + } + } +} diff --git a/extLib/commons-codec-1.9.jar b/extLib/commons-codec-1.9.jar new file mode 100644 index 0000000000000000000000000000000000000000..ef35f1c50d7c41278bc31f4b9fcfc8fbd708d55d GIT binary patch literal 263965 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 literal 0 HcmV?d00001 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..5adc37a --- /dev/null +++ b/pom.xml @@ -0,0 +1,241 @@ + + + 4.0.0 + + org.chenyon + qichenrent + 1.0-SNAPSHOT + + + 8 + 8 + UTF-8 + 1.8 + + + + + org.rcy.framework + framework-dependencies + 1.0-SNAPSHOT + pom + import + + + + + + org.rcy.framework + framework-data + + + + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.rcy.framework + framework-utils + + + org.springframework.boot + spring-boot-starter-web + + + junit + junit + test + + + com.maxmind.geoip2 + geoip2 + 2.12.0 + + + org.lionsoul + ip2region + 1.7.2 + + + com.chinaums.open + open-api-sdk + 1.0-SNAPSHOT + system + ${project.basedir}/extLib/chinaumsdk/chinaumsdk.jar + + + org.apache + commons-codec + 1.9 + system + ${project.basedir}/extLib/commons-codec-1.9.jar + + + + + qichenrent + + + + src/main/java + + **/*.xml + + + + + + config + config + + **/*.properties + **/*.yml + **/*.xml + + + + src/main/resources + + + install + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + + org.apache.maven.plugins + maven-resources-plugin + 3.2.0 + + + + copy-jar + package + + copy-resources + + + ${project.build.directory}/qichenrent + + + ${project.build.directory} + + ${project.build.finalName}.jar + + + + + + + + + copy-scripts + package + + copy-resources + + + ${project.build.directory}/qichenrent/bin + + + src/main/scripts + + *.sh + *.bat + + + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + ${java.version} + ${java.version} + ${project.build.sourceEncoding} + + -parameters + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + true + + + + org.apache.maven.plugins + maven-javadoc-plugin + + 128m + 512m + + 3.1.1 + + + org.apache.maven.plugins + maven-jar-plugin + 3.1.2 + + + org.apache.maven.plugins + maven-war-plugin + 3.2.3 + + + org.apache.maven.plugins + maven-source-plugin + 3.1.0 + + + org.apache.maven.plugins + maven-scm-plugin + 1.9.5 + + + org.apache.maven.plugins + maven-antrun-plugin + 1.8 + + + org.apache.maven.plugins + maven-dependency-plugin + 3.1.1 + + + org.springframework.boot + spring-boot-maven-plugin + 2.2.5.RELEASE + + + + + \ No newline at end of file diff --git a/src/main/java/org/chenyon/WepApplication.java b/src/main/java/org/chenyon/WepApplication.java new file mode 100644 index 0000000..0f4bfab --- /dev/null +++ b/src/main/java/org/chenyon/WepApplication.java @@ -0,0 +1,13 @@ +package org.chenyon; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class WepApplication { + + public static void main(String[] args) { + System.out.println("Current working dir: " + System.getProperty("user.dir")); + SpringApplication.run(WepApplication.class,args); + } +} \ No newline at end of file diff --git a/src/main/java/org/chenyon/assets/AssetsController.java b/src/main/java/org/chenyon/assets/AssetsController.java new file mode 100644 index 0000000..c935b33 --- /dev/null +++ b/src/main/java/org/chenyon/assets/AssetsController.java @@ -0,0 +1,66 @@ +package org.chenyon.assets; + +import org.chenyon.assets.vo.AssetsPageQueryCondition; +import org.chenyon.assets.vo.AssetsVo; +import org.chenyon.user.LoginCheck; +import org.chenyon.user.UserContext; +import org.rcy.framework.api.entity.PageResult; +import org.rcy.framework.api.entity.ResultMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; + +/** + * 资产查询 + */ +@RestController +@RequestMapping("/assets") +public class AssetsController { + + private static final Logger log = LoggerFactory.getLogger(AssetsController.class); + @Autowired + private AssetsQueryService assetsQueryService; + + @PostMapping("/queryPage") + public ResultMessage pageQueryAssets(@RequestBody AssetsPageQueryCondition condition) { + try { + PageResult pageResult = assetsQueryService.pageQueryAssets(condition); + return ResultMessage.success(pageResult); + }catch (Exception e) { + log.error(e.getMessage(),e); + } + return ResultMessage.success(new PageResult<>()); + } + + @PostMapping("/getMyAssetsList") + @LoginCheck + public ResultMessage getMyAssetsList(@RequestBody AssetsPageQueryCondition condition){ + try { + UserContext userContext = UserContext.get(); + if (userContext == null || userContext.getCusNo() == null) { + return ResultMessage.success(new PageResult()); + } + condition.setCusNo(userContext.getCusNo()); + PageResult pageResult = assetsQueryService.pageQueryAssets(condition); + return ResultMessage.success(pageResult); + }catch (Exception e) { + log.error(e.getMessage(),e); + } + return ResultMessage.success(new PageResult()); + } + + @GetMapping("/detail") + public ResultMessage getDetail(@RequestParam("id") String id) { + try { + AssetsVo assetsVo = assetsQueryService.getAssetsById(id); + return ResultMessage.success(assetsVo); + }catch (Exception e) { + log.error(e.getMessage(),e); + } + return ResultMessage.success(new AssetsVo()); + } + +} diff --git a/src/main/java/org/chenyon/assets/AssetsQueryService.java b/src/main/java/org/chenyon/assets/AssetsQueryService.java new file mode 100644 index 0000000..203c42b --- /dev/null +++ b/src/main/java/org/chenyon/assets/AssetsQueryService.java @@ -0,0 +1,88 @@ +package org.chenyon.assets; + +import org.apache.commons.lang3.StringUtils; +import org.chenyon.assets.vo.AssetsPageQueryCondition; +import org.chenyon.assets.vo.AssetsVo; +import org.chenyon.contract.RentFeeInfo; +import org.chenyon.file.OaFileHandlerService; +import org.chenyon.file.OaFileLocalRefVo; +import org.chenyon.file.OaFileVo; +import org.chenyon.oa.OaAssetService; +import org.chenyon.oa.asset.OaAssetsVo; +import org.rcy.framework.api.entity.PageResult; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + + +@Service +public class AssetsQueryService { + + @Autowired + private OaAssetService oaAssetService; + @Autowired + private OaFileHandlerService oaFileHandlerService; + + public PageResult pageQueryAssets(AssetsPageQueryCondition condition) throws Exception { + //调用OA接口查询 + PageResult pageResultOa = oaAssetService.pageQueryAssets(condition); + PageResult pageResult = new PageResult<>(); + pageResult.setPageNo(pageResultOa.getPageNo()); + pageResult.setPageSize(pageResultOa.getPageSize()); + pageResult.setRecordTotal(pageResultOa.getRecordTotal()); + List assetsVoList = new ArrayList<>(); + for (OaAssetsVo oaAssetsVo : pageResultOa.getResult()) { + AssetsVo assetsVo = new AssetsVo(); + assetsVo.setAssetsNo(oaAssetsVo.getAssetsNo()); + assetsVo.setAssetsType(oaAssetsVo.getAssetsType()); + RentFeeInfo rentFeeInfo = new RentFeeInfo(); + if(StringUtils.isNotBlank(oaAssetsVo.getRentFee())){ + rentFeeInfo.setRentFee(Double.parseDouble(oaAssetsVo.getRentFee())); + } + assetsVo.setFootPrint(oaAssetsVo.getFootPrint()); + assetsVo.setAssetsName(oaAssetsVo.getAssetsName()); + assetsVo.setDetailImgs(oaFileHandlerService.getUrls(true,oaAssetsVo.getAssetsNo(), oaAssetsVo.getFormId(),"AssetsDetailImg",oaAssetsVo.getDetailImg())); + assetsVo.setVrImgs(oaFileHandlerService.getUrls(true,oaAssetsVo.getAssetsNo(), oaAssetsVo.getFormId(),"AssetsVrImg",oaAssetsVo.getVrImg())); + if(assetsVo.getDetailImgs() != null && assetsVo.getDetailImgs().size() > 1) { + assetsVo.setCoverImgUrl(assetsVo.getDetailImgs().get(0)); + } + assetsVoList.add(assetsVo); + } + pageResult.setResult(assetsVoList); + return pageResult; + } + + public AssetsVo getAssetsById(String id) throws Exception { + OaAssetsVo oaAssetsVo = oaAssetService.queryAssetsDetail(id); + AssetsVo assetsVo = new AssetsVo(); + assetsVo.setAssetsNo(oaAssetsVo.getAssetsNo()); + assetsVo.setAssetsType(oaAssetsVo.getAssetsType()); + RentFeeInfo rentFeeInfo = new RentFeeInfo(); + if(StringUtils.isNotBlank(oaAssetsVo.getRentFee())){ + rentFeeInfo.setRentFee(Double.parseDouble(oaAssetsVo.getRentFee())); + } + assetsVo.setFeeInfo(rentFeeInfo); + assetsVo.setFootPrint(oaAssetsVo.getFootPrint()); + assetsVo.setAssetsName(oaAssetsVo.getAssetsName()); + assetsVo.setAssetsStatus(oaAssetsVo.getAssetsStatus()); + assetsVo.setAssetsAddress(oaAssetsVo.getAssetsAddress()); + assetsVo.setAssetsDesc(oaAssetsVo.getAssetsDesc()); + assetsVo.setFloorNo(oaAssetsVo.getFloorNo()); + assetsVo.setRoomNo(oaAssetsVo.getRoomNo()); + assetsVo.setHasLift(oaAssetsVo.getHasLift()); + assetsVo.setLatitude(oaAssetsVo.getLatitude()); + assetsVo.setLongitude(oaAssetsVo.getLongitude()); + assetsVo.setLayout(oaAssetsVo.getLayout()); + assetsVo.setUnitNo(oaAssetsVo.getUnitNo()); + assetsVo.setManagerName(oaAssetsVo.getManagerName()); + assetsVo.setManagerPhone(oaAssetsVo.getManagerPhone()); + assetsVo.setDetailImgs(oaFileHandlerService.getUrls(true,oaAssetsVo.getAssetsNo(), oaAssetsVo.getFormId(),"AssetsDetailImg",oaAssetsVo.getDetailImg())); + assetsVo.setVrImgs(oaFileHandlerService.getUrls(true,oaAssetsVo.getAssetsNo(), oaAssetsVo.getFormId(),"AssetsVrImg",oaAssetsVo.getVrImg())); + if(assetsVo.getDetailImgs() != null) { + assetsVo.setCoverImgUrl(assetsVo.getDetailImgs().get(0)); + } + return assetsVo; + } +} diff --git a/src/main/java/org/chenyon/assets/vo/AssetsPageQueryCondition.java b/src/main/java/org/chenyon/assets/vo/AssetsPageQueryCondition.java new file mode 100644 index 0000000..4bfc8bb --- /dev/null +++ b/src/main/java/org/chenyon/assets/vo/AssetsPageQueryCondition.java @@ -0,0 +1,88 @@ +package org.chenyon.assets.vo; + +import org.rcy.framework.api.entity.PageQueryRequest; + +public class AssetsPageQueryCondition extends PageQueryRequest { + + private String assetsNo;//资产编号 + private String assetsType;//资产类型 + private String city;//所属城市 + private String orderByColumn; //排序字段 + private String isAsc; //排序方式、 + private String assetsStatus;//资产状态 + private String assetsName;//资产名称 + private String cusNo; //客商编码 + private String keyWord; //关键字 + + public String getAssetsType() { + return assetsType; + } + + public void setAssetsType(String assetsType) { + this.assetsType = assetsType; + } + + public String getCity() { + return city; + } + + public void setCity(String city) { + this.city = city; + } + + public String getOrderByColumn() { + return orderByColumn; + } + + public void setOrderByColumn(String orderByColumn) { + this.orderByColumn = orderByColumn; + } + + public String getIsAsc() { + return isAsc; + } + + public void setIsAsc(String isAsc) { + this.isAsc = isAsc; + } + + public String getAssetsStatus() { + return assetsStatus; + } + + public void setAssetsStatus(String assetsStatus) { + this.assetsStatus = assetsStatus; + } + + public String getAssetsName() { + return assetsName; + } + + public void setAssetsName(String assetsName) { + this.assetsName = assetsName; + } + + public String getCusNo() { + return cusNo; + } + + public void setCusNo(String cusNo) { + this.cusNo = cusNo; + } + + public String getAssetsNo() { + return assetsNo; + } + + public void setAssetsNo(String assetsNo) { + this.assetsNo = assetsNo; + } + + public String getKeyWord() { + return keyWord; + } + + public void setKeyWord(String keyWord) { + this.keyWord = keyWord; + } +} diff --git a/src/main/java/org/chenyon/assets/vo/AssetsVo.java b/src/main/java/org/chenyon/assets/vo/AssetsVo.java new file mode 100644 index 0000000..5d889d2 --- /dev/null +++ b/src/main/java/org/chenyon/assets/vo/AssetsVo.java @@ -0,0 +1,199 @@ +package org.chenyon.assets.vo; + +import org.chenyon.contract.RentFeeInfo; + +import java.io.Serializable; +import java.util.List; + +public class AssetsVo implements Serializable { + + private String assetsNo; // 资产编号 + private String assetsName; // 资产名称 + private String assetsType; //资产类型 + private String assetsStatus; //资产状态 + private String footPrint; //占地大小 + private String coverImgUrl; //封面图片 + private List detailImgs; //详情图片 + private List vrImgs; //vr图 + private String assetsDesc; //资产描述 + private RentFeeInfo feeInfo; //租赁费用信息 + private String latitude; //纬度 + private String longitude; //经度 + private String managerName; //管理员 + private String managerPhone; //管理员电话 + private String unitNo; //单元号 + private String floorNo; //楼层号 + private String roomNo; //房间号 + private Boolean hasLift;//有无电梯 + private String layout; //户型 + private String orientation; //朝向 + private String assetsAddress; //资产地址 + + public String getManagerName() { + return managerName; + } + + public void setManagerName(String managerName) { + this.managerName = managerName; + } + + public String getManagerPhone() { + return managerPhone; + } + + public void setManagerPhone(String managerPhone) { + this.managerPhone = managerPhone; + } + + public String getAssetsName() { + return assetsName; + } + + public void setAssetsName(String assetsName) { + this.assetsName = assetsName; + } + + public String getAssetsType() { + return assetsType; + } + + public void setAssetsType(String assetsType) { + this.assetsType = assetsType; + } + + public String getAssetsStatus() { + return assetsStatus; + } + + public void setAssetsStatus(String assetsStatus) { + this.assetsStatus = assetsStatus; + } + + public String getFootPrint() { + return footPrint; + } + + public void setFootPrint(String footPrint) { + this.footPrint = footPrint; + } + + public String getCoverImgUrl() { + return coverImgUrl; + } + + public void setCoverImgUrl(String coverImgUrl) { + this.coverImgUrl = coverImgUrl; + } + + public String getAssetsDesc() { + return assetsDesc; + } + + public void setAssetsDesc(String assetsDesc) { + this.assetsDesc = assetsDesc; + } + + public String getAssetsNo() { + return assetsNo; + } + + public void setAssetsNo(String assetsNo) { + this.assetsNo = assetsNo; + } + + public List getDetailImgs() { + return detailImgs; + } + + public void setDetailImgs(List detailImgs) { + this.detailImgs = detailImgs; + } + + public List getVrImgs() { + return vrImgs; + } + + public void setVrImgs(List vrImgs) { + this.vrImgs = vrImgs; + } + + public RentFeeInfo getFeeInfo() { + return feeInfo; + } + + public void setFeeInfo(RentFeeInfo feeInfo) { + this.feeInfo = feeInfo; + } + + public String getLatitude() { + return latitude; + } + + public void setLatitude(String latitude) { + this.latitude = latitude; + } + + public String getLongitude() { + return longitude; + } + + public void setLongitude(String longitude) { + this.longitude = longitude; + } + + public String getUnitNo() { + return unitNo; + } + + public void setUnitNo(String unitNo) { + this.unitNo = unitNo; + } + + public String getFloorNo() { + return floorNo; + } + + public void setFloorNo(String floorNo) { + this.floorNo = floorNo; + } + + public String getRoomNo() { + return roomNo; + } + + public void setRoomNo(String roomNo) { + this.roomNo = roomNo; + } + + public Boolean getHasLift() { + return hasLift; + } + + public void setHasLift(Boolean hasLift) { + this.hasLift = hasLift; + } + + public String getLayout() { + return layout; + } + + public void setLayout(String layout) { + this.layout = layout; + } + + public String getOrientation() { + return orientation; + } + + public void setOrientation(String orientation) { + this.orientation = orientation; + } + + public String getAssetsAddress() { + return assetsAddress; + } + + public void setAssetsAddress(String assetsAddress) { + this.assetsAddress = assetsAddress; + } +} diff --git a/src/main/java/org/chenyon/auth/AuthController.java b/src/main/java/org/chenyon/auth/AuthController.java new file mode 100644 index 0000000..34f90dd --- /dev/null +++ b/src/main/java/org/chenyon/auth/AuthController.java @@ -0,0 +1,51 @@ +package org.chenyon.auth; + +import org.apache.commons.lang3.StringUtils; +import org.chenyon.file.OaFileHandlerService; +import org.chenyon.user.UserService; +import org.chenyon.user.UserVo; +import org.chenyon.wx.WxUserSession; +import org.chenyon.wx.WxUserSessionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; + +@RestController +@RequestMapping("/auth") +public class AuthController { + + @Autowired + private UserService userService; + @Autowired + private WxUserSessionService wxUserSessionService; + @Autowired + private OaFileHandlerService oaFileHandlerService; + + @GetMapping("/resourceCheck") + public ResponseEntity resourceCheck(HttpServletRequest request) { + String path = request.getHeader("X-Original-Path"); + String uri = request.getHeader("X-Original-URI"); + + if (uri.startsWith("/private")) { + String token = request.getHeader("X-Token"); + String userType = request.getHeader("USERTYPE"); + if(StringUtils.isAnyBlank(token, userType)) { + return ResponseEntity.status(403).build(); + } + WxUserSession session = wxUserSessionService.getSessionInfoByThirdSession(token); + if (session == null) { + return ResponseEntity.status(403).build(); + } + UserVo userVo = userService.findByOpenIdAndUserType(session.getOpenId(), userType); + String owner = oaFileHandlerService.findOwnerByUrl(uri); + if(owner == null || !owner.equals(userVo.getCusNo())) { + return ResponseEntity.status(403).build(); + } + } + return ResponseEntity.ok().build(); + } +} \ No newline at end of file diff --git a/src/main/java/org/chenyon/bill/BillController.java b/src/main/java/org/chenyon/bill/BillController.java new file mode 100644 index 0000000..73f17e0 --- /dev/null +++ b/src/main/java/org/chenyon/bill/BillController.java @@ -0,0 +1,98 @@ +package org.chenyon.bill; + +import org.chenyon.user.LoginCheck; +import org.chenyon.user.UserContext; +import org.rcy.framework.api.entity.PageResult; +import org.rcy.framework.api.entity.ResultMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/bill") +public class BillController { + + private static final Logger log = LoggerFactory.getLogger(BillController.class); + + @Autowired + private BillService billService; + + @LoginCheck + @PostMapping("/pageQueryContractBill") + public ResultMessage pageQueryContractBill(@RequestBody BillQueryCondition condition) { + try { + UserContext userContext = UserContext.get(); + if(userContext == null || userContext.getCusNo() == null) { + return ResultMessage.success(new PageResult()); + } + condition.setCusNo(userContext.getCusNo()); + return ResultMessage.success(billService.pageQueryContractBill(condition)); + }catch (Exception e) { + log.error(e.getMessage(),e); + } + return ResultMessage.success(new PageResult()); + } + + @LoginCheck + @PostMapping("/pageQueryWaeBill") + public ResultMessage pageQueryWaeBill(@RequestBody BillQueryCondition condition){ + try { + UserContext userContext = UserContext.get(); + if(userContext == null || userContext.getCusNo() == null) { + return ResultMessage.success(new PageResult()); + } + condition.setCusNo(userContext.getCusNo()); + return ResultMessage.success(billService.pageQueryWaeBill(condition)); + }catch (Exception e) { + log.error(e.getMessage(),e); + } + return ResultMessage.success(new PageResult()); + } + + @PostMapping("/pageQueryPayRecord") + @LoginCheck + public ResultMessage pageQueryWaePayRecord(@RequestBody PayRecordQueryConditon condition) { + try { + UserContext userContext = UserContext.get(); + if(userContext == null || userContext.getCusNo() == null) { + return ResultMessage.success(new PageResult()); + } + condition.setCusNo(userContext.getCusNo()); + return ResultMessage.success(billService.pageQueryContractPayRecord(condition)); + }catch (Exception e) { + log.error(e.getMessage(),e); + } + return ResultMessage.success(new PageResult()); + } + + @LoginCheck + @GetMapping("/countUnpayRentBills") + public ResultMessage countUnpayRentBills() { + try { + UserContext userContext = UserContext.get(); + if(userContext == null || userContext.getCusNo() == null) { + return ResultMessage.success(0); + } + return ResultMessage.success(billService.countUnpayRentBills(userContext.getCusNo())); + }catch (Exception e) { + log.error(e.getMessage(),e); + } + return ResultMessage.success(0); + } + + @LoginCheck + @GetMapping("/countUnpayWaeBills") + public ResultMessage countUnpayWaeBills() { + try { + UserContext userContext = UserContext.get(); + if(userContext == null || userContext.getCusNo() == null) { + return ResultMessage.success(0); + } + return ResultMessage.success(billService.countUnpayWaeBills(userContext.getCusNo())); + }catch (Exception e) { + log.error(e.getMessage(),e); + } + return ResultMessage.success(0); + } +} diff --git a/src/main/java/org/chenyon/bill/BillQueryCondition.java b/src/main/java/org/chenyon/bill/BillQueryCondition.java new file mode 100644 index 0000000..083b47a --- /dev/null +++ b/src/main/java/org/chenyon/bill/BillQueryCondition.java @@ -0,0 +1,34 @@ +package org.chenyon.bill; + +import org.rcy.framework.api.entity.PageQueryRequest; + +public class BillQueryCondition extends PageQueryRequest { + + private String cusNo; //客商编码 + private String year; //年份 + private String billStatus; //账单状态 + + public String getCusNo() { + return cusNo; + } + + public void setCusNo(String cusNo) { + this.cusNo = cusNo; + } + + public String getYear() { + return year; + } + + public void setYear(String year) { + this.year = year; + } + + public String getBillStatus() { + return billStatus; + } + + public void setBillStatus(String billStatus) { + this.billStatus = billStatus; + } +} diff --git a/src/main/java/org/chenyon/bill/BillService.java b/src/main/java/org/chenyon/bill/BillService.java new file mode 100644 index 0000000..8c2794c --- /dev/null +++ b/src/main/java/org/chenyon/bill/BillService.java @@ -0,0 +1,42 @@ +package org.chenyon.bill; + +import org.chenyon.oa.OaBillService; +import org.chenyon.oa.bill.OaBillVo; +import org.chenyon.oa.bill.OaPayRecordVo; +import org.rcy.framework.api.entity.PageResult; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; + +@Service +public class BillService { + + @Autowired + private OaBillService oaBillService; + + public PageResult pageQueryContractBill(BillQueryCondition condition) throws Exception { + return oaBillService.pageQueryContractBill(condition); + } + + public PageResult pageQueryWaeBill(BillQueryCondition condition) throws Exception { + return oaBillService.pageQueryWaeBill(condition); + } + public PageResult pageQueryContractPayRecord(PayRecordQueryConditon condition) throws Exception { + return oaBillService.pageQueryPayRecord(condition); + } + + public Integer countUnpayRentBills(String cusNo) throws Exception { + Map params = new HashMap<>(); + params.put("cusNo",cusNo); + return oaBillService.countUnpayRentBills(params); + } + + public Integer countUnpayWaeBills(String cusNo) throws Exception { + Map params = new HashMap<>(); + params.put("cusNo",cusNo); + return oaBillService.countUnpayWaeBills(params); + } + +} diff --git a/src/main/java/org/chenyon/bill/PayRecordQueryConditon.java b/src/main/java/org/chenyon/bill/PayRecordQueryConditon.java new file mode 100644 index 0000000..a10c585 --- /dev/null +++ b/src/main/java/org/chenyon/bill/PayRecordQueryConditon.java @@ -0,0 +1,42 @@ +package org.chenyon.bill; + +import org.rcy.framework.api.entity.PageQueryRequest; + +public class PayRecordQueryConditon extends PageQueryRequest { + private String cusNo; + private String leType; + private String year; //年份 + private String billType; + + public String getCusNo() { + return cusNo; + } + + public void setCusNo(String cusNo) { + this.cusNo = cusNo; + } + + public String getLeType() { + return leType; + } + + public void setLeType(String leType) { + this.leType = leType; + } + + public String getYear() { + return year; + } + + public void setYear(String year) { + this.year = year; + } + + public String getBillType() { + return billType; + } + + public void setBillType(String billType) { + this.billType = billType; + } +} diff --git a/src/main/java/org/chenyon/cache/WxTokenCache.java b/src/main/java/org/chenyon/cache/WxTokenCache.java new file mode 100644 index 0000000..aaccd4d --- /dev/null +++ b/src/main/java/org/chenyon/cache/WxTokenCache.java @@ -0,0 +1,23 @@ +package org.chenyon.cache; + +public class WxTokenCache { + + private String token; + private long expireTime; + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public long getExpireTime() { + return expireTime; + } + + public void setExpireTime(long expireTime) { + this.expireTime = expireTime; + } +} diff --git a/src/main/java/org/chenyon/config/SpringMvcConfigurer.java b/src/main/java/org/chenyon/config/SpringMvcConfigurer.java new file mode 100644 index 0000000..cf4841b --- /dev/null +++ b/src/main/java/org/chenyon/config/SpringMvcConfigurer.java @@ -0,0 +1,64 @@ +package org.chenyon.config; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.deser.std.DateDeserializers; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.databind.ser.std.DateSerializer; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import org.chenyon.interceptor.LoginCheckInterceptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; +import org.springframework.web.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +/** + * @author 吴康桥 + * @Description + * @date 2022/10/10 14:29 + */ + +@Configuration +public class SpringMvcConfigurer implements WebMvcConfigurer { + + @Autowired + private LoginCheckInterceptor loginCheckInterceptor; + + @Bean + @Primary + public ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) { + ObjectMapper mapper = builder.createXmlMapper(false).timeZone(TimeZone.getTimeZone("Asia/Shanghai")).build(); + //忽略值为null的属性 + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + SimpleModule module = new SimpleModule(); + module.addSerializer(Long.class, new ToStringSerializer()); + module.addSerializer(Date.class, new DateSerializer(false, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"))); + module.addDeserializer(Date.class, new DateDeserializers.DateDeserializer(new DateDeserializers.DateDeserializer(), new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"), "yyyy-MM-dd HH:mm:ss" )); + mapper.registerModule(module); + return mapper; + } + + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(loginCheckInterceptor) + .addPathPatterns("/**"); + } + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOrigins("*") // 允许所有域名访问,生产环境可以换成指定域名 + .allowedMethods("GET","POST","PUT","DELETE","OPTIONS") + .allowCredentials(true) + .maxAge(3600); + } +} diff --git a/src/main/java/org/chenyon/constants/OaApiUrl.java b/src/main/java/org/chenyon/constants/OaApiUrl.java new file mode 100644 index 0000000..911a350 --- /dev/null +++ b/src/main/java/org/chenyon/constants/OaApiUrl.java @@ -0,0 +1,116 @@ +package org.chenyon.constants; + +public final class OaApiUrl { + /** + * 匹配个人 + */ + public static final String MATCH_PERSON = "/cus/matchPerson"; + /** + * 匹配组织 + */ + public static final String MATCH_ORG = "/cus/matchOrg"; + /** + * 查询客商信息 + */ + public static final String CUS_INFO = "/cus/getCusInfo"; + /** + * 分页查询资产 + */ + public static final String PAGE_QUERY_ASSETS = "/assets/queryPage"; + /** + * 查询资产详情 + */ + public static final String QUERY_ASSETS_DETAIL = "/assets/detail"; + /** + * 分页查询合同 + */ + public static final String PAGE_QUERY_CONTRACT = "/contract/queryPage"; + /** + * 查询合同详情 + */ + public static final String CONTRACT_DETAIL = "/contract/detail"; + /** + * 查询合同详情 + */ + public static final String CONTRACT_SIGN_LINK = "/contract/getSignLink"; + /** + * 统计待签署合同份数 + */ + public static final String CONTRACT_COUNT_UNSIGN = "/contract/countUnsign"; + /** + * 查询客户所有已完成的合同信息 + */ + public static final String CONTRACT_ALL = "/contract/queryAll"; + /** + * 分页查询合同关联资产信息 + */ + public static final String PAGE_QUERY_CONTRACT_ASSETS = "/pageQueryAssets"; + /** + * 分页查询合同账单 + */ + public static final String PAGE_QUERY_CONTRACT_BILL = "/bill/contractBill/queryPage"; + /** + * 分页查询水电费账单 + */ + public static final String PAGE_QUERY_WAE_BILL = "/bill/waeBill/queryPage"; + /** + * 分页查询缴费记录 + */ + public static final String PAGE_QUERY_PAY_RECORD = "/bill/payRecord/queryPage"; + /** + * 统计未缴租金账单数 + */ + public static final String COUNT_UNPAY_RENT_BILLS = "/bill/countUnpay/rent"; + /** + * 统计未缴水电费账单数 + */ + public static final String COUNT_UNPAY_WAE_BILLS = "/bill/countUnpay/wae"; + /** + * 分页查询公告 + */ + public static final String PAGE_QUERY_NOTICE = "/notice/queryPage"; + /** + * 分页查询公告 + */ + public static final String QUERY_NOTICE_DETAIL = "/notice/detail"; + /** + * 分页查询留言 + */ + public static final String PAGE_QUERY_FALLBACK = "/fallback/queryPage"; + /** + * 查询留言详情 + */ + public static final String FALLBACK_DETAIL = "/fallback/detail"; + /** + * 提交留言 + */ + public static final String FALLBACK_SUBMIT = "/fallback/submit"; + /** + * 分页查询预约记录 + */ + public static final String PAGE_QUERY_RESERVATION = "/reserve/queryPage"; + /** + * 新增预约 + */ + public static final String RESERVATION_SUBMIT = "/reserve/apply"; + /** + * 新增预约 + */ + public static final String RESERVATION_COUNT_HANDLING = "/reserve/countHandling"; + /** + * 分页查询退租申请记录 + */ + public static final String PAGE_QUERY_DISCHARGE = "/discharge/queryPage"; + /** + * 提交退租申请 + */ + public static final String DISCHARGE_APPLY = "/discharge/apply"; + /** + * 下载文件 + */ + public static final String FILE_DOWNLOAD = "/fileTransport/downloadFile"; + /** + * 下载文件 + */ + public static final String VIEW_RECORD_ADD = "/potential/add"; +} diff --git a/src/main/java/org/chenyon/contract/ContractAssetsVo.java b/src/main/java/org/chenyon/contract/ContractAssetsVo.java new file mode 100644 index 0000000..8c172d8 --- /dev/null +++ b/src/main/java/org/chenyon/contract/ContractAssetsVo.java @@ -0,0 +1,68 @@ +package org.chenyon.contract; + +public class ContractAssetsVo { + + private String assetsNo; // 资产编号 + private String assetsName; // 资产名称 + private String rentFee; //租金 + private String formId; //表单记录ID + private String cover; //封面 + private RentFeeInfo feeInfo; + private String footPrint; //占地大小 + + public String getAssetsNo() { + return assetsNo; + } + + public void setAssetsNo(String assetsNo) { + this.assetsNo = assetsNo; + } + + public String getAssetsName() { + return assetsName; + } + + public void setAssetsName(String assetsName) { + this.assetsName = assetsName; + } + + public String getRentFee() { + return rentFee; + } + + public void setRentFee(String rentFee) { + this.rentFee = rentFee; + } + + public String getFormId() { + return formId; + } + + public void setFormId(String formId) { + this.formId = formId; + } + + public String getCover() { + return cover; + } + + public void setCover(String cover) { + this.cover = cover; + } + + public RentFeeInfo getFeeInfo() { + return feeInfo; + } + + public void setFeeInfo(RentFeeInfo feeInfo) { + this.feeInfo = feeInfo; + } + + public String getFootPrint() { + return footPrint; + } + + public void setFootPrint(String footPrint) { + this.footPrint = footPrint; + } +} \ No newline at end of file diff --git a/src/main/java/org/chenyon/contract/ContractController.java b/src/main/java/org/chenyon/contract/ContractController.java new file mode 100644 index 0000000..8a9f04e --- /dev/null +++ b/src/main/java/org/chenyon/contract/ContractController.java @@ -0,0 +1,103 @@ +package org.chenyon.contract; + +import org.chenyon.user.LoginCheck; +import org.chenyon.user.UserContext; +import org.rcy.framework.api.entity.PageResult; +import org.rcy.framework.api.entity.ResultMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import java.util.ArrayList; + +@RestController +@RequestMapping("/contract") +public class ContractController { + private static final Logger log = LoggerFactory.getLogger(ContractController.class); + + @Autowired + private ContractService contractService; + + @PostMapping("/queryPage") + @LoginCheck + public ResultMessage queryContractPage(@RequestBody ContractQueryCondition condition) { + try { + UserContext userContext = UserContext.get(); + if(userContext == null || userContext.getCusNo() == null) { + return ResultMessage.success(new PageResult()); + } + condition.setCusNo(userContext.getCusNo()); + PageResult pageResult = contractService.queryContractPage(condition); + return ResultMessage.success(pageResult); + }catch (Exception e) { + log.error(e.getMessage()); + } + return ResultMessage.success(); + } + + @GetMapping("/detail") + @LoginCheck + public ResultMessage contractDetail(@RequestParam("contractNo") String contractNo){ + try { + UserContext userContext = UserContext.get(); + if(userContext == null) { + return ResultMessage.success(); + } + return ResultMessage.success(contractService.queryContractDetail(userContext.getCusNo(), contractNo)); + }catch (Exception e) { + log.error(e.getMessage(),e); + } + return ResultMessage.error("查询合同信息失败"); + } + + @GetMapping("/countUnsign") + @LoginCheck + public ResultMessage countUnsign(){ + try { + UserContext userContext = UserContext.get(); + if(userContext == null || userContext.getCusNo() == null) { + return ResultMessage.success(0); + } + return ResultMessage.success(contractService.countUnsign(userContext.getCusNo())); + }catch (Exception e) { + log.error(e.getMessage(),e); + } + return ResultMessage.success(0); + } + + + @PostMapping("/queryAssets") + @LoginCheck + public ResultMessage queryAssets(String formId,Integer pageNo,Integer pageSize) throws Exception { + return ResultMessage.success(contractService.queryMoreContractAssets(formId,pageNo,pageSize)); + } + + @GetMapping("/getSignLink") + @LoginCheck + public ResultMessage getSignLink(@RequestParam("eFlowId") String eFlowId){ + try { + return ResultMessage.success(contractService.getSignLink(eFlowId)); + }catch (Exception e) { + log.error(e.getMessage(),e); + } + return ResultMessage.error("获取签署链接失败"); + } + + @GetMapping("/queryAll") + @LoginCheck + public ResultMessage queryAll(){ + try { + UserContext userContext = UserContext.get(); + if(userContext == null || userContext.getCusNo() == null) { + return ResultMessage.success(); + } + return ResultMessage.success(contractService.queryAll(userContext.getCusNo())); + }catch (Exception e) { + log.error(e.getMessage(),e); + } + return ResultMessage.success(new ArrayList<>()); + } + +} diff --git a/src/main/java/org/chenyon/contract/ContractQueryCondition.java b/src/main/java/org/chenyon/contract/ContractQueryCondition.java new file mode 100644 index 0000000..eaa48a9 --- /dev/null +++ b/src/main/java/org/chenyon/contract/ContractQueryCondition.java @@ -0,0 +1,52 @@ +package org.chenyon.contract; + +import org.rcy.framework.api.entity.PageQueryRequest; + +public class ContractQueryCondition extends PageQueryRequest { + + private String cusNo; + private String contractNo; + private String formmainId; + private String signStatus; + private String signWay; + + public String getCusNo() { + return cusNo; + } + + public void setCusNo(String cusNo) { + this.cusNo = cusNo; + } + + public String getContractNo() { + return contractNo; + } + + public void setContractNo(String contractNo) { + this.contractNo = contractNo; + } + + public String getFormmainId() { + return formmainId; + } + + public void setFormmainId(String formmainId) { + this.formmainId = formmainId; + } + + public String getSignStatus() { + return signStatus; + } + + public void setSignStatus(String signStatus) { + this.signStatus = signStatus; + } + + public String getSignWay() { + return signWay; + } + + public void setSignWay(String signWay) { + this.signWay = signWay; + } +} diff --git a/src/main/java/org/chenyon/contract/ContractService.java b/src/main/java/org/chenyon/contract/ContractService.java new file mode 100644 index 0000000..a5a805f --- /dev/null +++ b/src/main/java/org/chenyon/contract/ContractService.java @@ -0,0 +1,149 @@ +package org.chenyon.contract; + +import org.apache.commons.lang3.StringUtils; +import org.chenyon.assets.vo.AssetsVo; +import org.chenyon.file.OaFileHandlerService; +import org.chenyon.file.OaFileLocalRefVo; +import org.chenyon.file.OaFileVo; +import org.chenyon.oa.OaContractService; +import org.chenyon.oa.asset.OaAssetsVo; +import org.chenyon.oa.contract.OaContractVo; +import org.rcy.framework.api.entity.PageResult; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +@Service +public class ContractService { + + @Autowired + private OaContractService oaContractService; + @Autowired + private OaFileHandlerService oaFileHandlerService; + + private void hanldeSignStatus(ContractQueryCondition condition) { + if (StringUtils.isNotBlank(condition.getSignStatus())) { + switch (condition.getSignStatus()){ + case "all": condition.setSignStatus(null);break; + case "pending" : condition.setSignStatus("待签署");break; + case "signed" : condition.setSignStatus("已签署");break; + case "expired" : condition.setSignStatus("已过期");break; + } + } + } + + private String convertSignStatus(String status) { + if (StringUtils.isNotBlank(status)) { + switch (status){ + case "待签署" : return "pending"; + case "已签署" : return "signed"; + case "已过期" : return "expired"; + } + } + return ""; + } + + public PageResult queryContractPage(ContractQueryCondition condition) throws Exception { + //调用OA接口查询 + hanldeSignStatus(condition); + PageResult pageResultOa = oaContractService.pageQueryContract(condition); + PageResult pageResult = new PageResult<>(); + pageResult.setPageNo(pageResultOa.getPageNo()); + pageResult.setPageSize(pageResultOa.getPageSize()); + pageResult.setRecordTotal(pageResultOa.getRecordTotal()); + List contractVoList = new ArrayList<>(); + for (OaContractVo oaContractVo : pageResultOa.getResult()) { + ContractVo contractVo = new ContractVo(); + BeanUtils.copyProperties(oaContractVo, contractVo); + if(oaContractVo.getAssetsVos() != null) { + List assetsVos = oaContractVo.getAssetsVos(); + OaAssetsVo assetsVo = assetsVos.get(0); + List assetsDetailImgs = oaFileHandlerService.getUrls(true,assetsVo.getAssetsNo(), assetsVo.getFormId(), "AssetsDetailImg", assetsVo.getDetailImg()); + if(assetsDetailImgs != null) { + contractVo.setCoverImgUrl(assetsDetailImgs.get(0)); + } + } + contractVo.setSignStatus(convertSignStatus(contractVo.getSignStatus())); + contractVoList.add(contractVo); + } + pageResult.setResult(contractVoList); + return pageResult; + } + + public List queryAll(String cusNo) throws Exception { + ContractQueryCondition condition = new ContractQueryCondition(); + condition.setCusNo(cusNo); + condition.setSignStatus("已签署"); + List contractVos = new ArrayList<>(); + List oaContractVos = oaContractService.queryAll(condition); + for (OaContractVo oaContractVo : oaContractVos) { + ContractVo contractVo = new ContractVo(); + BeanUtils.copyProperties(oaContractVo, contractVo); + contractVos.add(contractVo); + } + return contractVos; + } + + public ContractAssetsVo queryMoreContractAssets(String formId,Integer pageNo,Integer pageSize) throws Exception { + ContractQueryCondition condition = new ContractQueryCondition(); + condition.setFormmainId(formId); + condition.setPageNo(pageNo); + condition.setPageSize(pageSize); + OaAssetsVo assetsVo = oaContractService.pageQueryContractAssets(condition); + List assetsDetailImgs = oaFileHandlerService.getUrls(true,assetsVo.getAssetsNo(), assetsVo.getFormId(), "AssetsDetailImg", assetsVo.getDetailImg()); + ContractAssetsVo assetsInfo = new ContractAssetsVo(); + BeanUtils.copyProperties(assetsVo, assetsInfo); + RentFeeInfo rentFeeInfo = new RentFeeInfo(); + if(StringUtils.isNotBlank(assetsVo.getRentFee())){ + rentFeeInfo.setRentFee(Double.parseDouble(assetsVo.getRentFee())); + } + assetsInfo.setFeeInfo(rentFeeInfo); + if(assetsDetailImgs != null) { + assetsInfo.setCover(assetsDetailImgs.get(0)); + } + return assetsInfo; + } + public Integer countUnsign(String cusNo) throws Exception { + Integer count = oaContractService.countUnsign(cusNo); + return count; + } + + public ContractVo queryContractDetail(String cusNo,String contractNo) throws Exception { + ContractQueryCondition condition = new ContractQueryCondition(); + condition.setContractNo(contractNo); + OaContractVo oaContractVo = oaContractService.queryContractDetail(condition); + if(!cusNo.equals(oaContractVo.getCusNo())) { + return null; + } + ContractVo contractVo = new ContractVo(); + BeanUtils.copyProperties(oaContractVo, contractVo); + List assetsVos = oaContractVo.getAssetsVos(); + OaAssetsVo assetsVo = assetsVos.get(0); + List assetsDetailImgs = oaFileHandlerService.getUrls(true,assetsVo.getAssetsNo(), assetsVo.getFormId(), "AssetsDetailImg", assetsVo.getDetailImg()); + List eContractUrl = oaFileHandlerService.getUrls(false,cusNo,oaContractVo.getContractNo(),oaContractVo.getFormId(),"eContractFile",oaContractVo.geteContractFile()); + ContractAssetsVo assetsInfo = new ContractAssetsVo(); + BeanUtils.copyProperties(assetsVo, assetsInfo); + RentFeeInfo rentFeeInfo = new RentFeeInfo(); + if(StringUtils.isNotBlank(assetsVo.getRentFee())){ + rentFeeInfo.setRentFee(Double.parseDouble(assetsVo.getRentFee())); + } + assetsInfo.setFeeInfo(rentFeeInfo); + if(assetsDetailImgs != null) { + assetsInfo.setCover(assetsDetailImgs.get(0)); + } + if(eContractUrl != null) { + contractVo.seteContractUrl(eContractUrl.get(0)); + } + List assetsInfoList = new ArrayList<>(); + assetsInfoList.add(assetsInfo); + contractVo.setAssetsInfos(assetsInfoList); + return contractVo; + } + public String getSignLink(String eFlowId) throws Exception { + String signLink = oaContractService.getSignLink(eFlowId); + return signLink; + } +} diff --git a/src/main/java/org/chenyon/contract/ContractVo.java b/src/main/java/org/chenyon/contract/ContractVo.java new file mode 100644 index 0000000..e8189f7 --- /dev/null +++ b/src/main/java/org/chenyon/contract/ContractVo.java @@ -0,0 +1,107 @@ +package org.chenyon.contract; + +import org.chenyon.assets.vo.AssetsVo; + +import java.util.List; + +public class ContractVo { + private String formId; //表单ID + private String contractNo; //合同编号 + private String contractName; //合同名称 + private String signStatus; //签订状态 + private String startDate; //开始日期 + private String endDate; //开始日期 + private String eContractUrl; //电子合同文件地址 + private String eContractFlowId; //电子合同签署流程ID + private List assetsInfos; //资产信息 + private String coverImgUrl; //封面图片信息 + private String cusNo; //客商编码 + + public String getContractNo() { + return contractNo; + } + + public void setContractNo(String contractNo) { + this.contractNo = contractNo; + } + + public String getContractName() { + return contractName; + } + + public void setContractName(String contractName) { + this.contractName = contractName; + } + + public String getSignStatus() { + return signStatus; + } + + public void setSignStatus(String signStatus) { + this.signStatus = signStatus; + } + + public List getAssetsInfos() { + return assetsInfos; + } + + public void setAssetsInfos(List assetsInfos) { + this.assetsInfos = assetsInfos; + } + + public String geteContractUrl() { + return eContractUrl; + } + + public void seteContractUrl(String eContractUrl) { + this.eContractUrl = eContractUrl; + } + + public String getCusNo() { + return cusNo; + } + + public void setCusNo(String cusNo) { + this.cusNo = cusNo; + } + + public String geteContractFlowId() { + return eContractFlowId; + } + + public void seteContractFlowId(String eContractFlowId) { + this.eContractFlowId = eContractFlowId; + } + + public String getCoverImgUrl() { + return coverImgUrl; + } + + public void setCoverImgUrl(String coverImgUrl) { + this.coverImgUrl = coverImgUrl; + } + + public String getFormId() { + return formId; + } + + public void setFormId(String formId) { + this.formId = formId; + } + + public String getStartDate() { + return startDate; + } + + public void setStartDate(String startDate) { + this.startDate = startDate; + } + + public String getEndDate() { + return endDate; + } + + public void setEndDate(String endDate) { + this.endDate = endDate; + } +} diff --git a/src/main/java/org/chenyon/contract/FeeUnit.java b/src/main/java/org/chenyon/contract/FeeUnit.java new file mode 100644 index 0000000..4a92529 --- /dev/null +++ b/src/main/java/org/chenyon/contract/FeeUnit.java @@ -0,0 +1,6 @@ +package org.chenyon.contract; + +public enum FeeUnit { + KWT, //度 + TON //吨 +} diff --git a/src/main/java/org/chenyon/contract/RentFeeInfo.java b/src/main/java/org/chenyon/contract/RentFeeInfo.java new file mode 100644 index 0000000..6ce0a9c --- /dev/null +++ b/src/main/java/org/chenyon/contract/RentFeeInfo.java @@ -0,0 +1,59 @@ +package org.chenyon.contract; + +public class RentFeeInfo { + + private Double deposit; //押金 + private Double rentFee; //租金 + private Double waterFee; //水费 + private FeeUnit waterFeeUnit; //水费单位 + private Double powerFee; //电费 + private FeeUnit powerFeeUnit; //电费单位 + + public Double getDeposit() { + return deposit; + } + + public void setDeposit(Double deposit) { + this.deposit = deposit; + } + + public Double getRentFee() { + return rentFee; + } + + public void setRentFee(Double rentFee) { + this.rentFee = rentFee; + } + + public Double getWaterFee() { + return waterFee; + } + + public void setWaterFee(Double waterFee) { + this.waterFee = waterFee; + } + + public FeeUnit getWaterFeeUnit() { + return waterFeeUnit; + } + + public void setWaterFeeUnit(FeeUnit waterFeeUnit) { + this.waterFeeUnit = waterFeeUnit; + } + + public Double getPowerFee() { + return powerFee; + } + + public void setPowerFee(Double powerFee) { + this.powerFee = powerFee; + } + + public FeeUnit getPowerFeeUnit() { + return powerFeeUnit; + } + + public void setPowerFeeUnit(FeeUnit powerFeeUnit) { + this.powerFeeUnit = powerFeeUnit; + } +} diff --git a/src/main/java/org/chenyon/discharge/DisChargeApplyQueryCondition.java b/src/main/java/org/chenyon/discharge/DisChargeApplyQueryCondition.java new file mode 100644 index 0000000..88d64ce --- /dev/null +++ b/src/main/java/org/chenyon/discharge/DisChargeApplyQueryCondition.java @@ -0,0 +1,15 @@ +package org.chenyon.discharge; + +import org.rcy.framework.api.entity.PageQueryRequest; + +public class DisChargeApplyQueryCondition extends PageQueryRequest { + private String cusNo; + + public String getCusNo() { + return cusNo; + } + + public void setCusNo(String cusNo) { + this.cusNo = cusNo; + } +} diff --git a/src/main/java/org/chenyon/discharge/DisChargeApplyVo.java b/src/main/java/org/chenyon/discharge/DisChargeApplyVo.java new file mode 100644 index 0000000..7b8fda7 --- /dev/null +++ b/src/main/java/org/chenyon/discharge/DisChargeApplyVo.java @@ -0,0 +1,87 @@ +package org.chenyon.discharge; + +import java.util.List; + +public class DisChargeApplyVo { + private String contractNo; + private String contractName; + private List assetsNoList; + private String reason; + private String dischargeDate; + private String cusNo; + private String cusName; + private String cusType; + private String phone; + + public String getContractNo() { + return contractNo; + } + + public void setContractNo(String contractNo) { + this.contractNo = contractNo; + } + + public List getAssetsNoList() { + return assetsNoList; + } + + public void setAssetsNoList(List assetsNoList) { + this.assetsNoList = assetsNoList; + } + + public String getReason() { + return reason; + } + + public void setReason(String reason) { + this.reason = reason; + } + + public String getDischargeDate() { + return dischargeDate; + } + + public void setDischargeDate(String dischargeDate) { + this.dischargeDate = dischargeDate; + } + + public String getCusNo() { + return cusNo; + } + + public void setCusNo(String cusNo) { + this.cusNo = cusNo; + } + + public String getContractName() { + return contractName; + } + + public void setContractName(String contractName) { + this.contractName = contractName; + } + + public String getCusName() { + return cusName; + } + + public void setCusName(String cusName) { + this.cusName = cusName; + } + + public String getCusType() { + return cusType; + } + + public void setCusType(String cusType) { + this.cusType = cusType; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } +} diff --git a/src/main/java/org/chenyon/discharge/DisChargeController.java b/src/main/java/org/chenyon/discharge/DisChargeController.java new file mode 100644 index 0000000..34edab9 --- /dev/null +++ b/src/main/java/org/chenyon/discharge/DisChargeController.java @@ -0,0 +1,60 @@ +package org.chenyon.discharge; + +import org.chenyon.oa.OaDisChargeService; +import org.chenyon.user.LoginCheck; +import org.chenyon.user.UserContext; +import org.rcy.framework.api.entity.PageResult; +import org.rcy.framework.api.entity.ResultMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/discharge") +public class DisChargeController { + + private static final Logger log = LoggerFactory.getLogger(DisChargeController.class); + + @Autowired + private OaDisChargeService oaDisChargeService; + + @PostMapping("/queryPage") + @LoginCheck + public ResultMessage queryPage(@RequestBody DisChargeApplyQueryCondition condition) { + try { + UserContext userContext = UserContext.get(); + if(userContext == null || userContext.getCusNo() == null) { + return ResultMessage.success(new PageResult()); + } + condition.setCusNo(userContext.getCusNo()); + return ResultMessage.success(oaDisChargeService.pageQueryApplyRecord(condition)); + }catch (Exception e) { + log.error(e.getMessage(),e); + } + return ResultMessage.success(new PageResult()); + } + + @PostMapping("/apply") + @LoginCheck + public ResultMessage apply(@RequestBody DisChargeApplyVo applyVo) throws Exception { + try { + UserContext userContext = UserContext.get(); + if(userContext == null || userContext.getCusNo() == null) { + return ResultMessage.success("您还未实名"); + } + applyVo.setCusNo(userContext.getCusNo()); + applyVo.setCusName(userContext.getUsername()); + applyVo.setPhone(userContext.getPhone()); + applyVo.setCusType(userContext.getUserType().equals("0") ? "个人" : "单位"); + oaDisChargeService.apply(applyVo); + return ResultMessage.success(); + }catch (Exception e) { + log.error(e.getMessage(),e); + } + return ResultMessage.error("申请失败"); + } +} diff --git a/src/main/java/org/chenyon/discharge/DisChargeRecordVo.java b/src/main/java/org/chenyon/discharge/DisChargeRecordVo.java new file mode 100644 index 0000000..b920071 --- /dev/null +++ b/src/main/java/org/chenyon/discharge/DisChargeRecordVo.java @@ -0,0 +1,58 @@ +package org.chenyon.discharge; + +public class DisChargeRecordVo { + private String contractName; + private String dischargeItem; + private String id; + private String status; + private String applyDate; + private String remark; + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getApplyDate() { + return applyDate; + } + + public void setApplyDate(String applyDate) { + this.applyDate = applyDate; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getContractName() { + return contractName; + } + + public void setContractName(String contractName) { + this.contractName = contractName; + } + + public String getDischargeItem() { + return dischargeItem; + } + + public void setDischargeItem(String dischargeItem) { + this.dischargeItem = dischargeItem; + } +} diff --git a/src/main/java/org/chenyon/fallback/FallbackController.java b/src/main/java/org/chenyon/fallback/FallbackController.java new file mode 100644 index 0000000..c8c0730 --- /dev/null +++ b/src/main/java/org/chenyon/fallback/FallbackController.java @@ -0,0 +1,73 @@ +package org.chenyon.fallback; + +import org.chenyon.discharge.DisChargeApplyQueryCondition; +import org.chenyon.discharge.DisChargeApplyVo; +import org.chenyon.oa.OaFallBackService; +import org.chenyon.user.LoginCheck; +import org.chenyon.user.UserContext; +import org.rcy.framework.api.entity.PageResult; +import org.rcy.framework.api.entity.ResultMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/fallback") +public class FallbackController { + + private static final Logger log = LoggerFactory.getLogger(FallbackController.class); + @Autowired + private OaFallBackService fallbackServcie; + + @PostMapping("/queryPage") + @LoginCheck + public ResultMessage queryPage(@RequestBody FallbackQueryCondition condition) { + try { + UserContext userContext = UserContext.get(); + if(userContext == null || userContext.getCusNo() == null) { + return ResultMessage.success(new PageResult()); + } + condition.setCusNo(userContext.getCusNo()); + return ResultMessage.success(fallbackServcie.pageQuery(condition)); + }catch (Exception e) { + log.error(e.getMessage(),e); + } + return ResultMessage.success(new PageResult()); + } + + @GetMapping("/detail") + @LoginCheck + public ResultMessage detail(@RequestParam("id") String id) { + try { + UserContext userContext = UserContext.get(); + if(userContext == null ) { + return ResultMessage.success(); + } + return ResultMessage.success(fallbackServcie.detail(id)); + }catch (Exception e) { + log.error(e.getMessage(),e); + } + return ResultMessage.error("查询留言详情失败"); + } + + @PostMapping("/submit") + @LoginCheck + public ResultMessage submit(@RequestBody FallbackSubmitVo submitVo) { + try { + UserContext userContext = UserContext.get(); + if(userContext == null || userContext.getCusNo() == null) { + return ResultMessage.success("您还未实名"); + } + submitVo.setCusNo(userContext.getCusNo()); + submitVo.setTenantType(userContext.getUserType().equals("0") ? "个人" : "单位"); + submitVo.setTenantName(userContext.getUsername()); + submitVo.setTenantPhone(userContext.getPhone()); + fallbackServcie.submit(submitVo); + return ResultMessage.success(); + }catch (Exception e){ + log.error(e.getMessage(),e); + } + return ResultMessage.error("提交失败"); + } +} diff --git a/src/main/java/org/chenyon/fallback/FallbackQueryCondition.java b/src/main/java/org/chenyon/fallback/FallbackQueryCondition.java new file mode 100644 index 0000000..524e4a5 --- /dev/null +++ b/src/main/java/org/chenyon/fallback/FallbackQueryCondition.java @@ -0,0 +1,24 @@ +package org.chenyon.fallback; + +import org.rcy.framework.api.entity.PageQueryRequest; + +public class FallbackQueryCondition extends PageQueryRequest { + private String cusNo; + private String id; + + public String getCusNo() { + return cusNo; + } + + public void setCusNo(String cusNo) { + this.cusNo = cusNo; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } +} diff --git a/src/main/java/org/chenyon/fallback/FallbackSubmitVo.java b/src/main/java/org/chenyon/fallback/FallbackSubmitVo.java new file mode 100644 index 0000000..b6824fa --- /dev/null +++ b/src/main/java/org/chenyon/fallback/FallbackSubmitVo.java @@ -0,0 +1,67 @@ +package org.chenyon.fallback; + +public class FallbackSubmitVo { + private String cusNo; + private String content; + private String status; + private String comment; + private String tenantName; + private String tenantType; + private String tenantPhone; + + public String getCusNo() { + return cusNo; + } + + public void setCusNo(String cusNo) { + this.cusNo = cusNo; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getComment() { + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + } + + public String getTenantName() { + return tenantName; + } + + public void setTenantName(String tenantName) { + this.tenantName = tenantName; + } + + public String getTenantType() { + return tenantType; + } + + public void setTenantType(String tenantType) { + this.tenantType = tenantType; + } + + public String getTenantPhone() { + return tenantPhone; + } + + public void setTenantPhone(String tenantPhone) { + this.tenantPhone = tenantPhone; + } +} diff --git a/src/main/java/org/chenyon/fallback/FallbackVo.java b/src/main/java/org/chenyon/fallback/FallbackVo.java new file mode 100644 index 0000000..2df7a4d --- /dev/null +++ b/src/main/java/org/chenyon/fallback/FallbackVo.java @@ -0,0 +1,58 @@ +package org.chenyon.fallback; + +public class FallbackVo { + private String id; + private String content; + private String status; + private String comment; + private String summitDate; + private String handleDate; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getComment() { + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + } + + public String getSummitDate() { + return summitDate; + } + + public void setSummitDate(String summitDate) { + this.summitDate = summitDate; + } + + public String getHandleDate() { + return handleDate; + } + + public void setHandleDate(String handleDate) { + this.handleDate = handleDate; + } +} diff --git a/src/main/java/org/chenyon/file/OaFileFindCondition.java b/src/main/java/org/chenyon/file/OaFileFindCondition.java new file mode 100644 index 0000000..f6da889 --- /dev/null +++ b/src/main/java/org/chenyon/file/OaFileFindCondition.java @@ -0,0 +1,43 @@ +package org.chenyon.file; + +import org.rcy.framework.api.entity.TypeAliases; + +public class OaFileFindCondition implements TypeAliases { + + private String bizId; + private String refId; + private String oaFormId; + private String oaFieldFlag; + + public String getBizId() { + return bizId; + } + + public void setBizId(String bizId) { + this.bizId = bizId; + } + + public String getRefId() { + return refId; + } + + public void setRefId(String refId) { + this.refId = refId; + } + + public String getOaFormId() { + return oaFormId; + } + + public void setOaFormId(String oaFormId) { + this.oaFormId = oaFormId; + } + + public String getOaFieldFlag() { + return oaFieldFlag; + } + + public void setOaFieldFlag(String oaFieldFlag) { + this.oaFieldFlag = oaFieldFlag; + } +} diff --git a/src/main/java/org/chenyon/file/OaFileHandlerService.java b/src/main/java/org/chenyon/file/OaFileHandlerService.java new file mode 100644 index 0000000..2eead7c --- /dev/null +++ b/src/main/java/org/chenyon/file/OaFileHandlerService.java @@ -0,0 +1,147 @@ +package org.chenyon.file; + +import org.chenyon.constants.OaApiUrl; +import org.chenyon.oa.SeeyonHttpClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +@Service +@Transactional +public class OaFileHandlerService { + + @Autowired + private OaFileLocalRefDao oaFileLocalRefDao; + @Autowired + private OaFileLocalSubRefDao oaFileLocalSubRefDao; + @Autowired + private SeeyonHttpClient seeyonHttpClient; + @Value("${local.fileStorage.path}") + private String fileStoragePath; + + public OaFileLocalRef findFileInfoByConditions(OaFileFindCondition condition) { + return oaFileLocalRefDao.findFileInfoByConditions(condition); + } + + public void update(OaFileLocalRef oaFileLocalRef) { + oaFileLocalRefDao.updateByPrimaryKeySelective(oaFileLocalRef); + } + + public List getUrls(Boolean viewPublic,String owner,String bizId, String formId, String oaFieldFlag, OaFileVo oaFileVo){ + if(bizId == null || formId == null || oaFieldFlag == null || oaFileVo == null) { + return null; + } + OaFileLocalRefVo oaFileLocalRefVo = new OaFileLocalRefVo(); + oaFileLocalRefVo.setBizId(bizId); + oaFileLocalRefVo.setOaFormId(formId); + oaFileLocalRefVo.setOaFieldFlag(oaFieldFlag); + oaFileLocalRefVo.setRefId(oaFileVo.getMainRefId()); + oaFileLocalRefVo.setSubRefIds(oaFileVo.getSubRefIds()); + oaFileLocalRefVo.setViewPublic(viewPublic); + oaFileLocalRefVo.setOwner(owner); + return refLocalUrl(oaFileLocalRefVo); + } + + public List getUrls(Boolean viewPublic,String bizId, String formId, String oaFieldFlag, OaFileVo oaFileVo){ + return getUrls(viewPublic,null,bizId,formId,oaFieldFlag,oaFileVo); + } + + public List refLocalUrl(OaFileLocalRefVo oaFileLocalRefVo) { + OaFileFindCondition condition1 = new OaFileFindCondition(); + condition1.setBizId(oaFileLocalRefVo.getBizId()); + condition1.setOaFormId(oaFileLocalRefVo.getOaFormId()); + condition1.setOaFieldFlag(oaFileLocalRefVo.getOaFieldFlag()); + OaFileLocalRef localRefDb = findFileInfoByConditions(condition1); + if (localRefDb != null && localRefDb.getRefId().equals(oaFileLocalRefVo.getRefId())) { + //附件信息没完全删除但是部分发生改变 + List subRefInfos = oaFileLocalSubRefDao.findFileInfoByMainRefId(localRefDb.getRefId()); + //先删除旧的 + Set subRefSet = oaFileLocalRefVo.getSubRefIds().stream().collect(Collectors.toSet()); + List nSubUrls = new ArrayList<>(); + for (OaFileLocalSubRef subRefInfo : subRefInfos) { + if (!subRefSet.contains(subRefInfo.getRefId())) { + //删除子表 + OaFileLocalSubRef temp = oaFileLocalSubRefDao.get(subRefInfo.getId()); + oaFileLocalSubRefDao.deleteByPrimaryKey(subRefInfo.getId()); + String tempFileUrl = fileStoragePath + temp.getUrl(); + //删除本地文件 + File tempFile = new File(tempFileUrl); + if (tempFile.exists()) { + tempFile.delete(); + } + }else { + nSubUrls.add(subRefInfo.getUrl()); + } + } + Set dbSubRefSet = subRefInfos.stream().map(s -> s.getRefId()).collect(Collectors.toSet()); + for (String subRefId : oaFileLocalRefVo.getSubRefIds()) { + if (!dbSubRefSet.contains(subRefId)) { + reBuildSubRef(oaFileLocalRefVo.getOaFieldFlag(),subRefId, localRefDb.getRefId(), localRefDb.getViewPublic(), localRefDb.getOwner(), nSubUrls); + } + } + return nSubUrls; + } + //附件信息完全删除 + List ncSubUrls = new ArrayList<>(); + List subRefIds = oaFileLocalRefVo.getSubRefIds(); + for (String subRefId : subRefIds) { + try { + reBuildSubRef(oaFileLocalRefVo.getOaFieldFlag(),subRefId, oaFileLocalRefVo.getRefId(), oaFileLocalRefVo.getViewPublic(), oaFileLocalRefVo.getOwner(), ncSubUrls); + } catch (Exception e) { + + } + } + if (localRefDb != null) { + localRefDb.setRefId(oaFileLocalRefVo.getRefId()); + oaFileLocalRefDao.updateByPrimaryKeySelective(localRefDb); + } + OaFileLocalRef oaFileLocalRef = new OaFileLocalRef(); + oaFileLocalRef.setBizId(oaFileLocalRefVo.getBizId()); + oaFileLocalRef.setOaFormId(oaFileLocalRefVo.getOaFormId()); + oaFileLocalRef.setOaFieldFlag(oaFileLocalRefVo.getOaFieldFlag()); + oaFileLocalRef.setRefId(oaFileLocalRefVo.getRefId()); + oaFileLocalRef.setViewPublic(oaFileLocalRefVo.getViewPublic()); + oaFileLocalRef.setOwner(oaFileLocalRefVo.getOwner()); + oaFileLocalRefDao.save(oaFileLocalRef); + return ncSubUrls; + } + + private void reBuildSubRef(String bizType,String subRefId, String mainRefId, Boolean isPublic, String owner, List nSubUrls) { + //新增 + OaFileLocalSubRef oaFileLocalSubRef = new OaFileLocalSubRef(); + oaFileLocalSubRef.setRefId(subRefId); + oaFileLocalSubRef.setMainRefId(mainRefId); + //调OA接口写入文件 + try { + String subUrl = seeyonHttpClient.downloadFile(bizType,OaApiUrl.FILE_DOWNLOAD,subRefId, isPublic, owner); + oaFileLocalSubRef.setUrl(subUrl); + oaFileLocalSubRefDao.save(oaFileLocalSubRef); + nSubUrls.add(subUrl); + } catch (Exception e) { + + } + } + + public String findOwnerByUrl(String url) { + OaFileLocalSubRef subRef = oaFileLocalSubRefDao.findByUrl(url); + if(subRef == null) { + return null; + }else { + String mainRefId = subRef.getMainRefId(); + OaFileFindCondition condition = new OaFileFindCondition(); + condition.setRefId(mainRefId); + OaFileLocalRef mainRef = oaFileLocalRefDao.findFileInfoByConditions(condition); + if(mainRef == null) { + return null; + } + return mainRef.getOwner(); + } + } +} diff --git a/src/main/java/org/chenyon/file/OaFileLocalRef.java b/src/main/java/org/chenyon/file/OaFileLocalRef.java new file mode 100644 index 0000000..297b4cc --- /dev/null +++ b/src/main/java/org/chenyon/file/OaFileLocalRef.java @@ -0,0 +1,65 @@ +package org.chenyon.file; + +import org.rcy.framework.api.entity.BaseEntity; + +import javax.persistence.Entity; +import javax.persistence.Table; + +@Entity +@Table(name = "OAFILELOCALREF") +public class OaFileLocalRef extends BaseEntity { + private String bizId; + private String refId; + private String oaFormId; + private String oaFieldFlag; + private String owner; + private Boolean viewPublic = true; + + public String getBizId() { + return bizId; + } + + public void setBizId(String bizId) { + this.bizId = bizId; + } + + public String getRefId() { + return refId; + } + + public void setRefId(String refId) { + this.refId = refId; + } + + public String getOaFormId() { + return oaFormId; + } + + public void setOaFormId(String oaFormId) { + this.oaFormId = oaFormId; + } + + public String getOaFieldFlag() { + return oaFieldFlag; + } + + public void setOaFieldFlag(String oaFieldFlag) { + this.oaFieldFlag = oaFieldFlag; + } + + public String getOwner() { + return owner; + } + + public void setOwner(String owner) { + this.owner = owner; + } + + public Boolean getViewPublic() { + return viewPublic; + } + + public void setViewPublic(Boolean viewPublic) { + this.viewPublic = viewPublic; + } +} diff --git a/src/main/java/org/chenyon/file/OaFileLocalRefDao.java b/src/main/java/org/chenyon/file/OaFileLocalRefDao.java new file mode 100644 index 0000000..86c4e3a --- /dev/null +++ b/src/main/java/org/chenyon/file/OaFileLocalRefDao.java @@ -0,0 +1,7 @@ +package org.chenyon.file; + +import org.rcy.framework.data.dao.BaseDao; + +public interface OaFileLocalRefDao extends BaseDao { + OaFileLocalRef findFileInfoByConditions(OaFileFindCondition condition); +} diff --git a/src/main/java/org/chenyon/file/OaFileLocalRefDao.xml b/src/main/java/org/chenyon/file/OaFileLocalRefDao.xml new file mode 100644 index 0000000..70979a0 --- /dev/null +++ b/src/main/java/org/chenyon/file/OaFileLocalRefDao.xml @@ -0,0 +1,28 @@ + + + + + + + + 1 = 1 + + AND bizId = #{bizId} + + + AND refId = #{refId} + + + AND oaFormId = #{oaFormId} + + + AND oaFieldFlag = #{oaFieldFlag} + + + + \ No newline at end of file diff --git a/src/main/java/org/chenyon/file/OaFileLocalRefVo.java b/src/main/java/org/chenyon/file/OaFileLocalRefVo.java new file mode 100644 index 0000000..eb328b1 --- /dev/null +++ b/src/main/java/org/chenyon/file/OaFileLocalRefVo.java @@ -0,0 +1,79 @@ +package org.chenyon.file; + + +import java.util.List; + +public class OaFileLocalRefVo { + private String id; + private String bizId; + private String refId; + private String oaFormId; + private String oaFieldFlag; + private String owner; + private Boolean viewPublic = true; + private List subRefIds; + + public String getBizId() { + return bizId; + } + + public void setBizId(String bizId) { + this.bizId = bizId; + } + + public String getRefId() { + return refId; + } + + public void setRefId(String refId) { + this.refId = refId; + } + + public String getOaFormId() { + return oaFormId; + } + + public void setOaFormId(String oaFormId) { + this.oaFormId = oaFormId; + } + + public String getOaFieldFlag() { + return oaFieldFlag; + } + + public void setOaFieldFlag(String oaFieldFlag) { + this.oaFieldFlag = oaFieldFlag; + } + + public String getOwner() { + return owner; + } + + public void setOwner(String owner) { + this.owner = owner; + } + + public Boolean getViewPublic() { + return viewPublic; + } + + public void setViewPublic(Boolean viewPublic) { + this.viewPublic = viewPublic; + } + + public List getSubRefIds() { + return subRefIds; + } + + public void setSubRefIds(List subRefIds) { + this.subRefIds = subRefIds; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } +} diff --git a/src/main/java/org/chenyon/file/OaFileLocalSubRef.java b/src/main/java/org/chenyon/file/OaFileLocalSubRef.java new file mode 100644 index 0000000..42832c4 --- /dev/null +++ b/src/main/java/org/chenyon/file/OaFileLocalSubRef.java @@ -0,0 +1,38 @@ +package org.chenyon.file; + +import org.rcy.framework.api.entity.BaseEntity; + +import javax.persistence.Entity; +import javax.persistence.Table; + +@Entity +@Table(name = "OAFILELOCALSUBREF") +public class OaFileLocalSubRef extends BaseEntity { + private String refId; + private String url; + private String mainRefId; + + public String getRefId() { + return refId; + } + + public void setRefId(String refId) { + this.refId = refId; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getMainRefId() { + return mainRefId; + } + + public void setMainRefId(String mainRefId) { + this.mainRefId = mainRefId; + } +} diff --git a/src/main/java/org/chenyon/file/OaFileLocalSubRefDao.java b/src/main/java/org/chenyon/file/OaFileLocalSubRefDao.java new file mode 100644 index 0000000..79d2651 --- /dev/null +++ b/src/main/java/org/chenyon/file/OaFileLocalSubRefDao.java @@ -0,0 +1,10 @@ +package org.chenyon.file; + +import org.rcy.framework.data.dao.BaseDao; + +import java.util.List; + +public interface OaFileLocalSubRefDao extends BaseDao { + List findFileInfoByMainRefId(String mainRefId); + OaFileLocalSubRef findByUrl(String url); +} diff --git a/src/main/java/org/chenyon/file/OaFileLocalSubRefDao.xml b/src/main/java/org/chenyon/file/OaFileLocalSubRefDao.xml new file mode 100644 index 0000000..1b42295 --- /dev/null +++ b/src/main/java/org/chenyon/file/OaFileLocalSubRefDao.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/src/main/java/org/chenyon/file/OaFileVo.java b/src/main/java/org/chenyon/file/OaFileVo.java new file mode 100644 index 0000000..ed39f1c --- /dev/null +++ b/src/main/java/org/chenyon/file/OaFileVo.java @@ -0,0 +1,26 @@ +package org.chenyon.file; + +import java.io.Serializable; +import java.util.List; + +public class OaFileVo implements Serializable { + private String mainRefId; + private List subRefIds; + + public List getSubRefIds() { + return subRefIds; + } + + public void setSubRefIds(List subRefIds) { + this.subRefIds = subRefIds; + } + + public String getMainRefId() { + return mainRefId; + } + + public void setMainRefId(String mainRefId) { + this.mainRefId = mainRefId; + } + +} \ No newline at end of file diff --git a/src/main/java/org/chenyon/global/GlobalExceptionHandler.java b/src/main/java/org/chenyon/global/GlobalExceptionHandler.java new file mode 100644 index 0000000..06c5fe2 --- /dev/null +++ b/src/main/java/org/chenyon/global/GlobalExceptionHandler.java @@ -0,0 +1,24 @@ +package org.chenyon.global; + +import org.rcy.framework.api.entity.ResultMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class GlobalExceptionHandler { + + private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class); + + @ExceptionHandler(Exception.class) + public ResponseEntity handle(Exception e) { + log.error(e.getMessage(), e); + return ResponseEntity + .status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(ResultMessage.error()); + } + +} \ No newline at end of file diff --git a/src/main/java/org/chenyon/interceptor/LoginCheckInterceptor.java b/src/main/java/org/chenyon/interceptor/LoginCheckInterceptor.java new file mode 100644 index 0000000..6432be0 --- /dev/null +++ b/src/main/java/org/chenyon/interceptor/LoginCheckInterceptor.java @@ -0,0 +1,96 @@ +package org.chenyon.interceptor; + +import org.chenyon.user.LoginCheck; +import org.chenyon.user.UserContext; +import org.chenyon.user.UserService; +import org.chenyon.user.UserVo; +import org.chenyon.wx.WxUserSession; +import org.chenyon.wx.WxUserSessionService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.lang.reflect.Method; + +@Component +public class LoginCheckInterceptor implements HandlerInterceptor { + + private static final Logger log = LoggerFactory.getLogger(LoginCheckInterceptor.class); + @Autowired + private WxUserSessionService wxUserSessionService; + @Autowired + private UserService userService; + + @Override + public boolean preHandle(HttpServletRequest request, + HttpServletResponse response, + Object handler) throws Exception { + + // 处理OPTIONS预检请求 + if ("OPTIONS".equals(request.getMethod())) { + return true; + } + + if (!(handler instanceof HandlerMethod)) { + return true; + } + + HandlerMethod handlerMethod = (HandlerMethod) handler; + Method method = handlerMethod.getMethod(); + + // 检查方法上是否有AuthCheck注解 + LoginCheck authCheck = method.getAnnotation(LoginCheck.class); + if (authCheck == null) { + return true; // 没有注解,直接放行 + } + + // 获取token进行验证 + String token = request.getHeader("WT"); + String userType = request.getHeader("USERTYPE"); + if (token == null || !validateToken(token) || userType == null) { + response.setStatus(401); + return false; + } + UserContext context = setUserContext(token,userType); + if(context != null) { + UserContext.set(context); + } + return true; + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { + // 清理线程变量 + UserContext.remove(); + } + + private UserContext setUserContext(String token,String userType) { + WxUserSession session = wxUserSessionService.getSessionInfoByThirdSession(token); + try { + UserVo userVo = userService.findByOpenIdAndUserType(session.getOpenId(), userType); + UserContext context = new UserContext(); + context.setUsername(userVo.getUserName()); + context.setOpenId(userVo.getOpenId()); + context.setCusNo(userVo.getCusNo()); + context.setToken(token); + context.setUserType(userType); + context.setPhone(userVo.getPhone()); + return context; + } catch (Exception e) { + log.error(e.getMessage(),e); + return null; + } + } + + private boolean validateToken(String token) { + // 实现token验证逻辑 + return !wxUserSessionService.sessionIsExpired(token); + } + +} + diff --git a/src/main/java/org/chenyon/location/IpLocationService.java b/src/main/java/org/chenyon/location/IpLocationService.java new file mode 100644 index 0000000..6d8d800 --- /dev/null +++ b/src/main/java/org/chenyon/location/IpLocationService.java @@ -0,0 +1,25 @@ +package org.chenyon.location; + +import org.rcy.framework.utils.net.HttpRequestUtils; +import org.rcy.framework.utils.net.HttpResponse; +import org.springframework.stereotype.Service; + +@Service +public class IpLocationService { + + private static final String API = "https://apis.map.qq.com/ws/location/v1/ip"; + + public String getLocationByIP(String ip) { + String key = "CQPBZ-R543L-ZCZPH-E5CPI-KMUF6-VRBGE"; + String url = API + "?ip=" + ip + "&key=" + key; + try { + HttpResponse response = HttpRequestUtils.sendGet(url, null); + if(response.getCode() == 200) { + return response.getRespStr(); + } + }catch (Exception e) { + + } + return null; + } +} diff --git a/src/main/java/org/chenyon/location/LocateController.java b/src/main/java/org/chenyon/location/LocateController.java new file mode 100644 index 0000000..57fc2f7 --- /dev/null +++ b/src/main/java/org/chenyon/location/LocateController.java @@ -0,0 +1,28 @@ +package org.chenyon.location; + +import org.rcy.framework.api.entity.ResultMessage; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +@RestController +@RequestMapping("/location") +public class LocateController { + @Autowired + private IpLocationService ipLocationService; + + @GetMapping("/getRealCity") + public ResultMessage getRealCity(HttpServletRequest request) throws IOException { +// String ip = ""; +// String locationJson = ipLocationService.getLocationByIP(ip); +// JsonNode root = JsonUtils.parseTree(locationJson); +// JsonNode adInfo = root.path("result").path("ad_info"); +// String city = adInfo.path("city").asText(); +// return ResultMessage.success(city != null ? city : "未知城市"); + return ResultMessage.success("宜昌"); + } +} diff --git a/src/main/java/org/chenyon/message/Message.java b/src/main/java/org/chenyon/message/Message.java new file mode 100644 index 0000000..aed7975 --- /dev/null +++ b/src/main/java/org/chenyon/message/Message.java @@ -0,0 +1,74 @@ +package org.chenyon.message; + +import org.rcy.framework.api.entity.BaseEntity; + +import javax.persistence.Entity; +import javax.persistence.Table; + +@Entity +@Table(name = "MESSAGE") +public class Message extends BaseEntity { + private String title; + private MessageType messageType; + private String messageContent; + private String messageTime; + private String messageReceiver; + private String bizId; + private Boolean hasRead = false; + + public MessageType getMessageType() { + return messageType; + } + + public void setMessageType(MessageType messageType) { + this.messageType = messageType; + } + + public String getMessageContent() { + return messageContent; + } + + public void setMessageContent(String messageContent) { + this.messageContent = messageContent; + } + + public String getMessageTime() { + return messageTime; + } + + public void setMessageTime(String messageTime) { + this.messageTime = messageTime; + } + + public String getMessageReceiver() { + return messageReceiver; + } + + public void setMessageReceiver(String messageReceiver) { + this.messageReceiver = messageReceiver; + } + + public String getBizId() { + return bizId; + } + + public void setBizId(String bizId) { + this.bizId = bizId; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Boolean getHasRead() { + return hasRead; + } + + public void setHasRead(Boolean hasRead) { + this.hasRead = hasRead; + } +} diff --git a/src/main/java/org/chenyon/message/MessageController.java b/src/main/java/org/chenyon/message/MessageController.java new file mode 100644 index 0000000..a0697d0 --- /dev/null +++ b/src/main/java/org/chenyon/message/MessageController.java @@ -0,0 +1,80 @@ +package org.chenyon.message; + +import org.chenyon.user.LoginCheck; +import org.chenyon.user.UserContext; +import org.rcy.framework.api.entity.PageResult; +import org.rcy.framework.api.entity.ResultMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/message") +public class MessageController { + + private static final Logger log = LoggerFactory.getLogger(MessageController.class); + + @Autowired + private MessageService messageService; + + @PostMapping("/queryPage") + @LoginCheck + public ResultMessage queryPage(@RequestBody MessageQueryCondition condition){ + UserContext userContext = UserContext.get(); + if(userContext == null || userContext.getCusNo() == null) { + return ResultMessage.success(new PageResult()); + } + try { + condition.setMessageReceiver(userContext.getCusNo()); + return ResultMessage.success(messageService.queryPage(condition)); + }catch (Exception e) { + log.error(e.getMessage(), e); + } + return ResultMessage.success(); + } + + @GetMapping("/detail") + @LoginCheck + public ResultMessage detail(@RequestParam("id") Long id){ + try { + return ResultMessage.success(messageService.detail(id)); + }catch (Exception e) { + log.error(e.getMessage(), e); + } + return ResultMessage.success(); + } + + @GetMapping("/read") + @LoginCheck + public ResultMessage read(@RequestParam("id") Long id){ + try { + messageService.read(id); + return ResultMessage.success(); + }catch (Exception e) { + log.error(e.getMessage(), e); + } + return ResultMessage.success(); + } + + @GetMapping("/countUnread") + @LoginCheck + public ResultMessage countUnread(){ + UserContext userContext = UserContext.get(); + if(userContext == null || userContext.getCusNo() == null) { + return ResultMessage.success(0); + } + try { + return ResultMessage.success(messageService.countUnread(userContext.getCusNo())); + }catch (Exception e) { + log.error(e.getMessage(), e); + } + return ResultMessage.success(0); + } + + + @PostMapping("/sendMessage") + public ResultMessage sendMessage(@RequestBody MessageVo vo){ + return ResultMessage.success(); + } +} diff --git a/src/main/java/org/chenyon/message/MessageDao.java b/src/main/java/org/chenyon/message/MessageDao.java new file mode 100644 index 0000000..b150dfe --- /dev/null +++ b/src/main/java/org/chenyon/message/MessageDao.java @@ -0,0 +1,10 @@ +package org.chenyon.message; + +import org.rcy.framework.data.dao.BaseDao; + +import java.util.List; + +public interface MessageDao extends BaseDao { + List pageQuery(MessageQueryCondition condition); + Long countCondition(MessageQueryCondition condition); +} diff --git a/src/main/java/org/chenyon/message/MessageDao.xml b/src/main/java/org/chenyon/message/MessageDao.xml new file mode 100644 index 0000000..5c67895 --- /dev/null +++ b/src/main/java/org/chenyon/message/MessageDao.xml @@ -0,0 +1,31 @@ + + + + + + + + + + 1 = 1 + + AND bizId = #{bizId} + + + AND messageReceiver = #{messageReceiver} + + + + + \ No newline at end of file diff --git a/src/main/java/org/chenyon/message/MessageQueryCondition.java b/src/main/java/org/chenyon/message/MessageQueryCondition.java new file mode 100644 index 0000000..4e2098d --- /dev/null +++ b/src/main/java/org/chenyon/message/MessageQueryCondition.java @@ -0,0 +1,16 @@ +package org.chenyon.message; + +import org.rcy.framework.api.entity.PageQueryRequest; + +public class MessageQueryCondition extends PageQueryRequest { + + private String messageReceiver; + + public String getMessageReceiver() { + return messageReceiver; + } + + public void setMessageReceiver(String messageReceiver) { + this.messageReceiver = messageReceiver; + } +} diff --git a/src/main/java/org/chenyon/message/MessageService.java b/src/main/java/org/chenyon/message/MessageService.java new file mode 100644 index 0000000..4dd62bd --- /dev/null +++ b/src/main/java/org/chenyon/message/MessageService.java @@ -0,0 +1,73 @@ +package org.chenyon.message; + +import org.chenyon.wx.AesException; +import org.chenyon.wx.WXBizMsgCrypt; +import org.rcy.framework.api.entity.PageResult; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.xml.parsers.ParserConfigurationException; +import java.util.List; + +@Service +@Transactional +public class MessageService { + + @Autowired + private MessageDao messageDao; + + + public MessageVo detail(Long id) { + Message message = messageDao.get(id); + MessageVo messageVo = new MessageVo(); + if(message != null) { + messageVo.setMessageContent(message.getMessageContent()); + messageVo.setTitle(message.getTitle()); + messageVo.setMessageTime(message.getMessageTime()); + } + return messageVo; + } + + public void read(Long id) { + Message message = messageDao.get(id); + message.setHasRead(true); + messageDao.updateByPrimaryKeySelective(message); + } + + public Integer countUnread(String cusNo){ + MessageQueryCondition messageQueryCondition = new MessageQueryCondition(); + messageQueryCondition.setMessageReceiver(cusNo); + Long count = messageDao.countCondition(messageQueryCondition); + return count.intValue(); + } + + public PageResult queryPage(MessageQueryCondition condition) { + List messages = messageDao.pageQuery(condition); + Long count = messageDao.countCondition(condition); + PageResult pageResult = new PageResult<>(); + pageResult.setResult(messages); + pageResult.setRecordTotal(count); + return pageResult; + } + + public void send(MessageVo messageVo) throws AesException, ParserConfigurationException { + // 消息入库 + // + String urlSend = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token="; + + + // 需要加密的明文 + String encodingAesKey = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG"; + String token = "pamtest"; + String timestamp = "1409304348"; + String nonce = "xxxxxx"; + String appId = "wxb11529c136998cb6"; + String replyMsg = " 中文1407743423"; + + WXBizMsgCrypt pc = new WXBizMsgCrypt(token, encodingAesKey, appId); + String mingwen = pc.encryptMsg(replyMsg, timestamp, nonce); + System.out.println("加密后: " + mingwen); + + } +} diff --git a/src/main/java/org/chenyon/message/MessageType.java b/src/main/java/org/chenyon/message/MessageType.java new file mode 100644 index 0000000..170ee2a --- /dev/null +++ b/src/main/java/org/chenyon/message/MessageType.java @@ -0,0 +1,11 @@ +package org.chenyon.message; + +public enum MessageType { + SIGN("合同签署"), + BILL("账单催缴"), + ; + private String desc; + MessageType(String desc) { + this.desc = desc; + } +} diff --git a/src/main/java/org/chenyon/message/MessageVo.java b/src/main/java/org/chenyon/message/MessageVo.java new file mode 100644 index 0000000..69e181e --- /dev/null +++ b/src/main/java/org/chenyon/message/MessageVo.java @@ -0,0 +1,76 @@ +package org.chenyon.message; + +public class MessageVo { + private String id; + private String title; + private String messageType; + private String messageContent; + private String messageTime; + private String messageReceiver; + private String bizId; + private Boolean hasRead; + + public String getMessageType() { + return messageType; + } + + public void setMessageType(String messageType) { + this.messageType = messageType; + } + + public String getMessageContent() { + return messageContent; + } + + public void setMessageContent(String messageContent) { + this.messageContent = messageContent; + } + + public String getMessageTime() { + return messageTime; + } + + public void setMessageTime(String messageTime) { + this.messageTime = messageTime; + } + + public String getMessageReceiver() { + return messageReceiver; + } + + public void setMessageReceiver(String messageReceiver) { + this.messageReceiver = messageReceiver; + } + + public String getBizId() { + return bizId; + } + + public void setBizId(String bizId) { + this.bizId = bizId; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public Boolean getHasRead() { + return hasRead; + } + + public void setHasRead(Boolean hasRead) { + this.hasRead = hasRead; + } +} \ No newline at end of file diff --git a/src/main/java/org/chenyon/notice/NoticeController.java b/src/main/java/org/chenyon/notice/NoticeController.java new file mode 100644 index 0000000..007e66c --- /dev/null +++ b/src/main/java/org/chenyon/notice/NoticeController.java @@ -0,0 +1,40 @@ +package org.chenyon.notice; + +import org.chenyon.oa.OaNoticeService; +import org.rcy.framework.api.entity.PageResult; +import org.rcy.framework.api.entity.ResultMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/notice") +public class NoticeController { + + private static final Logger log = LoggerFactory.getLogger(NoticeController.class); + + @Autowired + private OaNoticeService noticeService; + + @PostMapping("/pageQuery") + public ResultMessage pageQuery(@RequestBody NoticeQueryCondition condition) { + try { + PageResult pageList = noticeService.pageQuery(condition); + return ResultMessage.success(pageList); + }catch (Exception e){ + log.error(e.getMessage(),e); + } + return ResultMessage.success(new PageResult<>()); + } + + @GetMapping("/detail") + public ResultMessage detail(@RequestParam("id") String id) { + try { + return ResultMessage.success(noticeService.queryDetail(id)); + }catch (Exception e) { + log.error(e.getMessage(),e); + } + return ResultMessage.success(new NoticeVo()); + } +} diff --git a/src/main/java/org/chenyon/notice/NoticeQueryCondition.java b/src/main/java/org/chenyon/notice/NoticeQueryCondition.java new file mode 100644 index 0000000..8949c59 --- /dev/null +++ b/src/main/java/org/chenyon/notice/NoticeQueryCondition.java @@ -0,0 +1,6 @@ +package org.chenyon.notice; + +import org.rcy.framework.api.entity.PageQueryRequest; + +public class NoticeQueryCondition extends PageQueryRequest { +} diff --git a/src/main/java/org/chenyon/notice/NoticeVo.java b/src/main/java/org/chenyon/notice/NoticeVo.java new file mode 100644 index 0000000..5ff72de --- /dev/null +++ b/src/main/java/org/chenyon/notice/NoticeVo.java @@ -0,0 +1,115 @@ +package org.chenyon.notice; + +import java.util.List; + +public class NoticeVo { + + private String noticeId; + private String noticeTitle; + private String noticeType; + private String noticeContent; + private String status; + private String createBy; + private String createTime; + private String updateBy; + private String updateTime; + private String remark; + private List attachments; + private List imgs; + + public String getNoticeId() { + return noticeId; + } + + public void setNoticeId(String noticeId) { + this.noticeId = noticeId; + } + + public String getNoticeTitle() { + return noticeTitle; + } + + public void setNoticeTitle(String noticeTitle) { + this.noticeTitle = noticeTitle; + } + + public String getNoticeType() { + return noticeType; + } + + public void setNoticeType(String noticeType) { + this.noticeType = noticeType; + } + + public String getNoticeContent() { + return noticeContent; + } + + public void setNoticeContent(String noticeContent) { + this.noticeContent = noticeContent; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getCreateBy() { + return createBy; + } + + public void setCreateBy(String createBy) { + this.createBy = createBy; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getUpdateBy() { + return updateBy; + } + + public void setUpdateBy(String updateBy) { + this.updateBy = updateBy; + } + + public String getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(String updateTime) { + this.updateTime = updateTime; + } + + public String getRemark() { + return remark; + } + + public void setRemark(String remark) { + this.remark = remark; + } + + public List getAttachments() { + return attachments; + } + + public void setAttachments(List attachments) { + this.attachments = attachments; + } + + public List getImgs() { + return imgs; + } + + public void setImgs(List imgs) { + this.imgs = imgs; + } +} diff --git a/src/main/java/org/chenyon/oa/OaAssetService.java b/src/main/java/org/chenyon/oa/OaAssetService.java new file mode 100644 index 0000000..a5474ac --- /dev/null +++ b/src/main/java/org/chenyon/oa/OaAssetService.java @@ -0,0 +1,52 @@ +package org.chenyon.oa; + +import com.fasterxml.jackson.core.type.TypeReference; +import org.chenyon.assets.vo.AssetsPageQueryCondition; +import org.chenyon.constants.OaApiUrl; +import org.chenyon.oa.asset.OaAssetsVo; +import org.rcy.framework.api.entity.PageResult; +import org.rcy.framework.utils.json.JsonUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 查询OA资产信息的service + */ +@Service +public class OaAssetService { + + @Autowired + private SeeyonHttpClient seeyonHttpClient; + + public PageResult pageQueryAssets(AssetsPageQueryCondition condition) throws Exception { + OaResp oaResp = seeyonHttpClient.sendPost("分页查询资产信息",OaApiUrl.PAGE_QUERY_ASSETS, JsonUtils.convertJson(condition)); + String data = oaResp.getDataStr(); + Map mapRoot = JsonUtils.parseObject(data, Map.class); + Long totalCount = 0L; + List assetsVos = null; + if(mapRoot.get("totalCount") != null){ + totalCount = mapRoot.get("totalCount") instanceof Long ? (Long) mapRoot.get("totalCount") : Long.parseLong(mapRoot.get("totalCount") + ""); + } + if(mapRoot.get("datas") != null) { + assetsVos = JsonUtils.parseArray(JsonUtils.convertJson(mapRoot.get("datas")), OaAssetsVo.class); + } + PageResult pageResult = new PageResult<>(); + pageResult.setPageNo(condition.getPageNo()); + pageResult.setPageSize(condition.getPageSize()); + pageResult.setRecordTotal(totalCount.intValue()); + pageResult.setResult(assetsVos); + return pageResult; + } + + public OaAssetsVo queryAssetsDetail(String assetsNo) throws Exception { + Map params = new HashMap<>(); + params.put("assetsNo",assetsNo); + OaResp oaResp = seeyonHttpClient.sendPost("查询资产详情信息",OaApiUrl.QUERY_ASSETS_DETAIL, params); + return JsonUtils.parseObject(oaResp.getDataStr(),OaAssetsVo.class); + } + +} diff --git a/src/main/java/org/chenyon/oa/OaBillService.java b/src/main/java/org/chenyon/oa/OaBillService.java new file mode 100644 index 0000000..ec0e541 --- /dev/null +++ b/src/main/java/org/chenyon/oa/OaBillService.java @@ -0,0 +1,94 @@ +package org.chenyon.oa; + +import org.chenyon.bill.BillQueryCondition; +import org.chenyon.bill.PayRecordQueryConditon; +import org.chenyon.constants.OaApiUrl; +import org.chenyon.oa.asset.OaAssetsVo; +import org.chenyon.oa.bill.OaBillVo; +import org.chenyon.oa.bill.OaPayRecordVo; +import org.rcy.framework.api.entity.PageResult; +import org.rcy.framework.utils.json.JsonUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +@Service +public class OaBillService { + + @Autowired + private SeeyonHttpClient seeyonHttpClient; + + public PageResult pageQueryContractBill(BillQueryCondition condition) throws Exception { + OaResp oaResp = seeyonHttpClient.sendPost("分页查询合同账单信息", OaApiUrl.PAGE_QUERY_CONTRACT_BILL, JsonUtils.convertJson(condition)); + String data = oaResp.getDataStr(); + Map mapRoot = JsonUtils.parseObject(data, Map.class); + List oaBillVos = null; + Long totalCount = 0L; + if(mapRoot.get("totalCount") != null){ + totalCount = mapRoot.get("totalCount") instanceof Long ? (Long) mapRoot.get("totalCount") : Long.parseLong(mapRoot.get("totalCount") + ""); + } + if(mapRoot.get("datas") != null) { + oaBillVos = JsonUtils.parseArray(JsonUtils.convertJson(mapRoot.get("datas")), OaBillVo.class); + } + PageResult pageResult = new PageResult<>(); + pageResult.setPageNo(condition.getPageNo()); + pageResult.setPageSize(condition.getPageSize()); + pageResult.setRecordTotal(totalCount.intValue()); + pageResult.setResult(oaBillVos); + return pageResult; + } + + public PageResult pageQueryWaeBill(BillQueryCondition condition) throws Exception { + OaResp oaResp = seeyonHttpClient.sendPost("分页查询水电费账单信息", OaApiUrl.PAGE_QUERY_WAE_BILL, JsonUtils.convertJson(condition)); + String data = oaResp.getDataStr(); + Map mapRoot = JsonUtils.parseObject(data, Map.class); + List oaBillVos = null; + Long totalCount = 0L; + if(mapRoot.get("totalCount") != null){ + totalCount = mapRoot.get("totalCount") instanceof Long ? (Long) mapRoot.get("totalCount") : Long.parseLong(mapRoot.get("totalCount") + ""); + } + if(mapRoot.get("datas") != null) { + oaBillVos = JsonUtils.parseArray(JsonUtils.convertJson(mapRoot.get("datas")), OaBillVo.class); + } + PageResult pageResult = new PageResult<>(); + pageResult.setPageNo(condition.getPageNo()); + pageResult.setPageSize(condition.getPageSize()); + pageResult.setRecordTotal(totalCount.intValue()); + pageResult.setResult(oaBillVos); + return pageResult; + } + + public PageResult pageQueryPayRecord(PayRecordQueryConditon condition) throws Exception { + OaResp oaResp = seeyonHttpClient.sendPost("分页查询缴费记录信息", OaApiUrl.PAGE_QUERY_PAY_RECORD, JsonUtils.convertJson(condition)); + String data = oaResp.getDataStr(); + Map mapRoot = JsonUtils.parseObject(data, Map.class); + List oaPayRecordVos = null; + Long totalCount = 0L; + if(mapRoot.get("totalCount") != null){ + totalCount = mapRoot.get("totalCount") instanceof Long ? (Long) mapRoot.get("totalCount") : Long.parseLong(mapRoot.get("totalCount") + ""); + } + if(mapRoot.get("datas") != null) { + oaPayRecordVos = JsonUtils.parseArray(JsonUtils.convertJson(mapRoot.get("datas")), OaPayRecordVo.class); + } + PageResult pageResult = new PageResult<>(); + pageResult.setPageNo(condition.getPageNo()); + pageResult.setPageSize(condition.getPageSize()); + pageResult.setRecordTotal(totalCount.intValue()); + pageResult.setResult(oaPayRecordVos); + return pageResult; + } + + + public Integer countUnpayRentBills(Map params) throws Exception { + OaResp oaResp = seeyonHttpClient.sendPost("统计未缴租金账单数", OaApiUrl.COUNT_UNPAY_RENT_BILLS, JsonUtils.convertJson(params)); + return (Integer) oaResp.getData(); + } + + public Integer countUnpayWaeBills(Map params) throws Exception { + OaResp oaResp = seeyonHttpClient.sendPost("统计未缴水电费账单数", OaApiUrl.COUNT_UNPAY_WAE_BILLS, JsonUtils.convertJson(params)); + return (Integer) oaResp.getData(); + } + +} diff --git a/src/main/java/org/chenyon/oa/OaContractService.java b/src/main/java/org/chenyon/oa/OaContractService.java new file mode 100644 index 0000000..276f904 --- /dev/null +++ b/src/main/java/org/chenyon/oa/OaContractService.java @@ -0,0 +1,77 @@ +package org.chenyon.oa; + +import org.chenyon.constants.OaApiUrl; +import org.chenyon.contract.ContractQueryCondition; +import org.chenyon.oa.asset.OaAssetsVo; +import org.chenyon.oa.contract.OaContractVo; +import org.rcy.framework.api.entity.PageResult; +import org.rcy.framework.utils.json.JsonUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +public class OaContractService { + + @Autowired + private SeeyonHttpClient seeyonHttpClient; + + public PageResult pageQueryContract(ContractQueryCondition condition) throws Exception { + OaResp oaResp = seeyonHttpClient.sendPost("分页查询合同信息", OaApiUrl.PAGE_QUERY_CONTRACT, JsonUtils.convertJson(condition)); + String data = oaResp.getDataStr(); + Map mapRoot = JsonUtils.parseObject(data, Map.class); + List oaContractVos = null; + Long totalCount = 0L; + if(mapRoot.get("totalCount") != null){ + totalCount = mapRoot.get("totalCount") instanceof Long ? (Long) mapRoot.get("totalCount") : Long.parseLong(mapRoot.get("totalCount") + ""); + } + if(mapRoot.get("datas") != null) { + oaContractVos = JsonUtils.parseArray(JsonUtils.convertJson(mapRoot.get("datas")), OaContractVo.class); + } + PageResult pageResult = new PageResult<>(); + pageResult.setPageNo(condition.getPageNo()); + pageResult.setPageSize(condition.getPageSize()); + pageResult.setRecordTotal(totalCount.intValue()); + pageResult.setResult(oaContractVos); + return pageResult; + } + + public List queryAll(ContractQueryCondition condition) throws Exception { + OaResp oaResp = seeyonHttpClient.sendPost("查询客户所有已完成的合同信息", OaApiUrl.CONTRACT_ALL, JsonUtils.convertJson(condition)); + String data = oaResp.getDataStr(); + List vos = JsonUtils.parseArray(data, OaContractVo.class); + return vos; + } + + public OaContractVo queryContractDetail(ContractQueryCondition condition) throws Exception { + OaResp oaResp = seeyonHttpClient.sendPost("查询合同详情信息", OaApiUrl.CONTRACT_DETAIL, JsonUtils.convertJson(condition)); + String data = oaResp.getDataStr(); + OaContractVo oaContractVo = JsonUtils.parseObject(data, OaContractVo.class); + return oaContractVo; + } + + public Integer countUnsign(String cusNo) throws Exception { + Map params = new HashMap<>(); + params.put("cusNo", cusNo); + OaResp oaResp = seeyonHttpClient.sendPost("统计待签署合同份数", OaApiUrl.CONTRACT_COUNT_UNSIGN, JsonUtils.convertJson(params)); + String data = oaResp.getDataStr(); + return Integer.parseInt(data); + } + + public String getSignLink(String eFlowId) throws Exception { + OaResp oaResp = seeyonHttpClient.sendGet("获取签署链接", OaApiUrl.CONTRACT_SIGN_LINK + "?eFlowId=" +eFlowId); + return (String)oaResp.getData(); + } + + public OaAssetsVo pageQueryContractAssets(ContractQueryCondition condition) throws Exception { + OaResp oaResp = seeyonHttpClient.sendPost("分页查询合同关联资产信息", OaApiUrl.PAGE_QUERY_CONTRACT_ASSETS, JsonUtils.convertJson(condition)); + String data = oaResp.getDataStr(); + Map mapRoot = JsonUtils.parseObject(data, Map.class); + OaAssetsVo assetsVo = JsonUtils.parseObject(JsonUtils.convertJson(mapRoot.get("datas")), OaAssetsVo.class); + return assetsVo; + } +} diff --git a/src/main/java/org/chenyon/oa/OaCusService.java b/src/main/java/org/chenyon/oa/OaCusService.java new file mode 100644 index 0000000..f172170 --- /dev/null +++ b/src/main/java/org/chenyon/oa/OaCusService.java @@ -0,0 +1,61 @@ +package org.chenyon.oa; + +import org.chenyon.constants.OaApiUrl; +import org.chenyon.oa.cus.OaCusVo; +import org.chenyon.user.CusVo; +import org.rcy.framework.utils.json.JsonUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.Map; + +@Service +public class OaCusService { + + private static final Logger log = LoggerFactory.getLogger(OaCusService.class); + @Autowired + private SeeyonHttpClient seeyonHttpClient; + + public OaCusVo getCusInfo(String cusNo) { + try { + //调用OA接口查询 + Map params = new HashMap<>(); + params.put("cusNo",cusNo); + OaResp oaResp = seeyonHttpClient.sendPost("查询OA客商信息",OaApiUrl.CUS_INFO, params); + Map map = (Map) oaResp.getData(); + OaCusVo oaCusVo = new OaCusVo(); + oaCusVo.setCusName((String) map.get("cusName")); + oaCusVo.setPhone((String) map.get("cusPhone")); +// oaCusVo.setIdCardNo((String) data.get("cardNo")); +// oaCusVo.setOrgNo((String) data.get("orgNo")); + oaCusVo.setCusNo(cusNo); + return oaCusVo; + }catch (Exception e) { + log.error("调用OA接口查询客商信息失败:"+e.getMessage(),e); + } + return null; + } + + public CusVo matchPersonCus(String phone) throws Exception { + Map params = new HashMap<>(); + params.put("phone",phone); + OaResp oaResp = seeyonHttpClient.sendPost("匹配个人客户",OaApiUrl.MATCH_PERSON, params); + Object data = oaResp.getData(); + CusVo cusVo = new CusVo(); + cusVo.setCusNo((String)data); + return cusVo; + } + + public CusVo matchOrgCus(String orgNo) throws Exception { + Map params = new HashMap<>(); + params.put("orgNo",orgNo); + OaResp oaResp = seeyonHttpClient.sendPost("匹配组织客户",OaApiUrl.MATCH_ORG, params); + Object data = oaResp.getData(); + CusVo cusVo = new CusVo(); + cusVo.setCusNo((String)data); + return cusVo; + } +} diff --git a/src/main/java/org/chenyon/oa/OaDisChargeService.java b/src/main/java/org/chenyon/oa/OaDisChargeService.java new file mode 100644 index 0000000..fda404e --- /dev/null +++ b/src/main/java/org/chenyon/oa/OaDisChargeService.java @@ -0,0 +1,49 @@ +package org.chenyon.oa; + +import org.chenyon.constants.OaApiUrl; +import org.chenyon.discharge.DisChargeApplyQueryCondition; +import org.chenyon.discharge.DisChargeApplyVo; +import org.chenyon.discharge.DisChargeRecordVo; +import org.chenyon.oa.asset.OaAssetsVo; +import org.chenyon.oa.bill.OaPayRecordVo; +import org.rcy.framework.api.entity.PageResult; +import org.rcy.framework.utils.json.JsonUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +@Service +public class OaDisChargeService { + + @Autowired + private SeeyonHttpClient seeyonHttpClient; + + public void apply(DisChargeApplyVo vo) throws Exception { + OaResp oaResp = seeyonHttpClient.sendPost("提交退租申请", OaApiUrl.DISCHARGE_APPLY, JsonUtils.convertJson(vo)); + if(oaResp.getCode() != 0){ + throw new Exception("提交退租申请失败"); + } + } + + public PageResult pageQueryApplyRecord(DisChargeApplyQueryCondition condition) throws Exception { + OaResp oaResp = seeyonHttpClient.sendPost("分页查询退租申请信息", OaApiUrl.PAGE_QUERY_DISCHARGE, JsonUtils.convertJson(condition)); + String data = oaResp.getDataStr(); + Map mapRoot = JsonUtils.parseObject(data, Map.class); + Long totalCount = 0L; + List vos = null; + if(mapRoot.get("totalCount") != null){ + totalCount = mapRoot.get("totalCount") instanceof Long ? (Long) mapRoot.get("totalCount") : Long.parseLong(mapRoot.get("totalCount") + ""); + } + if(mapRoot.get("datas") != null) { + vos = JsonUtils.parseArray(JsonUtils.convertJson(mapRoot.get("datas")), DisChargeRecordVo.class); + } + PageResult pageResult = new PageResult<>(); + pageResult.setPageNo(condition.getPageNo()); + pageResult.setPageSize(condition.getPageSize()); + pageResult.setRecordTotal(totalCount); + pageResult.setResult(vos); + return pageResult; + } +} diff --git a/src/main/java/org/chenyon/oa/OaFallBackService.java b/src/main/java/org/chenyon/oa/OaFallBackService.java new file mode 100644 index 0000000..566b3ce --- /dev/null +++ b/src/main/java/org/chenyon/oa/OaFallBackService.java @@ -0,0 +1,57 @@ +package org.chenyon.oa; + +import org.chenyon.constants.OaApiUrl; +import org.chenyon.fallback.FallbackQueryCondition; +import org.chenyon.fallback.FallbackSubmitVo; +import org.chenyon.fallback.FallbackVo; +import org.rcy.framework.api.entity.PageResult; +import org.rcy.framework.utils.json.JsonUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; + +@Service +public class OaFallBackService { + + @Autowired + private SeeyonHttpClient seeyonHttpClient; + + public void submit(FallbackSubmitVo vo) throws Exception { + OaResp oaResp = seeyonHttpClient.sendPost("新增留言", OaApiUrl.FALLBACK_SUBMIT, JsonUtils.convertJson(vo)); + if(oaResp.getCode() != 0){ + throw new Exception("新增留言失败"); + } + } + + public FallbackVo detail(String id) throws Exception { + FallbackQueryCondition condition = new FallbackQueryCondition(); + condition.setId(id); + OaResp oaResp = seeyonHttpClient.sendPost("查询留言详情", OaApiUrl.FALLBACK_DETAIL, JsonUtils.convertJson(condition)); + String data = oaResp.getDataStr(); + FallbackVo fallbackVo = JsonUtils.parseObject(data, FallbackVo.class); + return fallbackVo; + } + + public PageResult pageQuery(FallbackQueryCondition condition) throws Exception { + OaResp oaResp = seeyonHttpClient.sendPost("分页查询留言", OaApiUrl.PAGE_QUERY_FALLBACK, JsonUtils.convertJson(condition)); + String data = oaResp.getDataStr(); + Map mapRoot = JsonUtils.parseObject(data, Map.class); + Long totalCount = 0L; + List vos = null; + if(mapRoot.get("totalCount") != null){ + totalCount = mapRoot.get("totalCount") instanceof Long ? (Long) mapRoot.get("totalCount") : Long.parseLong(mapRoot.get("totalCount") + ""); + } + if(mapRoot.get("datas") != null) { + vos = JsonUtils.parseArray(JsonUtils.convertJson(mapRoot.get("datas")), FallbackVo.class); + } + PageResult pageResult = new PageResult<>(); + pageResult.setPageNo(condition.getPageNo()); + pageResult.setPageSize(condition.getPageSize()); + pageResult.setRecordTotal(totalCount.intValue()); + pageResult.setResult(vos); + return pageResult; + } + +} diff --git a/src/main/java/org/chenyon/oa/OaNoticeService.java b/src/main/java/org/chenyon/oa/OaNoticeService.java new file mode 100644 index 0000000..15652e7 --- /dev/null +++ b/src/main/java/org/chenyon/oa/OaNoticeService.java @@ -0,0 +1,47 @@ +package org.chenyon.oa; + +import org.chenyon.constants.OaApiUrl; +import org.chenyon.notice.NoticeQueryCondition; +import org.chenyon.notice.NoticeVo; +import org.rcy.framework.api.entity.PageResult; +import org.rcy.framework.utils.json.JsonUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +public class OaNoticeService { + + @Autowired + private SeeyonHttpClient seeyonHttpClient; + + public PageResult pageQuery(NoticeQueryCondition condition) throws Exception { + OaResp oaResp = seeyonHttpClient.sendPost("分页查询招商公告信息", OaApiUrl.PAGE_QUERY_NOTICE, JsonUtils.convertJson(condition)); + String data = oaResp.getDataStr(); + Map mapRoot = JsonUtils.parseObject(data, Map.class); + Long totalCount = 0L; + List vos = null; + if(mapRoot.get("totalCount") != null){ + totalCount = mapRoot.get("totalCount") instanceof Long ? (Long) mapRoot.get("totalCount") : Long.parseLong(mapRoot.get("totalCount") + ""); + } + if(mapRoot.get("datas") != null) { + vos = JsonUtils.parseArray(JsonUtils.convertJson(mapRoot.get("datas")), NoticeVo.class); + } + PageResult pageResult = new PageResult<>(); + pageResult.setPageNo(condition.getPageNo()); + pageResult.setPageSize(condition.getPageSize()); + pageResult.setRecordTotal(totalCount.intValue()); + pageResult.setResult(vos); + return pageResult; + } + + public NoticeVo queryDetail(String id) throws Exception { + Map params = new HashMap<>(); + params.put("id",id); + OaResp oaResp = seeyonHttpClient.sendPost("查询公告详情",OaApiUrl.QUERY_NOTICE_DETAIL, params); + return JsonUtils.parseObject(oaResp.getDataStr(),NoticeVo.class); + } +} diff --git a/src/main/java/org/chenyon/oa/OaPotentialService.java b/src/main/java/org/chenyon/oa/OaPotentialService.java new file mode 100644 index 0000000..d56629c --- /dev/null +++ b/src/main/java/org/chenyon/oa/OaPotentialService.java @@ -0,0 +1,21 @@ +package org.chenyon.oa; + +import org.chenyon.constants.OaApiUrl; +import org.chenyon.potential.ViewRecordVo; +import org.rcy.framework.utils.json.JsonUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class OaPotentialService { + + @Autowired + private SeeyonHttpClient seeyonHttpClient; + + public void add(ViewRecordVo viewRecordVo) throws Exception { + OaResp oaResp = seeyonHttpClient.sendPost("新增租户浏览记录", OaApiUrl.VIEW_RECORD_ADD, JsonUtils.convertJson(viewRecordVo)); + if(oaResp.getCode() != 0){ + throw new Exception("新增租户浏览记录失败"); + } + } +} diff --git a/src/main/java/org/chenyon/oa/OaReservationService.java b/src/main/java/org/chenyon/oa/OaReservationService.java new file mode 100644 index 0000000..b8464d4 --- /dev/null +++ b/src/main/java/org/chenyon/oa/OaReservationService.java @@ -0,0 +1,59 @@ +package org.chenyon.oa; + +import org.chenyon.constants.OaApiUrl; +import org.chenyon.fallback.FallbackSubmitVo; +import org.chenyon.reservation.ReservationQueryCondition; +import org.chenyon.reservation.ReservationSubmitVo; +import org.chenyon.reservation.ReservationVo; +import org.rcy.framework.api.entity.PageResult; +import org.rcy.framework.utils.json.JsonUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +public class OaReservationService { + + @Autowired + private SeeyonHttpClient seeyonHttpClient; + + public PageResult pageQuery(ReservationQueryCondition condition) throws Exception { + OaResp oaResp = seeyonHttpClient.sendPost("分页看房预约信息", OaApiUrl.PAGE_QUERY_RESERVATION, JsonUtils.convertJson(condition)); + String data = oaResp.getDataStr(); + Map mapRoot = JsonUtils.parseObject(data, Map.class); + Long totalCount = 0L; + List vos = null; + if(mapRoot.get("totalCount") != null){ + totalCount = mapRoot.get("totalCount") instanceof Long ? (Long) mapRoot.get("totalCount") : Long.parseLong(mapRoot.get("totalCount") + ""); + } + if(mapRoot.get("datas") != null) { + vos = JsonUtils.parseArray(JsonUtils.convertJson(mapRoot.get("datas")), ReservationVo.class); + } + PageResult pageResult = new PageResult<>(); + pageResult.setPageNo(condition.getPageNo()); + pageResult.setPageSize(condition.getPageSize()); + pageResult.setRecordTotal(totalCount.intValue()); + pageResult.setResult(vos); + return pageResult; + } + + public Integer countHandling(String openId) throws Exception { + Map params = new HashMap<>(); + params.put("openId",openId); + OaResp oaResp = seeyonHttpClient.sendPost("查询处理中预约", OaApiUrl.RESERVATION_COUNT_HANDLING,JsonUtils.convertJson(params)); + String data = oaResp.getDataStr(); + return Integer.parseInt(data); + } + + public void submit(ReservationSubmitVo vo) throws Exception { + OaResp oaResp = seeyonHttpClient.sendPost("新增预约", OaApiUrl.RESERVATION_SUBMIT,JsonUtils.convertJson(vo)); + if(oaResp.getCode() != 0){ + throw new Exception("新增预约失败"); + } + } + + +} diff --git a/src/main/java/org/chenyon/oa/OaResp.java b/src/main/java/org/chenyon/oa/OaResp.java new file mode 100644 index 0000000..51c3bc0 --- /dev/null +++ b/src/main/java/org/chenyon/oa/OaResp.java @@ -0,0 +1,40 @@ +package org.chenyon.oa; + +public class OaResp { + private Integer code; + private String message; + private Object data; + private String dataStr; + + public Integer getCode() { + return code; + } + + public void setCode(Integer code) { + this.code = code; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public Object getData() { + return data; + } + + public void setData(Object data) { + this.data = data; + } + + public String getDataStr() { + return dataStr; + } + + public void setDataStr(String dataStr) { + this.dataStr = dataStr; + } +} diff --git a/src/main/java/org/chenyon/oa/SeeyonHttpClient.java b/src/main/java/org/chenyon/oa/SeeyonHttpClient.java new file mode 100644 index 0000000..279b9ff --- /dev/null +++ b/src/main/java/org/chenyon/oa/SeeyonHttpClient.java @@ -0,0 +1,147 @@ +package org.chenyon.oa; + +import org.rcy.framework.utils.json.JsonUtils; +import org.rcy.framework.utils.net.HttpRequestUtils; +import org.rcy.framework.utils.net.HttpResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Service +public class SeeyonHttpClient { + private static final Logger log = LoggerFactory.getLogger(SeeyonHttpClient.class); + @Value("${seeyon.host}") + private String oaHost; + @Value("${seeyon.rest.restName}") + private String restName; + @Value("${seeyon.rest.restPwd}") + private String restPwd; + @Value("${local.fileStorage.path}") + private String fileStoragePath; + + private ConcurrentHashMap tokenCache = new ConcurrentHashMap<>(); + + + public OaResp sendGet(String bizName,String url) throws Exception { + Map headers = new HashMap<>(); + headers.put("token",getToken()); + log.info(bizName + "请求链接为:" + url); + HttpResponse response = HttpRequestUtils.sendGet(oaHost + "/seeyon/rest" + url,headers); + String respStr = response.getRespStr(); + log.info(bizName + "响应结果为:" + respStr); + return resovleResp(respStr); + } + + public OaResp sendPost(String bizName,String url,Map params) throws Exception { + Map headers = new HashMap<>(); + headers.put("token",getToken()); + headers.put("Content-Type","application/json;charset=UTF-8"); + String paramStr = JsonUtils.convertJson(params); + log.info(bizName + "请求参数为:" + paramStr); + HttpResponse response = HttpRequestUtils.sendPost(oaHost + "/seeyon/rest" + url,paramStr,headers); + String respStr = response.getRespStr(); + log.info(bizName + "响应结果为:" + respStr); + return resovleResp(respStr); + } + + public OaResp sendPost(String bizName,String url,String paramStr) throws Exception { + Map headers = new HashMap<>(); + headers.put("token",getToken()); + headers.put("Content-Type","application/json;charset=UTF-8"); + log.info(bizName + "请求参数为:" + paramStr); + HttpResponse response = HttpRequestUtils.sendPost(oaHost + "/seeyon/rest" + url,paramStr,headers); + String respStr = response.getRespStr(); + log.info(bizName + "响应结果为:" + respStr); + return resovleResp(respStr); + } + + public String downloadFile(String bizType,String url,String refId,Boolean isPulic,String owner) throws Exception { + Map headers = new HashMap<>(); + headers.put("token",getToken()); + log.info("下载OA文件请求参数为:" + refId + "," + isPulic + "," + owner); + String savePath = fileStoragePath; + String returnUrl = null; + if(Boolean.TRUE.equals(isPulic)){ + savePath += File.separator + "public" + File.separator + bizType; + returnUrl = "/" + "public/" + bizType; + }else { + savePath += File.separator + "private" + File.separator + bizType + File.separator + owner; + returnUrl = "/" + "private" + "/" + bizType + "/" + owner; + } + File tempDir = new File(savePath); + if (!tempDir.exists()) { + tempDir.mkdirs(); + } + savePath += File.separator + refId; + String fileGetUrl = oaHost + "/seeyon/rest" + url + "?refId=" + refId; + File file = HttpRequestUtils.downloadFile(fileGetUrl, headers, savePath); + log.info("文件绝对路径为:" + file.getAbsolutePath()); + returnUrl += "/" + file.getName(); + return returnUrl; + } + + + OaResp resovleResp(String respStr) throws IOException { + OaResp oaResp = JsonUtils.parseObject(respStr, OaResp.class); + oaResp.setDataStr(JsonUtils.convertJson(oaResp.getData())); + return oaResp; + } + + private String applyToken() { + String url = oaHost +"/seeyon/rest/token/" + restName + "/" + restPwd; + try { + HttpResponse response = HttpRequestUtils.sendGet(url, null); + if(response.getCode() == 200) { + String respStr = response.getRespStr(); + if (respStr.startsWith("{") && respStr.endsWith("}")) { + Map map = JsonUtils.parseObject(respStr, Map.class); + if(map.get("id") != null) { + return map.get("id") + ""; + } + throw new RuntimeException("获取token失败"); + } else { + return respStr; + } + }else { + throw new RuntimeException("获取token失败:" + response.getCode()); + } + }catch (Exception e) { + throw new RuntimeException("获取oaToken异常:" + e.getMessage(),e); + } + } + + private String getToken(){ + String token = tokenCache.get(restName); + if(token != null && !checkExpire(token)) { + return token; + }else { + String tokenStr = applyToken(); + tokenCache.put(restName, tokenStr); + return tokenStr; + } + } + + private boolean checkExpire(String token) { + String url = oaHost + "/seeyon/rest/cap4/batch/refresh"; + try{ + Map headers = new HashMap<>(); + headers.put("token",token); + headers.put("loginName",restName); + HttpResponse response = HttpRequestUtils.sendPost(url, null, headers); + if(response.getCode() == 200) { + return false; + }else { + return true; + } + } catch (Exception e){ + return true; + } + } +} diff --git a/src/main/java/org/chenyon/oa/asset/OaAssetsVo.java b/src/main/java/org/chenyon/oa/asset/OaAssetsVo.java new file mode 100644 index 0000000..decc1d7 --- /dev/null +++ b/src/main/java/org/chenyon/oa/asset/OaAssetsVo.java @@ -0,0 +1,243 @@ +package org.chenyon.oa.asset; + + +import org.chenyon.file.OaFileVo; + +import java.io.Serializable; + +public class OaAssetsVo implements Serializable { + private String assetsNo; // 资产编号 + private String assetsName; // 资产名称 + private String assetsType; //资产类型 + private String assetsStatus; //资产状态 + private String rentFee; //租金 + private String footPrint; //占地大小 + private String formId; //表单记录ID + private OaFileVo detailImg; //详情图片 + private OaFileVo vrImg; //vr图 + private String assetsDesc; //资产描述 + private String assetsAddress; //资产地址 + private String latitude; //纬度 + private String longitude; //经度 + private String unitNo; //单元号 + private String floorNo; //楼层号 + private String roomNo; //房间号 + private Boolean hasLift;//有无电梯 + private String managerName; //管理员 + private String managerPhone; //管理员电话 + private String layout; //户型 + private String orientation; //朝向 + private String building; //楼栋 + private String waterFee; //水费 + private String waterFeeUnit; //水费单位 + private String powerFee; //电费 + private String powerFeeUnit; //电费单位 + + public String getAssetsNo() { + return assetsNo; + } + + public void setAssetsNo(String assetsNo) { + this.assetsNo = assetsNo; + } + + public String getAssetsName() { + return assetsName; + } + + public void setAssetsName(String assetsName) { + this.assetsName = assetsName; + } + + public String getAssetsType() { + return assetsType; + } + + public void setAssetsType(String assetsType) { + this.assetsType = assetsType; + } + + public String getAssetsStatus() { + return assetsStatus; + } + + public void setAssetsStatus(String assetsStatus) { + this.assetsStatus = assetsStatus; + } + + public String getRentFee() { + return rentFee; + } + + public void setRentFee(String rentFee) { + this.rentFee = rentFee; + } + + public String getFootPrint() { + return footPrint; + } + + public void setFootPrint(String footPrint) { + this.footPrint = footPrint; + } + + public String getFormId() { + return formId; + } + + public void setFormId(String formId) { + this.formId = formId; + } + + public OaFileVo getDetailImg() { + return detailImg; + } + + public void setDetailImg(OaFileVo detailImg) { + this.detailImg = detailImg; + } + + public OaFileVo getVrImg() { + return vrImg; + } + + public void setVrImg(OaFileVo vrImg) { + this.vrImg = vrImg; + } + + public String getAssetsDesc() { + return assetsDesc; + } + + public void setAssetsDesc(String assetsDesc) { + this.assetsDesc = assetsDesc; + } + + public String getAssetsAddress() { + return assetsAddress; + } + + public void setAssetsAddress(String assetsAddress) { + this.assetsAddress = assetsAddress; + } + + public String getLatitude() { + return latitude; + } + + public void setLatitude(String latitude) { + this.latitude = latitude; + } + + public String getLongitude() { + return longitude; + } + + public void setLongitude(String longitude) { + this.longitude = longitude; + } + + public String getUnitNo() { + return unitNo; + } + + public void setUnitNo(String unitNo) { + this.unitNo = unitNo; + } + + public String getFloorNo() { + return floorNo; + } + + public void setFloorNo(String floorNo) { + this.floorNo = floorNo; + } + + public String getRoomNo() { + return roomNo; + } + + public void setRoomNo(String roomNo) { + this.roomNo = roomNo; + } + + public Boolean getHasLift() { + return hasLift; + } + + public void setHasLift(Boolean hasLift) { + this.hasLift = hasLift; + } + + public String getManagerPhone() { + return managerPhone; + } + + public void setManagerPhone(String managerPhone) { + this.managerPhone = managerPhone; + } + + public String getLayout() { + return layout; + } + + public void setLayout(String layout) { + this.layout = layout; + } + + public String getOrientation() { + return orientation; + } + + public void setOrientation(String orientation) { + this.orientation = orientation; + } + + public String getBuilding() { + return building; + } + + public void setBuilding(String building) { + this.building = building; + } + + public String getWaterFee() { + return waterFee; + } + + public void setWaterFee(String waterFee) { + this.waterFee = waterFee; + } + + public String getWaterFeeUnit() { + return waterFeeUnit; + } + + public void setWaterFeeUnit(String waterFeeUnit) { + this.waterFeeUnit = waterFeeUnit; + } + + public String getPowerFee() { + return powerFee; + } + + public void setPowerFee(String powerFee) { + this.powerFee = powerFee; + } + + public String getPowerFeeUnit() { + return powerFeeUnit; + } + + public void setPowerFeeUnit(String powerFeeUnit) { + this.powerFeeUnit = powerFeeUnit; + } + + public String getManagerName() { + return managerName; + } + + public void setManagerName(String managerName) { + this.managerName = managerName; + } +} diff --git a/src/main/java/org/chenyon/oa/bill/OaBillVo.java b/src/main/java/org/chenyon/oa/bill/OaBillVo.java new file mode 100644 index 0000000..4399453 --- /dev/null +++ b/src/main/java/org/chenyon/oa/bill/OaBillVo.java @@ -0,0 +1,112 @@ +package org.chenyon.oa.bill; + +public class OaBillVo { + private String billType; //账单类型 + private String billNo; //账单编号 + private String cusNo; //租户编号 + private String contractNo; //合同编号 + private String billAmount; //账单金额 + private String billStatus; //账单状态 + private String billStartDate; //账单开始日期 + private String billEndDate; //账单结束日期 + private String billPayEndDate; //账单支付截止日期 + private String billName;// 账单名称 + private String billPayTime; + private String formId; + + public String getBillStartDate() { + return billStartDate; + } + + public void setBillStartDate(String billStartDate) { + this.billStartDate = billStartDate; + } + + public String getBillPayEndDate() { + return billPayEndDate; + } + + public void setBillPayEndDate(String billPayEndDate) { + this.billPayEndDate = billPayEndDate; + } + + public String getBillType() { + return billType; + } + + public void setBillType(String billType) { + this.billType = billType; + } + + public String getBillNo() { + return billNo; + } + + public void setBillNo(String billNo) { + this.billNo = billNo; + } + + public String getCusNo() { + return cusNo; + } + + public void setCusNo(String cusNo) { + this.cusNo = cusNo; + } + + public String getContractNo() { + return contractNo; + } + + public void setContractNo(String contractNo) { + this.contractNo = contractNo; + } + + public String getBillAmount() { + return billAmount; + } + + public void setBillAmount(String billAmount) { + this.billAmount = billAmount; + } + + public String getBillStatus() { + return billStatus; + } + + public void setBillStatus(String billStatus) { + this.billStatus = billStatus; + } + + public String getBillEndDate() { + return billEndDate; + } + + public void setBillEndDate(String billEndDate) { + this.billEndDate = billEndDate; + } + + public String getBillName() { + return billName; + } + + public void setBillName(String billName) { + this.billName = billName; + } + + public String getBillPayTime() { + return billPayTime; + } + + public void setBillPayTime(String billPayTime) { + this.billPayTime = billPayTime; + } + + public String getFormId() { + return formId; + } + + public void setFormId(String formId) { + this.formId = formId; + } +} diff --git a/src/main/java/org/chenyon/oa/bill/OaPayRecordVo.java b/src/main/java/org/chenyon/oa/bill/OaPayRecordVo.java new file mode 100644 index 0000000..c00fb1c --- /dev/null +++ b/src/main/java/org/chenyon/oa/bill/OaPayRecordVo.java @@ -0,0 +1,59 @@ +package org.chenyon.oa.bill; + +public class OaPayRecordVo { + + private String feeType; + private String itemName; //记录项名称 + private String itemAmount; //记录项金额 + private String payDate; //支付日期 + private String inDate; //入账日期 + private String inOutType; //收支类型 + + public String getItemName() { + return itemName; + } + + public void setItemName(String itemName) { + this.itemName = itemName; + } + + public String getItemAmount() { + return itemAmount; + } + + public void setItemAmount(String itemAmount) { + this.itemAmount = itemAmount; + } + + public String getPayDate() { + return payDate; + } + + public void setPayDate(String payDate) { + this.payDate = payDate; + } + + public String getInDate() { + return inDate; + } + + public void setInDate(String inDate) { + this.inDate = inDate; + } + + public String getInOutType() { + return inOutType; + } + + public void setInOutType(String inOutType) { + this.inOutType = inOutType; + } + + public String getFeeType() { + return feeType; + } + + public void setFeeType(String feeType) { + this.feeType = feeType; + } +} diff --git a/src/main/java/org/chenyon/oa/contract/OaContractVo.java b/src/main/java/org/chenyon/oa/contract/OaContractVo.java new file mode 100644 index 0000000..0a2fcea --- /dev/null +++ b/src/main/java/org/chenyon/oa/contract/OaContractVo.java @@ -0,0 +1,99 @@ +package org.chenyon.oa.contract; + +import org.chenyon.file.OaFileVo; +import org.chenyon.oa.asset.OaAssetsVo; + +import java.util.List; + +public class OaContractVo { + private String formId;//表单ID + private String contractNo; //合同编号 + private String contractName; //合同名称 + private String signStatus; //签订状态 + private String startDate; + private String endDate; + private String eContractFlowId; //电子合同签署流程ID + private List assetsVos; //资产信息 + private OaFileVo eContractFile; //电子合同文件 + private String cusNo; //客商编码 + + public String getContractNo() { + return contractNo; + } + + public void setContractNo(String contractNo) { + this.contractNo = contractNo; + } + + public String getContractName() { + return contractName; + } + + public void setContractName(String contractName) { + this.contractName = contractName; + } + + public String getSignStatus() { + return signStatus; + } + + public void setSignStatus(String signStatus) { + this.signStatus = signStatus; + } + + public List getAssetsVos() { + return assetsVos; + } + + public void setAssetsVos(List assetsVos) { + this.assetsVos = assetsVos; + } + + public String getCusNo() { + return cusNo; + } + + public void setCusNo(String cusNo) { + this.cusNo = cusNo; + } + + public String geteContractFlowId() { + return eContractFlowId; + } + + public void seteContractFlowId(String eContractFlowId) { + this.eContractFlowId = eContractFlowId; + } + + public String getFormId() { + return formId; + } + + public void setFormId(String formId) { + this.formId = formId; + } + + public String getStartDate() { + return startDate; + } + + public void setStartDate(String startDate) { + this.startDate = startDate; + } + + public String getEndDate() { + return endDate; + } + + public void setEndDate(String endDate) { + this.endDate = endDate; + } + + public OaFileVo geteContractFile() { + return eContractFile; + } + + public void seteContractFile(OaFileVo eContractFile) { + this.eContractFile = eContractFile; + } +} diff --git a/src/main/java/org/chenyon/oa/cus/OaCusVo.java b/src/main/java/org/chenyon/oa/cus/OaCusVo.java new file mode 100644 index 0000000..55dcb3c --- /dev/null +++ b/src/main/java/org/chenyon/oa/cus/OaCusVo.java @@ -0,0 +1,59 @@ +package org.chenyon.oa.cus; + +public class OaCusVo { + + private String cusName; + private String phone; + private String idCardNo; + private String orgNo; + private String userType; + private String cusNo; + + public String getCusName() { + return cusName; + } + + public void setCusName(String cusName) { + this.cusName = cusName; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getIdCardNo() { + return idCardNo; + } + + public void setIdCardNo(String idCardNo) { + this.idCardNo = idCardNo; + } + + public String getUserType() { + return userType; + } + + public void setUserType(String userType) { + this.userType = userType; + } + + public String getOrgNo() { + return orgNo; + } + + public void setOrgNo(String orgNo) { + this.orgNo = orgNo; + } + + public String getCusNo() { + return cusNo; + } + + public void setCusNo(String cusNo) { + this.cusNo = cusNo; + } +} diff --git a/src/main/java/org/chenyon/oa/notice/OaNoticeVo.java b/src/main/java/org/chenyon/oa/notice/OaNoticeVo.java new file mode 100644 index 0000000..9190449 --- /dev/null +++ b/src/main/java/org/chenyon/oa/notice/OaNoticeVo.java @@ -0,0 +1,4 @@ +package org.chenyon.oa.notice; + +public class OaNoticeVo { +} diff --git a/src/main/java/org/chenyon/pay/Goods.java b/src/main/java/org/chenyon/pay/Goods.java new file mode 100644 index 0000000..7ce9b0e --- /dev/null +++ b/src/main/java/org/chenyon/pay/Goods.java @@ -0,0 +1,110 @@ +package org.chenyon.pay; + +public class Goods { + + private String goodsId; + private String goodsName; + private String quantity; + private String price; + private String unit; + private String goodsCategory; + private String body; + private String discount; + + /** 子商户号 */ + private String subMerchantId; + + /** 子订单号 */ + private String merOrderId; + + /** 子订单金额(分) */ + private String subOrderAmount; + + public String getGoodsId() { + return goodsId; + } + + public void setGoodsId(String goodsId) { + this.goodsId = goodsId; + } + + public String getGoodsName() { + return goodsName; + } + + public void setGoodsName(String goodsName) { + this.goodsName = goodsName; + } + + public String getQuantity() { + return quantity; + } + + public void setQuantity(String quantity) { + this.quantity = quantity; + } + + public String getPrice() { + return price; + } + + public void setPrice(String price) { + this.price = price; + } + + public String getUnit() { + return unit; + } + + public void setUnit(String unit) { + this.unit = unit; + } + + public String getGoodsCategory() { + return goodsCategory; + } + + public void setGoodsCategory(String goodsCategory) { + this.goodsCategory = goodsCategory; + } + + public String getBody() { + return body; + } + + public void setBody(String body) { + this.body = body; + } + + public String getDiscount() { + return discount; + } + + public void setDiscount(String discount) { + this.discount = discount; + } + + public String getSubMerchantId() { + return subMerchantId; + } + + public void setSubMerchantId(String subMerchantId) { + this.subMerchantId = subMerchantId; + } + + public String getMerOrderId() { + return merOrderId; + } + + public void setMerOrderId(String merOrderId) { + this.merOrderId = merOrderId; + } + + public String getSubOrderAmount() { + return subOrderAmount; + } + + public void setSubOrderAmount(String subOrderAmount) { + this.subOrderAmount = subOrderAmount; + } +} diff --git a/src/main/java/org/chenyon/pay/Order.java b/src/main/java/org/chenyon/pay/Order.java new file mode 100644 index 0000000..b54b488 --- /dev/null +++ b/src/main/java/org/chenyon/pay/Order.java @@ -0,0 +1,52 @@ +package org.chenyon.pay; + +import org.rcy.framework.api.entity.BaseEntity; + +public class Order extends BaseEntity { + + private String bizId; + private String payerId; + private String payDate; + private String amount; + private String status; + + public String getBizId() { + return bizId; + } + + public void setBizId(String bizId) { + this.bizId = bizId; + } + + public String getPayerId() { + return payerId; + } + + public void setPayerId(String payerId) { + this.payerId = payerId; + } + + public String getPayDate() { + return payDate; + } + + public void setPayDate(String payDate) { + this.payDate = payDate; + } + + public String getAmount() { + return amount; + } + + public void setAmount(String amount) { + this.amount = amount; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } +} diff --git a/src/main/java/org/chenyon/pay/RetCommParams.java b/src/main/java/org/chenyon/pay/RetCommParams.java new file mode 100644 index 0000000..db497ee --- /dev/null +++ b/src/main/java/org/chenyon/pay/RetCommParams.java @@ -0,0 +1,32 @@ +package org.chenyon.pay; + +public class RetCommParams { + + private String foodOrderType; + private String parkId; + private String vehicleNo; + + public String getFoodOrderType() { + return foodOrderType; + } + + public void setFoodOrderType(String foodOrderType) { + this.foodOrderType = foodOrderType; + } + + public String getParkId() { + return parkId; + } + + public void setParkId(String parkId) { + this.parkId = parkId; + } + + public String getVehicleNo() { + return vehicleNo; + } + + public void setVehicleNo(String vehicleNo) { + this.vehicleNo = vehicleNo; + } +} \ No newline at end of file diff --git a/src/main/java/org/chenyon/pay/SubOrder.java b/src/main/java/org/chenyon/pay/SubOrder.java new file mode 100644 index 0000000..d6999e7 --- /dev/null +++ b/src/main/java/org/chenyon/pay/SubOrder.java @@ -0,0 +1,37 @@ +package org.chenyon.pay; + +public class SubOrder { + + /** 子商户号 */ + private String mid; + + /** 子订单号 */ + private String merOrderId; + + /** 金额(分) */ + private String totalAmount; + + public String getMid() { + return mid; + } + + public void setMid(String mid) { + this.mid = mid; + } + + public String getMerOrderId() { + return merOrderId; + } + + public void setMerOrderId(String merOrderId) { + this.merOrderId = merOrderId; + } + + public String getTotalAmount() { + return totalAmount; + } + + public void setTotalAmount(String totalAmount) { + this.totalAmount = totalAmount; + } +} \ No newline at end of file diff --git a/src/main/java/org/chenyon/pay/TmPayApiContextBuilder.java b/src/main/java/org/chenyon/pay/TmPayApiContextBuilder.java new file mode 100644 index 0000000..c826046 --- /dev/null +++ b/src/main/java/org/chenyon/pay/TmPayApiContextBuilder.java @@ -0,0 +1,27 @@ +package org.chenyon.pay; + +import com.chinaums.open.api.OpenApiCache; +import com.chinaums.open.api.OpenApiContext; +import com.chinaums.open.api.constants.ConfigBean; + +import java.util.UUID; + +public class TmPayApiContextBuilder { + + public static OpenApiContext build(String appId,String appKey,String url) { + + ConfigBean configBean = new ConfigBean(); + OpenApiContext context = new OpenApiContext(); + context.setStartTime(System.currentTimeMillis()); + context.setRequestId(UUID.randomUUID().toString().replace("-", "")); + context.setOpenServUrl(url.split("/v")[0].concat("/")); + context.setApiServiceUrl(url); + context.setVersion(url.split("/")[3]); + context.setServiceCode(url.split("/v")[1].substring(1)); + context.setAppId(appId); + context.setAppKey(appKey); + context.setConfigBean(configBean); + OpenApiCache.getCurrentToken(context); + return context; + } +} diff --git a/src/main/java/org/chenyon/pay/TmPayService.java b/src/main/java/org/chenyon/pay/TmPayService.java new file mode 100644 index 0000000..e952955 --- /dev/null +++ b/src/main/java/org/chenyon/pay/TmPayService.java @@ -0,0 +1,44 @@ +package org.chenyon.pay; + +import com.chinaums.open.api.OpenApiContext; + +import com.chinaums.open.api.internal.util.http.HttpTransport; +import org.rcy.framework.utils.json.JsonUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +@Service +public class TmPayService { + + @Value("${chinaums.api.dev.host}") + private String devHost; + @Value("chinaums.api.prod.host") + private String prodHost; + + public void weChatPayCreateOrder(UnifiedOrderRequest request) { + String url = "/v1/netpay/wx/unified-order"; + String appId = "123456"; + String appKey = "123456"; + OpenApiContext context = TmPayApiContextBuilder.build(appId, appKey, url); + Long totalAmount = null; +// if(Boolean.TRUE.equals(divisionFlag)){ +// request.setDivisionFlag(divisionFlag); +// List subOrders = new ArrayList<>(); +// }else { +// request.setTotalAmount(100); +// } + request.setRequestTimestamp(""); // 设置请求时间戳 + request.setMerOrderId("123456"); // 设置商户订单号 + request.setMid("");// 设置商户号 + request.setTid(""); + try { + HttpTransport.getInstance().doPost(context, JsonUtils.convertJson(request)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/src/main/java/org/chenyon/pay/UnifiedOrderRequest.java b/src/main/java/org/chenyon/pay/UnifiedOrderRequest.java new file mode 100644 index 0000000..8692535 --- /dev/null +++ b/src/main/java/org/chenyon/pay/UnifiedOrderRequest.java @@ -0,0 +1,198 @@ +package org.chenyon.pay; + +import java.util.List; + +public class UnifiedOrderRequest { + + /** 请求时间 yyyy-MM-dd HH:mm:ss */ + private String requestTimestamp; + + /** 商户订单号 */ + private String merOrderId; + + /** 商户号 */ + private String mid; + + /** 终端号 */ + private String tid; + + /** 订单总金额(分) */ + private Long totalAmount; + /** 微信子商户appId*/ + private String subAppId; + /** 用户子标识*/ + private String subOpenId; + /** 微信:MINI / JSAPI */ + private String tradeType; + + /** 消息ID */ + private String msgId; + + /** 机构号 */ + private String instMid; + + /** 订单描述 */ + private String orderDesc; + /** 同步分账标识*/ + private Boolean divisionFlag; + /** 分账金额*/ + private Long platformAmount; + /** 通知地址 */ + private String notifyUrl; + + /** 客户端IP */ + private String clientIp; + + /** 商品信息 */ + private List goods; + + /** 子订单(分账) */ + private List subOrders; + + /** 扩展参数 */ + private RetCommParams retCommParams; + + public String getRequestTimestamp() { + return requestTimestamp; + } + + public void setRequestTimestamp(String requestTimestamp) { + this.requestTimestamp = requestTimestamp; + } + + public String getMerOrderId() { + return merOrderId; + } + + public void setMerOrderId(String merOrderId) { + this.merOrderId = merOrderId; + } + + public String getMid() { + return mid; + } + + public void setMid(String mid) { + this.mid = mid; + } + + public String getTid() { + return tid; + } + + public void setTid(String tid) { + this.tid = tid; + } + + public String getTradeType() { + return tradeType; + } + + public void setTradeType(String tradeType) { + this.tradeType = tradeType; + } + + public String getMsgId() { + return msgId; + } + + public void setMsgId(String msgId) { + this.msgId = msgId; + } + + public String getInstMid() { + return instMid; + } + + public void setInstMid(String instMid) { + this.instMid = instMid; + } + + public String getOrderDesc() { + return orderDesc; + } + + public void setOrderDesc(String orderDesc) { + this.orderDesc = orderDesc; + } + + public String getNotifyUrl() { + return notifyUrl; + } + + public void setNotifyUrl(String notifyUrl) { + this.notifyUrl = notifyUrl; + } + + public String getClientIp() { + return clientIp; + } + + public void setClientIp(String clientIp) { + this.clientIp = clientIp; + } + + public List getGoods() { + return goods; + } + + public void setGoods(List goods) { + this.goods = goods; + } + + public List getSubOrders() { + return subOrders; + } + + public void setSubOrders(List subOrders) { + this.subOrders = subOrders; + } + + public RetCommParams getRetCommParams() { + return retCommParams; + } + + public void setRetCommParams(RetCommParams retCommParams) { + this.retCommParams = retCommParams; + } + + public Long getTotalAmount() { + return totalAmount; + } + + public void setTotalAmount(Long totalAmount) { + this.totalAmount = totalAmount; + } + + public String getSubAppId() { + return subAppId; + } + + public void setSubAppId(String subAppId) { + this.subAppId = subAppId; + } + + public String getSubOpenId() { + return subOpenId; + } + + public void setSubOpenId(String subOpenId) { + this.subOpenId = subOpenId; + } + + public Boolean getDivisionFlag() { + return divisionFlag; + } + + public void setDivisionFlag(Boolean divisionFlag) { + this.divisionFlag = divisionFlag; + } + + public Long getPlatformAmount() { + return platformAmount; + } + + public void setPlatformAmount(Long platformAmount) { + this.platformAmount = platformAmount; + } +} \ No newline at end of file diff --git a/src/main/java/org/chenyon/potential/PotentialController.java b/src/main/java/org/chenyon/potential/PotentialController.java new file mode 100644 index 0000000..c69ad69 --- /dev/null +++ b/src/main/java/org/chenyon/potential/PotentialController.java @@ -0,0 +1,51 @@ +package org.chenyon.potential; + +import org.chenyon.user.LoginCheck; +import org.chenyon.user.UserContext; +import org.chenyon.user.UserService; +import org.chenyon.user.UserVo; +import org.chenyon.wx.WxUserSession; +import org.chenyon.wx.WxUserSessionService; +import org.rcy.framework.api.entity.ResultMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; + +@RestController +@RequestMapping("/potential") +public class PotentialController { + + private static final Logger log = LoggerFactory.getLogger(PotentialController.class); + @Autowired + private PotentialService potentialService; + @Autowired + private UserService userService; + @Autowired + private WxUserSessionService wxUserSessionService; + + @GetMapping("/add") + public ResultMessage addViewRecord(HttpServletRequest request, @RequestParam("assetId") String assetId) { + try { + String token = request.getHeader("WT"); + String userType = request.getHeader("USERTYPE"); + WxUserSession session = wxUserSessionService.getSessionInfoByThirdSession(token); + UserVo userVo = userService.findByOpenIdAndUserType(session.getOpenId(), userType); + ViewRecordVo viewRecordVo = new ViewRecordVo(); + viewRecordVo.setAssetsNo(assetId); + viewRecordVo.setCusNo(userVo.getCusNo()); + viewRecordVo.setPhone(userVo.getPhone()); + viewRecordVo.setCusName(userVo.getUserName()); + potentialService.add(viewRecordVo); + }catch (Exception e) { + log.warn("记录租户浏览记录失败: " + e.getMessage(),e); + } + return ResultMessage.success(); + } + +} diff --git a/src/main/java/org/chenyon/potential/PotentialService.java b/src/main/java/org/chenyon/potential/PotentialService.java new file mode 100644 index 0000000..dc96f10 --- /dev/null +++ b/src/main/java/org/chenyon/potential/PotentialService.java @@ -0,0 +1,17 @@ +package org.chenyon.potential; + + +import org.chenyon.oa.OaPotentialService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class PotentialService { + + @Autowired + private OaPotentialService oaPotentialService; + + public void add(ViewRecordVo viewRecordVo) throws Exception { + oaPotentialService.add(viewRecordVo); + } +} diff --git a/src/main/java/org/chenyon/potential/ViewRecordVo.java b/src/main/java/org/chenyon/potential/ViewRecordVo.java new file mode 100644 index 0000000..1695117 --- /dev/null +++ b/src/main/java/org/chenyon/potential/ViewRecordVo.java @@ -0,0 +1,41 @@ +package org.chenyon.potential; + +public class ViewRecordVo { + + private String cusNo; + private String cusName; + private String phone; + private String assetsNo; + + public String getCusNo() { + return cusNo; + } + + public void setCusNo(String cusNo) { + this.cusNo = cusNo; + } + + public String getCusName() { + return cusName; + } + + public void setCusName(String cusName) { + this.cusName = cusName; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getAssetsNo() { + return assetsNo; + } + + public void setAssetsNo(String assetsNo) { + this.assetsNo = assetsNo; + } +} diff --git a/src/main/java/org/chenyon/reservation/ReservateController.java b/src/main/java/org/chenyon/reservation/ReservateController.java new file mode 100644 index 0000000..3d3300b --- /dev/null +++ b/src/main/java/org/chenyon/reservation/ReservateController.java @@ -0,0 +1,74 @@ +package org.chenyon.reservation; + +import org.chenyon.oa.OaReservationService; +import org.chenyon.user.LoginCheck; +import org.chenyon.user.UserContext; +import org.rcy.framework.api.entity.PageResult; +import org.rcy.framework.api.entity.ResultMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; + +@RestController +@RequestMapping("/reservate") +public class ReservateController { + private static final Logger log = LoggerFactory.getLogger(ReservateController.class); + @Autowired + private OaReservationService reservateService; + + @LoginCheck + @PostMapping("/queryPage") + public ResultMessage queryPage(@RequestBody ReservationQueryCondition condition) { + try { + UserContext userContext = UserContext.get(); + if(userContext == null || userContext.getOpenId() == null) { + return ResultMessage.success(new PageResult()); + } + condition.setOpenId(userContext.getOpenId()); + return ResultMessage.success(reservateService.pageQuery(condition)); + }catch (Exception e) { + log.error(e.getMessage(),e); + } + return ResultMessage.success(new PageResult()); + } + + @LoginCheck + @PostMapping("/submit") + public ResultMessage submit(@RequestBody ReservationSubmitVo submitVo) { + try { + DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + UserContext userContext = UserContext.get(); + if(userContext == null || userContext.getOpenId() == null) { + return ResultMessage.error("提交失败"); + } + submitVo.setReserveDate(df.format(new Date())); + submitVo.setOpenId(userContext.getOpenId()); + reservateService.submit(submitVo); + return ResultMessage.success(); + }catch (Exception e) { + log.error(e.getMessage(),e); + } + return ResultMessage.error("提交失败"); + } + + @LoginCheck + @GetMapping("/countHandling") + public ResultMessage countHandling() { + try { + UserContext userContext = UserContext.get(); + if(userContext == null || userContext.getCusNo() == null) { + return ResultMessage.success(0); + } + return ResultMessage.success(reservateService.countHandling(userContext.getOpenId())); + }catch (Exception e) { + log.error(e.getMessage(),e); + } + return ResultMessage.success(0); + } + +} diff --git a/src/main/java/org/chenyon/reservation/ReservationQueryCondition.java b/src/main/java/org/chenyon/reservation/ReservationQueryCondition.java new file mode 100644 index 0000000..2b2d468 --- /dev/null +++ b/src/main/java/org/chenyon/reservation/ReservationQueryCondition.java @@ -0,0 +1,15 @@ +package org.chenyon.reservation; + +import org.rcy.framework.api.entity.PageQueryRequest; + +public class ReservationQueryCondition extends PageQueryRequest { + private String openId; + + public String getOpenId() { + return openId; + } + + public void setOpenId(String openId) { + this.openId = openId; + } +} diff --git a/src/main/java/org/chenyon/reservation/ReservationSubmitVo.java b/src/main/java/org/chenyon/reservation/ReservationSubmitVo.java new file mode 100644 index 0000000..aa280a5 --- /dev/null +++ b/src/main/java/org/chenyon/reservation/ReservationSubmitVo.java @@ -0,0 +1,58 @@ +package org.chenyon.reservation; + +public class ReservationSubmitVo { + private String openId; + private String assetsNo; + private String assetsName; + private String phone; + private String reserveDate; + private String reserveName; + + public String getAssetsNo() { + return assetsNo; + } + + public void setAssetsNo(String assetsNo) { + this.assetsNo = assetsNo; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getReserveDate() { + return reserveDate; + } + + public void setReserveDate(String reserveDate) { + this.reserveDate = reserveDate; + } + + public String getOpenId() { + return openId; + } + + public void setOpenId(String openId) { + this.openId = openId; + } + + public String getReserveName() { + return reserveName; + } + + public void setReserveName(String reserveName) { + this.reserveName = reserveName; + } + + public String getAssetsName() { + return assetsName; + } + + public void setAssetsName(String assetsName) { + this.assetsName = assetsName; + } +} diff --git a/src/main/java/org/chenyon/reservation/ReservationVo.java b/src/main/java/org/chenyon/reservation/ReservationVo.java new file mode 100644 index 0000000..d72afb2 --- /dev/null +++ b/src/main/java/org/chenyon/reservation/ReservationVo.java @@ -0,0 +1,94 @@ +package org.chenyon.reservation; + +public class ReservationVo { + private String openId; + private String id; //id + private String date; //预约时间 + private String status; //状态 + private String assetName; //资产名称 + private String assetAddress; //资产地址 + private String managerName; //管理员姓名 + private String managerPhone; //管理员电话 + private String lat; //纬度 + private String lng; //经度 + + public String getOpenId() { + return openId; + } + + public void setOpenId(String openId) { + this.openId = openId; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getDate() { + return date; + } + + public void setDate(String date) { + this.date = date; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public String getAssetName() { + return assetName; + } + + public void setAssetName(String assetName) { + this.assetName = assetName; + } + + public String getAssetAddress() { + return assetAddress; + } + + public void setAssetAddress(String assetAddress) { + this.assetAddress = assetAddress; + } + + public String getManagerName() { + return managerName; + } + + public void setManagerName(String managerName) { + this.managerName = managerName; + } + + public String getManagerPhone() { + return managerPhone; + } + + public void setManagerPhone(String managerPhone) { + this.managerPhone = managerPhone; + } + + public String getLat() { + return lat; + } + + public void setLat(String lat) { + this.lat = lat; + } + + public String getLng() { + return lng; + } + + public void setLng(String lng) { + this.lng = lng; + } +} diff --git a/src/main/java/org/chenyon/user/AuthInfoVo.java b/src/main/java/org/chenyon/user/AuthInfoVo.java new file mode 100644 index 0000000..9a5079d --- /dev/null +++ b/src/main/java/org/chenyon/user/AuthInfoVo.java @@ -0,0 +1,23 @@ +package org.chenyon.user; + +public class AuthInfoVo { + + private String userType; + private String code; + + public String getUserType() { + return userType; + } + + public void setUserType(String userType) { + this.userType = userType; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } +} diff --git a/src/main/java/org/chenyon/user/CusVo.java b/src/main/java/org/chenyon/user/CusVo.java new file mode 100644 index 0000000..43644ad --- /dev/null +++ b/src/main/java/org/chenyon/user/CusVo.java @@ -0,0 +1,25 @@ +package org.chenyon.user; + +import java.io.Serializable; + +public class CusVo implements Serializable { + + private String cusNo; + private String CusName; + + public String getCusNo() { + return cusNo; + } + + public void setCusNo(String cusNo) { + this.cusNo = cusNo; + } + + public String getCusName() { + return CusName; + } + + public void setCusName(String cusName) { + CusName = cusName; + } +} diff --git a/src/main/java/org/chenyon/user/LoginCheck.java b/src/main/java/org/chenyon/user/LoginCheck.java new file mode 100644 index 0000000..51ee460 --- /dev/null +++ b/src/main/java/org/chenyon/user/LoginCheck.java @@ -0,0 +1,9 @@ +package org.chenyon.user; + +import java.lang.annotation.*; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface LoginCheck { +} diff --git a/src/main/java/org/chenyon/user/LoginController.java b/src/main/java/org/chenyon/user/LoginController.java new file mode 100644 index 0000000..e4d10fc --- /dev/null +++ b/src/main/java/org/chenyon/user/LoginController.java @@ -0,0 +1,94 @@ +package org.chenyon.user; + +import org.chenyon.utils.RSAUtil; +import org.chenyon.wx.*; +import org.rcy.framework.api.entity.ResultMessage; +import org.rcy.framework.utils.json.JsonUtils; +import org.rcy.framework.utils.net.HttpRequestUtils; +import org.rcy.framework.utils.net.HttpResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; +import java.util.UUID; + +@RestController +@RequestMapping("/login") +public class LoginController { + + private static final Logger log = LoggerFactory.getLogger(LoginController.class); + + @Autowired + private WeChatAccessTokenService weChatAccessTokenService; + @Autowired + private WeChatApi weChatApi; + @Autowired + private WxUserSessionService wxUserSessionService; + @Autowired + private UserService userService; + @Value("${rsa.privateKey}") + private String rasPrivateKey; + @Value("${rsa.publicKey}") + private String rasPublicKey; + + @PostMapping("/weChatLogin") + public ResultMessage weChatLogin(@RequestBody LoginVo loginVo) throws Exception{ + String accessToken = weChatAccessTokenService.getAccessToken(); + WeChatAuthInfo sessionInfo = weChatApi.getSessionInfo(loginVo.getLoginCode()); + WxUserSession wxUserSession = new WxUserSession(); + wxUserSession.setSessionKey(sessionInfo.getSession_key()); + wxUserSession.setOpenId(sessionInfo.getOpenid()); + wxUserSession.setUnionid(sessionInfo.getUnionid()); + String thirdSessionKey = UUID.randomUUID().toString().replace("-", ""); + wxUserSession.setThirdSession(thirdSessionKey); + String url = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=" + accessToken; + HttpResponse httpResponse = HttpRequestUtils.sendPost(url, "{\"code\":\"" + loginVo.getPhoneGetCode() + "\"}", null); + String respStr = httpResponse.getRespStr(); + Map respMap = JsonUtils.parseObject(respStr, Map.class); + Map phoneInfo = (Map) respMap.get("phone_info"); + User user = new User(); + if (phoneInfo != null) { + String phoneNumber = (String) phoneInfo.get("purePhoneNumber"); + user.setOpenId(sessionInfo.getOpenid()); + user.setPhone(phoneNumber); + user.setUserType(loginVo.getLoginType()); + userService.upsert(user); + } + wxUserSessionService.upsertWxUserSession(wxUserSession); + return ResultMessage.success(wxUserSession.getThirdSession()); + + } + + @GetMapping("/checkExpiration") + public ResultMessage checkExpiration(HttpServletRequest request) { + String token = request.getHeader("WT"); + return ResultMessage.success(wxUserSessionService.sessionIsExpired(token)); + } + + @GetMapping("/userInfo") + @LoginCheck + public ResultMessage userInfo() throws Exception { + UserContext userContext = UserContext.get(); + if(userContext == null) { + return ResultMessage.success(); + } + WxUserSession wxUserSession = wxUserSessionService.getSessionInfoByThirdSession(userContext.getToken()); + UserVo userVo = userService.findByOpenIdAndUserType(wxUserSession.getOpenId(), userContext.getUserType()); + return ResultMessage.success(userVo); + } + + @PostMapping("/updateVerifyCode") + @LoginCheck + public ResultMessage updateVerifyCode(HttpServletRequest request,@RequestBody AuthInfoVo authInfoVo) throws Exception { + String token = request.getHeader("WT"); + WxUserSession wxUserSession = wxUserSessionService.getSessionInfoByThirdSession(token); + userService.updateAuthInfo(wxUserSession.getOpenId(), + authInfoVo.getUserType(), + "0".equals(authInfoVo.getUserType()) ? RSAUtil.decrypt(authInfoVo.getCode(),rasPrivateKey) : authInfoVo.getCode()); + return ResultMessage.success(); + } +} diff --git a/src/main/java/org/chenyon/user/LoginVo.java b/src/main/java/org/chenyon/user/LoginVo.java new file mode 100644 index 0000000..06df8c2 --- /dev/null +++ b/src/main/java/org/chenyon/user/LoginVo.java @@ -0,0 +1,34 @@ +package org.chenyon.user; + +import org.springframework.web.bind.annotation.RequestParam; + +public class LoginVo { + + private String phoneGetCode; + private String loginCode; + private String loginType; + + public String getPhoneGetCode() { + return phoneGetCode; + } + + public void setPhoneGetCode(String phoneGetCode) { + this.phoneGetCode = phoneGetCode; + } + + public String getLoginCode() { + return loginCode; + } + + public void setLoginCode(String loginCode) { + this.loginCode = loginCode; + } + + public String getLoginType() { + return loginType; + } + + public void setLoginType(String loginType) { + this.loginType = loginType; + } +} diff --git a/src/main/java/org/chenyon/user/User.java b/src/main/java/org/chenyon/user/User.java new file mode 100644 index 0000000..df920cb --- /dev/null +++ b/src/main/java/org/chenyon/user/User.java @@ -0,0 +1,84 @@ +package org.chenyon.user; + +import org.rcy.framework.api.entity.BaseEntity; + +import javax.persistence.Entity; +import javax.persistence.Table; + +@Entity +@Table(name = "USER") +public class User extends BaseEntity { + + private String openId; + private String phone; + private Boolean oaAuth; + private String userType = "0"; + private String cusNo; + private String cardNo; + private String orgNo; + private Boolean subscribeMsg; + + public String getOpenId() { + return openId; + } + + public void setOpenId(String openId) { + this.openId = openId; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public Boolean getOaAuth() { + return oaAuth; + } + + public void setOaAuth(Boolean oaAuth) { + this.oaAuth = oaAuth; + } + + public String getUserType() { + return userType; + } + + public void setUserType(String userType) { + this.userType = userType; + } + + public String getCusNo() { + return cusNo; + } + + public void setCusNo(String cusNo) { + this.cusNo = cusNo; + } + + public String getCardNo() { + return cardNo; + } + + public void setCardNo(String cardNo) { + this.cardNo = cardNo; + } + + public String getOrgNo() { + return orgNo; + } + + public void setOrgNo(String orgNo) { + this.orgNo = orgNo; + } + + public Boolean getSubscribeMsg() { + return subscribeMsg; + } + + public void setSubscribeMsg(Boolean subscribeMsg) { + this.subscribeMsg = subscribeMsg; + } +} diff --git a/src/main/java/org/chenyon/user/UserContext.java b/src/main/java/org/chenyon/user/UserContext.java new file mode 100644 index 0000000..b566fb8 --- /dev/null +++ b/src/main/java/org/chenyon/user/UserContext.java @@ -0,0 +1,70 @@ +package org.chenyon.user; + +public class UserContext { + + private static final ThreadLocal userThreadLocal = new ThreadLocal<>(); + + private String openId; + private String username; + private String cusNo; + private String userType; + private String token; + private String phone; + + // 可扩展其他字段,如角色、权限等 + + public static void set(UserContext context) { + userThreadLocal.set(context); + } + + public static UserContext get() { + return userThreadLocal.get(); + } + + public static void remove() { + userThreadLocal.remove(); + } + + public String getOpenId() { + return openId; + } + + public void setOpenId(String openId) { + this.openId = openId; + } + + public String getCusNo() { + return cusNo; + } + + public void setCusNo(String cusNo) { + this.cusNo = cusNo; + } + + public String getUsername() { return username; } + public void setUsername(String username) { this.username = username; } + + public String getUserType() { + return userType; + } + + public void setUserType(String userType) { + this.userType = userType; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } +} diff --git a/src/main/java/org/chenyon/user/UserDao.java b/src/main/java/org/chenyon/user/UserDao.java new file mode 100644 index 0000000..03a92e6 --- /dev/null +++ b/src/main/java/org/chenyon/user/UserDao.java @@ -0,0 +1,8 @@ +package org.chenyon.user; + +import org.rcy.framework.data.dao.BaseDao; +import org.springframework.web.bind.annotation.RequestParam; + +public interface UserDao extends BaseDao { + User findByOpenIdAndUserType(@RequestParam("openId") String openId,@RequestParam("loginType") String loginType); +} diff --git a/src/main/java/org/chenyon/user/UserDao.xml b/src/main/java/org/chenyon/user/UserDao.xml new file mode 100644 index 0000000..d3000e3 --- /dev/null +++ b/src/main/java/org/chenyon/user/UserDao.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/src/main/java/org/chenyon/user/UserService.java b/src/main/java/org/chenyon/user/UserService.java new file mode 100644 index 0000000..1b97f0c --- /dev/null +++ b/src/main/java/org/chenyon/user/UserService.java @@ -0,0 +1,78 @@ +package org.chenyon.user; + +import org.chenyon.oa.OaCusService; +import org.chenyon.oa.cus.OaCusVo; +import org.rcy.framework.utils.aes.AESUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +public class UserService { + + private static final Logger log = LoggerFactory.getLogger(UserService.class); + @Autowired + private UserDao userDao; + @Autowired + private OaCusService oaCusService; + + public void upsert(User user) { + User oldDbData = userDao.findByOpenIdAndUserType(user.getOpenId(), user.getUserType()); + if(oldDbData != null) { + if(!oldDbData.getPhone().equals(user.getPhone())){ + user.setId(oldDbData.getId()); + userDao.updateByPrimaryKeySelective(user); + } + }else { + userDao.save(user); + } + } + + public UserVo findByOpenIdAndUserType(String openId,String userType) { + User user = userDao.findByOpenIdAndUserType(openId, userType); + OaCusVo cusInfo = null; + try { + if(user.getCusNo() != null) { + cusInfo = oaCusService.getCusInfo(user.getCusNo()); + } + }catch (Exception e) { + log.error(e.getMessage(),e); + } + UserVo userVo = new UserVo(); + BeanUtils.copyProperties(user,userVo); + if(userVo.getOaAuth() == null) { + userVo.setOaAuth(false); + } + if(cusInfo != null) { + userVo.setUserName(cusInfo.getCusName()); + } + return userVo; + } + + public void updateAuthInfo(String openId,String userType,String verifyCode) throws Exception { + //调用oa接口客商信息 + User user = userDao.findByOpenIdAndUserType(openId, userType); + if(user == null) { + throw new Exception("用户不存在"); + } + String cusNo = null; + if("0".equals(userType)) { + CusVo cusVo = oaCusService.matchPersonCus(user.getPhone()); + cusNo = cusVo == null ? null : cusVo.getCusNo(); + user.setCardNo(AESUtils.encrypt(verifyCode,"abc123")); + }else if("1".equals(user.getUserType())) { + CusVo cusVo = oaCusService.matchOrgCus(verifyCode); + cusNo = cusVo == null ? null : cusVo.getCusNo(); + user.setOrgNo(verifyCode); + } + if(cusNo != null) { + user.setCusNo(cusNo); + user.setOaAuth(true); + userDao.updateByPrimaryKeySelective(user); + } + } +} diff --git a/src/main/java/org/chenyon/user/UserVo.java b/src/main/java/org/chenyon/user/UserVo.java new file mode 100644 index 0000000..27ad496 --- /dev/null +++ b/src/main/java/org/chenyon/user/UserVo.java @@ -0,0 +1,61 @@ +package org.chenyon.user; + +import java.io.Serializable; + +public class UserVo implements Serializable { + + private String cusNo; + private String openId; + private String phone; + private Boolean oaAuth; + private String userType = "0"; + private String userName; + + public String getOpenId() { + return openId; + } + + public void setOpenId(String openId) { + this.openId = openId; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public Boolean getOaAuth() { + return oaAuth; + } + + public void setOaAuth(Boolean oaAuth) { + this.oaAuth = oaAuth; + } + + public String getUserType() { + return userType; + } + + public void setUserType(String userType) { + this.userType = userType; + } + + public String getCusNo() { + return cusNo; + } + + public void setCusNo(String cusNo) { + this.cusNo = cusNo; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } +} diff --git a/src/main/java/org/chenyon/utils/HmacSha256Util.java b/src/main/java/org/chenyon/utils/HmacSha256Util.java new file mode 100644 index 0000000..fd7135e --- /dev/null +++ b/src/main/java/org/chenyon/utils/HmacSha256Util.java @@ -0,0 +1,85 @@ +package org.chenyon.utils; + +import org.rcy.framework.utils.aes.AESUtils; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; + +public class HmacSha256Util { + + /** + * 使用HMAC-SHA256算法生成签名(十六进制格式) + * @param data 待签名的数据 + * @param key 密钥 + * @return 十六进制格式的签名结果 + */ + public static String hmacSha256Hex(String data, String key) { + try { + Mac mac = Mac.getInstance("HmacSHA256"); + SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256"); + mac.init(secretKey); + byte[] hash = mac.doFinal(data.getBytes(StandardCharsets.UTF_8)); + return bytesToHex(hash); + } catch (NoSuchAlgorithmException | InvalidKeyException e) { + throw new RuntimeException("HMAC-SHA256计算失败", e); + } + } + + /** + * 使用HMAC-SHA256算法生成签名(Base64格式) + * @param data 待签名的数据 + * @param key 密钥 + * @return Base64格式的签名结果 + */ + public static String hmacSha256Base64(String data, String key) { + try { + Mac mac = Mac.getInstance("HmacSHA256"); + SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256"); + mac.init(secretKey); + byte[] hash = mac.doFinal(data.getBytes(StandardCharsets.UTF_8)); + return Base64.getEncoder().encodeToString(hash); + } catch (NoSuchAlgorithmException | InvalidKeyException e) { + throw new RuntimeException("HMAC-SHA256计算失败", e); + } + } + + /** + * 字节数组转十六进制字符串 + * @param bytes 字节数组 + * @return 十六进制字符串 + */ + private static String bytesToHex(byte[] bytes) { + StringBuilder hexString = new StringBuilder(); + for (byte b : bytes) { + String hex = Integer.toHexString(0xff & b); + if (hex.length() == 1) { + hexString.append('0'); + } + hexString.append(hex); + } + return hexString.toString(); + } + + /** + * 测试方法 + */ + public static void main(String[] args) { + String data = "abcdefg"; + String key = "123"; + // 生成十六进制格式签名 + String hexSignature = hmacSha256Hex(data, key); + System.out.println("HMAC-SHA256 Hex: " + hexSignature); + + // 生成Base64格式签名 + String base64Signature = hmacSha256Base64(data, key); + System.out.println("HMAC-SHA256 Base64: " + base64Signature); + + // 验证签名一致性 + String hexSignature2 = hmacSha256Hex(data, key); + System.out.println("签名验证: " + hexSignature.equals(hexSignature2)); + } +} \ No newline at end of file diff --git a/src/main/java/org/chenyon/utils/RSAUtil.java b/src/main/java/org/chenyon/utils/RSAUtil.java new file mode 100644 index 0000000..6df5d42 --- /dev/null +++ b/src/main/java/org/chenyon/utils/RSAUtil.java @@ -0,0 +1,28 @@ +package org.chenyon.utils; + +import javax.crypto.Cipher; +import java.nio.charset.StandardCharsets; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Base64; + +public class RSAUtil { + + private static final String ALGORITHM = "RSA"; + + public static String decrypt(String encrypted, String privateKeyStr) throws Exception { + byte[] keyBytes = Base64.getDecoder().decode(privateKeyStr); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM); + PrivateKey privateKey = keyFactory.generatePrivate(keySpec); + + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(Cipher.DECRYPT_MODE, privateKey); + + byte[] decodedData = Base64.getDecoder().decode(encrypted); + byte[] decrypted = cipher.doFinal(decodedData); + + return new String(decrypted, StandardCharsets.UTF_8); + } +} \ No newline at end of file diff --git a/src/main/java/org/chenyon/wx/AesException.java b/src/main/java/org/chenyon/wx/AesException.java new file mode 100644 index 0000000..a1267cf --- /dev/null +++ b/src/main/java/org/chenyon/wx/AesException.java @@ -0,0 +1,59 @@ +package org.chenyon.wx; + +@SuppressWarnings("serial") +public class AesException extends Exception { + + public final static int OK = 0; + public final static int ValidateSignatureError = -40001; + public final static int ParseXmlError = -40002; + public final static int ComputeSignatureError = -40003; + public final static int IllegalAesKey = -40004; + public final static int ValidateAppidError = -40005; + public final static int EncryptAESError = -40006; + public final static int DecryptAESError = -40007; + public final static int IllegalBuffer = -40008; + //public final static int EncodeBase64Error = -40009; + //public final static int DecodeBase64Error = -40010; + //public final static int GenReturnXmlError = -40011; + + private int code; + + private static String getMessage(int code) { + switch (code) { + case ValidateSignatureError: + return "签名验证错误"; + case ParseXmlError: + return "xml解析失败"; + case ComputeSignatureError: + return "sha加密生成签名失败"; + case IllegalAesKey: + return "SymmetricKey非法"; + case ValidateAppidError: + return "appid校验失败"; + case EncryptAESError: + return "aes加密失败"; + case DecryptAESError: + return "aes解密失败"; + case IllegalBuffer: + return "解密后得到的buffer非法"; +// case EncodeBase64Error: +// return "base64加密错误"; +// case DecodeBase64Error: +// return "base64解密错误"; +// case GenReturnXmlError: +// return "xml生成失败"; + default: + return null; // cannot be + } + } + + public int getCode() { + return code; + } + + AesException(int code) { + super(getMessage(code)); + this.code = code; + } + +} diff --git a/src/main/java/org/chenyon/wx/ByteGroup.java b/src/main/java/org/chenyon/wx/ByteGroup.java new file mode 100644 index 0000000..e0838d8 --- /dev/null +++ b/src/main/java/org/chenyon/wx/ByteGroup.java @@ -0,0 +1,26 @@ +package org.chenyon.wx; + +import java.util.ArrayList; + +public class ByteGroup { + ArrayList byteContainer = new ArrayList(); + + public byte[] toBytes() { + byte[] bytes = new byte[byteContainer.size()]; + for (int i = 0; i < byteContainer.size(); i++) { + bytes[i] = byteContainer.get(i); + } + return bytes; + } + + public ByteGroup addBytes(byte[] bytes) { + for (byte b : bytes) { + byteContainer.add(b); + } + return this; + } + + public int size() { + return byteContainer.size(); + } +} diff --git a/src/main/java/org/chenyon/wx/PKCS7Encoder.java b/src/main/java/org/chenyon/wx/PKCS7Encoder.java new file mode 100644 index 0000000..0fff389 --- /dev/null +++ b/src/main/java/org/chenyon/wx/PKCS7Encoder.java @@ -0,0 +1,59 @@ +package org.chenyon.wx; + +import java.nio.charset.Charset; +import java.util.Arrays; + +/** + * 提供基于PKCS7算法的加解密接口. + */ +class PKCS7Encoder { + static Charset CHARSET = Charset.forName("utf-8"); + static int BLOCK_SIZE = 32; + + /** + * 获得对明文进行补位填充的字节. + * + * @param count 需要进行填充补位操作的明文字节个数 + * @return 补齐用的字节数组 + */ + static byte[] encode(int count) { + // 计算需要填充的位数 + int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE); + if (amountToPad == 0) { + amountToPad = BLOCK_SIZE; + } + // 获得补位所用的字符 + char padChr = chr(amountToPad); + String tmp = new String(); + for (int index = 0; index < amountToPad; index++) { + tmp += padChr; + } + return tmp.getBytes(CHARSET); + } + + /** + * 删除解密后明文的补位字符 + * + * @param decrypted 解密后的明文 + * @return 删除补位字符后的明文 + */ + static byte[] decode(byte[] decrypted) { + int pad = (int) decrypted[decrypted.length - 1]; + if (pad < 1 || pad > 32) { + pad = 0; + } + return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad); + } + + /** + * 将数字转化成ASCII码对应的字符,用于对明文进行补码 + * + * @param a 需要转化的数字 + * @return 转化得到的字符 + */ + static char chr(int a) { + byte target = (byte) (a & 0xFF); + return (char) target; + } + +} diff --git a/src/main/java/org/chenyon/wx/SHA1.java b/src/main/java/org/chenyon/wx/SHA1.java new file mode 100644 index 0000000..cf0573e --- /dev/null +++ b/src/main/java/org/chenyon/wx/SHA1.java @@ -0,0 +1,53 @@ +package org.chenyon.wx; + +import java.security.MessageDigest; +import java.util.Arrays; + +/** + * SHA1 class + * + * 计算公众平台的消息签名接口. + */ +class SHA1 { + + /** + * 用SHA1算法生成安全签名 + * @param token 票据 + * @param timestamp 时间戳 + * @param nonce 随机字符串 + * @param encrypt 密文 + * @return 安全签名 + * @throws AesException + */ + public static String getSHA1(String token, String timestamp, String nonce, String encrypt) throws AesException + { + try { + String[] array = new String[] { token, timestamp, nonce, encrypt }; + StringBuffer sb = new StringBuffer(); + // 字符串排序 + Arrays.sort(array); + for (int i = 0; i < 4; i++) { + sb.append(array[i]); + } + String str = sb.toString(); + // SHA1签名生成 + MessageDigest md = MessageDigest.getInstance("SHA-1"); + md.update(str.getBytes()); + byte[] digest = md.digest(); + + StringBuffer hexstr = new StringBuffer(); + String shaHex = ""; + for (int i = 0; i < digest.length; i++) { + shaHex = Integer.toHexString(digest[i] & 0xFF); + if (shaHex.length() < 2) { + hexstr.append(0); + } + hexstr.append(shaHex); + } + return hexstr.toString(); + } catch (Exception e) { + e.printStackTrace(); + throw new AesException(AesException.ComputeSignatureError); + } + } +} \ No newline at end of file diff --git a/src/main/java/org/chenyon/wx/WXBizMsgCrypt.java b/src/main/java/org/chenyon/wx/WXBizMsgCrypt.java new file mode 100644 index 0000000..63e1725 --- /dev/null +++ b/src/main/java/org/chenyon/wx/WXBizMsgCrypt.java @@ -0,0 +1,278 @@ +package org.chenyon.wx; + +import org.apache.commons.codec.binary.Base64; + +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.Random; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + + + +/** + * 提供接收和推送给公众平台消息的加解密接口(UTF8编码的字符串). + *
    + *
  1. 第三方回复加密消息给公众平台
  2. + *
  3. 第三方收到公众平台发送的消息,验证消息的安全性,并对消息进行解密。
  4. + *
+ * 说明:异常java.security.InvalidKeyException:illegal Key Size的解决方案 + *
    + *
  1. 在官方网站下载JCE无限制权限策略文件(JDK7的下载地址: + * http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
  2. + *
  3. 下载后解压,可以看到local_policy.jar和US_export_policy.jar以及readme.txt
  4. + *
  5. 如果安装了JRE,将两个jar文件放到%JRE_HOME%\lib\security目录下覆盖原来的文件
  6. + *
  7. 如果安装了JDK,将两个jar文件放到%JDK_HOME%\jre\lib\security目录下覆盖原来文件
  8. + *
+ */ +public class WXBizMsgCrypt { + static Charset CHARSET = Charset.forName("utf-8"); + Base64 base64 = new Base64(); + byte[] aesKey; + String token; + String appId; + + /** + * 构造函数 + * @param token 公众平台上,开发者设置的token + * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey + * @param appId 公众平台appid + * + * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息 + */ + public WXBizMsgCrypt(String token, String encodingAesKey, String appId) throws AesException { + if (encodingAesKey.length() != 43) { + throw new AesException(AesException.IllegalAesKey); + } + + this.token = token; + this.appId = appId; + aesKey = Base64.decodeBase64(encodingAesKey + "="); + } + + // 生成4个字节的网络字节序 + byte[] getNetworkBytesOrder(int sourceNumber) { + byte[] orderBytes = new byte[4]; + orderBytes[3] = (byte) (sourceNumber & 0xFF); + orderBytes[2] = (byte) (sourceNumber >> 8 & 0xFF); + orderBytes[1] = (byte) (sourceNumber >> 16 & 0xFF); + orderBytes[0] = (byte) (sourceNumber >> 24 & 0xFF); + return orderBytes; + } + + // 还原4个字节的网络字节序 + int recoverNetworkBytesOrder(byte[] orderBytes) { + int sourceNumber = 0; + for (int i = 0; i < 4; i++) { + sourceNumber <<= 8; + sourceNumber |= orderBytes[i] & 0xff; + } + return sourceNumber; + } + + // 随机生成16位字符串 + String getRandomStr() { + String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + Random random = new Random(); + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < 16; i++) { + int number = random.nextInt(base.length()); + sb.append(base.charAt(number)); + } + return sb.toString(); + } + + /** + * 对明文进行加密. + * + * @param text 需要加密的明文 + * @return 加密后base64编码的字符串 + * @throws AesException aes加密失败 + */ + String encrypt(String randomStr, String text) throws AesException { + ByteGroup byteCollector = new ByteGroup(); + byte[] randomStrBytes = randomStr.getBytes(CHARSET); + byte[] textBytes = text.getBytes(CHARSET); + byte[] networkBytesOrder = getNetworkBytesOrder(textBytes.length); + byte[] appidBytes = appId.getBytes(CHARSET); + + // randomStr + networkBytesOrder + text + appid + byteCollector.addBytes(randomStrBytes); + byteCollector.addBytes(networkBytesOrder); + byteCollector.addBytes(textBytes); + byteCollector.addBytes(appidBytes); + + // ... + pad: 使用自定义的填充方式对明文进行补位填充 + byte[] padBytes = PKCS7Encoder.encode(byteCollector.size()); + byteCollector.addBytes(padBytes); + + // 获得最终的字节流, 未加密 + byte[] unencrypted = byteCollector.toBytes(); + + try { + // 设置加密模式为AES的CBC模式 + Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); + SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES"); + IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16); + cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv); + + // 加密 + byte[] encrypted = cipher.doFinal(unencrypted); + + // 使用BASE64对加密后的字符串进行编码 + String base64Encrypted = base64.encodeToString(encrypted); + + return base64Encrypted; + } catch (Exception e) { + e.printStackTrace(); + throw new AesException(AesException.EncryptAESError); + } + } + + /** + * 对密文进行解密. + * + * @param text 需要解密的密文 + * @return 解密得到的明文 + * @throws AesException aes解密失败 + */ + String decrypt(String text) throws AesException { + byte[] original; + try { + // 设置解密模式为AES的CBC模式 + Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); + SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES"); + IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16)); + cipher.init(Cipher.DECRYPT_MODE, key_spec, iv); + + // 使用BASE64对密文进行解码 + byte[] encrypted = Base64.decodeBase64(text); + + // 解密 + original = cipher.doFinal(encrypted); + } catch (Exception e) { + e.printStackTrace(); + throw new AesException(AesException.DecryptAESError); + } + + String xmlContent, from_appid; + try { + // 去除补位字符 + byte[] bytes = PKCS7Encoder.decode(original); + + // 分离16位随机字符串,网络字节序和AppId + byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20); + + int xmlLength = recoverNetworkBytesOrder(networkOrder); + + xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET); + from_appid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), + CHARSET); + } catch (Exception e) { + e.printStackTrace(); + throw new AesException(AesException.IllegalBuffer); + } + + // appid不相同的情况 + if (!from_appid.equals(appId)) { + throw new AesException(AesException.ValidateAppidError); + } + return xmlContent; + + } + + /** + * 将公众平台回复用户的消息加密打包. + *
    + *
  1. 对要发送的消息进行AES-CBC加密
  2. + *
  3. 生成安全签名
  4. + *
  5. 将消息密文和安全签名打包成xml格式
  6. + *
+ * + * @param replyMsg 公众平台待回复用户的消息,xml格式的字符串 + * @param timeStamp 时间戳,可以自己生成,也可以用URL参数的timestamp + * @param nonce 随机串,可以自己生成,也可以用URL参数的nonce + * + * @return 加密后的可以直接回复用户的密文,包括msg_signature, timestamp, nonce, encrypt的xml格式的字符串 + * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息 + */ + public String encryptMsg(String replyMsg, String timeStamp, String nonce) throws AesException { + // 加密 + String encrypt = encrypt(getRandomStr(), replyMsg); + + // 生成安全签名 + if (timeStamp == "") { + timeStamp = Long.toString(System.currentTimeMillis()); + } + + String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt); + + // System.out.println("发送给平台的签名是: " + signature[1].toString()); + // 生成发送的xml + String result = XMLParse.generate(encrypt, signature, timeStamp, nonce); + return result; + } + + /** + * 检验消息的真实性,并且获取解密后的明文. + *
    + *
  1. 利用收到的密文生成安全签名,进行签名验证
  2. + *
  3. 若验证通过,则提取xml中的加密消息
  4. + *
  5. 对消息进行解密
  6. + *
+ * + * @param msgSignature 签名串,对应URL参数的msg_signature + * @param timeStamp 时间戳,对应URL参数的timestamp + * @param nonce 随机串,对应URL参数的nonce + * @param postData 密文,对应POST请求的数据 + * + * @return 解密后的原文 + * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息 + */ + public String decryptMsg(String msgSignature, String timeStamp, String nonce, String postData) + throws AesException { + + // 密钥,公众账号的app secret + // 提取密文 + Object[] encrypt = XMLParse.extract(postData); + + // 验证安全签名 + String signature = SHA1.getSHA1(token, timeStamp, nonce, encrypt[1].toString()); + + // 和URL中的签名比较是否相等 + // System.out.println("第三方收到URL中的签名:" + msg_sign); + // System.out.println("第三方校验签名:" + signature); + if (!signature.equals(msgSignature)) { + throw new AesException(AesException.ValidateSignatureError); + } + + // 解密 + String result = decrypt(encrypt[1].toString()); + return result; + } + + /** + * 验证URL + * @param msgSignature 签名串,对应URL参数的msg_signature + * @param timeStamp 时间戳,对应URL参数的timestamp + * @param nonce 随机串,对应URL参数的nonce + * @param echoStr 随机串,对应URL参数的echostr + * + * @return 解密之后的echostr + * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息 + */ + public String verifyUrl(String msgSignature, String timeStamp, String nonce, String echoStr) + throws AesException { + String signature = SHA1.getSHA1(token, timeStamp, nonce, echoStr); + + if (!signature.equals(msgSignature)) { + throw new AesException(AesException.ValidateSignatureError); + } + + String result = decrypt(echoStr); + return result; + } + +} \ No newline at end of file diff --git a/src/main/java/org/chenyon/wx/WeChatAccessTokenService.java b/src/main/java/org/chenyon/wx/WeChatAccessTokenService.java new file mode 100644 index 0000000..0f7bd3b --- /dev/null +++ b/src/main/java/org/chenyon/wx/WeChatAccessTokenService.java @@ -0,0 +1,71 @@ +package org.chenyon.wx; + +import org.chenyon.cache.WxTokenCache; +import org.rcy.framework.utils.json.JsonUtils; +import org.rcy.framework.utils.net.HttpRequestUtils; +import org.rcy.framework.utils.net.HttpResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 微信小程序AccessToken 服务 + */ + +@Service +public class WeChatAccessTokenService { + + private static final Logger log = LoggerFactory.getLogger(WeChatAccessTokenService.class); + @Value("${wx.appId}") + private String miniProgramAppId; + @Value("${wx.appSecret}") + private String miniProgramAppSecret; + private ConcurrentHashMap cache = new ConcurrentHashMap<>(); + + + /** + * 获取 AccessToken,优先返回缓存 + */ + public String getAccessToken() { + long now = System.currentTimeMillis(); + String appId = miniProgramAppId; + String appSecret = miniProgramAppSecret; + // 缓存有效 + WxTokenCache accessToken = cache.get(appId); + if (accessToken != null && now < accessToken.getExpireTime()) { + return accessToken.getToken(); + } + // 请求微信获取 access_token + String url = String.format( + "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s", + appId, appSecret); + try { + Map headers = new HashMap<>(); + headers.put("grant_type", "client_credential"); + headers.put("appid", appId); + headers.put("secret", appSecret); + HttpResponse response = HttpRequestUtils.sendGet(url, headers); + Map respMap = JsonUtils.parseObject(response.getRespStr(), Map.class); + if (respMap.get("errcode") != null) { + throw new IOException("获取 access_token 请求失败: " + respMap.get("errmsg")); + } + String tokenStr = respMap.get("access_token") + ""; + long ttl = Long.parseLong(respMap.get("expires_in") + ""); + WxTokenCache tokenCache = new WxTokenCache(); + tokenCache.setToken(tokenStr); + tokenCache.setExpireTime(now + (ttl - 20000)); + cache.put(appId, tokenCache); + return tokenStr; + }catch (Exception e){ + log.error(e.getMessage(),e); + } + return null; + } + +} diff --git a/src/main/java/org/chenyon/wx/WeChatApi.java b/src/main/java/org/chenyon/wx/WeChatApi.java new file mode 100644 index 0000000..c1bb680 --- /dev/null +++ b/src/main/java/org/chenyon/wx/WeChatApi.java @@ -0,0 +1,31 @@ +package org.chenyon.wx; + +import org.rcy.framework.utils.json.JsonUtils; +import org.rcy.framework.utils.net.HttpRequestUtils; +import org.rcy.framework.utils.net.HttpResponse; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.util.Map; + +@Service +public class WeChatApi { + + @Value("${wx.appId}") + private String miniProgramAppId; + @Value("${wx.appSecret}") + private String miniProgramAppSecret; + + public WeChatAuthInfo getSessionInfo(String code) throws Exception { + String url = "https://api.weixin.qq.com/sns/jscode2session"; + url += "?appid=" + miniProgramAppId + "&secret=" + miniProgramAppSecret + "&js_code=" + code + "&grant_type=authorization_code"; + HttpResponse httpResponse = HttpRequestUtils.sendGet(url, null); + if(httpResponse.getCode() == 200) { + String httpResponseStr = httpResponse.getRespStr(); + WeChatAuthInfo weChatAuthInfo = JsonUtils.parseObject(httpResponseStr, WeChatAuthInfo.class); + return weChatAuthInfo; + }else { + return null; + } + } +} diff --git a/src/main/java/org/chenyon/wx/WeChatAuthInfo.java b/src/main/java/org/chenyon/wx/WeChatAuthInfo.java new file mode 100644 index 0000000..d12f63b --- /dev/null +++ b/src/main/java/org/chenyon/wx/WeChatAuthInfo.java @@ -0,0 +1,31 @@ +package org.chenyon.wx; + +public class WeChatAuthInfo { + private String openid; + private String session_key; + private String unionid; + + public String getOpenid() { + return openid; + } + + public void setOpenid(String openid) { + this.openid = openid; + } + + public String getSession_key() { + return session_key; + } + + public void setSession_key(String session_key) { + this.session_key = session_key; + } + + public String getUnionid() { + return unionid; + } + + public void setUnionid(String unionid) { + this.unionid = unionid; + } +} diff --git a/src/main/java/org/chenyon/wx/WxUserSession.java b/src/main/java/org/chenyon/wx/WxUserSession.java new file mode 100644 index 0000000..9166817 --- /dev/null +++ b/src/main/java/org/chenyon/wx/WxUserSession.java @@ -0,0 +1,72 @@ +package org.chenyon.wx; + +import org.rcy.framework.api.entity.BaseEntity; + +import javax.persistence.Entity; +import javax.persistence.Table; +import java.util.Date; + +@Entity +@Table(name = "WX_USER_SESSION") +public class WxUserSession extends BaseEntity { + + private String openId; + + private String sessionKey; + + private String thirdSession; + + private Date createTime; + + private Date updateTime; + + private String unionid; + + public String getOpenId() { + return openId; + } + + public void setOpenId(String openId) { + this.openId = openId; + } + + public String getSessionKey() { + return sessionKey; + } + + public void setSessionKey(String sessionKey) { + this.sessionKey = sessionKey; + } + + public String getThirdSession() { + return thirdSession; + } + + public void setThirdSession(String thirdSession) { + this.thirdSession = thirdSession; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } + + public String getUnionid() { + return unionid; + } + + public void setUnionid(String unionid) { + this.unionid = unionid; + } +} diff --git a/src/main/java/org/chenyon/wx/WxUserSessionDao.java b/src/main/java/org/chenyon/wx/WxUserSessionDao.java new file mode 100644 index 0000000..b73c5b4 --- /dev/null +++ b/src/main/java/org/chenyon/wx/WxUserSessionDao.java @@ -0,0 +1,9 @@ +package org.chenyon.wx; + +import org.apache.ibatis.annotations.Param; +import org.rcy.framework.data.dao.BaseDao; + +public interface WxUserSessionDao extends BaseDao { + WxUserSession findByOpenId(@Param("openId") String openId); + WxUserSession findByThirdSession(String thirdSession); +} diff --git a/src/main/java/org/chenyon/wx/WxUserSessionDao.xml b/src/main/java/org/chenyon/wx/WxUserSessionDao.xml new file mode 100644 index 0000000..48cad2e --- /dev/null +++ b/src/main/java/org/chenyon/wx/WxUserSessionDao.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/org/chenyon/wx/WxUserSessionService.java b/src/main/java/org/chenyon/wx/WxUserSessionService.java new file mode 100644 index 0000000..1787c41 --- /dev/null +++ b/src/main/java/org/chenyon/wx/WxUserSessionService.java @@ -0,0 +1,79 @@ +package org.chenyon.wx; + +import org.chenyon.oa.OaCusService; +import org.chenyon.user.CusVo; +import org.chenyon.utils.HmacSha256Util; +import org.rcy.framework.utils.json.JsonUtils; +import org.rcy.framework.utils.net.HttpRequestUtils; +import org.rcy.framework.utils.net.HttpResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Map; + +@Service +@Transactional +public class WxUserSessionService { + + private static final Logger log = LoggerFactory.getLogger(WxUserSessionService.class); + + @Autowired + private WxUserSessionDao wxUserSessionDao; + @Autowired + private WeChatAccessTokenService tokenService; + @Autowired + private OaCusService oaCusService; + + public void upsertWxUserSession(WxUserSession wxUserSession) { + WxUserSession dbWxUserSession = wxUserSessionDao.findByOpenId(wxUserSession.getOpenId()); + if(dbWxUserSession == null) { + wxUserSessionDao.save(wxUserSession); + }else { + wxUserSession.setId(dbWxUserSession.getId()); + wxUserSessionDao.updateByPrimaryKeySelective(wxUserSession); + } + } + + public WxUserSession getSessionInfoByThirdSession(String thirdSession) { + WxUserSession wxUserSession = wxUserSessionDao.findByThirdSession(thirdSession); + return wxUserSession; + } + + public Boolean sessionIsExpired(String thirdSession) { + try { + WxUserSession session = wxUserSessionDao.findByThirdSession(thirdSession); + if(session == null) { + return true; + } + String accessToken = tokenService.getAccessToken(); + String url = "https://api.weixin.qq.com/wxa/checksession?access_token=" + accessToken + "&signature=" + HmacSha256Util.hmacSha256Hex("",session.getSessionKey()) + "&openid=" + session.getOpenId() +"&sig_method=hmac_sha256"; + HttpResponse response = HttpRequestUtils.sendGet(url, null); + if(response.getCode() != 200) { + return true; + } + Map map = JsonUtils.parseObject(response.getRespStr(), Map.class); + if((Integer) map.get("errcode") == 0) { + return false; + }else { + return true; + } + }catch (Exception e) { + log.error(e.getMessage(),e); + } + return true; + } + + public CusVo matchCus(String phone, String orgNo, String loginType) throws Exception { + //调用oa接口客商信息 + CusVo cusNo = null; + if("person".equals(loginType)) { + cusNo = oaCusService.matchPersonCus(phone); + }else if("compnay".equals(loginType)) { + cusNo = oaCusService.matchOrgCus(orgNo); + } + return cusNo; + } +} diff --git a/src/main/java/org/chenyon/wx/XMLParse.java b/src/main/java/org/chenyon/wx/XMLParse.java new file mode 100644 index 0000000..543a74b --- /dev/null +++ b/src/main/java/org/chenyon/wx/XMLParse.java @@ -0,0 +1,64 @@ +package org.chenyon.wx; + +import java.io.StringReader; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; + +/** + * XMLParse class + * + * 提供提取消息格式中的密文及生成回复消息格式的接口. + */ +public class XMLParse { + + /** + * 提取出xml数据包中的加密消息 + * @param xmltext 待提取的xml字符串 + * @return 提取出的加密消息字符串 + * @throws AesException + */ + public static Object[] extract(String xmltext) throws AesException { + Object[] result = new Object[3]; + try { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db = dbf.newDocumentBuilder(); + StringReader sr = new StringReader(xmltext); + InputSource is = new InputSource(sr); + Document document = db.parse(is); + + Element root = document.getDocumentElement(); + NodeList nodelist1 = root.getElementsByTagName("Encrypt"); + NodeList nodelist2 = root.getElementsByTagName("ToUserName"); + result[0] = 0; + result[1] = nodelist1.item(0).getTextContent(); + result[2] = nodelist2.item(0).getTextContent(); + return result; + } catch (Exception e) { + e.printStackTrace(); + throw new AesException(AesException.ParseXmlError); + } + } + + /** + * 生成xml消息 + * @param encrypt 加密后的消息密文 + * @param signature 安全签名 + * @param timestamp 时间戳 + * @param nonce 随机字符串 + * @return 生成的xml字符串 + */ + public static String generate(String encrypt, String signature, String timestamp, String nonce) { + + String format = "\n" + "\n" + + "\n" + + "%3$s\n" + "\n" + ""; + return String.format(format, encrypt, signature, timestamp, nonce); + + } +} \ No newline at end of file diff --git a/src/main/scripts/shutdown.bat b/src/main/scripts/shutdown.bat new file mode 100644 index 0000000..0c4ec62 --- /dev/null +++ b/src/main/scripts/shutdown.bat @@ -0,0 +1,40 @@ +@echo off +REM --------------------------------------------- +REM Spring Boot 停止脚本 (Windows) +REM --------------------------------------------- + +setlocal +set APP_NAME=..\qichenrent.jar + +echo Stopping %APP_NAME% ... + +REM 查找 java 进程里运行的 jar +for /f "tokens=2" %%i in ('jps -l ^| findstr /i %APP_NAME%') do ( + set PID=%%i +) + +if "%PID%"=="" ( + echo No running process found for %APP_NAME%. + goto :EOF +) + +REM 尝试优雅停止 +echo Attempting to stop process PID %PID% ... +taskkill /PID %PID% /T + +REM 检查是否还在运行 +timeout /t 5 /nobreak > nul + +for /f "tokens=2" %%i in ('jps -l ^| findstr /i %APP_NAME%') do ( + set PID=%%i +) + +if not "%PID%"=="" ( + REM 强制杀掉 + echo Process still running. Force killing PID %PID% ... + taskkill /PID %PID% /F /T +) else ( + echo Application stopped successfully. +) + +endlocal \ No newline at end of file diff --git a/src/main/scripts/shutdown.sh b/src/main/scripts/shutdown.sh new file mode 100644 index 0000000..f3d1117 --- /dev/null +++ b/src/main/scripts/shutdown.sh @@ -0,0 +1,47 @@ +#!/bin/bash +# --------------------------------------------- +# Spring Boot 停止脚本 +# --------------------------------------------- + +PID_FILE=/usr/local/qichenrent/qichenrent.pid +WAIT_TIME=10 # 等待秒数 + +# 检查 PID 文件是否存在 +if [ ! -f $PID_FILE ]; then + echo "PID file not found at $PID_FILE. Application may not be running." + exit 0 +fi + +PID=$(cat $PID_FILE) +echo "Stopping application, PID=$PID ..." + +# 检查进程是否存在 +if ! ps -p $PID > /dev/null; then + echo "Process $PID not found. Cleaning up PID file." + rm -f $PID_FILE + exit 0 +fi + +# 发送 SIGTERM 正常关闭 +kill $PID + +# 等待应用优雅退出 +for i in $(seq 1 $WAIT_TIME); do + if ! ps -p $PID > /dev/null; then + echo "Application stopped gracefully." + rm -f $PID_FILE + exit 0 + fi + echo "Waiting for application to stop... ($i/$WAIT_TIME)" + sleep 1 +done + +# 如果还没停,强制杀掉 +if ps -p $PID > /dev/null; then + echo "Application did not stop within $WAIT_TIME seconds, force killing..." + kill -9 $PID +fi + +# 清理 PID 文件 +rm -f $PID_FILE +echo "Application stopped." diff --git a/src/main/scripts/startup.bat b/src/main/scripts/startup.bat new file mode 100644 index 0000000..c6192af --- /dev/null +++ b/src/main/scripts/startup.bat @@ -0,0 +1,37 @@ +@echo off +REM --------------------------------------------- +REM Spring Boot 启动脚本 (Windows) +REM 控制台窗口保持打开 +REM --------------------------------------------- + +setlocal + +REM ---- 配置 ---- +set APP_NAME=..\qichenrent.jar +set CONFIG_DIR=..\config +set LOG_DIR=..\logs +set JAVA_OPTS=-Xms512m -Xmx1024m -Dfile.encoding=UTF-8 + +REM 创建日志目录 +if not exist %LOG_DIR% ( + mkdir %LOG_DIR% +) + +REM 检查 jar 是否存在 +if not exist %APP_NAME% ( + echo ERROR: %APP_NAME% not found! + pause + exit /b 1 +) + +echo Starting %APP_NAME% ... + +REM 直接在当前窗口运行,不使用 start +java %JAVA_OPTS% -jar %APP_NAME% --spring.config.location=%CONFIG_DIR%\ + +REM 程序退出后保持窗口 +echo. +echo Application has exited. Press any key to close this window. +pause + +endlocal diff --git a/src/main/scripts/startup.sh b/src/main/scripts/startup.sh new file mode 100644 index 0000000..75a5266 --- /dev/null +++ b/src/main/scripts/startup.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +APP_NAME=/usr/local/qichenrent/qichenrent.jar +CONFIG_DIR=file:/usr/local/qichenrent/config/ +LOG_DIR=/usr/local/qichenrent/logs +PID_FILE=/usr/local/qichenrent/qichenrent.pid +JAVA_OPTS="-Xms512m -Xmx1024m -Dfile.encoding=UTF-8" + +mkdir -p $LOG_DIR + +echo "Starting $APP_NAME ..." + +nohup java $JAVA_OPTS -jar $APP_NAME \ +--spring.config.additional-location=$CONFIG_DIR \ +> $LOG_DIR/console.log 2>&1 & + +echo $! > $PID_FILE + +echo "Application started, PID=$(cat $PID_FILE)"